Reset message status when contact unsubscribes from group. Dev task #68.

This commit is contained in:
akwizgran
2014-02-27 14:24:52 +00:00
parent 1cbaae0734
commit de5dac6ce3
4 changed files with 98 additions and 15 deletions

View File

@@ -703,7 +703,7 @@ interface Database<T> {
* true, unless an update with an equal or higher version number has
* already been received from the contact.
* <p>
* Locking: subscription write.
* Locking: message write, subscription write.
*/
boolean setGroups(T txn, ContactId c, Collection<Group> groups,
long version) throws DbException;

View File

@@ -1500,22 +1500,27 @@ DatabaseCleaner.Callback {
boolean updated;
contactLock.readLock().lock();
try {
subscriptionLock.writeLock().lock();
messageLock.writeLock().lock();
try {
T txn = db.startTransaction();
subscriptionLock.writeLock().lock();
try {
if(!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<Group> groups = u.getGroups();
long version = u.getVersion();
updated = db.setGroups(txn, c, groups, version);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
T txn = db.startTransaction();
try {
if(!db.containsContact(txn, c))
throw new NoSuchContactException();
Collection<Group> groups = u.getGroups();
long version = u.getVersion();
updated = db.setGroups(txn, c, groups, version);
db.commitTransaction(txn);
} catch(DbException e) {
db.abortTransaction(txn);
throw e;
}
} finally {
subscriptionLock.writeLock().unlock();
}
} finally {
subscriptionLock.writeLock().unlock();
messageLock.writeLock().unlock();
}
} finally {
contactLock.readLock().unlock();

View File

@@ -21,10 +21,12 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;
@@ -2896,8 +2898,7 @@ abstract class JdbcDatabase implements Database<Connection> {
throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE statuses"
+ " SET expiry = 0, txCount = 0"
String sql = "UPDATE statuses SET expiry = 0, txCount = 0"
+ " WHERE messageId = ? AND contactId = ?";
ps = txn.prepareStatement(sql);
ps.setBytes(1, m.getBytes());
@@ -2949,6 +2950,43 @@ abstract class JdbcDatabase implements Database<Connection> {
ps.close();
// Return false if the update is obsolete
if(affected == 0) return false;
// Find any messages in groups that are being removed
Set<GroupId> newIds = new HashSet<GroupId>();
for(Group g : groups) newIds.add(g.getId());
sql = "SELECT messageId, m.groupId"
+ " FROM messages AS m"
+ " JOIN contactGroups AS cg"
+ " ON m.groupId = cg.groupId"
+ " WHERE contactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
rs = ps.executeQuery();
List<MessageId> removed = new ArrayList<MessageId>();
while(rs.next()) {
if(!newIds.contains(new GroupId(rs.getBytes(2))))
removed.add(new MessageId(rs.getBytes(1)));
}
rs.close();
ps.close();
// Reset any statuses for messages in groups that are being removed
if(!removed.isEmpty()) {
sql = "UPDATE statuses SET ack = FALSE, seen = FALSE,"
+ " requested = FALSE, expiry = 0, txCount = 0"
+ " WHERE contactId = ? AND messageId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, c.getInt());
for(MessageId m : removed) {
ps.setBytes(2, m.getBytes());
ps.addBatch();
}
int[] batchAffected = ps.executeBatch();
if(batchAffected.length != removed.size())
throw new DbStateException();
for(int i = 0; i < batchAffected.length; i++) {
if(batchAffected[i] < 0) throw new DbStateException();
}
ps.close();
}
// Delete the existing subscriptions, if any
sql = "DELETE FROM contactGroups WHERE contactId = ?";
ps = txn.prepareStatement(sql);

View File

@@ -1577,6 +1577,46 @@ public class H2DatabaseTest extends BriarTestCase {
db.close();
}
@Test
public void testContactUnsubscribingResetsMessageStatus() throws Exception {
Database<Connection> db = open(false);
Connection txn = db.startTransaction();
// Add a contact who subscribes to a group
db.addLocalAuthor(txn, localAuthor);
assertEquals(contactId, db.addContact(txn, author, localAuthorId));
db.setGroups(txn, contactId, Arrays.asList(group), 1);
// Subscribe to the group and make it visible to the contact
db.addGroup(txn, group);
db.addVisibility(txn, contactId, groupId);
// Add a message - it should be sendable to the contact
db.addMessage(txn, message, true);
db.addStatus(txn, contactId, messageId, false, false);
Collection<MessageId> sendable = db.getMessagesToSend(txn, contactId,
ONE_MEGABYTE);
assertEquals(Arrays.asList(messageId), sendable);
// Mark the message as seen - it should no longer be sendable
db.raiseSeenFlag(txn, contactId, messageId);
sendable = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
assertEquals(Collections.emptyList(), sendable);
// The contact unsubscribes - the message should not be sendable
db.setGroups(txn, contactId, Collections.<Group>emptyList(), 2);
sendable = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
assertEquals(Collections.emptyList(), sendable);
// The contact resubscribes - the message should be sendable again
db.setGroups(txn, contactId, Arrays.asList(group), 3);
sendable = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE);
assertEquals(Arrays.asList(messageId), sendable);
db.commitTransaction(txn);
db.close();
}
@Test
public void testExceptionHandling() throws Exception {
Database<Connection> db = open(false);