From 718bd8c5401657c8965e36395fffa9dbc10df33b Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Fri, 14 Oct 2011 20:07:37 +0100
Subject: [PATCH] Moved DB accesses outside the lock.

---
 .../transport/stream/StreamConnection.java    | 51 +++++++++++--------
 1 file changed, 29 insertions(+), 22 deletions(-)

diff --git a/components/net/sf/briar/transport/stream/StreamConnection.java b/components/net/sf/briar/transport/stream/StreamConnection.java
index b6e619ca96..057459e754 100644
--- a/components/net/sf/briar/transport/stream/StreamConnection.java
+++ b/components/net/sf/briar/transport/stream/StreamConnection.java
@@ -113,26 +113,32 @@ abstract class StreamConnection implements Runnable, DatabaseListener {
 						notifyAll();
 					}
 				} else if(proto.hasRequest()) {
+					Collection<MessageId> offered, seen, unseen;
 					Request r = proto.readRequest();
 					synchronized(this) {
+						if(outgoingOffer == null)
+							throw new IOException("Unexpected request packet");
+						offered = outgoingOffer;
+					}
+					// Work out which messages were requested
+					BitSet b = r.getBitmap();
+					seen = new ArrayList<MessageId>();
+					unseen = new LinkedList<MessageId>();
+					int i = 0;
+					for(MessageId m : offered) {
+						if(b.get(i++)) unseen.add(m);
+						else seen.add(m);
+					}
+					synchronized(this) {
+						assert outgoingOffer != null;
+						if(requested != null && !requested.isEmpty())
+							throw new IOException("Unexpected request packet");
+						outgoingOffer = null;
+						requested = unseen;
 						writerFlags |= Flags.REQUEST_RECEIVED;
-						BitSet b = r.getBitmap();
-						// FIXME: Do we need to check the size of the BitSet?
-						if(outgoingOffer == null) throw new IOException();
-						if(requested != null) throw new IOException();
-						// Work out which messages were requested
-						requested = new LinkedList<MessageId>();
-						Collection<MessageId> seen = new ArrayList<MessageId>();
-						int i = 0;
-						for(MessageId m : outgoingOffer) {
-							if(b.get(i)) requested.add(m);
-							else seen.add(m);
-							i++;
-						}
-						// FIXME: Can this be done outside the lock?
-						db.setSeen(contactId, seen);
 						notifyAll();
 					}
+					db.setSeen(contactId, seen);
 				} else if(proto.hasSubscriptionUpdate()) {
 					SubscriptionUpdate s = proto.readSubscriptionUpdate();
 					db.receiveSubscriptionUpdate(contactId, s);
@@ -216,7 +222,7 @@ abstract class StreamConnection implements Runnable, DatabaseListener {
 						sendRequest(requestWriter);
 					}
 					if((flags & Flags.REQUEST_RECEIVED) != 0) {
-						throw new IOException();
+						throw new IOException("Unexpected request packet");
 					}
 					break;
 
@@ -285,7 +291,7 @@ abstract class StreamConnection implements Runnable, DatabaseListener {
 						sendRequest(requestWriter);
 					}
 					if((flags & Flags.REQUEST_RECEIVED) != 0) {
-						throw new IOException();
+						throw new IOException("Unexpected request packet");
 					}
 					// Send a batch if possible, otherwise an offer
 					if(!sendBatch(batchWriter)) state = State.SEND_OFFER;
@@ -308,21 +314,22 @@ abstract class StreamConnection implements Runnable, DatabaseListener {
 	}
 
 	private boolean sendBatch(BatchWriter b) throws DbException, IOException {
+		Collection<MessageId> ids;
 		synchronized(this) {
 			assert outgoingOffer == null;
 			assert requested != null;
-			// FIXME: Can this be done outside the lock?
-			boolean anyAdded = db.generateBatch(contactId, b, requested);
-			if(!anyAdded) requested = null;
-			return anyAdded;
+			ids = requested;
 		}
+		boolean anyAdded = db.generateBatch(contactId, b, ids);
+		if(!anyAdded) ids.clear();
+		return anyAdded;
 	}
 
 	private boolean sendOffer(OfferWriter o) throws DbException, IOException {
 		Collection<MessageId> ids = db.generateOffer(contactId, o);
 		synchronized(this) {
 			assert outgoingOffer == null;
-			assert requested == null;
+			assert requested == null || requested.isEmpty();
 			outgoingOffer = ids;
 		}
 		boolean anyOffered = !ids.isEmpty();
-- 
GitLab