diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java index 8fb1a905bf80dfa6b054f44c5926abe88f145fe9..6ce8e79a879444e6a901ba5084beb01e7340589a 100644 --- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java +++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java @@ -97,6 +97,7 @@ abstract class JdbcDatabase implements Database<Connection> { + " (contactId INT NOT NULL," + " groupId HASH NOT NULL," + " inbox BOOLEAN NOT NULL," + + " PRIMARY KEY (contactId, groupId)," + " FOREIGN KEY (contactId)" + " REFERENCES contacts (contactId)" + " ON DELETE CASCADE," @@ -156,21 +157,12 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String INDEX_MESSAGES_BY_TIMESTAMP = "CREATE INDEX messagesByTimestamp ON messages (timestamp)"; - // Locking: message - private static final String CREATE_MESSAGES_TO_ACK = - "CREATE TABLE messagesToAck" - + " (messageId HASH NOT NULL," // Not a foreign key - + " contactId INT NOT NULL," - + " PRIMARY KEY (messageId, contactId)," - + " FOREIGN KEY (contactId)" - + " REFERENCES contacts (contactId)" - + " ON DELETE CASCADE)"; - // Locking: message private static final String CREATE_STATUSES = "CREATE TABLE statuses" + " (messageId HASH NOT NULL," + " contactId INT NOT NULL," + + " ack BOOLEAN NOT NULL," + " seen BOOLEAN NOT NULL," + " expiry BIGINT NOT NULL," + " txCount INT NOT NULL," @@ -374,7 +366,6 @@ abstract class JdbcDatabase implements Database<Connection> { s.executeUpdate(insertTypeNames(CREATE_GROUP_VERSIONS)); s.executeUpdate(insertTypeNames(CREATE_MESSAGES)); s.executeUpdate(INDEX_MESSAGES_BY_TIMESTAMP); - s.executeUpdate(insertTypeNames(CREATE_MESSAGES_TO_ACK)); s.executeUpdate(insertTypeNames(CREATE_STATUSES)); s.executeUpdate(INDEX_STATUSES_BY_MESSAGE); s.executeUpdate(INDEX_STATUSES_BY_CONTACT); @@ -749,24 +740,13 @@ abstract class JdbcDatabase implements Database<Connection> { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT NULL FROM messagesToAck" + String sql = "UPDATE statuses SET ack = TRUE" + " WHERE messageId = ? AND contactId = ?"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getBytes()); ps.setInt(2, c.getInt()); - rs = ps.executeQuery(); - boolean found = rs.next(); - if(rs.next()) throw new DbStateException(); - rs.close(); - ps.close(); - if(found) return; - sql = "INSERT INTO messagesToAck (messageId, contactId)" - + " VALUES (?, ?)"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, m.getBytes()); - ps.setInt(2, c.getInt()); int affected = ps.executeUpdate(); - if(affected != 1) throw new DbStateException(); + if(affected > 1) throw new DbStateException(); ps.close(); } catch(SQLException e) { tryToClose(rs); @@ -826,8 +806,8 @@ abstract class JdbcDatabase implements Database<Connection> { PreparedStatement ps = null; try { String sql = "INSERT INTO statuses" - + " (messageId, contactId, seen, expiry, txCount)" - + " VALUES (?, ?, ?, 0, 0)"; + + " (messageId, contactId, ack, seen, expiry, txCount)" + + " VALUES (?, ?, FALSE, ?, 0, 0)"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getBytes()); ps.setInt(2, c.getInt()); @@ -1644,8 +1624,8 @@ abstract class JdbcDatabase implements Database<Connection> { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT messageId FROM messagesToAck" - + " WHERE contactId = ?" + String sql = "SELECT messageId FROM statuses" + + " WHERE contactId = ? AND ack = TRUE" + " LIMIT ?"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); @@ -2548,7 +2528,7 @@ abstract class JdbcDatabase implements Database<Connection> { Collection<MessageId> acked) throws DbException { PreparedStatement ps = null; try { - String sql = "DELETE FROM messagesToAck" + String sql = "UPDATE statuses SET ack = FALSE" + " WHERE contactId = ? AND messageId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); diff --git a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java index 0fc598ffd085e9a6f677841f78094b3b31d63497..99c74b2ade651189463057a1b138a47542eb9545 100644 --- a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java +++ b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java @@ -299,11 +299,21 @@ public class H2DatabaseTest extends BriarTestCase { Database<Connection> db = open(false); Connection txn = db.startTransaction(); - // Add a contact and some messages to ack - MessageId messageId1 = new MessageId(TestUtils.getRandomId()); + // Add a contact and subscribe to a group db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + db.addGroup(txn, group); + db.setGroups(txn, contactId, Arrays.asList(group), 1); + + // Add some messages to ack + MessageId messageId1 = new MessageId(TestUtils.getRandomId()); + Message message1 = new TestMessage(messageId1, null, group, author, + contentType, subject, timestamp, raw); + db.addMessage(txn, message, false); + db.addStatus(txn, contactId, messageId, true); db.addMessageToAck(txn, contactId, messageId); + db.addMessage(txn, message1, false); + db.addStatus(txn, contactId, messageId1, true); db.addMessageToAck(txn, contactId, messageId1); // Both message IDs should be returned @@ -326,9 +336,15 @@ public class H2DatabaseTest extends BriarTestCase { Database<Connection> db = open(false); Connection txn = db.startTransaction(); - // Add a contact and receive the same message twice + // Add a contact and subscribe to a group db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + db.addGroup(txn, group); + db.setGroups(txn, contactId, Arrays.asList(group), 1); + + // Receive the same message twice + db.addMessage(txn, message, false); + db.addStatus(txn, contactId, messageId, true); db.addMessageToAck(txn, contactId, messageId); db.addMessageToAck(txn, contactId, messageId);