From 8dd7ec93e7bffa08b542c9fbc9805fde3763166d Mon Sep 17 00:00:00 2001
From: akwizgran <akwizgran@users.sourceforge.net>
Date: Wed, 21 Sep 2011 17:51:17 +0100
Subject: [PATCH] DatabaseComponent.generateAck() now returns a boolean.

The return value indicates whether any batch IDs were written.
AckWriter.finish() and Database.removeBatchesToAck() are only called
if at least one batch ID was written.
---
 .../sf/briar/api/db/DatabaseComponent.java    |  7 +++--
 components/net/sf/briar/db/Database.java      |  2 +-
 .../sf/briar/db/DatabaseComponentImpl.java    | 30 +++++++++++++++----
 3 files changed, 30 insertions(+), 9 deletions(-)

diff --git a/api/net/sf/briar/api/db/DatabaseComponent.java b/api/net/sf/briar/api/db/DatabaseComponent.java
index 4228f41062..8f54a123fe 100644
--- a/api/net/sf/briar/api/db/DatabaseComponent.java
+++ b/api/net/sf/briar/api/db/DatabaseComponent.java
@@ -69,8 +69,11 @@ public interface DatabaseComponent {
 	/** Adds a locally generated private message to the database. */
 	void addLocalPrivateMessage(Message m, ContactId c) throws DbException;
 
-	/** Generates an acknowledgement for the given contact. */
-	void generateAck(ContactId c, AckWriter a) throws DbException,
+	/**
+	 * Generates an acknowledgement for the given contact.
+	 * @return True if any batch IDs were added to the acknowledgement.
+	 */
+	boolean generateAck(ContactId c, AckWriter a) throws DbException,
 	IOException;
 
 	/**
diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java
index f6e679a0ac..99809c23a9 100644
--- a/components/net/sf/briar/db/Database.java
+++ b/components/net/sf/briar/db/Database.java
@@ -161,7 +161,7 @@ interface Database<T> {
 	 * Returns the IDs of any batches received from the given contact that need
 	 * to be acknowledged.
 	 * <p>
-	 * Locking: contacts read, messageStatuses write.
+	 * Locking: contacts read, messageStatuses read.
 	 */
 	Collection<BatchId> getBatchesToAck(T txn, ContactId c) throws DbException;
 
diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java
index 8b8c7d5c98..a0f7a3b2fc 100644
--- a/components/net/sf/briar/db/DatabaseComponentImpl.java
+++ b/components/net/sf/briar/db/DatabaseComponentImpl.java
@@ -377,20 +377,21 @@ DatabaseCleaner.Callback {
 		}
 	}
 
-	public void generateAck(ContactId c, AckWriter a) throws DbException,
+	public boolean generateAck(ContactId c, AckWriter a) throws DbException,
 	IOException {
 		contactLock.readLock().lock();
 		try {
 			if(!containsContact(c)) throw new NoSuchContactException();
-			messageStatusLock.writeLock().lock();
+			Collection<BatchId> sent = new ArrayList<BatchId>();
+			messageStatusLock.readLock().lock();
 			try {
 				T txn = db.startTransaction();
 				try {
 					Collection<BatchId> acks = db.getBatchesToAck(txn, c);
-					Collection<BatchId> sent = new ArrayList<BatchId>();
-					for(BatchId b : acks) if(a.writeBatchId(b)) sent.add(b);
-					a.finish();
-					db.removeBatchesToAck(txn, c, sent);
+					for(BatchId b : acks) {
+						if(!a.writeBatchId(b)) break;
+						sent.add(b);
+					}
 					if(LOG.isLoggable(Level.FINE))
 						LOG.fine("Added " + acks.size() + " acks");
 					db.commitTransaction(txn);
@@ -401,6 +402,23 @@ DatabaseCleaner.Callback {
 					db.abortTransaction(txn);
 					throw e;
 				}
+			} finally {
+				messageStatusLock.readLock().unlock();
+			}
+			// Record the contents of the ack, unless it's empty
+			if(sent.isEmpty()) return false;
+			a.finish();
+			messageStatusLock.writeLock().lock();
+			try {
+				T txn = db.startTransaction();
+				try {
+					db.removeBatchesToAck(txn, c, sent);
+					db.commitTransaction(txn);
+					return true;
+				} catch(DbException e) {
+					db.abortTransaction(txn);
+					throw e;
+				}
 			} finally {
 				messageStatusLock.writeLock().unlock();
 			}
-- 
GitLab