diff --git a/briar-api/src/org/briarproject/api/contact/ContactManager.java b/briar-api/src/org/briarproject/api/contact/ContactManager.java
index 3b311d66d..ffc493477 100644
--- a/briar-api/src/org/briarproject/api/contact/ContactManager.java
+++ b/briar-api/src/org/briarproject/api/contact/ContactManager.java
@@ -1,6 +1,7 @@
package org.briarproject.api.contact;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId;
@@ -30,10 +31,10 @@ public interface ContactManager {
void removeContact(ContactId c) throws DbException;
interface AddContactHook {
- void addingContact(Contact c);
+ void addingContact(Transaction txn, Contact c) throws DbException;
}
interface RemoveContactHook {
- void removingContact(Contact c);
+ void removingContact(Transaction txn, Contact c) throws DbException;
}
}
diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
index 435d1025b..d38dc08d6 100644
--- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
+++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java
@@ -26,72 +26,85 @@ import java.util.Map;
/**
* Encapsulates the database implementation and exposes high-level operations
* to other components.
- *
+ *
* This interface's methods are blocking, but they do not call out into other
* components except to broadcast {@link org.briarproject.api.event.Event
* Events}, so they can safely be called while holding locks.
*/
public interface DatabaseComponent {
- /** Opens the database and returns true if the database already existed. */
+ /**
+ * Opens the database and returns true if the database already existed.
+ */
boolean open() throws DbException;
- /** Waits for any open transactions to finish and closes the database. */
+ /**
+ * Waits for any open transactions to finish and closes the database.
+ */
void close() throws DbException, IOException;
- /** Starts a new transaction and returns an object representing it. */
+ /**
+ * Starts a new transaction and returns an object representing it.
+ */
Transaction startTransaction() throws DbException;
/**
- * Aborts the given transaction - no changes made during the transaction
- * will be applied to the database.
+ * Ends a transaction. If the transaction's
+ * {@link Transaction#setComplete() commit} flag is set, the
+ * transaction is committed, otherwise it is aborted.
*/
- void abortTransaction(Transaction txn);
-
- /**
- * Commits the given transaction - all changes made during the transaction
- * will be applied to the database.
- */
- void commitTransaction(Transaction txn) throws DbException;
+ void endTransaction(Transaction txn) throws DbException;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact.
*/
- ContactId addContact(Author remote, AuthorId local) throws DbException;
-
- /** Stores a group. */
- void addGroup(Group g) throws DbException;
-
- /** Stores a local pseudonym. */
- void addLocalAuthor(LocalAuthor a) throws DbException;
-
- /** Stores a local message. */
- void addLocalMessage(Message m, ClientId c, Metadata meta, boolean shared)
+ ContactId addContact(Transaction txn, Author remote, AuthorId local)
throws DbException;
- /** Stores a transport. */
- void addTransport(TransportId t, int maxLatency) throws DbException;
+ /**
+ * Stores a group.
+ */
+ void addGroup(Transaction txn, Group g) throws DbException;
+
+ /**
+ * Stores a local pseudonym.
+ */
+ void addLocalAuthor(Transaction txn, LocalAuthor a) throws DbException;
+
+ /**
+ * Stores a local message.
+ */
+ void addLocalMessage(Transaction txn, Message m, ClientId c, Metadata meta,
+ boolean shared) throws DbException;
+
+ /**
+ * Stores a transport.
+ */
+ void addTransport(Transaction txn, TransportId t, int maxLatency)
+ throws DbException;
/**
* Stores transport keys for a newly added contact.
*/
- void addTransportKeys(ContactId c, TransportKeys k) throws DbException;
+ void addTransportKeys(Transaction txn, ContactId c, TransportKeys k)
+ throws DbException;
/**
* Deletes the message with the given ID. The message ID and any other
* associated data are not deleted.
*/
- void deleteMessage(MessageId m) throws DbException;
+ void deleteMessage(Transaction txn, MessageId m) throws DbException;
/** Deletes any metadata associated with the given message. */
- void deleteMessageMetadata(MessageId m) throws DbException;
+ void deleteMessageMetadata(Transaction txn, MessageId m) throws DbException;
/**
* Returns an acknowledgement for the given contact, or null if there are
* no messages to acknowledge.
*/
- Ack generateAck(ContactId c, int maxMessages) throws DbException;
+ Ack generateAck(Transaction txn, ContactId c, int maxMessages)
+ throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
@@ -99,22 +112,23 @@ public interface DatabaseComponent {
* transport with the given maximum latency. Returns null if there are no
* sendable messages that fit in the given length.
*/
- Collection generateBatch(ContactId c, int maxLength,
- int maxLatency) throws DbException;
+ Collection generateBatch(Transaction txn, ContactId c,
+ int maxLength, int maxLatency) throws DbException;
/**
* Returns an offer for the given contact for transmission over a
* transport with the given maximum latency, or null if there are no
* messages to offer.
*/
- Offer generateOffer(ContactId c, int maxMessages, int maxLatency)
- throws DbException;
+ Offer generateOffer(Transaction txn, ContactId c, int maxMessages,
+ int maxLatency) throws DbException;
/**
* Returns a request for the given contact, or null if there are no
* messages to request.
*/
- Request generateRequest(ContactId c, int maxMessages) throws DbException;
+ Request generateRequest(Transaction txn, ContactId c, int maxMessages)
+ throws DbException;
/**
* Returns a batch of raw messages for the given contact, with a total
@@ -123,158 +137,226 @@ public interface DatabaseComponent {
* requested by the contact are returned. Returns null if there are no
* sendable messages that fit in the given length.
*/
- Collection generateRequestedBatch(ContactId c, int maxLength,
- int maxLatency) throws DbException;
+ Collection generateRequestedBatch(Transaction txn, ContactId c,
+ int maxLength, int maxLatency) throws DbException;
- /** Returns the contact with the given ID. */
- Contact getContact(ContactId c) throws DbException;
+ /**
+ * Returns the contact with the given ID.
+ */
+ Contact getContact(Transaction txn, ContactId c) throws DbException;
- /** Returns all contacts. */
- Collection getContacts() throws DbException;
+ /**
+ * Returns all contacts.
+ */
+ Collection getContacts(Transaction txn) throws DbException;
- /** Returns all contacts associated with the given local pseudonym. */
- Collection getContacts(AuthorId a) throws DbException;
+ /**
+ * Returns all contacts associated with the given local pseudonym.
+ */
+ Collection getContacts(Transaction txn, AuthorId a)
+ throws DbException;
- /** Returns the unique ID for this device. */
- DeviceId getDeviceId() throws DbException;
+ /**
+ * Returns the unique ID for this device.
+ */
+ DeviceId getDeviceId(Transaction txn) throws DbException;
- /** Returns the group with the given ID. */
- Group getGroup(GroupId g) throws DbException;
+ /**
+ * Returns the group with the given ID.
+ */
+ Group getGroup(Transaction txn, GroupId g) throws DbException;
- /** Returns the metadata for the given group. */
- Metadata getGroupMetadata(GroupId g) throws DbException;
+ /**
+ * Returns the metadata for the given group.
+ */
+ Metadata getGroupMetadata(Transaction txn, GroupId g) throws DbException;
- /** Returns all groups belonging to the given client. */
- Collection getGroups(ClientId c) throws DbException;
+ /**
+ * Returns all groups belonging to the given client.
+ */
+ Collection getGroups(Transaction txn, ClientId c) throws DbException;
- /** Returns the local pseudonym with the given ID. */
- LocalAuthor getLocalAuthor(AuthorId a) throws DbException;
+ /**
+ * Returns the local pseudonym with the given ID.
+ */
+ LocalAuthor getLocalAuthor(Transaction txn, AuthorId a) throws DbException;
- /** Returns all local pseudonyms. */
- Collection getLocalAuthors() throws DbException;
+ /**
+ * Returns all local pseudonyms.
+ */
+ Collection getLocalAuthors(Transaction txn) throws DbException;
/**
* Returns the IDs of any messages that need to be validated by the given
* client.
*/
- Collection getMessagesToValidate(ClientId c) throws DbException;
-
- /** Returns the message with the given ID, in serialised form. */
- byte[] getRawMessage(MessageId m) throws DbException;
-
- /** Returns the metadata for all messages in the given group. */
- Map getMessageMetadata(GroupId g)
+ Collection getMessagesToValidate(Transaction txn, ClientId c)
throws DbException;
- /** Returns the metadata for the given message. */
- Metadata getMessageMetadata(MessageId m) throws DbException;
+ /**
+ * Returns the message with the given ID, in serialised form.
+ */
+ byte[] getRawMessage(Transaction txn, MessageId m) throws DbException;
+
+ /**
+ * Returns the metadata for all messages in the given group.
+ */
+ Map getMessageMetadata(Transaction txn, GroupId g)
+ throws DbException;
+
+ /**
+ * Returns the metadata for the given message.
+ */
+ Metadata getMessageMetadata(Transaction txn, MessageId m)
+ throws DbException;
/**
* Returns the status of all messages in the given group with respect to
* the given contact.
*/
- Collection getMessageStatus(ContactId c, GroupId g)
- throws DbException;
+ Collection getMessageStatus(Transaction txn, ContactId c,
+ GroupId g) throws DbException;
/**
* Returns the status of the given message with respect to the given
* contact.
*/
- MessageStatus getMessageStatus(ContactId c, MessageId m)
+ MessageStatus getMessageStatus(Transaction txn, ContactId c, MessageId m)
throws DbException;
- /** Returns all settings in the given namespace. */
- Settings getSettings(String namespace) throws DbException;
+ /**
+ * Returns all settings in the given namespace.
+ */
+ Settings getSettings(Transaction txn, String namespace) throws DbException;
- /** Returns all transport keys for the given transport. */
- Map getTransportKeys(TransportId t)
+ /**
+ * Returns all transport keys for the given transport.
+ */
+ Map getTransportKeys(Transaction txn,
+ TransportId t) throws DbException;
+
+ /**
+ * Returns the maximum latencies in milliseconds of all transports.
+ */
+ Map getTransportLatencies(Transaction txn)
throws DbException;
- /** Returns the maximum latencies in milliseconds of all transports. */
- Map getTransportLatencies() throws DbException;
-
/**
* Increments the outgoing stream counter for the given contact and
* transport in the given rotation period .
*/
- void incrementStreamCounter(ContactId c, TransportId t, long rotationPeriod)
- throws DbException;
+ void incrementStreamCounter(Transaction txn, ContactId c, TransportId t,
+ long rotationPeriod) throws DbException;
- /** Returns true if the given group is visible to the given contact. */
- boolean isVisibleToContact(ContactId c, GroupId g) throws DbException;
+ /**
+ * Returns true if the given group is visible to the given contact.
+ */
+ boolean isVisibleToContact(Transaction txn, ContactId c, GroupId g)
+ throws DbException;
/**
* Merges the given metadata with the existing metadata for the given
* group.
*/
- void mergeGroupMetadata(GroupId g, Metadata meta) throws DbException;
+ void mergeGroupMetadata(Transaction txn, GroupId g, Metadata meta)
+ throws DbException;
/**
* Merges the given metadata with the existing metadata for the given
* message.
*/
- void mergeMessageMetadata(MessageId m, Metadata meta) throws DbException;
+ void mergeMessageMetadata(Transaction txn, MessageId m, Metadata meta)
+ throws DbException;
/**
* Merges the given settings with the existing settings in the given
* namespace.
*/
- void mergeSettings(Settings s, String namespace) throws DbException;
+ void mergeSettings(Transaction txn, Settings s, String namespace)
+ throws DbException;
- /** Processes an ack from the given contact. */
- void receiveAck(ContactId c, Ack a) throws DbException;
+ /**
+ * Processes an ack from the given contact.
+ */
+ void receiveAck(Transaction txn, ContactId c, Ack a) throws DbException;
- /** Processes a message from the given contact. */
- void receiveMessage(ContactId c, Message m) throws DbException;
+ /**
+ * Processes a message from the given contact.
+ */
+ void receiveMessage(Transaction txn, ContactId c, Message m)
+ throws DbException;
- /** Processes an offer from the given contact. */
- void receiveOffer(ContactId c, Offer o) throws DbException;
+ /**
+ * Processes an offer from the given contact.
+ */
+ void receiveOffer(Transaction txn, ContactId c, Offer o) throws DbException;
- /** Processes a request from the given contact. */
- void receiveRequest(ContactId c, Request r) throws DbException;
+ /**
+ * Processes a request from the given contact.
+ */
+ void receiveRequest(Transaction txn, ContactId c, Request r)
+ throws DbException;
- /** Removes a contact (and all associated state) from the database. */
- void removeContact(ContactId c) throws DbException;
+ /**
+ * Removes a contact (and all associated state) from the database.
+ */
+ void removeContact(Transaction txn, ContactId c) throws DbException;
- /** Removes a group (and all associated state) from the database. */
- void removeGroup(Group g) throws DbException;
+ /**
+ * Removes a group (and all associated state) from the database.
+ */
+ void removeGroup(Transaction txn, Group g) throws DbException;
/**
* Removes a local pseudonym (and all associated state) from the database.
*/
- void removeLocalAuthor(AuthorId a) throws DbException;
+ void removeLocalAuthor(Transaction txn, AuthorId a) throws DbException;
- /** Removes a transport (and all associated state) from the database. */
- void removeTransport(TransportId t) throws DbException;
+ /**
+ * Removes a transport (and all associated state) from the database.
+ */
+ void removeTransport(Transaction txn, TransportId t) throws DbException;
- /** Sets the status of the given contact. */
- void setContactStatus(ContactId c, StorageStatus s) throws DbException;
+ /**
+ * Sets the status of the given contact.
+ */
+ void setContactStatus(Transaction txn, ContactId c, StorageStatus s)
+ throws DbException;
- /** Sets the status of the given local pseudonym. */
- void setLocalAuthorStatus(AuthorId a, StorageStatus s)
- throws DbException;
+ /**
+ * Sets the status of the given local pseudonym.
+ */
+ void setLocalAuthorStatus(Transaction txn, AuthorId a, StorageStatus s)
+ throws DbException;
- /** Marks the given message as shared or unshared. */
- void setMessageShared(Message m, boolean shared) throws DbException;
+ /**
+ * Marks the given message as shared or unshared.
+ */
+ void setMessageShared(Transaction txn, Message m, boolean shared)
+ throws DbException;
- /** Marks the given message as valid or invalid. */
- void setMessageValid(Message m, ClientId c, boolean valid)
+ /**
+ * Marks the given message as valid or invalid.
+ */
+ void setMessageValid(Transaction txn, Message m, ClientId c, boolean valid)
throws DbException;
/**
* Sets the reordering window for the given contact and transport in the
* given rotation period.
*/
- void setReorderingWindow(ContactId c, TransportId t, long rotationPeriod,
- long base, byte[] bitmap) throws DbException;
+ void setReorderingWindow(Transaction txn, ContactId c, TransportId t,
+ long rotationPeriod, long base, byte[] bitmap) throws DbException;
- /** Makes a group visible or invisible to a contact. */
- void setVisibleToContact(ContactId c, GroupId g, boolean visible)
- throws DbException;
+ /**
+ * Makes a group visible or invisible to a contact.
+ */
+ void setVisibleToContact(Transaction txn, ContactId c, GroupId g,
+ boolean visible) throws DbException;
/**
* Stores the given transport keys, deleting any keys they have replaced.
*/
- void updateTransportKeys(Map keys)
- throws DbException;
+ void updateTransportKeys(Transaction txn,
+ Map keys) throws DbException;
}
diff --git a/briar-api/src/org/briarproject/api/db/Transaction.java b/briar-api/src/org/briarproject/api/db/Transaction.java
index 2ea803b05..46497a039 100644
--- a/briar-api/src/org/briarproject/api/db/Transaction.java
+++ b/briar-api/src/org/briarproject/api/db/Transaction.java
@@ -1,15 +1,38 @@
package org.briarproject.api.db;
-/** A wrapper around a database transaction. */
+/**
+ * A wrapper around a database transaction. Transactions are not thread-safe.
+ */
public class Transaction {
private final Object txn;
+ private boolean complete = false;
public Transaction(Object txn) {
this.txn = txn;
}
+ /**
+ * Returns the database transaction. The type of the returned object
+ * depends on the database implementation.
+ */
public Object unbox() {
return txn;
}
+
+ /**
+ * Returns true if the transaction is ready to be committed.
+ */
+ public boolean isComplete() {
+ return complete;
+ }
+
+ /**
+ * Marks the transaction as ready to be committed. This method must not be
+ * called more than once.
+ */
+ public void setComplete() {
+ if (complete) throw new IllegalStateException();
+ complete = true;
+ }
}
diff --git a/briar-api/src/org/briarproject/api/identity/IdentityManager.java b/briar-api/src/org/briarproject/api/identity/IdentityManager.java
index e872d845e..f2a4db2d9 100644
--- a/briar-api/src/org/briarproject/api/identity/IdentityManager.java
+++ b/briar-api/src/org/briarproject/api/identity/IdentityManager.java
@@ -1,6 +1,7 @@
package org.briarproject.api.identity;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import java.util.Collection;
@@ -25,10 +26,11 @@ public interface IdentityManager {
void removeLocalAuthor(AuthorId a) throws DbException;
interface AddIdentityHook {
- void addingIdentity(LocalAuthor a);
+ void addingIdentity(Transaction txn, LocalAuthor a) throws DbException;
}
interface RemoveIdentityHook {
- void removingIdentity(LocalAuthor a);
+ void removingIdentity(Transaction txn, LocalAuthor a)
+ throws DbException;
}
}
diff --git a/briar-api/src/org/briarproject/api/sync/ValidationManager.java b/briar-api/src/org/briarproject/api/sync/ValidationManager.java
index ff1e854c3..690bc54e2 100644
--- a/briar-api/src/org/briarproject/api/sync/ValidationManager.java
+++ b/briar-api/src/org/briarproject/api/sync/ValidationManager.java
@@ -1,6 +1,8 @@
package org.briarproject.api.sync;
+import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
+import org.briarproject.api.db.Transaction;
/**
* Responsible for managing message validators and passing them messages to
@@ -35,6 +37,7 @@ public interface ValidationManager {
void registerValidationHook(ValidationHook hook);
interface ValidationHook {
- void validatingMessage(Message m, ClientId c, Metadata meta);
+ void validatingMessage(Transaction txn, Message m, ClientId c,
+ Metadata meta) throws DbException;
}
}
diff --git a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java
index b8f9553c8..7bdb3bc45 100644
--- a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java
+++ b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java
@@ -8,6 +8,7 @@ import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.NoSuchContactException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.ContactAddedEvent;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.EventBus;
@@ -52,19 +53,31 @@ class ContactManagerImpl implements ContactManager, Service,
public boolean start() {
// Finish adding/removing any partly added/removed contacts
try {
- for (Contact c : db.getContacts()) {
- if (c.getStatus().equals(ADDING)) {
- for (AddContactHook hook : addHooks)
- hook.addingContact(c);
- db.setContactStatus(c.getId(), ACTIVE);
- eventBus.broadcast(new ContactAddedEvent(c.getId()));
- } else if (c.getStatus().equals(REMOVING)) {
- for (RemoveContactHook hook : removeHooks)
- hook.removingContact(c);
- db.removeContact(c.getId());
- eventBus.broadcast(new ContactRemovedEvent(c.getId()));
+ List added = new ArrayList();
+ List removed = new ArrayList();
+ Transaction txn = db.startTransaction();
+ try {
+ for (Contact c : db.getContacts(txn)) {
+ if (c.getStatus().equals(ADDING)) {
+ for (AddContactHook hook : addHooks)
+ hook.addingContact(txn, c);
+ db.setContactStatus(txn, c.getId(), ACTIVE);
+ added.add(c.getId());
+ } else if (c.getStatus().equals(REMOVING)) {
+ for (RemoveContactHook hook : removeHooks)
+ hook.removingContact(txn, c);
+ db.removeContact(txn, c.getId());
+ removed.add(c.getId());
+ }
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
+ for (ContactId c : added)
+ eventBus.broadcast(new ContactAddedEvent(c));
+ for (ContactId c : removed)
+ eventBus.broadcast(new ContactRemovedEvent(c));
return true;
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -90,24 +103,46 @@ class ContactManagerImpl implements ContactManager, Service,
@Override
public ContactId addContact(Author remote, AuthorId local)
throws DbException {
- ContactId c = db.addContact(remote, local);
- Contact contact = db.getContact(c);
- for (AddContactHook hook : addHooks) hook.addingContact(contact);
- db.setContactStatus(c, ACTIVE);
+ ContactId c;
+ Transaction txn = db.startTransaction();
+ try {
+ c = db.addContact(txn, remote, local);
+ Contact contact = db.getContact(txn, c);
+ for (AddContactHook hook : addHooks)
+ hook.addingContact(txn, contact);
+ db.setContactStatus(txn, c, ACTIVE);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
eventBus.broadcast(new ContactAddedEvent(c));
return c;
}
@Override
public Contact getContact(ContactId c) throws DbException {
- Contact contact = db.getContact(c);
+ Contact contact;
+ Transaction txn = db.startTransaction();
+ try {
+ contact = db.getContact(txn, c);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (contact.getStatus().equals(ACTIVE)) return contact;
throw new NoSuchContactException();
}
@Override
public Collection getContacts() throws DbException {
- Collection contacts = db.getContacts();
+ Collection contacts;
+ Transaction txn = db.startTransaction();
+ try {
+ contacts = db.getContacts(txn);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
// Filter out any contacts that are being added or removed
List active = new ArrayList(contacts.size());
for (Contact c : contacts)
@@ -117,21 +152,30 @@ class ContactManagerImpl implements ContactManager, Service,
@Override
public void removeContact(ContactId c) throws DbException {
- Contact contact = db.getContact(c);
- db.setContactStatus(c, REMOVING);
- for (RemoveContactHook hook : removeHooks)
- hook.removingContact(contact);
- db.removeContact(c);
+ Transaction txn = db.startTransaction();
+ try {
+ removeContact(txn, c);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
eventBus.broadcast(new ContactRemovedEvent(c));
}
+ private void removeContact(Transaction txn, ContactId c)
+ throws DbException {
+ Contact contact = db.getContact(txn, c);
+ db.setContactStatus(txn, c, REMOVING);
+ for (RemoveContactHook hook : removeHooks)
+ hook.removingContact(txn, contact);
+ db.removeContact(txn, c);
+ }
+
@Override
- public void removingIdentity(LocalAuthor a) {
+ public void removingIdentity(Transaction txn, LocalAuthor a)
+ throws DbException {
// Remove any contacts of the local pseudonym that's being removed
- try {
- for (ContactId c : db.getContacts(a.getId())) removeContact(c);
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- }
+ for (ContactId c : db.getContacts(txn, a.getId()))
+ removeContact(txn, c);
}
}
diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java
index 9e46dabb9..8d4c71166 100644
--- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java
+++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java
@@ -66,6 +66,8 @@ import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN;
import static org.briarproject.api.sync.ValidationManager.Validity.VALID;
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
+// TODO: Callers should broadcast events after committing transactions
+
/**
* An implementation of DatabaseComponent using reentrant read-write locks.
* Depending on the JVM's lock implementation, this implementation may allow
@@ -123,76 +125,55 @@ class DatabaseComponentImpl implements DatabaseComponent {
return new Transaction(db.startTransaction());
}
- public void abortTransaction(Transaction txn) {
- db.abortTransaction(txnClass.cast(txn.unbox()));
+ public void endTransaction(Transaction transaction) throws DbException {
+ T txn = txnClass.cast(transaction.unbox());
+ if (transaction.isComplete()) db.commitTransaction(txn);
+ else db.abortTransaction(txn);
}
- public void commitTransaction(Transaction txn) throws DbException {
- db.commitTransaction(txnClass.cast(txn.unbox()));
+ private T unbox(Transaction transaction) {
+ if (transaction.isComplete()) throw new IllegalStateException();
+ return txnClass.cast(transaction.unbox());
}
- public ContactId addContact(Author remote, AuthorId local)
- throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsLocalAuthor(txn, local))
- throw new NoSuchLocalAuthorException();
- if (db.containsContact(txn, remote.getId(), local))
- throw new ContactExistsException();
- ContactId c = db.addContact(txn, remote, local);
- db.commitTransaction(txn);
- return c;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public ContactId addContact(Transaction transaction, Author remote,
+ AuthorId local) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsLocalAuthor(txn, local))
+ throw new NoSuchLocalAuthorException();
+ if (db.containsContact(txn, remote.getId(), local))
+ throw new ContactExistsException();
+ return db.addContact(txn, remote, local);
}
- public void addGroup(Group g) throws DbException {
+ public void addGroup(Transaction transaction, Group g) throws DbException {
boolean added = false;
- T txn = db.startTransaction();
- try {
- if (!db.containsGroup(txn, g.getId())) {
- db.addGroup(txn, g);
- added = true;
- }
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ T txn = unbox(transaction);
+ if (!db.containsGroup(txn, g.getId())) {
+ db.addGroup(txn, g);
+ added = true;
}
if (added) eventBus.broadcast(new GroupAddedEvent(g));
}
- public void addLocalAuthor(LocalAuthor a) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsLocalAuthor(txn, a.getId()))
- db.addLocalAuthor(txn, a);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void addLocalAuthor(Transaction transaction, LocalAuthor a)
+ throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsLocalAuthor(txn, a.getId()))
+ db.addLocalAuthor(txn, a);
}
- public void addLocalMessage(Message m, ClientId c, Metadata meta,
- boolean shared) throws DbException {
+ public void addLocalMessage(Transaction transaction, Message m, ClientId c,
+ Metadata meta, boolean shared) throws DbException {
boolean added = false;
- T txn = db.startTransaction();
- try {
- if (!db.containsGroup(txn, m.getGroupId()))
- throw new NoSuchGroupException();
- if (!db.containsMessage(txn, m.getId())) {
- addMessage(txn, m, VALID, shared, null);
- added = true;
- }
- db.mergeMessageMetadata(txn, m.getId(), meta);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ T txn = unbox(transaction);
+ if (!db.containsGroup(txn, m.getGroupId()))
+ throw new NoSuchGroupException();
+ if (!db.containsMessage(txn, m.getId())) {
+ addMessage(txn, m, VALID, shared, null);
+ added = true;
}
+ db.mergeMessageMetadata(txn, m.getId(), meta);
if (added) {
eventBus.broadcast(new MessageAddedEvent(m, null));
eventBus.broadcast(new MessageValidatedEvent(m, c, true, true));
@@ -223,538 +204,327 @@ class DatabaseComponentImpl implements DatabaseComponent {
}
}
- public void addTransport(TransportId t, int maxLatency) throws DbException {
+ public void addTransport(Transaction transaction, TransportId t,
+ int maxLatency) throws DbException {
boolean added = false;
- T txn = db.startTransaction();
- try {
- if (!db.containsTransport(txn, t)) {
- db.addTransport(txn, t, maxLatency);
- added = true;
- }
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ T txn = unbox(transaction);
+ if (!db.containsTransport(txn, t)) {
+ db.addTransport(txn, t, maxLatency);
+ added = true;
}
if (added) eventBus.broadcast(new TransportAddedEvent(t, maxLatency));
}
- public void addTransportKeys(ContactId c, TransportKeys k)
+ public void addTransportKeys(Transaction transaction, ContactId c,
+ TransportKeys k) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsTransport(txn, k.getTransportId()))
+ throw new NoSuchTransportException();
+ db.addTransportKeys(txn, c, k);
+ }
+
+ public void deleteMessage(Transaction transaction, MessageId m)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsTransport(txn, k.getTransportId()))
- throw new NoSuchTransportException();
- db.addTransportKeys(txn, c, k);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m))
+ throw new NoSuchMessageException();
+ db.deleteMessage(txn, m);
}
- public void deleteMessage(MessageId m) throws DbException {
- lock.writeLock().lock();
- try {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m))
- throw new NoSuchMessageException();
- db.deleteMessage(txn, m);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- } finally {
- lock.writeLock().unlock();
- }
+ public void deleteMessageMetadata(Transaction transaction, MessageId m)
+ throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m))
+ throw new NoSuchMessageException();
+ db.deleteMessageMetadata(txn, m);
}
- public void deleteMessageMetadata(MessageId m) throws DbException {
- lock.writeLock().lock();
- try {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m))
- throw new NoSuchMessageException();
- db.deleteMessageMetadata(txn, m);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- } finally {
- lock.writeLock().unlock();
- }
- }
-
- public Ack generateAck(ContactId c, int maxMessages) throws DbException {
+ public Ack generateAck(Transaction transaction, ContactId c,
+ int maxMessages) throws DbException {
Collection ids;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- ids = db.getMessagesToAck(txn, c, maxMessages);
- if (!ids.isEmpty()) db.lowerAckFlag(txn, c, ids);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ ids = db.getMessagesToAck(txn, c, maxMessages);
+ if (!ids.isEmpty()) db.lowerAckFlag(txn, c, ids);
if (ids.isEmpty()) return null;
return new Ack(ids);
}
- public Collection generateBatch(ContactId c, int maxLength,
- int maxLatency) throws DbException {
+ public Collection generateBatch(Transaction transaction,
+ ContactId c, int maxLength, int maxLatency) throws DbException {
Collection ids;
- List messages = new ArrayList();
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- ids = db.getMessagesToSend(txn, c, maxLength);
- for (MessageId m : ids) {
- messages.add(db.getRawMessage(txn, m));
- db.updateExpiryTime(txn, c, m, maxLatency);
- }
- if (!ids.isEmpty()) db.lowerRequestedFlag(txn, c, ids);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ List messages;
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ ids = db.getMessagesToSend(txn, c, maxLength);
+ messages = new ArrayList(ids.size());
+ for (MessageId m : ids) {
+ messages.add(db.getRawMessage(txn, m));
+ db.updateExpiryTime(txn, c, m, maxLatency);
}
+ if (!ids.isEmpty()) db.lowerRequestedFlag(txn, c, ids);
if (messages.isEmpty()) return null;
if (!ids.isEmpty()) eventBus.broadcast(new MessagesSentEvent(c, ids));
return Collections.unmodifiableList(messages);
}
- public Offer generateOffer(ContactId c, int maxMessages, int maxLatency)
- throws DbException {
+ public Offer generateOffer(Transaction transaction, ContactId c,
+ int maxMessages, int maxLatency) throws DbException {
Collection ids;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- ids = db.getMessagesToOffer(txn, c, maxMessages);
- for (MessageId m : ids) db.updateExpiryTime(txn, c, m, maxLatency);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ ids = db.getMessagesToOffer(txn, c, maxMessages);
+ for (MessageId m : ids) db.updateExpiryTime(txn, c, m, maxLatency);
if (ids.isEmpty()) return null;
return new Offer(ids);
}
- public Request generateRequest(ContactId c, int maxMessages)
- throws DbException {
+ public Request generateRequest(Transaction transaction, ContactId c,
+ int maxMessages) throws DbException {
Collection ids;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- ids = db.getMessagesToRequest(txn, c, maxMessages);
- if (!ids.isEmpty()) db.removeOfferedMessages(txn, c, ids);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ ids = db.getMessagesToRequest(txn, c, maxMessages);
+ if (!ids.isEmpty()) db.removeOfferedMessages(txn, c, ids);
if (ids.isEmpty()) return null;
return new Request(ids);
}
- public Collection generateRequestedBatch(ContactId c, int maxLength,
- int maxLatency) throws DbException {
+ public Collection generateRequestedBatch(Transaction transaction,
+ ContactId c, int maxLength, int maxLatency) throws DbException {
Collection ids;
- List messages = new ArrayList();
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- ids = db.getRequestedMessagesToSend(txn, c, maxLength);
- for (MessageId m : ids) {
- messages.add(db.getRawMessage(txn, m));
- db.updateExpiryTime(txn, c, m, maxLatency);
- }
- if (!ids.isEmpty()) db.lowerRequestedFlag(txn, c, ids);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ List messages;
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ ids = db.getRequestedMessagesToSend(txn, c, maxLength);
+ messages = new ArrayList(ids.size());
+ for (MessageId m : ids) {
+ messages.add(db.getRawMessage(txn, m));
+ db.updateExpiryTime(txn, c, m, maxLatency);
}
+ if (!ids.isEmpty()) db.lowerRequestedFlag(txn, c, ids);
if (messages.isEmpty()) return null;
if (!ids.isEmpty()) eventBus.broadcast(new MessagesSentEvent(c, ids));
return Collections.unmodifiableList(messages);
}
- public Contact getContact(ContactId c) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- Contact contact = db.getContact(txn, c);
- db.commitTransaction(txn);
- return contact;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Collection getContacts() throws DbException {
- T txn = db.startTransaction();
- try {
- Collection contacts = db.getContacts(txn);
- db.commitTransaction(txn);
- return contacts;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Collection getContacts(AuthorId a) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsLocalAuthor(txn, a))
- throw new NoSuchLocalAuthorException();
- Collection contacts = db.getContacts(txn, a);
- db.commitTransaction(txn);
- return contacts;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public DeviceId getDeviceId() throws DbException {
- T txn = db.startTransaction();
- try {
- DeviceId id = db.getDeviceId(txn);
- db.commitTransaction(txn);
- return id;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Group getGroup(GroupId g) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- Group group = db.getGroup(txn, g);
- db.commitTransaction(txn);
- return group;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Metadata getGroupMetadata(GroupId g) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- Metadata metadata = db.getGroupMetadata(txn, g);
- db.commitTransaction(txn);
- return metadata;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Collection getGroups(ClientId c) throws DbException {
- T txn = db.startTransaction();
- try {
- Collection groups = db.getGroups(txn, c);
- db.commitTransaction(txn);
- return groups;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public LocalAuthor getLocalAuthor(AuthorId a) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsLocalAuthor(txn, a))
- throw new NoSuchLocalAuthorException();
- LocalAuthor localAuthor = db.getLocalAuthor(txn, a);
- db.commitTransaction(txn);
- return localAuthor;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Collection getLocalAuthors() throws DbException {
- T txn = db.startTransaction();
- try {
- Collection authors = db.getLocalAuthors(txn);
- db.commitTransaction(txn);
- return authors;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Collection getMessagesToValidate(ClientId c)
+ public Contact getContact(Transaction transaction, ContactId c)
throws DbException {
- T txn = db.startTransaction();
- try {
- Collection ids = db.getMessagesToValidate(txn, c);
- db.commitTransaction(txn);
- return ids;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ return db.getContact(txn, c);
}
- public byte[] getRawMessage(MessageId m) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m))
- throw new NoSuchMessageException();
- byte[] raw = db.getRawMessage(txn, m);
- db.commitTransaction(txn);
- return raw;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Map getMessageMetadata(GroupId g)
+ public Collection getContacts(Transaction transaction)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- Map metadata = db.getMessageMetadata(txn, g);
- db.commitTransaction(txn);
- return metadata;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ return db.getContacts(txn);
}
- public Metadata getMessageMetadata(MessageId m) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m))
- throw new NoSuchMessageException();
- Metadata metadata = db.getMessageMetadata(txn, m);
- db.commitTransaction(txn);
- return metadata;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public Collection getContacts(Transaction transaction,
+ AuthorId a) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsLocalAuthor(txn, a))
+ throw new NoSuchLocalAuthorException();
+ return db.getContacts(txn, a);
}
- public Collection getMessageStatus(ContactId c, GroupId g)
+ public DeviceId getDeviceId(Transaction transaction) throws DbException {
+ T txn = unbox(transaction);
+ return db.getDeviceId(txn);
+ }
+
+ public Group getGroup(Transaction transaction, GroupId g)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- Collection statuses = db.getMessageStatus(txn, c, g);
- db.commitTransaction(txn);
- return statuses;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ return db.getGroup(txn, g);
}
- public MessageStatus getMessageStatus(ContactId c, MessageId m)
+ public Metadata getGroupMetadata(Transaction transaction, GroupId g)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsMessage(txn, m))
- throw new NoSuchMessageException();
- MessageStatus status = db.getMessageStatus(txn, c, m);
- db.commitTransaction(txn);
- return status;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ return db.getGroupMetadata(txn, g);
}
- public Settings getSettings(String namespace) throws DbException {
- T txn = db.startTransaction();
- try {
- Settings s = db.getSettings(txn, namespace);
- db.commitTransaction(txn);
- return s;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public Map getTransportKeys(TransportId t)
+ public Collection getGroups(Transaction transaction, ClientId c)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsTransport(txn, t))
- throw new NoSuchTransportException();
- Map keys = db.getTransportKeys(txn, t);
- db.commitTransaction(txn);
- return keys;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ return db.getGroups(txn, c);
}
- public Map getTransportLatencies()
+ public LocalAuthor getLocalAuthor(Transaction transaction, AuthorId a)
throws DbException {
- T txn = db.startTransaction();
- try {
- Map latencies = db.getTransportLatencies(txn);
- db.commitTransaction(txn);
- return latencies;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsLocalAuthor(txn, a))
+ throw new NoSuchLocalAuthorException();
+ return db.getLocalAuthor(txn, a);
}
- public void incrementStreamCounter(ContactId c, TransportId t,
- long rotationPeriod) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsTransport(txn, t))
- throw new NoSuchTransportException();
- db.incrementStreamCounter(txn, c, t, rotationPeriod);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
- }
-
- public boolean isVisibleToContact(ContactId c, GroupId g)
+ public Collection getLocalAuthors(Transaction transaction)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- boolean visible = db.containsVisibleGroup(txn, c, g);
- db.commitTransaction(txn);
- return visible;
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ return db.getLocalAuthors(txn);
}
- public void mergeGroupMetadata(GroupId g, Metadata meta)
+ public Collection getMessagesToValidate(Transaction transaction,
+ ClientId c) throws DbException {
+ T txn = unbox(transaction);
+ return db.getMessagesToValidate(txn, c);
+ }
+
+ public byte[] getRawMessage(Transaction transaction, MessageId m)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- db.mergeGroupMetadata(txn, g, meta);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m))
+ throw new NoSuchMessageException();
+ return db.getRawMessage(txn, m);
}
- public void mergeMessageMetadata(MessageId m, Metadata meta)
+ public Map getMessageMetadata(Transaction transaction,
+ GroupId g) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ return db.getMessageMetadata(txn, g);
+ }
+
+ public Metadata getMessageMetadata(Transaction transaction, MessageId m)
throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m))
- throw new NoSuchMessageException();
- db.mergeMessageMetadata(txn, m, meta);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m))
+ throw new NoSuchMessageException();
+ return db.getMessageMetadata(txn, m);
}
- public void mergeSettings(Settings s, String namespace) throws DbException {
+ public Collection getMessageStatus(Transaction transaction,
+ ContactId c, GroupId g) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ return db.getMessageStatus(txn, c, g);
+ }
+
+ public MessageStatus getMessageStatus(Transaction transaction, ContactId c,
+ MessageId m) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsMessage(txn, m))
+ throw new NoSuchMessageException();
+ return db.getMessageStatus(txn, c, m);
+ }
+
+ public Settings getSettings(Transaction transaction, String namespace)
+ throws DbException {
+ T txn = unbox(transaction);
+ return db.getSettings(txn, namespace);
+ }
+
+ public Map getTransportKeys(
+ Transaction transaction, TransportId t) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsTransport(txn, t))
+ throw new NoSuchTransportException();
+ return db.getTransportKeys(txn, t);
+ }
+
+ public Map getTransportLatencies(
+ Transaction transaction) throws DbException {
+ T txn = unbox(transaction);
+ return db.getTransportLatencies(txn);
+ }
+
+ public void incrementStreamCounter(Transaction transaction, ContactId c,
+ TransportId t, long rotationPeriod) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsTransport(txn, t))
+ throw new NoSuchTransportException();
+ db.incrementStreamCounter(txn, c, t, rotationPeriod);
+ }
+
+ public boolean isVisibleToContact(Transaction transaction, ContactId c,
+ GroupId g) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ return db.containsVisibleGroup(txn, c, g);
+ }
+
+ public void mergeGroupMetadata(Transaction transaction, GroupId g,
+ Metadata meta) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ db.mergeGroupMetadata(txn, g, meta);
+ }
+
+ public void mergeMessageMetadata(Transaction transaction, MessageId m,
+ Metadata meta) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m))
+ throw new NoSuchMessageException();
+ db.mergeMessageMetadata(txn, m, meta);
+ }
+
+ public void mergeSettings(Transaction transaction, Settings s,
+ String namespace) throws DbException {
boolean changed = false;
- T txn = db.startTransaction();
- try {
- Settings old = db.getSettings(txn, namespace);
- Settings merged = new Settings();
- merged.putAll(old);
- merged.putAll(s);
- if (!merged.equals(old)) {
- db.mergeSettings(txn, s, namespace);
- changed = true;
- }
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ T txn = unbox(transaction);
+ Settings old = db.getSettings(txn, namespace);
+ Settings merged = new Settings();
+ merged.putAll(old);
+ merged.putAll(s);
+ if (!merged.equals(old)) {
+ db.mergeSettings(txn, s, namespace);
+ changed = true;
}
if (changed) eventBus.broadcast(new SettingsUpdatedEvent(namespace));
}
- public void receiveAck(ContactId c, Ack a) throws DbException {
+ public void receiveAck(Transaction transaction, ContactId c, Ack a)
+ throws DbException {
Collection acked = new ArrayList();
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- for (MessageId m : a.getMessageIds()) {
- if (db.containsVisibleMessage(txn, c, m)) {
- db.raiseSeenFlag(txn, c, m);
- acked.add(m);
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ for (MessageId m : a.getMessageIds()) {
+ if (db.containsVisibleMessage(txn, c, m)) {
+ db.raiseSeenFlag(txn, c, m);
+ acked.add(m);
}
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
}
eventBus.broadcast(new MessagesAckedEvent(c, acked));
}
- public void receiveMessage(ContactId c, Message m) throws DbException {
+ public void receiveMessage(Transaction transaction, ContactId c, Message m)
+ throws DbException {
boolean duplicate, visible;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- duplicate = db.containsMessage(txn, m.getId());
- visible = db.containsVisibleGroup(txn, c, m.getGroupId());
- if (visible) {
- if (!duplicate) addMessage(txn, m, UNKNOWN, false, c);
- db.raiseAckFlag(txn, c, m.getId());
- }
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ duplicate = db.containsMessage(txn, m.getId());
+ visible = db.containsVisibleGroup(txn, c, m.getGroupId());
+ if (visible) {
+ if (!duplicate) addMessage(txn, m, UNKNOWN, false, c);
+ db.raiseAckFlag(txn, c, m.getId());
}
if (visible) {
if (!duplicate) eventBus.broadcast(new MessageAddedEvent(m, c));
@@ -762,228 +532,157 @@ class DatabaseComponentImpl implements DatabaseComponent {
}
}
- public void receiveOffer(ContactId c, Offer o) throws DbException {
+ public void receiveOffer(Transaction transaction, ContactId c, Offer o)
+ throws DbException {
boolean ack = false, request = false;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- int count = db.countOfferedMessages(txn, c);
- for (MessageId m : o.getMessageIds()) {
- if (db.containsVisibleMessage(txn, c, m)) {
- db.raiseSeenFlag(txn, c, m);
- db.raiseAckFlag(txn, c, m);
- ack = true;
- } else if (count < MAX_OFFERED_MESSAGES) {
- db.addOfferedMessage(txn, c, m);
- request = true;
- count++;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ int count = db.countOfferedMessages(txn, c);
+ for (MessageId m : o.getMessageIds()) {
+ if (db.containsVisibleMessage(txn, c, m)) {
+ db.raiseSeenFlag(txn, c, m);
+ db.raiseAckFlag(txn, c, m);
+ ack = true;
+ } else if (count < MAX_OFFERED_MESSAGES) {
+ db.addOfferedMessage(txn, c, m);
+ request = true;
+ count++;
}
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
}
if (ack) eventBus.broadcast(new MessageToAckEvent(c));
if (request) eventBus.broadcast(new MessageToRequestEvent(c));
}
- public void receiveRequest(ContactId c, Request r) throws DbException {
+ public void receiveRequest(Transaction transaction, ContactId c, Request r)
+ throws DbException {
boolean requested = false;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- for (MessageId m : r.getMessageIds()) {
- if (db.containsVisibleMessage(txn, c, m)) {
- db.raiseRequestedFlag(txn, c, m);
- db.resetExpiryTime(txn, c, m);
- requested = true;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ for (MessageId m : r.getMessageIds()) {
+ if (db.containsVisibleMessage(txn, c, m)) {
+ db.raiseRequestedFlag(txn, c, m);
+ db.resetExpiryTime(txn, c, m);
+ requested = true;
}
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
}
if (requested) eventBus.broadcast(new MessageRequestedEvent(c));
}
- public void removeContact(ContactId c) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- db.removeContact(txn, c);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void removeContact(Transaction transaction, ContactId c)
+ throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ db.removeContact(txn, c);
}
- public void removeGroup(Group g) throws DbException {
+ public void removeGroup(Transaction transaction, Group g)
+ throws DbException {
Collection affected;
- T txn = db.startTransaction();
- try {
- GroupId id = g.getId();
- if (!db.containsGroup(txn, id))
- throw new NoSuchGroupException();
- affected = db.getVisibility(txn, id);
- db.removeGroup(txn, id);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ GroupId id = g.getId();
+ if (!db.containsGroup(txn, id))
+ throw new NoSuchGroupException();
+ affected = db.getVisibility(txn, id);
+ db.removeGroup(txn, id);
eventBus.broadcast(new GroupRemovedEvent(g));
eventBus.broadcast(new GroupVisibilityUpdatedEvent(affected));
}
- public void removeLocalAuthor(AuthorId a) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsLocalAuthor(txn, a))
- throw new NoSuchLocalAuthorException();
- db.removeLocalAuthor(txn, a);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void removeLocalAuthor(Transaction transaction, AuthorId a)
+ throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsLocalAuthor(txn, a))
+ throw new NoSuchLocalAuthorException();
+ db.removeLocalAuthor(txn, a);
}
- public void removeTransport(TransportId t) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsTransport(txn, t))
- throw new NoSuchTransportException();
- db.removeTransport(txn, t);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void removeTransport(Transaction transaction, TransportId t)
+ throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsTransport(txn, t))
+ throw new NoSuchTransportException();
+ db.removeTransport(txn, t);
eventBus.broadcast(new TransportRemovedEvent(t));
}
- public void setContactStatus(ContactId c, StorageStatus s)
- throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- db.setContactStatus(txn, c, s);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void setContactStatus(Transaction transaction, ContactId c,
+ StorageStatus s) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ db.setContactStatus(txn, c, s);
}
- public void setLocalAuthorStatus(AuthorId a, StorageStatus s)
- throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsLocalAuthor(txn, a))
- throw new NoSuchLocalAuthorException();
- db.setLocalAuthorStatus(txn, a, s);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void setLocalAuthorStatus(Transaction transaction, AuthorId a,
+ StorageStatus s) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsLocalAuthor(txn, a))
+ throw new NoSuchLocalAuthorException();
+ db.setLocalAuthorStatus(txn, a, s);
}
- public void setMessageShared(Message m, boolean shared)
- throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m.getId()))
- throw new NoSuchMessageException();
- db.setMessageShared(txn, m.getId(), shared);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void setMessageShared(Transaction transaction, Message m,
+ boolean shared) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m.getId()))
+ throw new NoSuchMessageException();
+ db.setMessageShared(txn, m.getId(), shared);
if (shared) eventBus.broadcast(new MessageSharedEvent(m));
}
- public void setMessageValid(Message m, ClientId c, boolean valid)
- throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsMessage(txn, m.getId()))
- throw new NoSuchMessageException();
- db.setMessageValid(txn, m.getId(), valid);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void setMessageValid(Transaction transaction, Message m, ClientId c,
+ boolean valid) throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsMessage(txn, m.getId()))
+ throw new NoSuchMessageException();
+ db.setMessageValid(txn, m.getId(), valid);
eventBus.broadcast(new MessageValidatedEvent(m, c, false, valid));
}
- public void setReorderingWindow(ContactId c, TransportId t,
- long rotationPeriod, long base, byte[] bitmap) throws DbException {
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsTransport(txn, t))
- throw new NoSuchTransportException();
- db.setReorderingWindow(txn, c, t, rotationPeriod, base, bitmap);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ public void setReorderingWindow(Transaction transaction, ContactId c,
+ TransportId t, long rotationPeriod, long base, byte[] bitmap)
+ throws DbException {
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsTransport(txn, t))
+ throw new NoSuchTransportException();
+ db.setReorderingWindow(txn, c, t, rotationPeriod, base, bitmap);
}
- public void setVisibleToContact(ContactId c, GroupId g, boolean visible)
- throws DbException {
+ public void setVisibleToContact(Transaction transaction, ContactId c,
+ GroupId g, boolean visible) throws DbException {
boolean wasVisible;
- T txn = db.startTransaction();
- try {
- if (!db.containsContact(txn, c))
- throw new NoSuchContactException();
- if (!db.containsGroup(txn, g))
- throw new NoSuchGroupException();
- wasVisible = db.containsVisibleGroup(txn, c, g);
- if (visible && !wasVisible) db.addVisibility(txn, c, g);
- else if (!visible && wasVisible) db.removeVisibility(txn, c, g);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
- }
+ T txn = unbox(transaction);
+ if (!db.containsContact(txn, c))
+ throw new NoSuchContactException();
+ if (!db.containsGroup(txn, g))
+ throw new NoSuchGroupException();
+ wasVisible = db.containsVisibleGroup(txn, c, g);
+ if (visible && !wasVisible) db.addVisibility(txn, c, g);
+ else if (!visible && wasVisible) db.removeVisibility(txn, c, g);
if (visible != wasVisible) {
eventBus.broadcast(new GroupVisibilityUpdatedEvent(
Collections.singletonList(c)));
}
}
- public void updateTransportKeys(Map keys)
- throws DbException {
- T txn = db.startTransaction();
- try {
- Map filtered =
- new HashMap();
- for (Entry e : keys.entrySet()) {
- ContactId c = e.getKey();
- TransportKeys k = e.getValue();
- if (db.containsContact(txn, c)
- && db.containsTransport(txn, k.getTransportId())) {
- filtered.put(c, k);
- }
+ public void updateTransportKeys(Transaction transaction,
+ Map keys) throws DbException {
+ Map filtered =
+ new HashMap();
+ T txn = unbox(transaction);
+ for (Entry e : keys.entrySet()) {
+ ContactId c = e.getKey();
+ TransportKeys k = e.getValue();
+ if (db.containsContact(txn, c)
+ && db.containsTransport(txn, k.getTransportId())) {
+ filtered.put(c, k);
}
- db.updateTransportKeys(txn, filtered);
- db.commitTransaction(txn);
- } catch (DbException e) {
- db.abortTransaction(txn);
- throw e;
}
+ db.updateTransportKeys(txn, filtered);
}
}
diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
index 6820afb47..9da89c671 100644
--- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java
@@ -4,7 +4,6 @@ import com.google.inject.Inject;
import org.briarproject.api.FormatException;
import org.briarproject.api.contact.Contact;
-import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.data.BdfDictionary;
import org.briarproject.api.data.BdfReader;
import org.briarproject.api.data.BdfReaderFactory;
@@ -13,13 +12,13 @@ import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumPost;
import org.briarproject.api.forum.ForumPostHeader;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.AuthorId;
-import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.identity.LocalAuthor;
import org.briarproject.api.sync.ClientId;
import org.briarproject.api.sync.Group;
@@ -37,7 +36,6 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
@@ -59,22 +57,14 @@ class ForumManagerImpl implements ForumManager {
Logger.getLogger(ForumManagerImpl.class.getName());
private final DatabaseComponent db;
- private final ContactManager contactManager;
- private final IdentityManager identityManager;
private final BdfReaderFactory bdfReaderFactory;
private final MetadataEncoder metadataEncoder;
private final MetadataParser metadataParser;
- /** Ensures isolation between database reads and writes. */
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
@Inject
- ForumManagerImpl(DatabaseComponent db, ContactManager contactManager,
- IdentityManager identityManager, BdfReaderFactory bdfReaderFactory,
+ ForumManagerImpl(DatabaseComponent db, BdfReaderFactory bdfReaderFactory,
MetadataEncoder metadataEncoder, MetadataParser metadataParser) {
this.db = db;
- this.contactManager = contactManager;
- this.identityManager = identityManager;
this.bdfReaderFactory = bdfReaderFactory;
this.metadataEncoder = metadataEncoder;
this.metadataParser = metadataParser;
@@ -87,7 +77,6 @@ class ForumManagerImpl implements ForumManager {
@Override
public void addLocalPost(ForumPost p) throws DbException {
- lock.writeLock().lock();
try {
BdfDictionary d = new BdfDictionary();
d.put("timestamp", p.getMessage().getTimestamp());
@@ -105,45 +94,65 @@ class ForumManagerImpl implements ForumManager {
d.put("local", true);
d.put("read", true);
Metadata meta = metadataEncoder.encode(d);
- db.addLocalMessage(p.getMessage(), CLIENT_ID, meta, true);
+ Transaction txn = db.startTransaction();
+ try {
+ db.addLocalMessage(txn, p.getMessage(), CLIENT_ID, meta, true);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (FormatException e) {
throw new RuntimeException(e);
- } finally {
- lock.writeLock().unlock();
}
}
@Override
public Forum getForum(GroupId g) throws DbException {
- lock.readLock().lock();
try {
- return parseForum(db.getGroup(g));
+ Group group;
+ Transaction txn = db.startTransaction();
+ try {
+ group = db.getGroup(txn, g);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
+ return parseForum(group);
} catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public Collection getForums() throws DbException {
- lock.readLock().lock();
try {
+ Collection groups;
+ Transaction txn = db.startTransaction();
+ try {
+ groups = db.getGroups(txn, CLIENT_ID);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
List forums = new ArrayList();
- for (Group g : db.getGroups(CLIENT_ID)) forums.add(parseForum(g));
+ for (Group g : groups) forums.add(parseForum(g));
return Collections.unmodifiableList(forums);
} catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public byte[] getPostBody(MessageId m) throws DbException {
- lock.readLock().lock();
try {
- byte[] raw = db.getRawMessage(m);
+ byte[] raw;
+ Transaction txn = db.startTransaction();
+ try {
+ raw = db.getRawMessage(txn, m);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
@@ -164,74 +173,76 @@ class ForumManagerImpl implements ForumManager {
} catch (IOException e) {
// Shouldn't happen with ByteArrayInputStream
throw new RuntimeException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public Collection getPostHeaders(GroupId g)
throws DbException {
- lock.readLock().lock();
+ Set localAuthorIds = new HashSet();
+ Set contactAuthorIds = new HashSet();
+ Map metadata;
+ Transaction txn = db.startTransaction();
try {
// Load the IDs of the user's identities
- Set localAuthorIds = new HashSet();
- for (LocalAuthor a : identityManager.getLocalAuthors())
+ for (LocalAuthor a : db.getLocalAuthors(txn))
localAuthorIds.add(a.getId());
// Load the IDs of contacts' identities
- Set contactAuthorIds = new HashSet();
- for (Contact c : contactManager.getContacts())
+ for (Contact c : db.getContacts(txn))
contactAuthorIds.add(c.getAuthor().getId());
- // Load and parse the metadata
- Map metadata = db.getMessageMetadata(g);
- Collection headers =
- new ArrayList();
- for (Entry e : metadata.entrySet()) {
- MessageId messageId = e.getKey();
- Metadata meta = e.getValue();
- try {
- BdfDictionary d = metadataParser.parse(meta);
- long timestamp = d.getInteger("timestamp");
- Author author = null;
- Author.Status authorStatus = ANONYMOUS;
- BdfDictionary d1 = d.getDictionary("author", null);
- if (d1 != null) {
- AuthorId authorId = new AuthorId(d1.getRaw("id"));
- String name = d1.getString("name");
- byte[] publicKey = d1.getRaw("publicKey");
- author = new Author(authorId, name, publicKey);
- if (localAuthorIds.contains(authorId))
- authorStatus = VERIFIED;
- else if (contactAuthorIds.contains(authorId))
- authorStatus = VERIFIED;
- else authorStatus = UNKNOWN;
- }
- String contentType = d.getString("contentType");
- boolean read = d.getBoolean("read");
- headers.add(new ForumPostHeader(messageId, timestamp,
- author, authorStatus, contentType, read));
- } catch (FormatException ex) {
- if (LOG.isLoggable(WARNING))
- LOG.log(WARNING, ex.toString(), ex);
- }
- }
- return headers;
+ // Load the metadata
+ metadata = db.getMessageMetadata(txn, g);
+ txn.setComplete();
} finally {
- lock.readLock().unlock();
+ db.endTransaction(txn);
}
+ // Parse the metadata
+ Collection headers = new ArrayList();
+ for (Entry e : metadata.entrySet()) {
+ try {
+ BdfDictionary d = metadataParser.parse(e.getValue());
+ long timestamp = d.getInteger("timestamp");
+ Author author = null;
+ Author.Status authorStatus = ANONYMOUS;
+ BdfDictionary d1 = d.getDictionary("author", null);
+ if (d1 != null) {
+ AuthorId authorId = new AuthorId(d1.getRaw("id"));
+ String name = d1.getString("name");
+ byte[] publicKey = d1.getRaw("publicKey");
+ author = new Author(authorId, name, publicKey);
+ if (localAuthorIds.contains(authorId))
+ authorStatus = VERIFIED;
+ else if (contactAuthorIds.contains(authorId))
+ authorStatus = VERIFIED;
+ else authorStatus = UNKNOWN;
+ }
+ String contentType = d.getString("contentType");
+ boolean read = d.getBoolean("read");
+ headers.add(new ForumPostHeader(e.getKey(), timestamp, author,
+ authorStatus, contentType, read));
+ } catch (FormatException ex) {
+ if (LOG.isLoggable(WARNING))
+ LOG.log(WARNING, ex.toString(), ex);
+ }
+ }
+ return headers;
}
@Override
public void setReadFlag(MessageId m, boolean read) throws DbException {
- lock.writeLock().lock();
try {
BdfDictionary d = new BdfDictionary();
d.put("read", read);
- db.mergeMessageMetadata(m, metadataEncoder.encode(d));
+ Metadata meta = metadataEncoder.encode(d);
+ Transaction txn = db.startTransaction();
+ try {
+ db.mergeMessageMetadata(txn, m, meta);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (FormatException e) {
throw new RuntimeException(e);
- } finally {
- lock.writeLock().unlock();
}
}
diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
index 72efd00ac..6f8554ce8 100644
--- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
+++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java
@@ -5,7 +5,6 @@ import com.google.inject.Inject;
import org.briarproject.api.FormatException;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
-import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.contact.ContactManager.AddContactHook;
import org.briarproject.api.contact.ContactManager.RemoveContactHook;
import org.briarproject.api.data.BdfDictionary;
@@ -18,6 +17,7 @@ import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.forum.Forum;
import org.briarproject.api.forum.ForumManager;
import org.briarproject.api.forum.ForumSharingManager;
@@ -45,10 +45,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Logger;
-import static java.util.logging.Level.WARNING;
import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH;
import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_NAME_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
@@ -62,11 +60,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0];
- private static final Logger LOG =
- Logger.getLogger(ForumSharingManagerImpl.class.getName());
-
private final DatabaseComponent db;
- private final ContactManager contactManager;
private final ForumManager forumManager;
private final GroupFactory groupFactory;
private final PrivateGroupFactory privateGroupFactory;
@@ -79,18 +73,14 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
private final Clock clock;
private final Group localGroup;
- /** Ensures isolation between database reads and writes. */
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
@Inject
ForumSharingManagerImpl(DatabaseComponent db,
- ContactManager contactManager, ForumManager forumManager,
- GroupFactory groupFactory, PrivateGroupFactory privateGroupFactory,
+ ForumManager forumManager, GroupFactory groupFactory,
+ PrivateGroupFactory privateGroupFactory,
MessageFactory messageFactory, BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser, SecureRandom random, Clock clock) {
this.db = db;
- this.contactManager = contactManager;
this.forumManager = forumManager;
this.groupFactory = groupFactory;
this.privateGroupFactory = privateGroupFactory;
@@ -106,57 +96,39 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
}
@Override
- public void addingContact(Contact c) {
- lock.writeLock().lock();
+ public void addingContact(Transaction txn, Contact c) throws DbException {
try {
// Create a group to share with the contact
Group g = getContactGroup(c);
// Store the group and share it with the contact
- db.addGroup(g);
- db.setVisibleToContact(c.getId(), g.getId(), true);
+ db.addGroup(txn, g);
+ db.setVisibleToContact(txn, c.getId(), g.getId(), true);
// Attach the contact ID to the group
BdfDictionary d = new BdfDictionary();
d.put("contactId", c.getId().getInt());
- db.mergeGroupMetadata(g.getId(), metadataEncoder.encode(d));
+ db.mergeGroupMetadata(txn, g.getId(), metadataEncoder.encode(d));
// Share any forums that are shared with all contacts
- List shared = getForumsSharedWithAllContacts();
- storeMessage(g.getId(), shared, 0);
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ List shared = getForumsSharedWithAllContacts(txn);
+ storeMessage(txn, g.getId(), shared, 0);
} catch (FormatException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- } finally {
- lock.writeLock().unlock();
+ throw new DbException(e);
}
}
@Override
- public void removingContact(Contact c) {
- lock.writeLock().lock();
- try {
- db.removeGroup(getContactGroup(c));
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- } finally {
- lock.writeLock().unlock();
- }
+ public void removingContact(Transaction txn, Contact c) throws DbException {
+ db.removeGroup(txn, getContactGroup(c));
}
@Override
- public void validatingMessage(Message m, ClientId c, Metadata meta) {
+ public void validatingMessage(Transaction txn, Message m, ClientId c,
+ Metadata meta) throws DbException {
if (c.equals(CLIENT_ID)) {
- lock.writeLock().lock();
try {
- ContactId contactId = getContactId(m.getGroupId());
- setForumVisibility(contactId, getVisibleForums(m));
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING))
- LOG.log(WARNING, e.toString(), e);
+ ContactId contactId = getContactId(txn, m.getGroupId());
+ setForumVisibility(txn, contactId, getVisibleForums(txn, m));
} catch (FormatException e) {
- if (LOG.isLoggable(WARNING))
- LOG.log(WARNING, e.toString(), e);
- } finally {
- lock.writeLock().unlock();
+ throw new DbException(e);
}
}
}
@@ -179,149 +151,162 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
@Override
public void addForum(Forum f) throws DbException {
- lock.writeLock().lock();
+ Transaction txn = db.startTransaction();
try {
- db.addGroup(f.getGroup());
+ db.addGroup(txn, f.getGroup());
+ txn.setComplete();
} finally {
- lock.writeLock().unlock();
+ db.endTransaction(txn);
}
}
@Override
public void removeForum(Forum f) throws DbException {
- lock.writeLock().lock();
try {
- // Update the list of forums shared with each contact
- for (Contact c : contactManager.getContacts()) {
- Group contactGroup = getContactGroup(c);
- removeFromList(contactGroup.getId(), f);
+ // Update the list shared with each contact
+ Transaction txn = db.startTransaction();
+ try {
+ for (Contact c : db.getContacts(txn))
+ removeFromList(txn, getContactGroup(c).getId(), f);
+ db.removeGroup(txn, f.getGroup());
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
- db.removeGroup(f.getGroup());
} catch (IOException e) {
throw new DbException(e);
- } finally {
- lock.writeLock().unlock();
}
}
@Override
public Collection getAvailableForums() throws DbException {
- lock.readLock().lock();
try {
- // Get any forums we subscribe to
- Set subscribed = new HashSet(db.getGroups(
- forumManager.getClientId()));
- // Get all forums shared by contacts
Set available = new HashSet();
- for (Contact c : contactManager.getContacts()) {
- Group g = getContactGroup(c);
- // Find the latest update version
- LatestUpdate latest = findLatest(g.getId(), false);
- if (latest != null) {
- // Retrieve and parse the latest update
- byte[] raw = db.getRawMessage(latest.messageId);
- for (Forum f : parseForumList(raw)) {
- if (!subscribed.contains(f.getGroup()))
- available.add(f);
+ Transaction txn = db.startTransaction();
+ try {
+ // Get any forums we subscribe to
+ Set subscribed = new HashSet(db.getGroups(txn,
+ forumManager.getClientId()));
+ // Get all forums shared by contacts
+ for (Contact c : db.getContacts(txn)) {
+ Group g = getContactGroup(c);
+ // Find the latest update version
+ LatestUpdate latest = findLatest(txn, g.getId(), false);
+ if (latest != null) {
+ // Retrieve and parse the latest update
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ for (Forum f : parseForumList(raw)) {
+ if (!subscribed.contains(f.getGroup()))
+ available.add(f);
+ }
}
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
return Collections.unmodifiableSet(available);
} catch (IOException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public Collection getSharedBy(GroupId g) throws DbException {
- lock.readLock().lock();
try {
List subscribers = new ArrayList();
- for (Contact c : contactManager.getContacts()) {
- Group contactGroup = getContactGroup(c);
- if (listContains(contactGroup.getId(), g, false))
- subscribers.add(c);
+ Transaction txn = db.startTransaction();
+ try {
+ for (Contact c : db.getContacts(txn)) {
+ if (listContains(txn, getContactGroup(c).getId(), g, false))
+ subscribers.add(c);
+ }
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
return Collections.unmodifiableList(subscribers);
} catch (IOException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public Collection getSharedWith(GroupId g) throws DbException {
- lock.readLock().lock();
try {
List shared = new ArrayList();
- for (Contact c : contactManager.getContacts()) {
- Group contactGroup = getContactGroup(c);
- if (listContains(contactGroup.getId(), g, true))
- shared.add(c.getId());
+ Transaction txn = db.startTransaction();
+ try {
+ for (Contact c : db.getContacts(txn)) {
+ if (listContains(txn, getContactGroup(c).getId(), g, true))
+ shared.add(c.getId());
+ }
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
return Collections.unmodifiableList(shared);
} catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public void setSharedWith(GroupId g, Collection shared)
throws DbException {
- lock.writeLock().lock();
try {
- // Retrieve the forum
- Forum f = parseForum(db.getGroup(g));
- // Remove the forum from the list of forums shared with all contacts
- removeFromList(localGroup.getId(), f);
- // Update the list of forums shared with each contact
- shared = new HashSet(shared);
- for (Contact c : contactManager.getContacts()) {
- Group contactGroup = getContactGroup(c);
- if (shared.contains(c.getId())) {
- if (addToList(contactGroup.getId(), f)) {
- // If the contact is sharing the forum, make it visible
- if (listContains(contactGroup.getId(), g, false))
- db.setVisibleToContact(c.getId(), g, true);
+ Transaction txn = db.startTransaction();
+ try {
+ // Retrieve the forum
+ Forum f = parseForum(db.getGroup(txn, g));
+ // Remove the forum from the list shared with all contacts
+ removeFromList(txn, localGroup.getId(), f);
+ // Update the list shared with each contact
+ shared = new HashSet(shared);
+ for (Contact c : db.getContacts(txn)) {
+ Group cg = getContactGroup(c);
+ if (shared.contains(c.getId())) {
+ if (addToList(txn, cg.getId(), f)) {
+ if (listContains(txn, cg.getId(), g, false))
+ db.setVisibleToContact(txn, c.getId(), g, true);
+ }
+ } else {
+ removeFromList(txn, cg.getId(), f);
+ db.setVisibleToContact(txn, c.getId(), g, false);
}
- } else {
- removeFromList(contactGroup.getId(), f);
- db.setVisibleToContact(c.getId(), g, false);
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
} catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.writeLock().unlock();
}
}
@Override
public void setSharedWithAll(GroupId g) throws DbException {
- lock.writeLock().lock();
try {
- // Retrieve the forum
- Forum f = parseForum(db.getGroup(g));
- // Add the forum to the list of forums shared with all contacts
- addToList(localGroup.getId(), f);
- // Add the forum to the list of forums shared with each contact
- for (Contact c : contactManager.getContacts()) {
- Group contactGroup = getContactGroup(c);
- if (addToList(contactGroup.getId(), f)) {
- // If the contact is sharing the forum, make it visible
- if (listContains(contactGroup.getId(), g, false))
- db.setVisibleToContact(getContactId(g), g, true);
+ Transaction txn = db.startTransaction();
+ try {
+ // Retrieve the forum
+ Forum f = parseForum(db.getGroup(txn, g));
+ // Add the forum to the list shared with all contacts
+ addToList(txn, localGroup.getId(), f);
+ // Add the forum to the list shared with each contact
+ for (Contact c : db.getContacts(txn)) {
+ Group cg = getContactGroup(c);
+ if (addToList(txn, cg.getId(), f)) {
+ if (listContains(txn, cg.getId(), g, false))
+ db.setVisibleToContact(txn, c.getId(), g, true);
+ }
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
} catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.writeLock().unlock();
}
}
@@ -329,23 +314,21 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
}
- // Locking: lock.writeLock
- private List getForumsSharedWithAllContacts() throws DbException,
- FormatException {
+ private List getForumsSharedWithAllContacts(Transaction txn)
+ throws DbException, FormatException {
// Ensure the local group exists
- db.addGroup(localGroup);
+ db.addGroup(txn, localGroup);
// Find the latest update in the local group
- LatestUpdate latest = findLatest(localGroup.getId(), true);
+ LatestUpdate latest = findLatest(txn, localGroup.getId(), true);
if (latest == null) return Collections.emptyList();
// Retrieve and parse the latest update
- return parseForumList(db.getRawMessage(latest.messageId));
+ return parseForumList(db.getRawMessage(txn, latest.messageId));
}
- // Locking: lock.readLock
- private LatestUpdate findLatest(GroupId g, boolean local)
+ private LatestUpdate findLatest(Transaction txn, GroupId g, boolean local)
throws DbException, FormatException {
LatestUpdate latest = null;
- Map metadata = db.getMessageMetadata(g);
+ Map metadata = db.getMessageMetadata(txn, g);
for (Entry e : metadata.entrySet()) {
BdfDictionary d = metadataParser.parse(e.getValue());
if (d.getBoolean("local") != local) continue;
@@ -384,16 +367,20 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
}
}
- // Locking: lock.writeLock
- private void storeMessage(GroupId g, List forums, long version)
- throws DbException, FormatException {
- byte[] body = encodeForumList(forums, version);
- long now = clock.currentTimeMillis();
- Message m = messageFactory.createMessage(g, now, body);
- BdfDictionary d = new BdfDictionary();
- d.put("version", version);
- d.put("local", true);
- db.addLocalMessage(m, CLIENT_ID, metadataEncoder.encode(d), true);
+ private void storeMessage(Transaction txn, GroupId g, List forums,
+ long version) throws DbException {
+ try {
+ byte[] body = encodeForumList(forums, version);
+ long now = clock.currentTimeMillis();
+ Message m = messageFactory.createMessage(g, now, body);
+ BdfDictionary d = new BdfDictionary();
+ d.put("version", version);
+ d.put("local", true);
+ db.addLocalMessage(txn, m, CLIENT_ID, metadataEncoder.encode(d),
+ true);
+ } catch (FormatException e) {
+ throw new RuntimeException(e);
+ }
}
private byte[] encodeForumList(List forums, long version) {
@@ -418,23 +405,21 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
return out.toByteArray();
}
- // Locking: lock.readLock
- private ContactId getContactId(GroupId contactGroupId) throws DbException,
- FormatException {
- Metadata meta = db.getGroupMetadata(contactGroupId);
+ private ContactId getContactId(Transaction txn, GroupId contactGroupId)
+ throws DbException, FormatException {
+ Metadata meta = db.getGroupMetadata(txn, contactGroupId);
BdfDictionary d = metadataParser.parse(meta);
return new ContactId(d.getInteger("contactId").intValue());
}
- // Locking: lock.readLock
- private Set getVisibleForums(Message remoteUpdate)
- throws DbException, FormatException {
+ private Set getVisibleForums(Transaction txn,
+ Message remoteUpdate) throws DbException, FormatException {
// Get the latest local update
- LatestUpdate local = findLatest(remoteUpdate.getGroupId(), true);
+ LatestUpdate local = findLatest(txn, remoteUpdate.getGroupId(), true);
// If there's no local update, no forums are visible
if (local == null) return Collections.emptySet();
// Intersect the sets of shared forums
- byte[] localRaw = db.getRawMessage(local.messageId);
+ byte[] localRaw = db.getRawMessage(txn, local.messageId);
Set shared = new HashSet(parseForumList(localRaw));
shared.retainAll(parseForumList(remoteUpdate.getRaw()));
// Forums in the intersection should be visible
@@ -443,16 +428,15 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
return visible;
}
- // Locking: lock.writeLock
- private void setForumVisibility(ContactId c, Set visible)
- throws DbException {
- for (Group g : db.getGroups(forumManager.getClientId())) {
- boolean isVisible = db.isVisibleToContact(c, g.getId());
+ private void setForumVisibility(Transaction txn, ContactId c,
+ Set visible) throws DbException {
+ for (Group g : db.getGroups(txn, forumManager.getClientId())) {
+ boolean isVisible = db.isVisibleToContact(txn, c, g.getId());
boolean shouldBeVisible = visible.contains(g.getId());
if (isVisible && !shouldBeVisible)
- db.setVisibleToContact(c, g.getId(), false);
+ db.setVisibleToContact(txn, c, g.getId(), false);
else if (!isVisible && shouldBeVisible)
- db.setVisibleToContact(c, g.getId(), true);
+ db.setVisibleToContact(txn, c, g.getId(), true);
}
}
@@ -491,38 +475,38 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook,
}
}
- // Locking: lock.readLock
- private boolean listContains(GroupId g, GroupId forum, boolean local)
- throws DbException, FormatException {
- LatestUpdate latest = findLatest(g, local);
+ private boolean listContains(Transaction txn, GroupId g, GroupId forum,
+ boolean local) throws DbException, FormatException {
+ LatestUpdate latest = findLatest(txn, g, local);
if (latest == null) return false;
- List list = parseForumList(db.getRawMessage(latest.messageId));
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ List list = parseForumList(raw);
for (Forum f : list) if (f.getId().equals(forum)) return true;
return false;
}
- // Locking: lock.writeLock
- private boolean addToList(GroupId g, Forum f) throws DbException,
- FormatException {
- LatestUpdate latest = findLatest(g, true);
+ private boolean addToList(Transaction txn, GroupId g, Forum f)
+ throws DbException, FormatException {
+ LatestUpdate latest = findLatest(txn, g, true);
if (latest == null) {
- storeMessage(g, Collections.singletonList(f), 0);
+ storeMessage(txn, g, Collections.singletonList(f), 0);
return true;
}
- List list = parseForumList(db.getRawMessage(latest.messageId));
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ List list = parseForumList(raw);
if (list.contains(f)) return false;
list.add(f);
- storeMessage(g, list, latest.version + 1);
+ storeMessage(txn, g, list, latest.version + 1);
return true;
}
- // Locking: lock.writeLock
- private void removeFromList(GroupId g, Forum f) throws DbException,
- FormatException {
- LatestUpdate latest = findLatest(g, true);
+ private void removeFromList(Transaction txn, GroupId g, Forum f)
+ throws DbException, FormatException {
+ LatestUpdate latest = findLatest(txn, g, true);
if (latest == null) return;
- List list = parseForumList(db.getRawMessage(latest.messageId));
- if (list.remove(f)) storeMessage(g, list, latest.version + 1);
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ List list = parseForumList(raw);
+ if (list.remove(f)) storeMessage(txn, g, list, latest.version + 1);
}
private static class LatestUpdate {
diff --git a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java
index 71b34eac9..475ead3e4 100644
--- a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java
+++ b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java
@@ -5,6 +5,7 @@ import com.google.inject.Inject;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.NoSuchLocalAuthorException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.LocalAuthorAddedEvent;
import org.briarproject.api.event.LocalAuthorRemovedEvent;
@@ -47,19 +48,31 @@ class IdentityManagerImpl implements IdentityManager, Service {
public boolean start() {
// Finish adding/removing any partly added/removed pseudonyms
try {
- for (LocalAuthor a : db.getLocalAuthors()) {
- if (a.getStatus().equals(ADDING)) {
- for (AddIdentityHook hook : addHooks)
- hook.addingIdentity(a);
- db.setLocalAuthorStatus(a.getId(), ACTIVE);
- eventBus.broadcast(new LocalAuthorAddedEvent(a.getId()));
- } else if (a.getStatus().equals(REMOVING)) {
- for (RemoveIdentityHook hook : removeHooks)
- hook.removingIdentity(a);
- db.removeLocalAuthor(a.getId());
- eventBus.broadcast(new LocalAuthorRemovedEvent(a.getId()));
+ List added = new ArrayList();
+ List removed = new ArrayList();
+ Transaction txn = db.startTransaction();
+ try {
+ for (LocalAuthor a : db.getLocalAuthors(txn)) {
+ if (a.getStatus().equals(ADDING)) {
+ for (AddIdentityHook hook : addHooks)
+ hook.addingIdentity(txn, a);
+ db.setLocalAuthorStatus(txn, a.getId(), ACTIVE);
+ added.add(a.getId());
+ } else if (a.getStatus().equals(REMOVING)) {
+ for (RemoveIdentityHook hook : removeHooks)
+ hook.removingIdentity(txn, a);
+ db.removeLocalAuthor(txn, a.getId());
+ removed.add(a.getId());
+ }
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
+ for (AuthorId a : added)
+ eventBus.broadcast(new LocalAuthorAddedEvent(a));
+ for (AuthorId a : removed)
+ eventBus.broadcast(new LocalAuthorRemovedEvent(a));
return true;
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -84,22 +97,43 @@ class IdentityManagerImpl implements IdentityManager, Service {
@Override
public void addLocalAuthor(LocalAuthor localAuthor) throws DbException {
- db.addLocalAuthor(localAuthor);
- for (AddIdentityHook hook : addHooks) hook.addingIdentity(localAuthor);
- db.setLocalAuthorStatus(localAuthor.getId(), ACTIVE);
+ Transaction txn = db.startTransaction();
+ try {
+ db.addLocalAuthor(txn, localAuthor);
+ for (AddIdentityHook hook : addHooks)
+ hook.addingIdentity(txn, localAuthor);
+ db.setLocalAuthorStatus(txn, localAuthor.getId(), ACTIVE);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
eventBus.broadcast(new LocalAuthorAddedEvent(localAuthor.getId()));
}
@Override
public LocalAuthor getLocalAuthor(AuthorId a) throws DbException {
- LocalAuthor author = db.getLocalAuthor(a);
+ LocalAuthor author;
+ Transaction txn = db.startTransaction();
+ try {
+ author = db.getLocalAuthor(txn, a);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (author.getStatus().equals(ACTIVE)) return author;
throw new NoSuchLocalAuthorException();
}
@Override
public Collection getLocalAuthors() throws DbException {
- Collection authors = db.getLocalAuthors();
+ Collection authors;
+ Transaction txn = db.startTransaction();
+ try {
+ authors = db.getLocalAuthors(txn);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
// Filter out any pseudonyms that are being added or removed
List active = new ArrayList(authors.size());
for (LocalAuthor a : authors)
@@ -109,11 +143,17 @@ class IdentityManagerImpl implements IdentityManager, Service {
@Override
public void removeLocalAuthor(AuthorId a) throws DbException {
- LocalAuthor localAuthor = db.getLocalAuthor(a);
- db.setLocalAuthorStatus(a, REMOVING);
- for (RemoveIdentityHook hook : removeHooks)
- hook.removingIdentity(localAuthor);
- db.removeLocalAuthor(a);
+ Transaction txn = db.startTransaction();
+ try {
+ LocalAuthor localAuthor = db.getLocalAuthor(txn, a);
+ db.setLocalAuthorStatus(txn, a, REMOVING);
+ for (RemoveIdentityHook hook : removeHooks)
+ hook.removingIdentity(txn, localAuthor);
+ db.removeLocalAuthor(txn, a);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
eventBus.broadcast(new LocalAuthorRemovedEvent(a));
}
}
diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
index 5185cac6e..0441d27ce 100644
--- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
+++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java
@@ -5,7 +5,6 @@ import com.google.inject.Inject;
import org.briarproject.api.FormatException;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
-import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.contact.ContactManager.AddContactHook;
import org.briarproject.api.contact.ContactManager.RemoveContactHook;
import org.briarproject.api.data.BdfDictionary;
@@ -16,7 +15,7 @@ import org.briarproject.api.data.MetadataParser;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
-import org.briarproject.api.db.NoSuchContactException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.messaging.MessagingManager;
import org.briarproject.api.messaging.PrivateMessage;
import org.briarproject.api.messaging.PrivateMessageHeader;
@@ -50,19 +49,17 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
Logger.getLogger(MessagingManagerImpl.class.getName());
private final DatabaseComponent db;
- private final ContactManager contactManager;
private final PrivateGroupFactory privateGroupFactory;
private final BdfReaderFactory bdfReaderFactory;
private final MetadataEncoder metadataEncoder;
private final MetadataParser metadataParser;
@Inject
- MessagingManagerImpl(DatabaseComponent db, ContactManager contactManager,
+ MessagingManagerImpl(DatabaseComponent db,
PrivateGroupFactory privateGroupFactory,
BdfReaderFactory bdfReaderFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser) {
this.db = db;
- this.contactManager = contactManager;
this.privateGroupFactory = privateGroupFactory;
this.bdfReaderFactory = bdfReaderFactory;
this.metadataEncoder = metadataEncoder;
@@ -70,19 +67,17 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
}
@Override
- public void addingContact(Contact c) {
+ public void addingContact(Transaction txn, Contact c) throws DbException {
try {
// Create a group to share with the contact
Group g = getContactGroup(c);
// Store the group and share it with the contact
- db.addGroup(g);
- db.setVisibleToContact(c.getId(), g.getId(), true);
+ db.addGroup(txn, g);
+ db.setVisibleToContact(txn, c.getId(), g.getId(), true);
// Attach the contact ID to the group
BdfDictionary d = new BdfDictionary();
d.put("contactId", c.getId().getInt());
- db.mergeGroupMetadata(g.getId(), metadataEncoder.encode(d));
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
+ db.mergeGroupMetadata(txn, g.getId(), metadataEncoder.encode(d));
} catch (FormatException e) {
throw new RuntimeException(e);
}
@@ -93,12 +88,8 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
}
@Override
- public void removingContact(Contact c) {
- try {
- db.removeGroup(getContactGroup(c));
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- }
+ public void removingContact(Transaction txn, Contact c) throws DbException {
+ db.removeGroup(txn, getContactGroup(c));
}
@Override
@@ -108,15 +99,22 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override
public void addLocalMessage(PrivateMessage m) throws DbException {
- BdfDictionary d = new BdfDictionary();
- d.put("timestamp", m.getMessage().getTimestamp());
- if (m.getParent() != null) d.put("parent", m.getParent().getBytes());
- d.put("contentType", m.getContentType());
- d.put("local", true);
- d.put("read", true);
try {
+ BdfDictionary d = new BdfDictionary();
+ d.put("timestamp", m.getMessage().getTimestamp());
+ if (m.getParent() != null)
+ d.put("parent", m.getParent().getBytes());
+ d.put("contentType", m.getContentType());
+ d.put("local", true);
+ d.put("read", true);
Metadata meta = metadataEncoder.encode(d);
- db.addLocalMessage(m.getMessage(), CLIENT_ID, meta, true);
+ Transaction txn = db.startTransaction();
+ try {
+ db.addLocalMessage(txn, m.getMessage(), CLIENT_ID, meta, true);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (FormatException e) {
throw new RuntimeException(e);
}
@@ -125,26 +123,48 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override
public ContactId getContactId(GroupId g) throws DbException {
try {
- BdfDictionary d = metadataParser.parse(db.getGroupMetadata(g));
- long id = d.getInteger("contactId");
- return new ContactId((int) id);
+ Metadata meta;
+ Transaction txn = db.startTransaction();
+ try {
+ meta = db.getGroupMetadata(txn, g);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
+ BdfDictionary d = metadataParser.parse(meta);
+ return new ContactId(d.getInteger("contactId").intValue());
} catch (FormatException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- throw new NoSuchContactException();
+ throw new DbException(e);
}
}
@Override
public GroupId getConversationId(ContactId c) throws DbException {
- return getContactGroup(contactManager.getContact(c)).getId();
+ Contact contact;
+ Transaction txn = db.startTransaction();
+ try {
+ contact = db.getContact(txn, c);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
+ return getContactGroup(contact).getId();
}
@Override
public Collection getMessageHeaders(ContactId c)
throws DbException {
- GroupId groupId = getConversationId(c);
- Map metadata = db.getMessageMetadata(groupId);
- Collection statuses = db.getMessageStatus(c, groupId);
+ GroupId g = getConversationId(c);
+ Map metadata;
+ Collection statuses;
+ Transaction txn = db.startTransaction();
+ try {
+ metadata = db.getMessageMetadata(txn, g);
+ statuses = db.getMessageStatus(txn, c, g);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
Collection headers =
new ArrayList();
for (MessageStatus s : statuses) {
@@ -168,7 +188,14 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override
public byte[] getMessageBody(MessageId m) throws DbException {
- byte[] raw = db.getRawMessage(m);
+ byte[] raw;
+ Transaction txn = db.startTransaction();
+ try {
+ raw = db.getRawMessage(txn, m);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
@@ -191,10 +218,17 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook,
@Override
public void setReadFlag(MessageId m, boolean read) throws DbException {
- BdfDictionary d = new BdfDictionary();
- d.put("read", read);
try {
- db.mergeMessageMetadata(m, metadataEncoder.encode(d));
+ BdfDictionary d = new BdfDictionary();
+ d.put("read", read);
+ Metadata meta = metadataEncoder.encode(d);
+ Transaction txn = db.startTransaction();
+ try {
+ db.mergeMessageMetadata(txn, m, meta);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (FormatException e) {
throw new RuntimeException(e);
}
diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
index 66987c4fd..bd110d0cf 100644
--- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
+++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java
@@ -4,6 +4,7 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.TransportDisabledEvent;
import org.briarproject.api.event.TransportEnabledEvent;
@@ -27,6 +28,7 @@ import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.settings.Settings;
+import org.briarproject.api.settings.SettingsManager;
import org.briarproject.api.system.Clock;
import org.briarproject.api.ui.UiCallback;
@@ -60,6 +62,7 @@ class PluginManagerImpl implements PluginManager, Service {
private final DatabaseComponent db;
private final Poller poller;
private final ConnectionManager connectionManager;
+ private final SettingsManager settingsManager;
private final TransportPropertyManager transportPropertyManager;
private final UiCallback uiCallback;
private final Map plugins;
@@ -72,6 +75,7 @@ class PluginManagerImpl implements PluginManager, Service {
DuplexPluginConfig duplexPluginConfig, Clock clock,
DatabaseComponent db, Poller poller,
ConnectionManager connectionManager,
+ SettingsManager settingsManager,
TransportPropertyManager transportPropertyManager,
UiCallback uiCallback) {
this.ioExecutor = ioExecutor;
@@ -82,6 +86,7 @@ class PluginManagerImpl implements PluginManager, Service {
this.db = db;
this.poller = poller;
this.connectionManager = connectionManager;
+ this.settingsManager = settingsManager;
this.transportPropertyManager = transportPropertyManager;
this.uiCallback = uiCallback;
plugins = new ConcurrentHashMap();
@@ -181,7 +186,13 @@ class PluginManagerImpl implements PluginManager, Service {
}
try {
long start = clock.currentTimeMillis();
- db.addTransport(id, plugin.getMaxLatency());
+ Transaction txn = db.startTransaction();
+ try {
+ db.addTransport(txn, id, plugin.getMaxLatency());
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
long duration = clock.currentTimeMillis() - start;
if (LOG.isLoggable(INFO))
LOG.info("Adding transport took " + duration + " ms");
@@ -244,7 +255,13 @@ class PluginManagerImpl implements PluginManager, Service {
}
try {
long start = clock.currentTimeMillis();
- db.addTransport(id, plugin.getMaxLatency());
+ Transaction txn = db.startTransaction();
+ try {
+ db.addTransport(txn, id, plugin.getMaxLatency());
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
long duration = clock.currentTimeMillis() - start;
if (LOG.isLoggable(INFO))
LOG.info("Adding transport took " + duration + " ms");
@@ -319,7 +336,7 @@ class PluginManagerImpl implements PluginManager, Service {
public Settings getSettings() {
try {
- return db.getSettings(id.getString());
+ return settingsManager.getSettings(id.getString());
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return new Settings();
@@ -348,7 +365,7 @@ class PluginManagerImpl implements PluginManager, Service {
public void mergeSettings(Settings s) {
try {
- db.mergeSettings(s, id.getString());
+ settingsManager.mergeSettings(s, id.getString());
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
}
diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
index a7babd5cd..1032717f5 100644
--- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
+++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java
@@ -7,7 +7,6 @@ import org.briarproject.api.FormatException;
import org.briarproject.api.TransportId;
import org.briarproject.api.contact.Contact;
import org.briarproject.api.contact.ContactId;
-import org.briarproject.api.contact.ContactManager;
import org.briarproject.api.contact.ContactManager.AddContactHook;
import org.briarproject.api.contact.ContactManager.RemoveContactHook;
import org.briarproject.api.data.BdfDictionary;
@@ -21,6 +20,7 @@ import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.NoSuchGroupException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.properties.TransportProperties;
import org.briarproject.api.properties.TransportPropertyManager;
import org.briarproject.api.sync.ClientId;
@@ -41,10 +41,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-import java.util.logging.Logger;
-import static java.util.logging.Level.WARNING;
import static org.briarproject.api.properties.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
@@ -57,11 +54,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
private static final byte[] LOCAL_GROUP_DESCRIPTOR = new byte[0];
- private static final Logger LOG =
- Logger.getLogger(TransportPropertyManagerImpl.class.getName());
-
private final DatabaseComponent db;
- private final ContactManager contactManager;
private final PrivateGroupFactory privateGroupFactory;
private final MessageFactory messageFactory;
private final BdfReaderFactory bdfReaderFactory;
@@ -71,18 +64,13 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
private final Clock clock;
private final Group localGroup;
- /** Ensures isolation between database reads and writes. */
- private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
-
@Inject
TransportPropertyManagerImpl(DatabaseComponent db,
- ContactManager contactManager, GroupFactory groupFactory,
- PrivateGroupFactory privateGroupFactory,
+ GroupFactory groupFactory, PrivateGroupFactory privateGroupFactory,
MessageFactory messageFactory, BdfReaderFactory bdfReaderFactory,
BdfWriterFactory bdfWriterFactory, MetadataEncoder metadataEncoder,
MetadataParser metadataParser, Clock clock) {
this.db = db;
- this.contactManager = contactManager;
this.privateGroupFactory = privateGroupFactory;
this.messageFactory = messageFactory;
this.bdfReaderFactory = bdfReaderFactory;
@@ -95,165 +83,171 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
}
@Override
- public void addingContact(Contact c) {
- lock.writeLock().lock();
- try {
- // Create a group to share with the contact
- Group g = getContactGroup(c);
- // Store the group and share it with the contact
- db.addGroup(g);
- db.setVisibleToContact(c.getId(), g.getId(), true);
- // Copy the latest local properties into the group
- DeviceId dev = db.getDeviceId();
- Map local = getLocalProperties();
- for (Entry e : local.entrySet()) {
- storeMessage(g.getId(), dev, e.getKey(), e.getValue(), 1, true,
- true);
- }
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- } catch (FormatException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- } finally {
- lock.writeLock().unlock();
+ public void addingContact(Transaction txn, Contact c) throws DbException {
+ // Create a group to share with the contact
+ Group g = getContactGroup(c);
+ // Store the group and share it with the contact
+ db.addGroup(txn, g);
+ db.setVisibleToContact(txn, c.getId(), g.getId(), true);
+ // Copy the latest local properties into the group
+ DeviceId dev = db.getDeviceId(txn);
+ Map local = getLocalProperties();
+ for (Entry e : local.entrySet()) {
+ storeMessage(txn, g.getId(), dev, e.getKey(), e.getValue(), 1,
+ true, true);
}
}
@Override
- public void removingContact(Contact c) {
- lock.writeLock().lock();
- try {
- db.removeGroup(getContactGroup(c));
- } catch (DbException e) {
- if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
- } finally {
- lock.writeLock().unlock();
- }
+ public void removingContact(Transaction txn, Contact c) throws DbException {
+ db.removeGroup(txn, getContactGroup(c));
}
@Override
public void addRemoteProperties(ContactId c, DeviceId dev,
Map props) throws DbException {
- lock.writeLock().lock();
+ Transaction txn = db.startTransaction();
try {
- Group g = getContactGroup(contactManager.getContact(c));
+ Group g = getContactGroup(db.getContact(txn, c));
for (Entry e : props.entrySet()) {
- storeMessage(g.getId(), dev, e.getKey(), e.getValue(), 0, false,
- false);
+ storeMessage(txn, g.getId(), dev, e.getKey(), e.getValue(), 0,
+ false, false);
}
- } catch (FormatException e) {
- throw new DbException(e);
+ txn.setComplete();
} finally {
- lock.writeLock().unlock();
+ db.endTransaction(txn);
}
}
@Override
public Map getLocalProperties()
throws DbException {
- lock.readLock().lock();
try {
- // Find the latest local update for each transport
- Map latest =
- findLatest(localGroup.getId(), true);
- // Retrieve and parse the latest local properties
Map local =
new HashMap();
- for (Entry e : latest.entrySet()) {
- byte[] raw = db.getRawMessage(e.getValue().messageId);
- local.put(e.getKey(), parseProperties(raw));
+ Transaction txn = db.startTransaction();
+ try {
+ // Find the latest local update for each transport
+ Map latest = findLatest(txn,
+ localGroup.getId(), true);
+ // Retrieve and parse the latest local properties
+ for (Entry e : latest.entrySet()) {
+ byte[] raw = db.getRawMessage(txn, e.getValue().messageId);
+ local.put(e.getKey(), parseProperties(raw));
+ }
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
return Collections.unmodifiableMap(local);
} catch (NoSuchGroupException e) {
// Local group doesn't exist - there are no local properties
return Collections.emptyMap();
- } catch (IOException e) {
+ } catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public TransportProperties getLocalProperties(TransportId t)
throws DbException {
- lock.readLock().lock();
try {
- // Find the latest local update
- LatestUpdate latest = findLatest(localGroup.getId(), t, true);
- if (latest == null) return null;
- // Retrieve and parse the latest local properties
- return parseProperties(db.getRawMessage(latest.messageId));
+ TransportProperties p = null;
+ Transaction txn = db.startTransaction();
+ try {
+ // Find the latest local update
+ LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
+ true);
+ if (latest != null) {
+ // Retrieve and parse the latest local properties
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ p = parseProperties(raw);
+ }
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
+ return p;
} catch (NoSuchGroupException e) {
// Local group doesn't exist - there are no local properties
return null;
- } catch (IOException e) {
+ } catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public Map getRemoteProperties(
TransportId t) throws DbException {
- lock.readLock().lock();
try {
Map remote =
new HashMap();
- for (Contact c : contactManager.getContacts()) {
- Group g = getContactGroup(c);
- // Find the latest remote update
- LatestUpdate latest = findLatest(g.getId(), t, false);
- if (latest != null) {
- // Retrieve and parse the latest remote properties
- byte[] raw = db.getRawMessage(latest.messageId);
- remote.put(c.getId(), parseProperties(raw));
+ Transaction txn = db.startTransaction();
+ try {
+ for (Contact c : db.getContacts(txn)) {
+ Group g = getContactGroup(c);
+ // Find the latest remote update
+ LatestUpdate latest = findLatest(txn, g.getId(), t, false);
+ if (latest != null) {
+ // Retrieve and parse the latest remote properties
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ remote.put(c.getId(), parseProperties(raw));
+ }
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
return Collections.unmodifiableMap(remote);
- } catch (IOException e) {
+ } catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.readLock().unlock();
}
}
@Override
public void mergeLocalProperties(TransportId t, TransportProperties p)
throws DbException {
- lock.writeLock().lock();
try {
- // Create the local group if necessary
- db.addGroup(localGroup);
- // Merge the new properties with any existing properties
- TransportProperties merged;
- LatestUpdate latest = findLatest(localGroup.getId(), t, true);
- if (latest == null) {
- merged = p;
- } else {
- byte[] raw = db.getRawMessage(latest.messageId);
- TransportProperties old = parseProperties(raw);
- merged = new TransportProperties(old);
- merged.putAll(p);
- if (merged.equals(old)) return; // Unchanged
+ Transaction txn = db.startTransaction();
+ try {
+ // Create the local group if necessary
+ db.addGroup(txn, localGroup);
+ // Merge the new properties with any existing properties
+ TransportProperties merged;
+ boolean changed;
+ LatestUpdate latest = findLatest(txn, localGroup.getId(), t,
+ true);
+ if (latest == null) {
+ merged = p;
+ changed = true;
+ } else {
+ byte[] raw = db.getRawMessage(txn, latest.messageId);
+ TransportProperties old = parseProperties(raw);
+ merged = new TransportProperties(old);
+ merged.putAll(p);
+ changed = !merged.equals(old);
+ }
+ if (changed) {
+ // Store the merged properties in the local group
+ DeviceId dev = db.getDeviceId(txn);
+ long version = latest == null ? 1 : latest.version + 1;
+ storeMessage(txn, localGroup.getId(), dev, t, merged,
+ version, true, false);
+ // Store the merged properties in each contact's group
+ for (Contact c : db.getContacts(txn)) {
+ Group g = getContactGroup(c);
+ latest = findLatest(txn, g.getId(), t, true);
+ version = latest == null ? 1 : latest.version + 1;
+ storeMessage(txn, g.getId(), dev, t, merged, version,
+ true, true);
+ }
+ }
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
- // Store the merged properties in the local group
- DeviceId dev = db.getDeviceId();
- long version = latest == null ? 1 : latest.version + 1;
- storeMessage(localGroup.getId(), dev, t, merged, version, true,
- false);
- // Store the merged properties in each contact's group
- for (Contact c : contactManager.getContacts()) {
- Group g = getContactGroup(c);
- latest = findLatest(g.getId(), t, true);
- version = latest == null ? 1 : latest.version + 1;
- storeMessage(g.getId(), dev, t, merged, version, true, true);
- }
- } catch (IOException e) {
+ } catch (FormatException e) {
throw new DbException(e);
- } finally {
- lock.writeLock().unlock();
}
}
@@ -261,18 +255,22 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
return privateGroupFactory.createPrivateGroup(CLIENT_ID, c);
}
- // Locking: lock.writeLock
- private void storeMessage(GroupId g, DeviceId dev, TransportId t,
- TransportProperties p, long version, boolean local, boolean shared)
- throws DbException, FormatException {
- byte[] body = encodeProperties(dev, t, p, version);
- long now = clock.currentTimeMillis();
- Message m = messageFactory.createMessage(g, now, body);
- BdfDictionary d = new BdfDictionary();
- d.put("transportId", t.getString());
- d.put("version", version);
- d.put("local", local);
- db.addLocalMessage(m, CLIENT_ID, metadataEncoder.encode(d), shared);
+ private void storeMessage(Transaction txn, GroupId g, DeviceId dev,
+ TransportId t, TransportProperties p, long version, boolean local,
+ boolean shared) throws DbException {
+ try {
+ byte[] body = encodeProperties(dev, t, p, version);
+ long now = clock.currentTimeMillis();
+ Message m = messageFactory.createMessage(g, now, body);
+ BdfDictionary d = new BdfDictionary();
+ d.put("transportId", t.getString());
+ d.put("version", version);
+ d.put("local", local);
+ Metadata meta = metadataEncoder.encode(d);
+ db.addLocalMessage(txn, m, CLIENT_ID, meta, shared);
+ } catch (FormatException e) {
+ throw new RuntimeException(e);
+ }
}
private byte[] encodeProperties(DeviceId dev, TransportId t,
@@ -293,12 +291,11 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
return out.toByteArray();
}
- // Locking: lock.readLock
- private Map findLatest(GroupId g, boolean local)
- throws DbException, FormatException {
+ private Map findLatest(Transaction txn,
+ GroupId g, boolean local) throws DbException, FormatException {
Map latestUpdates =
new HashMap();
- Map metadata = db.getMessageMetadata(g);
+ Map metadata = db.getMessageMetadata(txn, g);
for (Entry e : metadata.entrySet()) {
BdfDictionary d = metadataParser.parse(e.getValue());
if (d.getBoolean("local") == local) {
@@ -312,11 +309,10 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
return latestUpdates;
}
- // Locking: lock.readLock
- private LatestUpdate findLatest(GroupId g, TransportId t, boolean local)
- throws DbException, FormatException {
+ private LatestUpdate findLatest(Transaction txn, GroupId g, TransportId t,
+ boolean local) throws DbException, FormatException {
LatestUpdate latest = null;
- Map metadata = db.getMessageMetadata(g);
+ Map metadata = db.getMessageMetadata(txn, g);
for (Entry e : metadata.entrySet()) {
BdfDictionary d = metadataParser.parse(e.getValue());
if (d.getString("transportId").equals(t.getString())
@@ -330,25 +326,32 @@ class TransportPropertyManagerImpl implements TransportPropertyManager,
}
private TransportProperties parseProperties(byte[] raw)
- throws IOException {
+ throws FormatException {
TransportProperties p = new TransportProperties();
ByteArrayInputStream in = new ByteArrayInputStream(raw,
MESSAGE_HEADER_LENGTH, raw.length - MESSAGE_HEADER_LENGTH);
BdfReader r = bdfReaderFactory.createReader(in);
- r.readListStart();
- r.skipRaw(); // Device ID
- r.skipString(); // Transport ID
- r.skipInteger(); // Version
- r.readDictionaryStart();
- while (!r.hasDictionaryEnd()) {
- String key = r.readString(MAX_PROPERTY_LENGTH);
- String value = r.readString(MAX_PROPERTY_LENGTH);
- p.put(key, value);
+ try {
+ r.readListStart();
+ r.skipRaw(); // Device ID
+ r.skipString(); // Transport ID
+ r.skipInteger(); // Version
+ r.readDictionaryStart();
+ while (!r.hasDictionaryEnd()) {
+ String key = r.readString(MAX_PROPERTY_LENGTH);
+ String value = r.readString(MAX_PROPERTY_LENGTH);
+ p.put(key, value);
+ }
+ r.readDictionaryEnd();
+ r.readListEnd();
+ if (!r.eof()) throw new FormatException();
+ return p;
+ } catch (FormatException e) {
+ throw e;
+ } catch (IOException e) {
+ // Shouldn't happen with ByteArrayInputStream
+ throw new RuntimeException(e);
}
- r.readDictionaryEnd();
- r.readListEnd();
- if (!r.eof()) throw new FormatException();
- return p;
}
private static class LatestUpdate {
diff --git a/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java b/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java
index ee7a3ed68..639d822bb 100644
--- a/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java
+++ b/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java
@@ -4,6 +4,7 @@ import com.google.inject.Inject;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.settings.Settings;
import org.briarproject.api.settings.SettingsManager;
@@ -18,11 +19,24 @@ class SettingsManagerImpl implements SettingsManager {
@Override
public Settings getSettings(String namespace) throws DbException {
- return db.getSettings(namespace);
+ Transaction txn = db.startTransaction();
+ try {
+ Settings s = db.getSettings(txn, namespace);
+ txn.setComplete();
+ return s;
+ } finally {
+ db.endTransaction(txn);
+ }
}
@Override
public void mergeSettings(Settings s, String namespace) throws DbException {
- db.mergeSettings(s, namespace);
+ Transaction txn = db.startTransaction();
+ try {
+ db.mergeSettings(txn, s, namespace);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
}
}
diff --git a/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java
index d0af71201..8976eb7d1 100644
--- a/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java
+++ b/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java
@@ -4,6 +4,7 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
@@ -50,8 +51,8 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
private static final ThrowingRunnable CLOSE =
new ThrowingRunnable() {
- public void run() {}
- };
+ public void run() {}
+ };
private final DatabaseComponent db;
private final Executor dbExecutor;
@@ -178,7 +179,14 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
- Ack a = db.generateAck(contactId, MAX_MESSAGE_IDS);
+ Ack a;
+ Transaction txn = db.startTransaction();
+ try {
+ a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (LOG.isLoggable(INFO))
LOG.info("Generated ack: " + (a != null));
if (a != null) writerTasks.add(new WriteAck(a));
@@ -212,8 +220,15 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
- Collection b = db.generateRequestedBatch(contactId,
- MAX_PACKET_PAYLOAD_LENGTH, maxLatency);
+ Collection b;
+ Transaction txn = db.startTransaction();
+ try {
+ b = db.generateRequestedBatch(txn, contactId,
+ MAX_PACKET_PAYLOAD_LENGTH, maxLatency);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null));
if (b != null) writerTasks.add(new WriteBatch(b));
@@ -247,8 +262,15 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
- Offer o = db.generateOffer(contactId, MAX_MESSAGE_IDS,
- maxLatency);
+ Offer o;
+ Transaction txn = db.startTransaction();
+ try {
+ o = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS,
+ maxLatency);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (LOG.isLoggable(INFO))
LOG.info("Generated offer: " + (o != null));
if (o != null) writerTasks.add(new WriteOffer(o));
@@ -282,7 +304,14 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
- Request r = db.generateRequest(contactId, MAX_MESSAGE_IDS);
+ Request r;
+ Transaction txn = db.startTransaction();
+ try {
+ r = db.generateRequest(txn, contactId, MAX_MESSAGE_IDS);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (LOG.isLoggable(INFO))
LOG.info("Generated request: " + (r != null));
if (r != null) writerTasks.add(new WriteRequest(r));
diff --git a/briar-core/src/org/briarproject/sync/IncomingSession.java b/briar-core/src/org/briarproject/sync/IncomingSession.java
index 6fbfdd242..5e5f4c6df 100644
--- a/briar-core/src/org/briarproject/sync/IncomingSession.java
+++ b/briar-core/src/org/briarproject/sync/IncomingSession.java
@@ -5,6 +5,7 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
@@ -24,7 +25,9 @@ import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
-/** An incoming {@link org.briarproject.api.sync.SyncSession SyncSession}. */
+/**
+ * An incoming {@link org.briarproject.api.sync.SyncSession SyncSession}.
+ */
class IncomingSession implements SyncSession, EventListener {
private static final Logger LOG =
@@ -103,7 +106,13 @@ class IncomingSession implements SyncSession, EventListener {
public void run() {
try {
- db.receiveAck(contactId, ack);
+ Transaction txn = db.startTransaction();
+ try {
+ db.receiveAck(txn, contactId, ack);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
@@ -121,7 +130,13 @@ class IncomingSession implements SyncSession, EventListener {
public void run() {
try {
- db.receiveMessage(contactId, message);
+ Transaction txn = db.startTransaction();
+ try {
+ db.receiveMessage(txn, contactId, message);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
@@ -139,7 +154,13 @@ class IncomingSession implements SyncSession, EventListener {
public void run() {
try {
- db.receiveOffer(contactId, offer);
+ Transaction txn = db.startTransaction();
+ try {
+ db.receiveOffer(txn, contactId, offer);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
@@ -157,7 +178,13 @@ class IncomingSession implements SyncSession, EventListener {
public void run() {
try {
- db.receiveRequest(contactId, request);
+ Transaction txn = db.startTransaction();
+ try {
+ db.receiveRequest(txn, contactId, request);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
interrupt();
diff --git a/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java b/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java
index 620e23a4b..31ca62684 100644
--- a/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java
+++ b/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java
@@ -4,6 +4,7 @@ import org.briarproject.api.TransportId;
import org.briarproject.api.contact.ContactId;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventBus;
@@ -40,8 +41,8 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
private static final ThrowingRunnable CLOSE =
new ThrowingRunnable() {
- public void run() {}
- };
+ public void run() {}
+ };
private final DatabaseComponent db;
private final Executor dbExecutor;
@@ -119,7 +120,14 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
- Ack a = db.generateAck(contactId, MAX_MESSAGE_IDS);
+ Ack a;
+ Transaction txn = db.startTransaction();
+ try {
+ a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (LOG.isLoggable(INFO))
LOG.info("Generated ack: " + (a != null));
if (a == null) decrementOutstandingQueries();
@@ -154,8 +162,15 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
public void run() {
if (interrupted) return;
try {
- Collection b = db.generateBatch(contactId,
- MAX_PACKET_PAYLOAD_LENGTH, maxLatency);
+ Collection b;
+ Transaction txn = db.startTransaction();
+ try {
+ b = db.generateBatch(txn, contactId,
+ MAX_PACKET_PAYLOAD_LENGTH, maxLatency);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
if (LOG.isLoggable(INFO))
LOG.info("Generated batch: " + (b != null));
if (b == null) decrementOutstandingQueries();
diff --git a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
index 5fca14584..e075f341f 100644
--- a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
+++ b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java
@@ -9,7 +9,7 @@ import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.NoSuchGroupException;
-import org.briarproject.api.db.NoSuchMessageException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
import org.briarproject.api.event.MessageAddedEvent;
@@ -82,14 +82,17 @@ class ValidationManagerImpl implements ValidationManager, Service,
public void run() {
try {
// TODO: Don't do all of this in a single DB task
- for (MessageId id : db.getMessagesToValidate(c)) {
- try {
- Message m = parseMessage(id, db.getRawMessage(id));
- Group g = db.getGroup(m.getGroupId());
+ Transaction txn = db.startTransaction();
+ try {
+ for (MessageId id : db.getMessagesToValidate(txn, c)) {
+ byte[] raw = db.getRawMessage(txn, id);
+ Message m = parseMessage(id, raw);
+ Group g = db.getGroup(txn, m.getGroupId());
validateMessage(m, g);
- } catch (NoSuchMessageException e) {
- LOG.info("Message removed before validation");
}
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
@@ -127,17 +130,21 @@ class ValidationManagerImpl implements ValidationManager, Service,
dbExecutor.execute(new Runnable() {
public void run() {
try {
- if (meta == null) {
- db.setMessageValid(m, c, false);
- } else {
- for (ValidationHook hook : hooks)
- hook.validatingMessage(m, c, meta);
- db.mergeMessageMetadata(m.getId(), meta);
- db.setMessageValid(m, c, true);
- db.setMessageShared(m, true);
+ Transaction txn = db.startTransaction();
+ try {
+ if (meta == null) {
+ db.setMessageValid(txn, m, c, false);
+ } else {
+ for (ValidationHook hook : hooks)
+ hook.validatingMessage(txn, m, c, meta);
+ db.mergeMessageMetadata(txn, m.getId(), meta);
+ db.setMessageValid(txn, m, c, true);
+ db.setMessageShared(txn, m, true);
+ }
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
}
- } catch (NoSuchMessageException e) {
- LOG.info("Message removed during validation");
} catch (DbException e) {
if (LOG.isLoggable(WARNING))
LOG.log(WARNING, e.toString(), e);
@@ -159,7 +166,13 @@ class ValidationManagerImpl implements ValidationManager, Service,
dbExecutor.execute(new Runnable() {
public void run() {
try {
- validateMessage(m, db.getGroup(m.getGroupId()));
+ Transaction txn = db.startTransaction();
+ try {
+ validateMessage(m, db.getGroup(txn, m.getGroupId()));
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (NoSuchGroupException e) {
LOG.info("Group removed before validation");
} catch (DbException e) {
diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
index b1fa018fc..7e31a877c 100644
--- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
+++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java
@@ -7,6 +7,7 @@ import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.ContactRemovedEvent;
import org.briarproject.api.event.Event;
import org.briarproject.api.event.EventListener;
@@ -55,7 +56,14 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
@Override
public boolean start() {
try {
- Map latencies = db.getTransportLatencies();
+ Map latencies;
+ Transaction txn = db.startTransaction();
+ try {
+ latencies = db.getTransportLatencies(txn);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
for (Entry e : latencies.entrySet())
addTransport(e.getKey(), e.getValue());
} catch (DbException e) {
diff --git a/briar-core/src/org/briarproject/transport/TransportKeyManager.java b/briar-core/src/org/briarproject/transport/TransportKeyManager.java
index 2df96ccc7..ce15995ac 100644
--- a/briar-core/src/org/briarproject/transport/TransportKeyManager.java
+++ b/briar-core/src/org/briarproject/transport/TransportKeyManager.java
@@ -7,6 +7,7 @@ import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DbException;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.system.Clock;
import org.briarproject.api.system.Timer;
import org.briarproject.api.transport.StreamContext;
@@ -66,7 +67,13 @@ class TransportKeyManager extends TimerTask {
// Load the transport keys from the DB
Map loaded;
try {
- loaded = db.getTransportKeys(transportId);
+ Transaction txn = db.startTransaction();
+ try {
+ loaded = db.getTransportKeys(txn, transportId);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
return;
@@ -90,7 +97,13 @@ class TransportKeyManager extends TimerTask {
for (Entry e : current.entrySet())
addKeys(e.getKey(), new MutableTransportKeys(e.getValue()));
// Write any rotated keys back to the DB
- db.updateTransportKeys(rotated);
+ Transaction txn = db.startTransaction();
+ try {
+ db.updateTransportKeys(txn, rotated);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
@@ -135,7 +148,13 @@ class TransportKeyManager extends TimerTask {
// Initialise mutable state for the contact
addKeys(c, new MutableTransportKeys(k));
// Write the keys back to the DB
- db.addTransportKeys(c, k);
+ Transaction txn = db.startTransaction();
+ try {
+ db.addTransportKeys(txn, c, k);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
@@ -171,8 +190,14 @@ class TransportKeyManager extends TimerTask {
outKeys.getStreamCounter());
// Increment the stream counter and write it back to the DB
outKeys.incrementStreamCounter();
- db.incrementStreamCounter(c, transportId,
- outKeys.getRotationPeriod());
+ Transaction txn = db.startTransaction();
+ try {
+ db.incrementStreamCounter(txn, c, transportId,
+ outKeys.getRotationPeriod());
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
return ctx;
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -210,9 +235,15 @@ class TransportKeyManager extends TimerTask {
inContexts.remove(new Bytes(removeTag));
}
// Write the window back to the DB
- db.setReorderingWindow(tagCtx.contactId, transportId,
- inKeys.getRotationPeriod(), window.getBase(),
- window.getBitmap());
+ Transaction txn = db.startTransaction();
+ try {
+ db.setReorderingWindow(txn, tagCtx.contactId, transportId,
+ inKeys.getRotationPeriod(), window.getBase(),
+ window.getBitmap());
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
return ctx;
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
@@ -249,7 +280,13 @@ class TransportKeyManager extends TimerTask {
for (Entry e : current.entrySet())
addKeys(e.getKey(), new MutableTransportKeys(e.getValue()));
// Write any rotated keys back to the DB
- db.updateTransportKeys(rotated);
+ Transaction txn = db.startTransaction();
+ try {
+ db.updateTransportKeys(txn, rotated);
+ txn.setComplete();
+ } finally {
+ db.endTransaction(txn);
+ }
} catch (DbException e) {
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
} finally {
diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
index 0743df949..48e6ea037 100644
--- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
+++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java
@@ -14,6 +14,7 @@ import org.briarproject.api.db.NoSuchLocalAuthorException;
import org.briarproject.api.db.NoSuchMessageException;
import org.briarproject.api.db.NoSuchTransportException;
import org.briarproject.api.db.StorageStatus;
+import org.briarproject.api.db.Transaction;
import org.briarproject.api.event.EventBus;
import org.briarproject.api.event.GroupAddedEvent;
import org.briarproject.api.event.GroupRemovedEvent;
@@ -50,11 +51,13 @@ import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Map;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.sync.SyncConstants.MAX_GROUP_DESCRIPTOR_LENGTH;
import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN;
import static org.briarproject.api.sync.ValidationManager.Validity.VALID;
+import static org.briarproject.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -121,14 +124,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
- exactly(9).of(database).startTransaction();
- will(returnValue(txn));
- exactly(9).of(database).commitTransaction(txn);
// open()
oneOf(database).open();
will(returnValue(false));
oneOf(shutdown).addShutdownHook(with(any(Runnable.class)));
will(returnValue(shutdownHandle));
+ // startTransaction()
+ oneOf(database).startTransaction();
+ will(returnValue(txn));
// addLocalAuthor()
oneOf(database).containsLocalAuthor(txn, localAuthorId);
will(returnValue(false));
@@ -171,6 +174,8 @@ public class DatabaseComponentImplTest extends BriarTestCase {
oneOf(database).containsLocalAuthor(txn, localAuthorId);
will(returnValue(true));
oneOf(database).removeLocalAuthor(txn, localAuthorId);
+ // endTransaction()
+ oneOf(database).commitTransaction(txn);
// close()
oneOf(shutdown).removeShutdownHook(shutdownHandle);
oneOf(database).close();
@@ -179,15 +184,21 @@ public class DatabaseComponentImplTest extends BriarTestCase {
shutdown);
assertFalse(db.open());
- db.addLocalAuthor(localAuthor);
- assertEquals(contactId, db.addContact(author, localAuthorId));
- assertEquals(Collections.singletonList(contact), db.getContacts());
- db.addGroup(group); // First time - listeners called
- db.addGroup(group); // Second time - not called
- assertEquals(Collections.singletonList(group), db.getGroups(clientId));
- db.removeGroup(group);
- db.removeContact(contactId);
- db.removeLocalAuthor(localAuthorId);
+ Transaction transaction = db.startTransaction();
+ db.addLocalAuthor(transaction, localAuthor);
+ assertEquals(contactId,
+ db.addContact(transaction, author, localAuthorId));
+ assertEquals(Collections.singletonList(contact),
+ db.getContacts(transaction));
+ db.addGroup(transaction, group); // First time - listeners called
+ db.addGroup(transaction, group); // Second time - not called
+ assertEquals(Collections.singletonList(group),
+ db.getGroups(transaction, clientId));
+ db.removeGroup(transaction, group);
+ db.removeContact(transaction, contactId);
+ db.removeLocalAuthor(transaction, localAuthorId);
+ transaction.setComplete();
+ db.endTransaction(transaction);
db.close();
context.assertIsSatisfied();
@@ -211,11 +222,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
+ Transaction transaction = db.startTransaction();
try {
- db.addLocalMessage(message, clientId, metadata, true);
+ db.addLocalMessage(transaction, message, clientId, metadata, true);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
context.assertIsSatisfied();
@@ -253,7 +267,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.addLocalMessage(message, clientId, metadata, true);
+ Transaction transaction = db.startTransaction();
+ try {
+ db.addLocalMessage(transaction, message, clientId, metadata, true);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -277,126 +297,178 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
+ Transaction transaction = db.startTransaction();
try {
- db.addTransportKeys(contactId, createTransportKeys());
+ db.addTransportKeys(transaction, contactId, createTransportKeys());
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.generateAck(contactId, 123);
+ db.generateAck(transaction, contactId, 123);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.generateBatch(contactId, 123, 456);
+ db.generateBatch(transaction, contactId, 123, 456);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.generateOffer(contactId, 123, 456);
+ db.generateOffer(transaction, contactId, 123, 456);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.generateRequest(contactId, 123);
+ db.generateRequest(transaction, contactId, 123);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getContact(contactId);
+ db.getContact(transaction, contactId);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getMessageStatus(contactId, groupId);
+ db.getMessageStatus(transaction, contactId, groupId);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getMessageStatus(contactId, messageId);
+ db.getMessageStatus(transaction, contactId, messageId);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.incrementStreamCounter(contactId, transportId, 0);
+ db.incrementStreamCounter(transaction, contactId, transportId, 0);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.isVisibleToContact(contactId, groupId);
+ db.isVisibleToContact(transaction, contactId, groupId);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
Ack a = new Ack(Collections.singletonList(messageId));
- db.receiveAck(contactId, a);
+ db.receiveAck(transaction, contactId, a);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.receiveMessage(contactId, message);
+ db.receiveMessage(transaction, contactId, message);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
Offer o = new Offer(Collections.singletonList(messageId));
- db.receiveOffer(contactId, o);
+ db.receiveOffer(transaction, contactId, o);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
Request r = new Request(Collections.singletonList(messageId));
- db.receiveRequest(contactId, r);
+ db.receiveRequest(transaction, contactId, r);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.removeContact(contactId);
+ db.removeContact(transaction, contactId);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.setReorderingWindow(contactId, transportId, 0, 0, new byte[4]);
+ db.setReorderingWindow(transaction, contactId, transportId, 0, 0,
+ new byte[REORDERING_WINDOW_SIZE / 8]);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.setVisibleToContact(contactId, groupId, true);
+ db.setVisibleToContact(transaction, contactId, groupId, true);
fail();
} catch (NoSuchContactException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
context.assertIsSatisfied();
@@ -421,25 +493,34 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
+ Transaction transaction = db.startTransaction();
try {
- db.addContact(author, localAuthorId);
+ db.addContact(transaction, author, localAuthorId);
fail();
} catch (NoSuchLocalAuthorException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getLocalAuthor(localAuthorId);
+ db.getLocalAuthor(transaction, localAuthorId);
fail();
} catch (NoSuchLocalAuthorException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.removeLocalAuthor(localAuthorId);
+ db.removeLocalAuthor(transaction, localAuthorId);
fail();
} catch (NoSuchLocalAuthorException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
context.assertIsSatisfied();
@@ -468,53 +549,74 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
+ Transaction transaction = db.startTransaction();
try {
- db.getGroup(groupId);
+ db.getGroup(transaction, groupId);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getGroupMetadata(groupId);
+ db.getGroupMetadata(transaction, groupId);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getMessageStatus(contactId, groupId);
+ db.getMessageStatus(transaction, contactId, groupId);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.isVisibleToContact(contactId, groupId);
+ db.isVisibleToContact(transaction, contactId, groupId);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.mergeGroupMetadata(groupId, metadata);
+ db.mergeGroupMetadata(transaction, groupId, metadata);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.removeGroup(group);
+ db.removeGroup(transaction, group);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.setVisibleToContact(contactId, groupId, true);
+ db.setVisibleToContact(transaction, contactId, groupId, true);
fail();
} catch (NoSuchGroupException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
context.assertIsSatisfied();
@@ -542,60 +644,84 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
+ Transaction transaction = db.startTransaction();
try {
- db.deleteMessage(messageId);
+ db.deleteMessage(transaction, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.deleteMessageMetadata(messageId);
+ db.deleteMessageMetadata(transaction, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getRawMessage(messageId);
+ db.getRawMessage(transaction, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getMessageMetadata(messageId);
+ db.getMessageMetadata(transaction, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.getMessageStatus(contactId, messageId);
+ db.getMessageStatus(transaction, contactId, messageId);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.mergeMessageMetadata(messageId, metadata);
+ db.mergeMessageMetadata(transaction, messageId, metadata);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.setMessageShared(message, true);
+ db.setMessageShared(transaction, message, true);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.setMessageValid(message, clientId, true);
+ db.setMessageValid(transaction, message, clientId, true);
fail();
} catch (NoSuchMessageException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
context.assertIsSatisfied();
@@ -610,22 +736,21 @@ public class DatabaseComponentImplTest extends BriarTestCase {
final ShutdownManager shutdown = context.mock(ShutdownManager.class);
final EventBus eventBus = context.mock(EventBus.class);
context.checking(new Expectations() {{
- // addLocalAuthor()
+ // startTransaction()
oneOf(database).startTransaction();
will(returnValue(txn));
+ // addLocalAuthor()
oneOf(database).containsLocalAuthor(txn, localAuthorId);
will(returnValue(false));
oneOf(database).addLocalAuthor(txn, localAuthor);
- oneOf(database).commitTransaction(txn);
// addContact()
- oneOf(database).startTransaction();
- will(returnValue(txn));
oneOf(database).containsLocalAuthor(txn, localAuthorId);
will(returnValue(true));
oneOf(database).containsContact(txn, authorId, localAuthorId);
will(returnValue(false));
oneOf(database).addContact(txn, author, localAuthorId);
will(returnValue(contactId));
+ // endTransaction()
oneOf(database).commitTransaction(txn);
// Check whether the transport is in the DB (which it's not)
exactly(4).of(database).startTransaction();
@@ -639,35 +764,55 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.addLocalAuthor(localAuthor);
- assertEquals(contactId, db.addContact(author, localAuthorId));
-
+ Transaction transaction = db.startTransaction();
try {
- db.getTransportKeys(transportId);
- fail();
- } catch (NoSuchTransportException expected) {
- // Expected
+ db.addLocalAuthor(transaction, localAuthor);
+ assertEquals(contactId,
+ db.addContact(transaction, author, localAuthorId));
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.incrementStreamCounter(contactId, transportId, 0);
+ db.getTransportKeys(transaction, transportId);
fail();
} catch (NoSuchTransportException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.removeTransport(transportId);
+ db.incrementStreamCounter(transaction, contactId, transportId, 0);
fail();
} catch (NoSuchTransportException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
}
+ transaction = db.startTransaction();
try {
- db.setReorderingWindow(contactId, transportId, 0, 0, new byte[4]);
+ db.removeTransport(transaction, transportId);
fail();
} catch (NoSuchTransportException expected) {
// Expected
+ } finally {
+ db.endTransaction(transaction);
+ }
+
+ transaction = db.startTransaction();
+ try {
+ db.setReorderingWindow(transaction, contactId, transportId, 0, 0,
+ new byte[REORDERING_WINDOW_SIZE / 8]);
+ fail();
+ } catch (NoSuchTransportException expected) {
+ // Expected
+ } finally {
+ db.endTransaction(transaction);
}
context.assertIsSatisfied();
@@ -695,8 +840,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- Ack a = db.generateAck(contactId, 123);
- assertEquals(messagesToAck, a.getMessageIds());
+ Transaction transaction = db.startTransaction();
+ try {
+ Ack a = db.generateAck(transaction, contactId, 123);
+ assertEquals(messagesToAck, a.getMessageIds());
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -733,8 +884,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- assertEquals(messages, db.generateBatch(contactId, size * 2,
- maxLatency));
+ Transaction transaction = db.startTransaction();
+ try {
+ assertEquals(messages, db.generateBatch(transaction, contactId,
+ size * 2, maxLatency));
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -764,8 +921,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- Offer o = db.generateOffer(contactId, 123, maxLatency);
- assertEquals(ids, o.getMessageIds());
+ Transaction transaction = db.startTransaction();
+ try {
+ Offer o = db.generateOffer(transaction, contactId, 123, maxLatency);
+ assertEquals(ids, o.getMessageIds());
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -792,8 +955,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- Request r = db.generateRequest(contactId, 123);
- assertEquals(ids, r.getMessageIds());
+ Transaction transaction = db.startTransaction();
+ try {
+ Request r = db.generateRequest(transaction, contactId, 123);
+ assertEquals(ids, r.getMessageIds());
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -831,8 +1000,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- assertEquals(messages, db.generateRequestedBatch(contactId, size * 2,
- maxLatency));
+ Transaction transaction = db.startTransaction();
+ try {
+ assertEquals(messages, db.generateRequestedBatch(transaction,
+ contactId, size * 2, maxLatency));
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -858,7 +1033,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.receiveAck(contactId, new Ack(Collections.singletonList(messageId)));
+ Transaction transaction = db.startTransaction();
+ try {
+ Ack a = new Ack(Collections.singletonList(messageId));
+ db.receiveAck(transaction, contactId, a);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -896,7 +1078,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.receiveMessage(contactId, message);
+ Transaction transaction = db.startTransaction();
+ try {
+ db.receiveMessage(transaction, contactId, message);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -926,7 +1114,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.receiveMessage(contactId, message);
+ Transaction transaction = db.startTransaction();
+ try {
+ db.receiveMessage(transaction, contactId, message);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -952,7 +1146,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.receiveMessage(contactId, message);
+ Transaction transaction = db.startTransaction();
+ try {
+ db.receiveMessage(transaction, contactId, message);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -998,9 +1198,16 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- Offer o = new Offer(Arrays.asList(messageId, messageId1, messageId2,
- messageId3));
- db.receiveOffer(contactId, o);
+ Transaction transaction = db.startTransaction();
+ try {
+ Offer o = new Offer(Arrays.asList(messageId, messageId1,
+ messageId2, messageId3));
+ db.receiveOffer(transaction, contactId, o);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
+
context.assertIsSatisfied();
}
@@ -1026,8 +1233,14 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.receiveRequest(contactId, new Request(Collections.singletonList(
- messageId)));
+ Transaction transaction = db.startTransaction();
+ try {
+ Request r = new Request(Collections.singletonList(messageId));
+ db.receiveRequest(transaction, contactId, r);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -1056,7 +1269,13 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.setVisibleToContact(contactId, groupId, true);
+ Transaction transaction = db.startTransaction();
+ try {
+ db.setVisibleToContact(transaction, contactId, groupId, true);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@@ -1083,45 +1302,56 @@ public class DatabaseComponentImplTest extends BriarTestCase {
DatabaseComponent db = createDatabaseComponent(database, eventBus,
shutdown);
- db.setVisibleToContact(contactId, groupId, true);
+ Transaction transaction = db.startTransaction();
+ try {
+ db.setVisibleToContact(transaction, contactId, groupId, true);
+ transaction.setComplete();
+ } finally {
+ db.endTransaction(transaction);
+ }
context.assertIsSatisfied();
}
@Test
public void testTransportKeys() throws Exception {
- final TransportKeys keys = createTransportKeys();
+ final TransportKeys transportKeys = createTransportKeys();
+ final Map keys = Collections.singletonMap(
+ contactId, transportKeys);
Mockery context = new Mockery();
@SuppressWarnings("unchecked")
final Database