diff --git a/api/net/sf/briar/api/db/NeighbourId.java b/api/net/sf/briar/api/db/ContactId.java similarity index 65% rename from api/net/sf/briar/api/db/NeighbourId.java rename to api/net/sf/briar/api/db/ContactId.java index 943db44f1a8e5cb5ef72fbde85e5ea35bf44aa93..3e793c4bfe5e1d1ee74c37a3657b6d3c8e7a5fb2 100644 --- a/api/net/sf/briar/api/db/NeighbourId.java +++ b/api/net/sf/briar/api/db/ContactId.java @@ -1,11 +1,11 @@ package net.sf.briar.api.db; -/** Uniquely identifies a neighbour. */ -public class NeighbourId { +/** Uniquely identifies a contact. */ +public class ContactId { private final int id; - public NeighbourId(int id) { + public ContactId(int id) { this.id = id; } @@ -15,7 +15,7 @@ public class NeighbourId { @Override public boolean equals(Object o) { - if(o instanceof NeighbourId) return id == ((NeighbourId) o).id; + if(o instanceof ContactId) return id == ((ContactId) o).id; return false; } diff --git a/api/net/sf/briar/api/db/DatabaseComponent.java b/api/net/sf/briar/api/db/DatabaseComponent.java index b710127813cfdb973e1eccf74f6abf2f7f45d327..59261e2e1b9b6490259ace35300b59043a86c016 100644 --- a/api/net/sf/briar/api/db/DatabaseComponent.java +++ b/api/net/sf/briar/api/db/DatabaseComponent.java @@ -29,14 +29,14 @@ public interface DatabaseComponent { /** Waits for any open transactions to finish and closes the database. */ void close() throws DbException; + /** Adds a new contact to the database. */ + void addContact(ContactId c) throws DbException; + /** Adds a locally generated message to the database. */ void addLocallyGeneratedMessage(Message m) throws DbException; - /** Adds a new neighbour to the database. */ - void addNeighbour(NeighbourId n) throws DbException; - - /** Generates a bundle of messages for the given neighbour. */ - void generateBundle(NeighbourId n, Bundle b) throws DbException; + /** Generates a bundle of messages for the given contact. */ + void generateBundle(ContactId c, Bundle b) throws DbException; /** Returns the user's rating for the given author. */ Rating getRating(AuthorId a) throws DbException; @@ -45,13 +45,13 @@ public interface DatabaseComponent { Set<GroupId> getSubscriptions() throws DbException; /** - * Processes a bundle of messages received from the given neighbour. Some + * Processes a bundle of messages received from the given contact. Some * or all of the messages in the bundle may be stored. */ - void receiveBundle(NeighbourId n, Bundle b) throws DbException; + void receiveBundle(ContactId c, Bundle b) throws DbException; - /** Removes a neighbour (and all associated state) from the database. */ - void removeNeighbour(NeighbourId n) throws DbException; + /** Removes a contact (and all associated state) from the database. */ + void removeContact(ContactId c) throws DbException; /** Records the user's rating for the given author. */ void setRating(AuthorId a, Rating r) throws DbException; diff --git a/api/net/sf/briar/api/db/Status.java b/api/net/sf/briar/api/db/Status.java index 0f80ba176b38b99e81a41ee0923b9a18b896fe60..92a7070e6cea152f92717fdd1d90f5a4da90aeac 100644 --- a/api/net/sf/briar/api/db/Status.java +++ b/api/net/sf/briar/api/db/Status.java @@ -1,17 +1,11 @@ package net.sf.briar.api.db; -/** The status of a message with respect to a neighbour. */ +/** The status of a message with respect to a particular contact. */ public enum Status { - /** - * The message has not been sent to, received from, or acked by the - * neighbour. - */ + /** The message has not been sent, received, or acked. */ NEW, - /** - * The message has been sent to, but not received from or acked by, the - * neighbour. - */ + /** The message has been sent, but not received or acked. */ SENT, - /** The message has been received from or acked by the neighbour. */ + /** The message has been received or acked. */ SEEN } diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java index b00fa2ee062146d0a3f077ab089a8dd085e6ad69..7c3021d919abb7d99975f9da25c3e03de1cdc15e 100644 --- a/components/net/sf/briar/db/Database.java +++ b/components/net/sf/briar/db/Database.java @@ -3,7 +3,7 @@ package net.sf.briar.db; import java.util.Set; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.db.NeighbourId; +import net.sf.briar.api.db.ContactId; import net.sf.briar.api.db.Rating; import net.sf.briar.api.db.Status; import net.sf.briar.api.protocol.AuthorId; @@ -62,7 +62,7 @@ interface Database<T> { * <p> * Locking: contacts read, messageStatuses write. */ - void addBatchToAck(T txn, NeighbourId n, BatchId b) throws DbException; + void addBatchToAck(T txn, ContactId c, BatchId b) throws DbException; /** * Returns false if the given message is already in the database. Otherwise @@ -73,18 +73,18 @@ interface Database<T> { boolean addMessage(T txn, Message m) throws DbException; /** - * Adds a new neighbour to the database. + * Adds a new contact to the database. * <p> * Locking: contacts write, messageStatuses write. */ - void addNeighbour(T txn, NeighbourId n) throws DbException; + void addContact(T txn, ContactId c) throws DbException; /** * Records a sent batch as needing to be acknowledged. * <p> * Locking: contacts read, messages read, messageStatuses write. */ - void addOutstandingBatch(T txn, NeighbourId n, BatchId b, Set<MessageId> sent) throws DbException; + void addOutstandingBatch(T txn, ContactId c, BatchId b, Set<MessageId> sent) throws DbException; /** * Records a received bundle. This should be called after processing the @@ -93,7 +93,7 @@ interface Database<T> { * <p> * Locking: contacts read, messages read, messageStatuses write. */ - Set<BatchId> addReceivedBundle(T txn, NeighbourId n, BundleId b) throws DbException; + Set<BatchId> addReceivedBundle(T txn, ContactId c, BundleId b) throws DbException; /** * Subscribes to the given group. @@ -103,32 +103,32 @@ interface Database<T> { void addSubscription(T txn, GroupId g) throws DbException; /** - * Records a neighbour's subscription to a group. + * Records a contact's subscription to a group. * <p> * Locking: contacts read, messageStatuses write. */ - void addSubscription(T txn, NeighbourId n, GroupId g) throws DbException; + void addSubscription(T txn, ContactId c, GroupId g) throws DbException; /** - * Removes all recorded subscriptions for the given neighbour. + * Removes all recorded subscriptions for the given contact. * <p> * Locking: contacts read, messageStatuses write. */ - void clearSubscriptions(T txn, NeighbourId n) throws DbException; + void clearSubscriptions(T txn, ContactId c) throws DbException; /** - * Returns true iff the database contains the given message. + * Returns true iff the database contains the given contact. * <p> - * Locking: messages read. + * Locking: contacts read. */ - boolean containsMessage(T txn, MessageId m) throws DbException; + boolean containsContact(T txn, ContactId c) throws DbException; /** - * Returns true iff the database contains the given neighbour. + * Returns true iff the database contains the given message. * <p> - * Locking: contacts read. + * Locking: messages read. */ - boolean containsNeighbour(T txn, NeighbourId n) throws DbException; + boolean containsMessage(T txn, MessageId m) throws DbException; /** * Returns true iff the user is subscribed to the given group. @@ -137,6 +137,13 @@ interface Database<T> { */ boolean containsSubscription(T txn, GroupId g) throws DbException; + /** + * Returns the IDs of all contacts. + * <p> + * Locking: contacts read, messageStatuses read. + */ + Set<ContactId> getContacts(T txn) throws DbException; + /** * Returns the amount of free storage space available to the database, in * bytes. This is based on the minimum of the space available on the device @@ -168,13 +175,6 @@ interface Database<T> { */ Iterable<MessageId> getMessagesByParent(T txn, MessageId m) throws DbException; - /** - * Returns the IDs of all neighbours. - * <p> - * Locking: contacts read, messageStatuses read. - */ - Set<NeighbourId> getNeighbours(T txn) throws DbException; - /** * Returns the IDs of the oldest messages in the database, with a total * size less than or equal to the given size. @@ -200,7 +200,7 @@ interface Database<T> { /** * Returns the sendability score of the given message. Messages with * sendability scores greater than zero are eligible to be sent to - * neighbours. + * contacts. * <p> * Locking: messages read. */ @@ -208,11 +208,11 @@ interface Database<T> { /** * Returns the IDs of some messages that are eligible to be sent to the - * given neighbour, with a total size less than or equal to the given size. + * given contact, with a total size less than or equal to the given size. * <p> * Locking: contacts read, messages read, messageStatuses read. */ - Iterable<MessageId> getSendableMessages(T txn, NeighbourId n, long capacity) throws DbException; + Iterable<MessageId> getSendableMessages(T txn, ContactId c, long capacity) throws DbException; /** * Returns the groups to which the user subscribes. @@ -224,28 +224,35 @@ interface Database<T> { /** * Removes an outstanding batch that has been acknowledged. Any messages in * the batch that are still considered outstanding (Status.SENT) with - * respect to the given neighbour are now considered seen (Status.SEEN). + * respect to the given contact are now considered seen (Status.SEEN). * <p> * Locking: contacts read, messages read, messageStatuses write. */ - void removeAckedBatch(T txn, NeighbourId n, BatchId b) throws DbException; + void removeAckedBatch(T txn, ContactId c, BatchId b) throws DbException; /** * Removes and returns the IDs of any batches received from the given - * neighbour that need to be acknowledged. + * contact that need to be acknowledged. * <p> * Locking: contacts read, messageStatuses write. */ - Set<BatchId> removeBatchesToAck(T txn, NeighbourId n) throws DbException; + Set<BatchId> removeBatchesToAck(T txn, ContactId c) throws DbException; + + /** + * Removes a contact (and all associated state) from the database. + * <p> + * Locking: contacts write, messageStatuses write. + */ + void removeContact(T txn, ContactId c) throws DbException; /** * Removes an outstanding batch that has been lost. Any messages in the * batch that are still considered outstanding (Status.SENT) with respect - * to the given neighbour are now considered unsent (Status.NEW). + * to the given contact are now considered unsent (Status.NEW). * <p> * Locking: contacts read, messages read, messageStatuses write. */ - void removeLostBatch(T txn, NeighbourId n, BatchId b) throws DbException; + void removeLostBatch(T txn, ContactId c, BatchId b) throws DbException; /** * Removes a message (and all associated state) from the database. @@ -254,13 +261,6 @@ interface Database<T> { */ void removeMessage(T txn, MessageId m) throws DbException; - /** - * Removes a neighbour (and all associated state) from the database. - * <p> - * Locking: contacts write, messageStatuses write. - */ - void removeNeighbour(T txn, NeighbourId n) throws DbException; - /** * Unsubscribes from the given group. Any messages belonging to the group * are deleted from the database. @@ -285,9 +285,9 @@ interface Database<T> { void setSendability(T txn, MessageId m, int sendability) throws DbException; /** - * Sets the status of the given message with respect to the given neighbour. + * Sets the status of the given message with respect to the given contact. * <p> * Locking: contacts read, messages read, messageStatuses write. */ - void setStatus(T txn, NeighbourId n, MessageId m, Status s) throws DbException; + void setStatus(T txn, ContactId c, MessageId m, Status s) throws DbException; } diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index 638eecd3892b618a92b17ea5ecc1d41d1207a2c8..ed6ba26912d3a307d4c4a988b672c14b329e0da5 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -5,7 +5,7 @@ import java.util.logging.Logger; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.db.NeighbourId; +import net.sf.briar.api.db.ContactId; import net.sf.briar.api.db.Rating; import net.sf.briar.api.db.Status; import net.sf.briar.api.protocol.AuthorId; @@ -75,10 +75,10 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent { } // Locking: contacts read - protected boolean containsNeighbour(NeighbourId n) throws DbException { + protected boolean containsContact(ContactId c) throws DbException { Txn txn = db.startTransaction(); try { - boolean contains = db.containsNeighbour(txn, n); + boolean contains = db.containsContact(txn, c); db.commitTransaction(txn); return contains; } catch(DbException e) { @@ -141,16 +141,16 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent { } // Locking: contacts read, messages write, messageStatuses write - protected boolean storeMessage(Txn txn, Message m, NeighbourId sender) + protected boolean storeMessage(Txn txn, Message m, ContactId sender) throws DbException { boolean added = db.addMessage(txn, m); // Mark the message as seen by the sender MessageId id = m.getId(); if(sender != null) db.setStatus(txn, sender, id, Status.SEEN); if(added) { - // Mark the message as unseen by other neighbours - for(NeighbourId n : db.getNeighbours(txn)) { - if(!n.equals(sender)) db.setStatus(txn, n, id, Status.NEW); + // Mark the message as unseen by other contacts + for(ContactId c : db.getContacts(txn)) { + if(!c.equals(sender)) db.setStatus(txn, c, id, Status.NEW); } // Calculate and store the message's sendability int sendability = calculateSendability(txn, m); diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java index 173d0ac7b44199e2b2a322f123c7745b1f9585dc..2f861175147ac152b1fffbbd215e52c3be03dc3e 100644 --- a/components/net/sf/briar/db/JdbcDatabase.java +++ b/components/net/sf/briar/db/JdbcDatabase.java @@ -19,7 +19,7 @@ import java.util.logging.Logger; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.db.NeighbourId; +import net.sf.briar.api.db.ContactId; import net.sf.briar.api.db.Rating; import net.sf.briar.api.db.Status; import net.sf.briar.api.protocol.AuthorId; @@ -64,46 +64,46 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String INDEX_MESSAGES_BY_SENDABILITY = "CREATE INDEX messagesBySendability ON messages (sendability)"; - private static final String CREATE_NEIGHBOURS = - "CREATE TABLE neighbours" - + " (neighbourId INT NOT NULL," + private static final String CREATE_CONTACTS = + "CREATE TABLE contacts" + + " (contactId INT NOT NULL," + " lastBundleReceived XXXX NOT NULL," - + " PRIMARY KEY (neighbourId))"; + + " PRIMARY KEY (contactId))"; private static final String CREATE_BATCHES_TO_ACK = "CREATE TABLE batchesToAck" + " (batchId XXXX NOT NULL," - + " neighbourId INT NOT NULL," + + " contactId INT NOT NULL," + " PRIMARY KEY (batchId)," - + " FOREIGN KEY (neighbourId) REFERENCES neighbours (neighbourId)" + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; - private static final String CREATE_NEIGHBOUR_SUBSCRIPTIONS = - "CREATE TABLE neighbourSubscriptions" - + " (neighbourId INT NOT NULL," + private static final String CREATE_CONTACT_SUBSCRIPTIONS = + "CREATE TABLE contactSubscriptions" + + " (contactId INT NOT NULL," + " groupId XXXX NOT NULL," - + " PRIMARY KEY (neighbourId, groupId)," - + " FOREIGN KEY (neighbourId) REFERENCES neighbours (neighbourId)" + + " PRIMARY KEY (contactId, groupId)," + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; private static final String CREATE_OUTSTANDING_BATCHES = "CREATE TABLE outstandingBatches" + " (batchId XXXX NOT NULL," - + " neighbourId INT NOT NULL," + + " contactId INT NOT NULL," + " lastBundleReceived XXXX NOT NULL," + " PRIMARY KEY (batchId)," - + " FOREIGN KEY (neighbourId) REFERENCES neighbours (neighbourId)" + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; private static final String CREATE_OUTSTANDING_MESSAGES = "CREATE TABLE outstandingMessages" + " (batchId XXXX NOT NULL," - + " neighbourId INT NOT NULL," + + " contactId INT NOT NULL," + " messageId XXXX NOT NULL," + " PRIMARY KEY (batchId, messageId)," + " FOREIGN KEY (batchId) REFERENCES outstandingBatches (batchId)" + " ON DELETE CASCADE," - + " FOREIGN KEY (neighbourId) REFERENCES neighbours (neighbourId)" + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE," + " FOREIGN KEY (messageId) REFERENCES messages (messageId)" + " ON DELETE CASCADE)"; @@ -121,28 +121,28 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String CREATE_RECEIVED_BUNDLES = "CREATE TABLE receivedBundles" + " (bundleId XXXX NOT NULL," - + " neighbourId INT NOT NULL," + + " contactId INT NOT NULL," + " timestamp BIGINT NOT NULL," + " PRIMARY KEY (bundleId)," - + " FOREIGN KEY (neighbourId) REFERENCES neighbours (neighbourId)" + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; private static final String CREATE_STATUSES = "CREATE TABLE statuses" + " (messageId XXXX NOT NULL," - + " neighbourId INT NOT NULL," + + " contactId INT NOT NULL," + " status SMALLINT NOT NULL," - + " PRIMARY KEY (messageId, neighbourId)," + + " PRIMARY KEY (messageId, contactId)," + " FOREIGN KEY (messageId) REFERENCES messages (messageId)" + " ON DELETE CASCADE," - + " FOREIGN KEY (neighbourId) REFERENCES neighbours (neighbourId)" + + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; private static final String INDEX_STATUSES_BY_MESSAGE = "CREATE INDEX statusesByMessage ON statuses (messageId)"; - private static final String INDEX_STATUSES_BY_NEIGHBOUR = - "CREATE INDEX statusesByNeighbour ON statuses (neighbourId)"; + private static final String INDEX_STATUSES_BY_CONTACT = + "CREATE INDEX statusesByContact ON statuses (contactId)"; private static final Logger LOG = Logger.getLogger(JdbcDatabase.class.getName()); @@ -207,14 +207,14 @@ abstract class JdbcDatabase implements Database<Connection> { s.executeUpdate(INDEX_MESSAGES_BY_TIMESTAMP); s.executeUpdate(INDEX_MESSAGES_BY_SENDABILITY); if(LOG.isLoggable(Level.FINE)) - LOG.fine("Creating neighbours table"); - s.executeUpdate(insertHashType(CREATE_NEIGHBOURS)); + LOG.fine("Creating contacts table"); + s.executeUpdate(insertHashType(CREATE_CONTACTS)); if(LOG.isLoggable(Level.FINE)) LOG.fine("Creating batchesToAck table"); s.executeUpdate(insertHashType(CREATE_BATCHES_TO_ACK)); if(LOG.isLoggable(Level.FINE)) - LOG.fine("Creating neighbourSubscriptions table"); - s.executeUpdate(insertHashType(CREATE_NEIGHBOUR_SUBSCRIPTIONS)); + LOG.fine("Creating contactSubscriptions table"); + s.executeUpdate(insertHashType(CREATE_CONTACT_SUBSCRIPTIONS)); if(LOG.isLoggable(Level.FINE)) LOG.fine("Creating outstandingBatches table"); s.executeUpdate(insertHashType(CREATE_OUTSTANDING_BATCHES)); @@ -232,7 +232,7 @@ abstract class JdbcDatabase implements Database<Connection> { LOG.fine("Creating statuses table"); s.executeUpdate(insertHashType(CREATE_STATUSES)); s.executeUpdate(INDEX_STATUSES_BY_MESSAGE); - s.executeUpdate(INDEX_STATUSES_BY_NEIGHBOUR); + s.executeUpdate(INDEX_STATUSES_BY_CONTACT); s.close(); } catch(SQLException e) { tryToClose(s); @@ -340,16 +340,35 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void addBatchToAck(Connection txn, NeighbourId n, BatchId b) + public void addBatchToAck(Connection txn, ContactId c, BatchId b) throws DbException { PreparedStatement ps = null; try { String sql = "INSERT INTO batchesToAck" - + " (batchId, neighbourId)" + + " (batchId, contactId)" + " VALUES (?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, b.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); + int rowsAffected = ps.executeUpdate(); + assert rowsAffected == 1; + ps.close(); + } catch(SQLException e) { + tryToClose(ps); + tryToClose(txn); + throw new DbException(e); + } + } + + public void addContact(Connection txn, ContactId c) throws DbException { + PreparedStatement ps = null; + try { + String sql = "INSERT INTO contacts" + + " (contactId, lastBundleReceived)" + + " VALUES (?, ?)"; + ps = txn.prepareStatement(sql); + ps.setInt(1, c.getInt()); + ps.setBytes(2, BundleId.NONE.getBytes()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; ps.close(); @@ -388,35 +407,16 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void addNeighbour(Connection txn, NeighbourId n) throws DbException { - PreparedStatement ps = null; - try { - String sql = "INSERT INTO neighbours" - + " (neighbourId, lastBundleReceived)" - + " VALUES (?, ?)"; - ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); - ps.setBytes(2, BundleId.NONE.getBytes()); - int rowsAffected = ps.executeUpdate(); - assert rowsAffected == 1; - ps.close(); - } catch(SQLException e) { - tryToClose(ps); - tryToClose(txn); - throw new DbException(e); - } - } - - public void addOutstandingBatch(Connection txn, NeighbourId n, BatchId b, + public void addOutstandingBatch(Connection txn, ContactId c, BatchId b, Set<MessageId> sent) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { - // Find the ID of the last bundle received from n - String sql = "SELECT lastBundleReceived FROM neighbours" - + " WHERE neighbourId = ?"; + // Find the ID of the last bundle received from c + String sql = "SELECT lastBundleReceived FROM contacts" + + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); rs = ps.executeQuery(); boolean found = rs.next(); assert found; @@ -427,22 +427,22 @@ abstract class JdbcDatabase implements Database<Connection> { ps.close(); // Create an outstanding batch row sql = "INSERT INTO outstandingBatches" - + " (batchId, neighbourId, lastBundleReceived)" + + " (batchId, contactId, lastBundleReceived)" + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, b.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); ps.setBytes(3, lastBundleReceived); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; ps.close(); // Create an outstanding message row for each message in the batch sql = "INSERT INTO outstandingMessages" - + " (batchId, neighbourId, messageId)" + + " (batchId, contactId, messageId)" + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, b.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); for(MessageId m : sent) { ps.setBytes(3, m.getBytes()); ps.addBatch(); @@ -455,10 +455,10 @@ abstract class JdbcDatabase implements Database<Connection> { ps.close(); // Set the status of each message in the batch to SENT sql = "UPDATE statuses SET status = ?" - + " WHERE messageId = ? AND neighbourId = ? AND status = ?"; + + " WHERE messageId = ? AND contactId = ? AND status = ?"; ps = txn.prepareStatement(sql); ps.setShort(1, (short) Status.SENT.ordinal()); - ps.setInt(3, n.getInt()); + ps.setInt(3, c.getInt()); ps.setShort(4, (short) Status.NEW.ordinal()); for(MessageId m : sent) { ps.setBytes(2, m.getBytes()); @@ -478,25 +478,25 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Set<BatchId> addReceivedBundle(Connection txn, NeighbourId n, + public Set<BatchId> addReceivedBundle(Connection txn, ContactId c, BundleId b) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { - // Update the ID of the last bundle received from n - String sql = "UPDATE neighbours SET lastBundleReceived = ?" - + " WHERE neighbourId = ?"; + // Update the ID of the last bundle received from c + String sql = "UPDATE contacts SET lastBundleReceived = ?" + + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); ps.setBytes(1, b.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; ps.close(); - // Count the received bundle records for n and find the oldest + // Count the received bundle records for c and find the oldest sql = "SELECT bundleId, timestamp FROM receivedBundles" - + " WHERE neighbourId = ?"; + + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); rs = ps.executeQuery(); int received = 0; long oldestTimestamp = Long.MAX_VALUE; @@ -516,7 +516,7 @@ abstract class JdbcDatabase implements Database<Connection> { if(received == DatabaseComponent.RETRANSMIT_THRESHOLD) { // Expire batches related to the oldest received bundle assert oldestBundle != null; - lost = findLostBatches(txn, n, oldestBundle); + lost = findLostBatches(txn, c, oldestBundle); sql = "DELETE FROM receivedBundles WHERE bundleId = ?"; ps = txn.prepareStatement(sql); ps.setBytes(1, oldestBundle); @@ -528,11 +528,11 @@ abstract class JdbcDatabase implements Database<Connection> { } // Record the new received bundle sql = "INSERT INTO receivedBundles" - + " (bundleId, neighbourId, timestamp)" + + " (bundleId, contactId, timestamp)" + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, b.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); ps.setLong(3, System.currentTimeMillis()); rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; @@ -546,15 +546,15 @@ abstract class JdbcDatabase implements Database<Connection> { } } - private Set<BatchId> findLostBatches(Connection txn, NeighbourId n, + private Set<BatchId> findLostBatches(Connection txn, ContactId c, byte[] lastBundleReceived) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { String sql = "SELECT batchId FROM outstandingBatches" - + " WHERE neighbourId = ? AND lastBundleReceived = ?"; + + " WHERE contactId = ? AND lastBundleReceived = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); ps.setBytes(2, lastBundleReceived); rs = ps.executeQuery(); Set<BatchId> lost = new HashSet<BatchId>(); @@ -586,15 +586,15 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void addSubscription(Connection txn, NeighbourId n, GroupId g) + public void addSubscription(Connection txn, ContactId c, GroupId g) throws DbException { PreparedStatement ps = null; try { - String sql = "INSERT INTO neighbourSubscriptions" - + " (neighbourId, groupId)" + String sql = "INSERT INTO contactSubscriptions" + + " (contactId, groupId)" + " VALUES (?, ?)"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); ps.setBytes(2, g.getBytes()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; @@ -606,14 +606,14 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void clearSubscriptions(Connection txn, NeighbourId n) + public void clearSubscriptions(Connection txn, ContactId c) throws DbException { PreparedStatement ps = null; try { - String sql = "DELETE FROM neighbourSubscriptions" - + " WHERE neighbourId = ?"; + String sql = "DELETE FROM contactSubscriptions" + + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); ps.executeUpdate(); ps.close(); } catch(SQLException e) { @@ -623,15 +623,15 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public boolean containsMessage(Connection txn, MessageId m) + public boolean containsContact(Connection txn, ContactId c) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT COUNT(messageId) FROM messages" - + " WHERE messageId = ?"; + String sql = "SELECT COUNT(contactId) FROM contacts" + + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setBytes(1, m.getBytes()); + ps.setInt(1, c.getInt()); rs = ps.executeQuery(); boolean found = rs.next(); assert found; @@ -650,15 +650,15 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public boolean containsNeighbour(Connection txn, NeighbourId n) + public boolean containsMessage(Connection txn, MessageId m) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT COUNT(neighbourId) FROM neighbours" - + " WHERE neighbourId = ?"; + String sql = "SELECT COUNT(messageId) FROM messages" + + " WHERE messageId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setBytes(1, m.getBytes()); rs = ps.executeQuery(); boolean found = rs.next(); assert found; @@ -704,6 +704,26 @@ abstract class JdbcDatabase implements Database<Connection> { } } + public Set<ContactId> getContacts(Connection txn) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT contactId FROM contacts"; + ps = txn.prepareStatement(sql); + rs = ps.executeQuery(); + Set<ContactId> ids = new HashSet<ContactId>(); + while(rs.next()) ids.add(new ContactId(rs.getInt(1))); + rs.close(); + ps.close(); + return ids; + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + tryToClose(txn); + throw new DbException(e); + } + } + protected long getDiskSpace(File f) { long total = 0L; if(f.isDirectory()) { @@ -790,26 +810,6 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Set<NeighbourId> getNeighbours(Connection txn) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT neighbourId FROM neighbours"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - Set<NeighbourId> ids = new HashSet<NeighbourId>(); - while(rs.next()) ids.add(new NeighbourId(rs.getInt(1))); - rs.close(); - ps.close(); - return ids; - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - tryToClose(txn); - throw new DbException(e); - } - } - public int getNumberOfMessages(Connection txn) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -936,19 +936,19 @@ abstract class JdbcDatabase implements Database<Connection> { } public Iterable<MessageId> getSendableMessages(Connection txn, - NeighbourId n, long capacity) throws DbException { + ContactId c, long capacity) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { String sql = "SELECT size, messages.messageId FROM messages" - + " JOIN neighbourSubscriptions" - + " ON messages.groupId = neighbourSubscriptions.groupId" + + " JOIN contactSubscriptions" + + " ON messages.groupId = contactSubscriptions.groupId" + " JOIN statuses ON messages.messageId = statuses.messageId" - + " WHERE neighbourSubscriptions.neighbourId = ?" - + " AND statuses.neighbourId = ? AND status = ?"; + + " WHERE contactSubscriptions.contactId = ?" + + " AND statuses.contactId = ? AND status = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); - ps.setInt(2, n.getInt()); + ps.setInt(1, c.getInt()); + ps.setInt(2, c.getInt()); ps.setShort(3, (short) Status.NEW.ordinal()); rs = ps.executeQuery(); List<MessageId> ids = new ArrayList<MessageId>(); @@ -995,27 +995,27 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void removeAckedBatch(Connection txn, NeighbourId n, BatchId b) + public void removeAckedBatch(Connection txn, ContactId c, BatchId b) throws DbException { - removeBatch(txn, n, b, Status.SEEN); + removeBatch(txn, c, b, Status.SEEN); } - private void removeBatch(Connection txn, NeighbourId n, BatchId b, + private void removeBatch(Connection txn, ContactId c, BatchId b, Status newStatus) throws DbException { PreparedStatement ps = null, ps1 = null; ResultSet rs = null; try { String sql = "SELECT messageId FROM outstandingMessages" - + " WHERE neighbourId = ? AND batchId = ?"; + + " WHERE contactId = ? AND batchId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); ps.setBytes(2, b.getBytes()); rs = ps.executeQuery(); sql = "UPDATE statuses SET status = ?" - + " WHERE messageId = ? AND neighbourId = ? AND status = ?"; + + " WHERE messageId = ? AND contactId = ? AND status = ?"; ps1 = txn.prepareStatement(sql); ps1.setShort(1, (short) newStatus.ordinal()); - ps1.setInt(3, n.getInt()); + ps1.setInt(3, c.getInt()); ps1.setShort(4, (short) Status.SENT.ordinal()); int messages = 0; while(rs.next()) { @@ -1047,23 +1047,23 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Set<BatchId> removeBatchesToAck(Connection txn, NeighbourId n) + public Set<BatchId> removeBatchesToAck(Connection txn, ContactId c) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { String sql = "SELECT batchId FROM batchesToAck" - + " WHERE neighbourId = ?"; + + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); rs = ps.executeQuery(); Set<BatchId> ids = new HashSet<BatchId>(); while(rs.next()) ids.add(new BatchId(rs.getBytes(1))); rs.close(); ps.close(); - sql = "DELETE FROM batchesToAck WHERE neighbourId = ?"; + sql = "DELETE FROM batchesToAck WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setInt(1, c.getInt()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == ids.size(); ps.close(); @@ -1076,17 +1076,13 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void removeLostBatch(Connection txn, NeighbourId n, BatchId b) + public void removeContact(Connection txn, ContactId c) throws DbException { - removeBatch(txn, n, b, Status.NEW); - } - - public void removeMessage(Connection txn, MessageId m) throws DbException { PreparedStatement ps = null; try { - String sql = "DELETE FROM messages WHERE messageId = ?"; + String sql = "DELETE FROM contacts WHERE contactId = ?"; ps = txn.prepareStatement(sql); - ps.setBytes(1, m.getBytes()); + ps.setInt(1, c.getInt()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; ps.close(); @@ -1097,13 +1093,17 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void removeNeighbour(Connection txn, NeighbourId n) + public void removeLostBatch(Connection txn, ContactId c, BatchId b) throws DbException { + removeBatch(txn, c, b, Status.NEW); + } + + public void removeMessage(Connection txn, MessageId m) throws DbException { PreparedStatement ps = null; try { - String sql = "DELETE FROM neighbours WHERE neighbourId = ?"; + String sql = "DELETE FROM messages WHERE messageId = ?"; ps = txn.prepareStatement(sql); - ps.setInt(1, n.getInt()); + ps.setBytes(1, m.getBytes()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; ps.close(); @@ -1194,16 +1194,16 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void setStatus(Connection txn, NeighbourId n, MessageId m, Status s) + public void setStatus(Connection txn, ContactId c, MessageId m, Status s) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { String sql = "SELECT status FROM statuses" - + " WHERE messageId = ? AND neighbourId = ?"; + + " WHERE messageId = ? AND contactId = ?"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); rs = ps.executeQuery(); if(rs.next()) { Status old = Status.values()[rs.getByte(1)]; @@ -1213,11 +1213,11 @@ abstract class JdbcDatabase implements Database<Connection> { ps.close(); if(!old.equals(Status.SEEN) && !old.equals(s)) { sql = "UPDATE statuses SET status = ?" - + " WHERE messageId = ? AND neighbourId = ?"; + + " WHERE messageId = ? AND contactId = ?"; ps = txn.prepareStatement(sql); ps.setShort(1, (short) s.ordinal()); ps.setBytes(2, m.getBytes()); - ps.setInt(3, n.getInt()); + ps.setInt(3, c.getInt()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; ps.close(); @@ -1225,11 +1225,11 @@ abstract class JdbcDatabase implements Database<Connection> { } else { rs.close(); ps.close(); - sql = "INSERT INTO statuses (messageId, neighbourId, status)" + sql = "INSERT INTO statuses (messageId, contactId, status)" + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, m.getBytes()); - ps.setInt(2, n.getInt()); + ps.setInt(2, c.getInt()); ps.setShort(3, (short) s.ordinal()); int rowsAffected = ps.executeUpdate(); assert rowsAffected == 1; diff --git a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java index dc75fe9e00052ba4177615797355c0ba84810b13..f6d874fbe9aa024f826e26a28f42fda475b3fe9a 100644 --- a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java +++ b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java @@ -8,7 +8,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.db.NeighbourId; +import net.sf.briar.api.db.ContactId; import net.sf.briar.api.db.Rating; import net.sf.briar.api.protocol.AuthorId; import net.sf.briar.api.protocol.Batch; @@ -49,34 +49,6 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { super(db, batchProvider); } - protected void expireMessages(long size) throws DbException { - contactLock.readLock().lock(); - try { - messageLock.writeLock().lock(); - try { - messageStatusLock.writeLock().lock(); - try { - Txn txn = db.startTransaction(); - try { - for(MessageId m : db.getOldMessages(txn, size)) { - removeMessage(txn, m); - } - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } finally { - messageStatusLock.writeLock().unlock(); - } - } finally { - messageLock.writeLock().unlock(); - } - } finally { - contactLock.readLock().unlock(); - } - } - public void close() throws DbException { contactLock.writeLock().lock(); try { @@ -106,15 +78,15 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public void addNeighbour(NeighbourId n) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding neighbour " + n); + public void addContact(ContactId c) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact " + c); contactLock.writeLock().lock(); try { messageStatusLock.writeLock().lock(); try { Txn txn = db.startTransaction(); try { - db.addNeighbour(txn, n); + db.addContact(txn, c); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -166,126 +138,22 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public Rating getRating(AuthorId a) throws DbException { - ratingLock.readLock().lock(); - try { - Txn txn = db.startTransaction(); - try { - Rating r = db.getRating(txn, a); - db.commitTransaction(txn); - return r; - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } finally { - ratingLock.readLock().unlock(); - } - } - - public void removeNeighbour(NeighbourId n) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing neighbour " + n); - contactLock.writeLock().lock(); - try { - messageStatusLock.writeLock().lock(); - try { - Txn txn = db.startTransaction(); - try { - db.removeNeighbour(txn, n); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } finally { - messageStatusLock.writeLock().unlock(); - } - } finally { - contactLock.writeLock().unlock(); - } - } - - public void setRating(AuthorId a, Rating r) throws DbException { - messageLock.writeLock().lock(); - try { - ratingLock.writeLock().lock(); - try { - Txn txn = db.startTransaction(); - try { - Rating old = db.setRating(txn, a, r); - // Update the sendability of the author's messages - if(r == Rating.GOOD && old != Rating.GOOD) - updateAuthorSendability(txn, a, true); - else if(r != Rating.GOOD && old == Rating.GOOD) - updateAuthorSendability(txn, a, false); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } finally { - ratingLock.writeLock().unlock(); - } - } finally { - messageLock.writeLock().unlock(); - } - } - - public Set<GroupId> getSubscriptions() throws DbException { - subscriptionLock.readLock().lock(); - try { - Txn txn = db.startTransaction(); - try { - HashSet<GroupId> subs = new HashSet<GroupId>(); - for(GroupId g : db.getSubscriptions(txn)) subs.add(g); - db.commitTransaction(txn); - return subs; - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } finally { - subscriptionLock.readLock().unlock(); - } - } - - public void subscribe(GroupId g) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g); - subscriptionLock.writeLock().lock(); - try { - Txn txn = db.startTransaction(); - try { - db.addSubscription(txn, g); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } finally { - subscriptionLock.writeLock().unlock(); - } - } - - public void unsubscribe(GroupId g) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g); + protected void expireMessages(long size) throws DbException { contactLock.readLock().lock(); try { messageLock.writeLock().lock(); try { messageStatusLock.writeLock().lock(); try { - subscriptionLock.writeLock().lock(); + Txn txn = db.startTransaction(); try { - Txn txn = db.startTransaction(); - try { - db.removeSubscription(txn, g); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; + for(MessageId m : db.getOldMessages(txn, size)) { + removeMessage(txn, m); } - } finally { - subscriptionLock.writeLock().unlock(); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; } } finally { messageStatusLock.writeLock().unlock(); @@ -298,18 +166,18 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public void generateBundle(NeighbourId n, Bundle b) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Generating bundle for " + n); - // Ack all batches received from the neighbour + public void generateBundle(ContactId c, Bundle b) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Generating bundle for " + c); + // Ack all batches received from c contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; messageStatusLock.writeLock().lock(); try { Txn txn = db.startTransaction(); try { int numAcks = 0; - for(BatchId ack : db.removeBatchesToAck(txn, n)) { + for(BatchId ack : db.removeBatchesToAck(txn, c)) { b.addAck(ack); numAcks++; } @@ -329,7 +197,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { // Add a list of subscriptions contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; subscriptionLock.readLock().lock(); try { Txn txn = db.startTransaction(); @@ -355,7 +223,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { // Add as many messages as possible to the bundle long capacity = b.getCapacity(); while(true) { - Batch batch = fillBatch(n, capacity); + Batch batch = fillBatch(c, capacity); if(batch == null) break; // No more messages to send b.addBatch(batch); capacity -= batch.getSize(); @@ -369,10 +237,10 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { System.gc(); } - private Batch fillBatch(NeighbourId n, long capacity) throws DbException { + private Batch fillBatch(ContactId c, long capacity) throws DbException { contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return null; + if(!containsContact(c)) return null; messageLock.readLock().lock(); try { Set<MessageId> sent; @@ -383,7 +251,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { try { capacity = Math.min(capacity, Batch.CAPACITY); Iterator<MessageId> it = - db.getSendableMessages(txn, n, capacity).iterator(); + db.getSendableMessages(txn, c, capacity).iterator(); if(!it.hasNext()) { db.commitTransaction(txn); return null; // No more messages to send @@ -410,7 +278,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Txn txn = db.startTransaction(); try { assert !sent.isEmpty(); - db.addOutstandingBatch(txn, n, b.getId(), sent); + db.addOutstandingBatch(txn, c, b.getId(), sent); db.commitTransaction(txn); return b; } catch(DbException e) { @@ -428,14 +296,49 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public void receiveBundle(NeighbourId n, Bundle b) throws DbException { + public Rating getRating(AuthorId a) throws DbException { + ratingLock.readLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + Rating r = db.getRating(txn, a); + db.commitTransaction(txn); + return r; + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + ratingLock.readLock().unlock(); + } + } + + public Set<GroupId> getSubscriptions() throws DbException { + subscriptionLock.readLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + HashSet<GroupId> subs = new HashSet<GroupId>(); + for(GroupId g : db.getSubscriptions(txn)) subs.add(g); + db.commitTransaction(txn); + return subs; + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + subscriptionLock.readLock().unlock(); + } + } + + public void receiveBundle(ContactId c, Bundle b) throws DbException { if(LOG.isLoggable(Level.FINE)) - LOG.fine("Received bundle from " + n + ", " + LOG.fine("Received bundle from " + c + ", " + b.getSize() + " bytes"); // Mark all messages in acked batches as seen contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; messageLock.readLock().lock(); try { messageStatusLock.writeLock().lock(); @@ -445,7 +348,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { acks++; Txn txn = db.startTransaction(); try { - db.removeAckedBatch(txn, n, ack); + db.removeAckedBatch(txn, c, ack); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -463,19 +366,19 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } finally { contactLock.readLock().unlock(); } - // Update the neighbour's subscriptions + // Update the contact's subscriptions contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; messageStatusLock.writeLock().lock(); try { Txn txn = db.startTransaction(); try { - db.clearSubscriptions(txn, n); + db.clearSubscriptions(txn, c); int subs = 0; for(GroupId g : b.getSubscriptions()) { subs++; - db.addSubscription(txn, n, g); + db.addSubscription(txn, c, g); } if(LOG.isLoggable(Level.FINE)) LOG.fine("Received " + subs + " subscriptions"); @@ -497,7 +400,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { waitForPermissionToWrite(); contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; messageLock.writeLock().lock(); try { messageStatusLock.writeLock().lock(); @@ -511,13 +414,13 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { received++; GroupId g = m.getGroup(); if(db.containsSubscription(txn, g)) { - if(storeMessage(txn, m, n)) stored++; + if(storeMessage(txn, m, c)) stored++; } } if(LOG.isLoggable(Level.FINE)) LOG.fine("Received " + received + " messages, stored " + stored); - db.addBatchToAck(txn, n, batch.getId()); + db.addBatchToAck(txn, c, batch.getId()); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -542,14 +445,14 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Set<BatchId> lost; contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; messageLock.readLock().lock(); try { messageStatusLock.writeLock().lock(); try { Txn txn = db.startTransaction(); try { - lost = db.addReceivedBundle(txn, n, b.getId()); + lost = db.addReceivedBundle(txn, c, b.getId()); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -567,7 +470,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { for(BatchId batch : lost) { contactLock.readLock().lock(); try { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; messageLock.readLock().lock(); try { messageStatusLock.writeLock().lock(); @@ -576,7 +479,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { try { if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing lost batch"); - db.removeLostBatch(txn, n, batch); + db.removeLostBatch(txn, c, batch); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -594,4 +497,101 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } System.gc(); } + + public void removeContact(ContactId c) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing contact " + c); + contactLock.writeLock().lock(); + try { + messageStatusLock.writeLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + db.removeContact(txn, c); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + messageStatusLock.writeLock().unlock(); + } + } finally { + contactLock.writeLock().unlock(); + } + } + + public void setRating(AuthorId a, Rating r) throws DbException { + messageLock.writeLock().lock(); + try { + ratingLock.writeLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + Rating old = db.setRating(txn, a, r); + // Update the sendability of the author's messages + if(r == Rating.GOOD && old != Rating.GOOD) + updateAuthorSendability(txn, a, true); + else if(r != Rating.GOOD && old == Rating.GOOD) + updateAuthorSendability(txn, a, false); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + ratingLock.writeLock().unlock(); + } + } finally { + messageLock.writeLock().unlock(); + } + } + + public void subscribe(GroupId g) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g); + subscriptionLock.writeLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + db.addSubscription(txn, g); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + subscriptionLock.writeLock().unlock(); + } + } + + public void unsubscribe(GroupId g) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g); + contactLock.readLock().lock(); + try { + messageLock.writeLock().lock(); + try { + messageStatusLock.writeLock().lock(); + try { + subscriptionLock.writeLock().lock(); + try { + Txn txn = db.startTransaction(); + try { + db.removeSubscription(txn, g); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } finally { + subscriptionLock.writeLock().unlock(); + } + } finally { + messageStatusLock.writeLock().unlock(); + } + } finally { + messageLock.writeLock().unlock(); + } + } finally { + contactLock.readLock().unlock(); + } + } } \ No newline at end of file diff --git a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java index 1008156d17883b44a11f4aba35fac877da39e699..6e514a2c48eaa5ef45e56a335b46b47497b5ff14 100644 --- a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java +++ b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java @@ -7,7 +7,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.db.NeighbourId; +import net.sf.briar.api.db.ContactId; import net.sf.briar.api.db.Rating; import net.sf.briar.api.protocol.AuthorId; import net.sf.briar.api.protocol.Batch; @@ -42,25 +42,6 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { super(db, batchProvider); } - protected void expireMessages(long size) throws DbException { - synchronized(contactLock) { - synchronized(messageLock) { - synchronized(messageStatusLock) { - Txn txn = db.startTransaction(); - try { - for(MessageId m : db.getOldMessages(txn, size)) { - removeMessage(txn, m); - } - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } - } - } - } - public void close() throws DbException { synchronized(contactLock) { synchronized(messageLock) { @@ -75,13 +56,13 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public void addNeighbour(NeighbourId n) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding neighbour " + n); + public void addContact(ContactId c) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Adding contact " + c); synchronized(contactLock) { synchronized(messageStatusLock) { Txn txn = db.startTransaction(); try { - db.addNeighbour(txn, n); + db.addContact(txn, c); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -117,99 +98,35 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public Rating getRating(AuthorId a) throws DbException { - synchronized(ratingLock) { - Txn txn = db.startTransaction(); - try { - Rating r = db.getRating(txn, a); - db.commitTransaction(txn); - return r; - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } - } - - public void setRating(AuthorId a, Rating r) throws DbException { - synchronized(messageLock) { - synchronized(ratingLock) { - Txn txn = db.startTransaction(); - try { - Rating old = db.setRating(txn, a, r); - // Update the sendability of the author's messages - if(r == Rating.GOOD && old != Rating.GOOD) - updateAuthorSendability(txn, a, true); - else if(r != Rating.GOOD && old == Rating.GOOD) - updateAuthorSendability(txn, a, false); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } - } - } - - public Set<GroupId> getSubscriptions() throws DbException { - synchronized(subscriptionLock) { - Txn txn = db.startTransaction(); - try { - HashSet<GroupId> subs = new HashSet<GroupId>(); - for(GroupId g : db.getSubscriptions(txn)) subs.add(g); - db.commitTransaction(txn); - return subs; - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } - } - - public void subscribe(GroupId g) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g); - synchronized(subscriptionLock) { - Txn txn = db.startTransaction(); - try { - db.addSubscription(txn, g); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } - } - } - - public void unsubscribe(GroupId g) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g); + protected void expireMessages(long size) throws DbException { synchronized(contactLock) { synchronized(messageLock) { synchronized(messageStatusLock) { - synchronized(subscriptionLock) { - Txn txn = db.startTransaction(); - try { - db.removeSubscription(txn, g); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; + Txn txn = db.startTransaction(); + try { + for(MessageId m : db.getOldMessages(txn, size)) { + removeMessage(txn, m); } + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; } } } } } - public void generateBundle(NeighbourId n, Bundle b) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Generating bundle for " + n); - // Ack all batches received from the neighbour + public void generateBundle(ContactId c, Bundle b) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Generating bundle for " + c); + // Ack all batches received from c synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(messageStatusLock) { Txn txn = db.startTransaction(); try { int numAcks = 0; - for(BatchId ack : db.removeBatchesToAck(txn, n)) { + for(BatchId ack : db.removeBatchesToAck(txn, c)) { b.addAck(ack); numAcks++; } @@ -224,7 +141,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } // Add a list of subscriptions synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(subscriptionLock) { Txn txn = db.startTransaction(); try { @@ -245,7 +162,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { // Add as many messages as possible to the bundle long capacity = b.getCapacity(); while(true) { - Batch batch = fillBatch(n, capacity); + Batch batch = fillBatch(c, capacity); if(batch == null) break; // No more messages to send b.addBatch(batch); capacity -= batch.getSize(); @@ -259,16 +176,16 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { System.gc(); } - private Batch fillBatch(NeighbourId n, long capacity) throws DbException { + private Batch fillBatch(ContactId c, long capacity) throws DbException { synchronized(contactLock) { - if(!containsNeighbour(n)) return null; + if(!containsContact(c)) return null; synchronized(messageLock) { synchronized(messageStatusLock) { Txn txn = db.startTransaction(); try { capacity = Math.min(capacity, Batch.CAPACITY); Iterator<MessageId> it = - db.getSendableMessages(txn, n, capacity).iterator(); + db.getSendableMessages(txn, c, capacity).iterator(); if(!it.hasNext()) { db.commitTransaction(txn); return null; // No more messages to send @@ -283,7 +200,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { b.seal(); // Record the contents of the batch assert !sent.isEmpty(); - db.addOutstandingBatch(txn, n, b.getId(), sent); + db.addOutstandingBatch(txn, c, b.getId(), sent); db.commitTransaction(txn); return b; } catch(DbException e) { @@ -295,29 +212,42 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } - public void removeNeighbour(NeighbourId n) throws DbException { - if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing neighbour " + n); - synchronized(contactLock) { - synchronized(messageStatusLock) { - Txn txn = db.startTransaction(); - try { - db.removeNeighbour(txn, n); - db.commitTransaction(txn); - } catch(DbException e) { - db.abortTransaction(txn); - throw e; - } + public Rating getRating(AuthorId a) throws DbException { + synchronized(ratingLock) { + Txn txn = db.startTransaction(); + try { + Rating r = db.getRating(txn, a); + db.commitTransaction(txn); + return r; + } catch(DbException e) { + db.abortTransaction(txn); + throw e; } } } - public void receiveBundle(NeighbourId n, Bundle b) throws DbException { + public Set<GroupId> getSubscriptions() throws DbException { + synchronized(subscriptionLock) { + Txn txn = db.startTransaction(); + try { + HashSet<GroupId> subs = new HashSet<GroupId>(); + for(GroupId g : db.getSubscriptions(txn)) subs.add(g); + db.commitTransaction(txn); + return subs; + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + } + + public void receiveBundle(ContactId c, Bundle b) throws DbException { if(LOG.isLoggable(Level.FINE)) - LOG.fine("Received bundle from " + n + ", " + LOG.fine("Received bundle from " + c + ", " + b.getSize() + " bytes"); // Mark all messages in acked batches as seen synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(messageLock) { synchronized(messageStatusLock) { int acks = 0; @@ -325,7 +255,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { acks++; Txn txn = db.startTransaction(); try { - db.removeAckedBatch(txn, n, ack); + db.removeAckedBatch(txn, c, ack); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -337,17 +267,17 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } } } - // Update the neighbour's subscriptions + // Update the contact's subscriptions synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(messageStatusLock) { Txn txn = db.startTransaction(); try { - db.clearSubscriptions(txn, n); + db.clearSubscriptions(txn, c); int subs = 0; for(GroupId g : b.getSubscriptions()) { subs++; - db.addSubscription(txn, n, g); + db.addSubscription(txn, c, g); } if(LOG.isLoggable(Level.FINE)) LOG.fine("Received " + subs + " subscriptions"); @@ -364,7 +294,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { batches++; waitForPermissionToWrite(); synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(messageLock) { synchronized(messageStatusLock) { synchronized(subscriptionLock) { @@ -375,13 +305,13 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { received++; GroupId g = m.getGroup(); if(db.containsSubscription(txn, g)) { - if(storeMessage(txn, m, n)) stored++; + if(storeMessage(txn, m, c)) stored++; } } if(LOG.isLoggable(Level.FINE)) LOG.fine("Received " + received + " messages, stored " + stored); - db.addBatchToAck(txn, n, batch.getId()); + db.addBatchToAck(txn, c, batch.getId()); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -397,12 +327,12 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { // Find any lost batches that need to be retransmitted Set<BatchId> lost; synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(messageLock) { synchronized(messageStatusLock) { Txn txn = db.startTransaction(); try { - lost = db.addReceivedBundle(txn, n, b.getId()); + lost = db.addReceivedBundle(txn, c, b.getId()); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -413,14 +343,14 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } for(BatchId batch : lost) { synchronized(contactLock) { - if(!containsNeighbour(n)) return; + if(!containsContact(c)) return; synchronized(messageLock) { synchronized(messageStatusLock) { Txn txn = db.startTransaction(); try { if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing lost batch"); - db.removeLostBatch(txn, n, batch); + db.removeLostBatch(txn, c, batch); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -432,4 +362,74 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { } System.gc(); } + + public void removeContact(ContactId c) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Removing contact " + c); + synchronized(contactLock) { + synchronized(messageStatusLock) { + Txn txn = db.startTransaction(); + try { + db.removeContact(txn, c); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + } + } + + public void setRating(AuthorId a, Rating r) throws DbException { + synchronized(messageLock) { + synchronized(ratingLock) { + Txn txn = db.startTransaction(); + try { + Rating old = db.setRating(txn, a, r); + // Update the sendability of the author's messages + if(r == Rating.GOOD && old != Rating.GOOD) + updateAuthorSendability(txn, a, true); + else if(r != Rating.GOOD && old == Rating.GOOD) + updateAuthorSendability(txn, a, false); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + } + } + + public void subscribe(GroupId g) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g); + synchronized(subscriptionLock) { + Txn txn = db.startTransaction(); + try { + db.addSubscription(txn, g); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + } + + public void unsubscribe(GroupId g) throws DbException { + if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g); + synchronized(contactLock) { + synchronized(messageLock) { + synchronized(messageStatusLock) { + synchronized(subscriptionLock) { + Txn txn = db.startTransaction(); + try { + db.removeSubscription(txn, g); + db.commitTransaction(txn); + } catch(DbException e) { + db.abortTransaction(txn); + throw e; + } + } + } + } + } + } }