Added DatabaseComponent.setSeen() for handling requests.

Also moved IO out of the lock in receiveOffer().
This commit is contained in:
akwizgran
2011-09-23 16:06:14 +01:00
parent ba1c61810d
commit b470afb4ef
3 changed files with 73 additions and 6 deletions

View File

@@ -171,6 +171,9 @@ public interface DatabaseComponent {
/** Records the user's rating for the given author. */ /** Records the user's rating for the given author. */
void setRating(AuthorId a, Rating r) throws DbException; void setRating(AuthorId a, Rating r) throws DbException;
/** Records the given messages as having been seen by the given contact. */
void setSeen(ContactId c, Collection<MessageId> seen) throws DbException;
/** /**
* Sets the configuration for the transport with the given name, replacing * Sets the configuration for the transport with the given name, replacing
* any existing configuration for that transport. * any existing configuration for that transport.

View File

@@ -963,6 +963,8 @@ DatabaseCleaner.Callback {
public void receiveOffer(ContactId c, Offer o, RequestWriter r) public void receiveOffer(ContactId c, Offer o, RequestWriter r)
throws DbException, IOException { throws DbException, IOException {
Collection<MessageId> offered;
BitSet request;
contactLock.readLock().lock(); contactLock.readLock().lock();
try { try {
if(!containsContact(c)) throw new NoSuchContactException(); if(!containsContact(c)) throw new NoSuchContactException();
@@ -972,10 +974,10 @@ DatabaseCleaner.Callback {
try { try {
subscriptionLock.readLock().lock(); subscriptionLock.readLock().lock();
try { try {
Collection<MessageId> offered = o.getMessageIds();
BitSet request = new BitSet(offered.size());
T txn = db.startTransaction(); T txn = db.startTransaction();
try { try {
offered = o.getMessageIds();
request = new BitSet(offered.size());
Iterator<MessageId> it = offered.iterator(); Iterator<MessageId> it = offered.iterator();
for(int i = 0; it.hasNext(); i++) { for(int i = 0; it.hasNext(); i++) {
// If the message is not in the database, or if // If the message is not in the database, or if
@@ -989,7 +991,6 @@ DatabaseCleaner.Callback {
db.abortTransaction(txn); db.abortTransaction(txn);
throw e; throw e;
} }
r.writeRequest(request, offered.size());
} finally { } finally {
subscriptionLock.readLock().unlock(); subscriptionLock.readLock().unlock();
} }
@@ -1002,6 +1003,7 @@ DatabaseCleaner.Callback {
} finally { } finally {
contactLock.readLock().unlock(); contactLock.readLock().unlock();
} }
r.writeRequest(request, offered.size());
} }
public void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s) public void receiveSubscriptionUpdate(ContactId c, SubscriptionUpdate s)
@@ -1147,6 +1149,41 @@ DatabaseCleaner.Callback {
} }
} }
public void setSeen(ContactId c, Collection<MessageId> seen)
throws DbException {
contactLock.readLock().lock();
try {
if(!containsContact(c)) throw new NoSuchContactException();
messageLock.readLock().lock();
try {
messageStatusLock.writeLock().lock();
try {
subscriptionLock.readLock().lock();
try {
T txn = db.startTransaction();
try {
for(MessageId m : seen) {
db.setStatus(txn, c, m, Status.SEEN);
}
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
subscriptionLock.readLock().unlock();
}
} finally {
messageStatusLock.writeLock().unlock();
}
} finally {
messageLock.readLock().unlock();
}
} finally {
contactLock.readLock().unlock();
}
}
/** /**
* Updates the sendability of all messages written by the given author, and * Updates the sendability of all messages written by the given author, and
* the ancestors of those messages if necessary. * the ancestors of those messages if necessary.

View File

@@ -586,11 +586,11 @@ public abstract class DatabaseComponentTest extends TestCase {
final TransportUpdate transportsUpdate = context.mock(TransportUpdate.class); final TransportUpdate transportsUpdate = context.mock(TransportUpdate.class);
context.checking(new Expectations() {{ context.checking(new Expectations() {{
// Check whether the contact is still in the DB (which it's not) // Check whether the contact is still in the DB (which it's not)
exactly(17).of(database).startTransaction(); exactly(18).of(database).startTransaction();
will(returnValue(txn)); will(returnValue(txn));
exactly(17).of(database).containsContact(txn, contactId); exactly(18).of(database).containsContact(txn, contactId);
will(returnValue(false)); will(returnValue(false));
exactly(17).of(database).commitTransaction(txn); exactly(18).of(database).commitTransaction(txn);
}}); }});
DatabaseComponent db = createDatabaseComponent(database, cleaner); DatabaseComponent db = createDatabaseComponent(database, cleaner);
@@ -680,6 +680,11 @@ public abstract class DatabaseComponentTest extends TestCase {
fail(); fail();
} catch(NoSuchContactException expected) {} } catch(NoSuchContactException expected) {}
try {
db.setSeen(contactId, Collections.singleton(messageId));
fail();
} catch(NoSuchContactException expected) {}
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@@ -1488,4 +1493,26 @@ public abstract class DatabaseComponentTest extends TestCase {
context.assertIsSatisfied(); context.assertIsSatisfied();
} }
@Test
public void testSetSeen() throws Exception {
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database<Object> database = context.mock(Database.class);
final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class);
context.checking(new Expectations() {{
allowing(database).startTransaction();
will(returnValue(txn));
allowing(database).commitTransaction(txn);
allowing(database).containsContact(txn, contactId);
will(returnValue(true));
// setSeen(contactId, Collections.singleton(messageId))
oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN);
}});
DatabaseComponent db = createDatabaseComponent(database, cleaner);
db.setSeen(contactId, Collections.singleton(messageId));
context.assertIsSatisfied();
}
} }