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.
This commit is contained in:
akwizgran
2011-09-21 17:51:17 +01:00
parent fadd95ae49
commit 8dd7ec93e7
3 changed files with 30 additions and 9 deletions

View File

@@ -69,8 +69,11 @@ public interface DatabaseComponent {
/** Adds a locally generated private message to the database. */ /** Adds a locally generated private message to the database. */
void addLocalPrivateMessage(Message m, ContactId c) throws DbException; 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; IOException;
/** /**

View File

@@ -161,7 +161,7 @@ interface Database<T> {
* Returns the IDs of any batches received from the given contact that need * Returns the IDs of any batches received from the given contact that need
* to be acknowledged. * to be acknowledged.
* <p> * <p>
* Locking: contacts read, messageStatuses write. * Locking: contacts read, messageStatuses read.
*/ */
Collection<BatchId> getBatchesToAck(T txn, ContactId c) throws DbException; Collection<BatchId> getBatchesToAck(T txn, ContactId c) throws DbException;

View File

@@ -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 { IOException {
contactLock.readLock().lock(); contactLock.readLock().lock();
try { try {
if(!containsContact(c)) throw new NoSuchContactException(); if(!containsContact(c)) throw new NoSuchContactException();
messageStatusLock.writeLock().lock(); Collection<BatchId> sent = new ArrayList<BatchId>();
messageStatusLock.readLock().lock();
try { try {
T txn = db.startTransaction(); T txn = db.startTransaction();
try { try {
Collection<BatchId> acks = db.getBatchesToAck(txn, c); Collection<BatchId> acks = db.getBatchesToAck(txn, c);
Collection<BatchId> sent = new ArrayList<BatchId>(); for(BatchId b : acks) {
for(BatchId b : acks) if(a.writeBatchId(b)) sent.add(b); if(!a.writeBatchId(b)) break;
a.finish(); sent.add(b);
db.removeBatchesToAck(txn, c, sent); }
if(LOG.isLoggable(Level.FINE)) if(LOG.isLoggable(Level.FINE))
LOG.fine("Added " + acks.size() + " acks"); LOG.fine("Added " + acks.size() + " acks");
db.commitTransaction(txn); db.commitTransaction(txn);
@@ -401,6 +402,23 @@ DatabaseCleaner.Callback {
db.abortTransaction(txn); db.abortTransaction(txn);
throw e; 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 { } finally {
messageStatusLock.writeLock().unlock(); messageStatusLock.writeLock().unlock();
} }