mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-21 07:09:56 +01:00
Added new database events and simplified database locking.
This commit is contained in:
@@ -9,20 +9,20 @@ import net.sf.briar.api.ContactId;
|
|||||||
* An event that is broadcast when the set of subscriptions visible to one or
|
* An event that is broadcast when the set of subscriptions visible to one or
|
||||||
* more contacts is updated.
|
* more contacts is updated.
|
||||||
*/
|
*/
|
||||||
public class SubscriptionsUpdatedEvent extends DatabaseEvent {
|
public class LocalSubscriptionsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
private final Collection<ContactId> affectedContacts;
|
private final Collection<ContactId> affected;
|
||||||
|
|
||||||
public SubscriptionsUpdatedEvent() {
|
public LocalSubscriptionsUpdatedEvent() {
|
||||||
affectedContacts = Collections.emptyList();
|
affected = Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionsUpdatedEvent(Collection<ContactId> affectedContacts) {
|
public LocalSubscriptionsUpdatedEvent(Collection<ContactId> affected) {
|
||||||
this.affectedContacts = affectedContacts;
|
this.affected = affected;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the contacts affected by the update. */
|
/** Returns the contacts affected by the update. */
|
||||||
public Collection<ContactId> getAffectedContacts() {
|
public Collection<ContactId> getAffectedContacts() {
|
||||||
return affectedContacts;
|
return affected;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,6 @@ package net.sf.briar.api.db.event;
|
|||||||
* An event that is broadcast when the local transport properties are
|
* An event that is broadcast when the local transport properties are
|
||||||
* updated.
|
* updated.
|
||||||
*/
|
*/
|
||||||
public class TransportsUpdatedEvent extends DatabaseEvent {
|
public class LocalTransportsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
import net.sf.briar.api.ContactId;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a contact's subscriptions are updated. */
|
||||||
|
public class RemoteSubscriptionsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
|
private final ContactId contactId;
|
||||||
|
|
||||||
|
public RemoteSubscriptionsUpdatedEvent(ContactId contactId) {
|
||||||
|
this.contactId = contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
import net.sf.briar.api.ContactId;
|
||||||
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An event that is broadcast when a contact's remote transport properties
|
||||||
|
* are updated.
|
||||||
|
*/
|
||||||
|
public class RemoteTransportsUpdatedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
|
private final ContactId contactId;
|
||||||
|
private final TransportId transportId;
|
||||||
|
|
||||||
|
public RemoteTransportsUpdatedEvent(ContactId contactId,
|
||||||
|
TransportId transportId) {
|
||||||
|
this.contactId = contactId;
|
||||||
|
this.transportId = transportId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ContactId getContactId() {
|
||||||
|
return contactId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportId getTransportId() {
|
||||||
|
return transportId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a transport is added. */
|
||||||
|
public class TransportAddedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
|
private final TransportId transportId;
|
||||||
|
|
||||||
|
public TransportAddedEvent(TransportId transportId) {
|
||||||
|
this.transportId = transportId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportId getTransportId() {
|
||||||
|
return transportId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package net.sf.briar.api.db.event;
|
||||||
|
|
||||||
|
import net.sf.briar.api.protocol.TransportId;
|
||||||
|
|
||||||
|
/** An event that is broadcast when a transport is removed. */
|
||||||
|
public class TransportRemovedEvent extends DatabaseEvent {
|
||||||
|
|
||||||
|
private final TransportId transportId;
|
||||||
|
|
||||||
|
public TransportRemovedEvent(TransportId transportId) {
|
||||||
|
this.transportId = transportId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransportId getTransportId() {
|
||||||
|
return transportId;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -31,12 +31,10 @@ import net.sf.briar.api.transport.TemporarySecret;
|
|||||||
* {@link #commitTransaction(T)}, even if an exception is thrown.
|
* {@link #commitTransaction(T)}, even if an exception is thrown.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking is provided by the DatabaseComponent implementation. To prevent
|
* Locking is provided by the DatabaseComponent implementation. To prevent
|
||||||
* deadlock, locks must be acquired in the following order:
|
* deadlock, locks must be acquired in the following (alphabetical) order:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> contact
|
* <li> contact
|
||||||
* <li> message
|
* <li> message
|
||||||
* <li> messageFlag
|
|
||||||
* <li> messageStatus
|
|
||||||
* <li> rating
|
* <li> rating
|
||||||
* <li> subscription
|
* <li> subscription
|
||||||
* <li> transport
|
* <li> transport
|
||||||
@@ -83,7 +81,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Adds a contact transport to the database.
|
* Adds a contact transport to the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window write.
|
* Locking: contact read, transport read, window write.
|
||||||
*/
|
*/
|
||||||
void addContactTransport(T txn, ContactTransport ct) throws DbException;
|
void addContactTransport(T txn, ContactTransport ct) throws DbException;
|
||||||
|
|
||||||
@@ -98,14 +96,14 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Records a received message as needing to be acknowledged.
|
* Records a received message as needing to be acknowledged.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, messageStatus write.
|
* Locking: contact read, message write.
|
||||||
*/
|
*/
|
||||||
void addMessageToAck(T txn, ContactId c, MessageId m) throws DbException;
|
void addMessageToAck(T txn, ContactId c, MessageId m) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Records a collection of sent messages as needing to be acknowledged.
|
* Records a collection of sent messages as needing to be acknowledged.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus write.
|
* Locking: contact read, message write.
|
||||||
*/
|
*/
|
||||||
void addOutstandingMessages(T txn, ContactId c, Collection<MessageId> sent)
|
void addOutstandingMessages(T txn, ContactId c, Collection<MessageId> sent)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -122,7 +120,7 @@ interface Database<T> {
|
|||||||
* Stores the given temporary secrets and deletes any secrets that have
|
* Stores the given temporary secrets and deletes any secrets that have
|
||||||
* been made obsolete.
|
* been made obsolete.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window write.
|
* Locking: contact read, transport read, window write.
|
||||||
*/
|
*/
|
||||||
void addSecrets(T txn, Collection<TemporarySecret> secrets)
|
void addSecrets(T txn, Collection<TemporarySecret> secrets)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -158,7 +156,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns true if the database contains the given contact transport.
|
* Returns true if the database contains the given contact transport.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window read.
|
* Locking: contact read, transport read, window read.
|
||||||
*/
|
*/
|
||||||
boolean containsContactTransport(T txn, ContactId c, TransportId t)
|
boolean containsContactTransport(T txn, ContactId c, TransportId t)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -203,7 +201,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns all contact transports.
|
* Returns all contact transports.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window read.
|
* Locking: contact read, transport read, window read.
|
||||||
*/
|
*/
|
||||||
Collection<ContactTransport> getContactTransports(T txn) throws DbException;
|
Collection<ContactTransport> getContactTransports(T txn) throws DbException;
|
||||||
|
|
||||||
@@ -257,7 +255,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns the headers of all messages in the given group.
|
* Returns the headers of all messages in the given group.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: message read, messageFlag read.
|
* Locking: message read.
|
||||||
*/
|
*/
|
||||||
Collection<MessageHeader> getMessageHeaders(T txn, GroupId g)
|
Collection<MessageHeader> getMessageHeaders(T txn, GroupId g)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -267,8 +265,7 @@ interface Database<T> {
|
|||||||
* if the message is not present in the database or is not sendable to the
|
* if the message is not present in the database or is not sendable to the
|
||||||
* given contact.
|
* given contact.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus read,
|
* Locking: contact read, message read, subscription read.
|
||||||
* subscription read.
|
|
||||||
*/
|
*/
|
||||||
byte[] getMessageIfSendable(T txn, ContactId c, MessageId m)
|
byte[] getMessageIfSendable(T txn, ContactId c, MessageId m)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -285,7 +282,7 @@ interface Database<T> {
|
|||||||
* Returns the IDs of some messages received from the given contact that
|
* Returns the IDs of some messages received from the given contact that
|
||||||
* need to be acknowledged, up to the given number of messages.
|
* need to be acknowledged, up to the given number of messages.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, messageStatus read.
|
* Locking: contact read, message read.
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToAck(T txn, ContactId c, int maxMessages)
|
Collection<MessageId> getMessagesToAck(T txn, ContactId c, int maxMessages)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -294,8 +291,7 @@ interface Database<T> {
|
|||||||
* Returns the IDs of some messages that are eligible to be sent to the
|
* Returns the IDs of some messages that are eligible to be sent to the
|
||||||
* given contact, up to the given number of messages.
|
* given contact, up to the given number of messages.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus read,
|
* Locking: contact read, message read, subscription read.
|
||||||
* subscription read.
|
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
|
Collection<MessageId> getMessagesToOffer(T txn, ContactId c,
|
||||||
int maxMessages) throws DbException;
|
int maxMessages) throws DbException;
|
||||||
@@ -327,7 +323,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns true if the given message has been read.
|
* Returns true if the given message has been read.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: message read, messageFlag read.
|
* Locking: message read.
|
||||||
*/
|
*/
|
||||||
boolean getReadFlag(T txn, MessageId m) throws DbException;
|
boolean getReadFlag(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
@@ -342,7 +338,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns all temporary secrets.
|
* Returns all temporary secrets.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window read.
|
* Locking: contact read, transport read, window read.
|
||||||
*/
|
*/
|
||||||
Collection<TemporarySecret> getSecrets(T txn) throws DbException;
|
Collection<TemporarySecret> getSecrets(T txn) throws DbException;
|
||||||
|
|
||||||
@@ -358,8 +354,7 @@ interface Database<T> {
|
|||||||
* given contact, with a total length less than or equal to the given
|
* given contact, with a total length less than or equal to the given
|
||||||
* length.
|
* length.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus read,
|
* Locking: contact read, message read, subscription read.
|
||||||
* subscription read.
|
|
||||||
*/
|
*/
|
||||||
Collection<MessageId> getSendableMessages(T txn, ContactId c, int maxLength)
|
Collection<MessageId> getSendableMessages(T txn, ContactId c, int maxLength)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -367,7 +362,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns true if the given message has been starred.
|
* Returns true if the given message has been starred.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: message read, messageFlag read.
|
* Locking: message read.
|
||||||
*/
|
*/
|
||||||
boolean getStarredFlag(T txn, MessageId m) throws DbException;
|
boolean getStarredFlag(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
@@ -425,7 +420,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns the number of unread messages in each subscribed group.
|
* Returns the number of unread messages in each subscribed group.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: message read, messageFlag read, subscription read.
|
* Locking: message read, subscription read.
|
||||||
*/
|
*/
|
||||||
Map<GroupId, Integer> getUnreadMessageCounts(T txn) throws DbException;
|
Map<GroupId, Integer> getUnreadMessageCounts(T txn) throws DbException;
|
||||||
|
|
||||||
@@ -439,7 +434,7 @@ interface Database<T> {
|
|||||||
/**
|
/**
|
||||||
* Returns true if any messages are sendable to the given contact.
|
* Returns true if any messages are sendable to the given contact.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus read.
|
* Locking: contact read, message read.
|
||||||
*/
|
*/
|
||||||
boolean hasSendableMessages(T txn, ContactId c) throws DbException;
|
boolean hasSendableMessages(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
@@ -447,7 +442,7 @@ interface Database<T> {
|
|||||||
* Increments the outgoing connection counter for the given contact
|
* Increments the outgoing connection counter for the given contact
|
||||||
* transport in the given rotation period and returns the old value;
|
* transport in the given rotation period and returns the old value;
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window write.
|
* Locking: contact read, transport read, window write.
|
||||||
*/
|
*/
|
||||||
long incrementConnectionCounter(T txn, ContactId c, TransportId t,
|
long incrementConnectionCounter(T txn, ContactId c, TransportId t,
|
||||||
long period) throws DbException;
|
long period) throws DbException;
|
||||||
@@ -470,54 +465,52 @@ interface Database<T> {
|
|||||||
void mergeLocalProperties(T txn, TransportId t, TransportProperties p)
|
void mergeLocalProperties(T txn, TransportId t, TransportProperties p)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|
||||||
/**
|
|
||||||
* Removes outstanding messages that have been acknowledged. Any of the
|
|
||||||
* messages that are still considered outstanding (Status.SENT) with
|
|
||||||
* respect to the given contact are now considered seen (Status.SEEN).
|
|
||||||
* <p>
|
|
||||||
* Locking: contact read, message read, messageStatus write.
|
|
||||||
*/
|
|
||||||
void removeOutstandingMessages(T txn, ContactId c,
|
|
||||||
Collection<MessageId> acked) throws DbException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Marks the given messages received from the given contact as having been
|
|
||||||
* acknowledged.
|
|
||||||
* <p>
|
|
||||||
* Locking: contact read, messageStatus write.
|
|
||||||
*/
|
|
||||||
void removeMessagesToAck(T txn, ContactId c, Collection<MessageId> acked)
|
|
||||||
throws DbException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a contact (and all associated state) from the database.
|
* Removes a contact (and all associated state) from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact write, message write, messageFlag write,
|
* Locking: contact write, message write, subscription write,
|
||||||
* messageStatus write, subscription write, transport write, window write.
|
* transport write, window write.
|
||||||
*/
|
*/
|
||||||
void removeContact(T txn, ContactId c) throws DbException;
|
void removeContact(T txn, ContactId c) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a message (and all associated state) from the database.
|
* Removes a message (and all associated state) from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message write, messageFlag write,
|
* Locking: contact read, message write.
|
||||||
* messageStatus write.
|
|
||||||
*/
|
*/
|
||||||
void removeMessage(T txn, MessageId m) throws DbException;
|
void removeMessage(T txn, MessageId m) throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks the given messages received from the given contact as having been
|
||||||
|
* acknowledged.
|
||||||
|
* <p>
|
||||||
|
* Locking: contact read, message write.
|
||||||
|
*/
|
||||||
|
void removeMessagesToAck(T txn, ContactId c, Collection<MessageId> acked)
|
||||||
|
throws DbException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes outstanding messages that have been acknowledged. Any of the
|
||||||
|
* messages that are still considered outstanding (Status.SENT) with
|
||||||
|
* respect to the given contact are now considered seen (Status.SEEN).
|
||||||
|
* <p>
|
||||||
|
* Locking: contact read, message write.
|
||||||
|
*/
|
||||||
|
void removeOutstandingMessages(T txn, ContactId c,
|
||||||
|
Collection<MessageId> acked) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unsubscribes from the given group. Any messages belonging to the group
|
* Unsubscribes from the given group. Any messages belonging to the group
|
||||||
* are deleted from the database.
|
* are deleted from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact write, message write, messageFlag write,
|
* Locking: contact write, message write, subscription write.
|
||||||
* messageStatus write, subscription write.
|
|
||||||
*/
|
*/
|
||||||
void removeSubscription(T txn, GroupId g) throws DbException;
|
void removeSubscription(T txn, GroupId g) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes a transport (and all associated state) from the database.
|
* Removes a transport (and all associated state) from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, transport write.
|
* Locking: transport write.
|
||||||
*/
|
*/
|
||||||
void removeTransport(T txn, TransportId t) throws DbException;
|
void removeTransport(T txn, TransportId t) throws DbException;
|
||||||
|
|
||||||
@@ -532,7 +525,7 @@ interface Database<T> {
|
|||||||
* Sets the connection reordering window for the given contact transport in
|
* Sets the connection reordering window for the given contact transport in
|
||||||
* the given rotation period.
|
* the given rotation period.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, window write.
|
* Locking: contact read, transport read, window write.
|
||||||
*/
|
*/
|
||||||
void setConnectionWindow(T txn, ContactId c, TransportId t, long period,
|
void setConnectionWindow(T txn, ContactId c, TransportId t, long period,
|
||||||
long centre, byte[] bitmap) throws DbException;
|
long centre, byte[] bitmap) throws DbException;
|
||||||
@@ -555,7 +548,7 @@ interface Database<T> {
|
|||||||
* Marks the given message read or unread and returns true if it was
|
* Marks the given message read or unread and returns true if it was
|
||||||
* previously read.
|
* previously read.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: message read, messageFlag write.
|
* Locking: message write.
|
||||||
*/
|
*/
|
||||||
boolean setRead(T txn, MessageId m, boolean read) throws DbException;
|
boolean setRead(T txn, MessageId m, boolean read) throws DbException;
|
||||||
|
|
||||||
@@ -581,14 +574,14 @@ interface Database<T> {
|
|||||||
* Marks the given message starred or unstarred and returns true if it was
|
* Marks the given message starred or unstarred and returns true if it was
|
||||||
* previously starred.
|
* previously starred.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: message read, messageFlag write.
|
* Locking: message write.
|
||||||
*/
|
*/
|
||||||
boolean setStarred(T txn, MessageId m, boolean starred) throws DbException;
|
boolean setStarred(T txn, MessageId m, boolean starred) throws DbException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the status of the given message with respect to the given contact.
|
* Sets the status of the given message with respect to the given contact.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus write.
|
* Locking: contact read, message write.
|
||||||
*/
|
*/
|
||||||
void setStatus(T txn, ContactId c, MessageId m, Status s)
|
void setStatus(T txn, ContactId c, MessageId m, Status s)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
@@ -599,8 +592,7 @@ interface Database<T> {
|
|||||||
* with respect to the contact to Status.SEEN and returns true; otherwise
|
* with respect to the contact to Status.SEEN and returns true; otherwise
|
||||||
* returns false.
|
* returns false.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message read, messageStatus write,
|
* Locking: contact read, message write, subscription read.
|
||||||
* subscription read.
|
|
||||||
*/
|
*/
|
||||||
boolean setStatusSeenIfVisible(T txn, ContactId c, MessageId m)
|
boolean setStatusSeenIfVisible(T txn, ContactId c, MessageId m)
|
||||||
throws DbException;
|
throws DbException;
|
||||||
|
|||||||
@@ -34,11 +34,15 @@ import net.sf.briar.api.db.event.ContactAddedEvent;
|
|||||||
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
import net.sf.briar.api.db.event.ContactRemovedEvent;
|
||||||
import net.sf.briar.api.db.event.DatabaseEvent;
|
import net.sf.briar.api.db.event.DatabaseEvent;
|
||||||
import net.sf.briar.api.db.event.DatabaseListener;
|
import net.sf.briar.api.db.event.DatabaseListener;
|
||||||
|
import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
|
||||||
|
import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
|
||||||
import net.sf.briar.api.db.event.MessageAddedEvent;
|
import net.sf.briar.api.db.event.MessageAddedEvent;
|
||||||
import net.sf.briar.api.db.event.MessageReceivedEvent;
|
import net.sf.briar.api.db.event.MessageReceivedEvent;
|
||||||
import net.sf.briar.api.db.event.RatingChangedEvent;
|
import net.sf.briar.api.db.event.RatingChangedEvent;
|
||||||
import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent;
|
import net.sf.briar.api.db.event.RemoteSubscriptionsUpdatedEvent;
|
||||||
import net.sf.briar.api.db.event.TransportsUpdatedEvent;
|
import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent;
|
||||||
|
import net.sf.briar.api.db.event.TransportAddedEvent;
|
||||||
|
import net.sf.briar.api.db.event.TransportRemovedEvent;
|
||||||
import net.sf.briar.api.lifecycle.ShutdownManager;
|
import net.sf.briar.api.lifecycle.ShutdownManager;
|
||||||
import net.sf.briar.api.protocol.Ack;
|
import net.sf.briar.api.protocol.Ack;
|
||||||
import net.sf.briar.api.protocol.AuthorId;
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
@@ -79,10 +83,6 @@ DatabaseCleaner.Callback {
|
|||||||
new ReentrantReadWriteLock(true);
|
new ReentrantReadWriteLock(true);
|
||||||
private final ReentrantReadWriteLock messageLock =
|
private final ReentrantReadWriteLock messageLock =
|
||||||
new ReentrantReadWriteLock(true);
|
new ReentrantReadWriteLock(true);
|
||||||
private final ReentrantReadWriteLock messageFlagLock =
|
|
||||||
new ReentrantReadWriteLock(true);
|
|
||||||
private final ReentrantReadWriteLock messageStatusLock =
|
|
||||||
new ReentrantReadWriteLock(true);
|
|
||||||
private final ReentrantReadWriteLock ratingLock =
|
private final ReentrantReadWriteLock ratingLock =
|
||||||
new ReentrantReadWriteLock(true);
|
new ReentrantReadWriteLock(true);
|
||||||
private final ReentrantReadWriteLock subscriptionLock =
|
private final ReentrantReadWriteLock subscriptionLock =
|
||||||
@@ -193,6 +193,8 @@ DatabaseCleaner.Callback {
|
|||||||
|
|
||||||
public void addContactTransport(ContactTransport ct) throws DbException {
|
public void addContactTransport(ContactTransport ct) throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
transportLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
windowLock.writeLock().lock();
|
windowLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -209,6 +211,9 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
windowLock.writeLock().unlock();
|
windowLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.readLock().unlock();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -219,8 +224,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -238,9 +241,6 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -257,7 +257,7 @@ DatabaseCleaner.Callback {
|
|||||||
* sendability of its ancestors if necessary, marks the message as seen by
|
* sendability of its ancestors if necessary, marks the message as seen by
|
||||||
* the sender and unseen by all other contacts, and returns true.
|
* the sender and unseen by all other contacts, and returns true.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message write, messageStatus write.
|
* Locking: contact read, message write.
|
||||||
* @param sender may be null for a locally generated message.
|
* @param sender may be null for a locally generated message.
|
||||||
*/
|
*/
|
||||||
private boolean storeGroupMessage(T txn, Message m, ContactId sender)
|
private boolean storeGroupMessage(T txn, Message m, ContactId sender)
|
||||||
@@ -343,8 +343,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -356,9 +354,6 @@ DatabaseCleaner.Callback {
|
|||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -372,6 +367,8 @@ DatabaseCleaner.Callback {
|
|||||||
public void addSecrets(Collection<TemporarySecret> secrets)
|
public void addSecrets(Collection<TemporarySecret> secrets)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
transportLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
windowLock.writeLock().lock();
|
windowLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -394,6 +391,9 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
windowLock.writeLock().unlock();
|
windowLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.readLock().unlock();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -413,6 +413,8 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
transportLock.writeLock().unlock();
|
transportLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
// Call the listeners outside the lock
|
||||||
|
callListeners(new TransportAddedEvent(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -421,7 +423,7 @@ DatabaseCleaner.Callback {
|
|||||||
* incoming, respectively; or returns false if the message is already in
|
* incoming, respectively; or returns false if the message is already in
|
||||||
* the database.
|
* the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message write, messageStatus write.
|
* Locking: contact read, message write.
|
||||||
*/
|
*/
|
||||||
private boolean storePrivateMessage(T txn, Message m, ContactId c,
|
private boolean storePrivateMessage(T txn, Message m, ContactId c,
|
||||||
boolean incoming) throws DbException {
|
boolean incoming) throws DbException {
|
||||||
@@ -442,7 +444,7 @@ DatabaseCleaner.Callback {
|
|||||||
Collection<MessageId> acked;
|
Collection<MessageId> acked;
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageStatusLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -455,11 +457,11 @@ DatabaseCleaner.Callback {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.readLock().unlock();
|
messageLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
if(acked.isEmpty()) return null;
|
if(acked.isEmpty()) return null;
|
||||||
// Record the contents of the ack
|
// Record the contents of the ack
|
||||||
messageStatusLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -470,7 +472,7 @@ DatabaseCleaner.Callback {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -486,8 +488,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.readLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -508,10 +508,11 @@ DatabaseCleaner.Callback {
|
|||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.readLock().unlock();
|
messageLock.readLock().lock();
|
||||||
}
|
}
|
||||||
if(messages.isEmpty()) return null;
|
if(messages.isEmpty()) return null;
|
||||||
messageStatusLock.writeLock().lock();
|
// Record the message as sent
|
||||||
|
messageLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -522,10 +523,7 @@ DatabaseCleaner.Callback {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageLock.readLock().unlock();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -542,8 +540,6 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageStatusLock.readLock().lock();
|
|
||||||
try{
|
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
@@ -571,10 +567,11 @@ DatabaseCleaner.Callback {
|
|||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.readLock().unlock();
|
messageLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
if(messages.isEmpty()) return null;
|
if(messages.isEmpty()) return null;
|
||||||
messageStatusLock.writeLock().lock();
|
// Record the messages as sent
|
||||||
|
messageLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -585,10 +582,7 @@ DatabaseCleaner.Callback {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageLock.readLock().unlock();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -602,8 +596,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.readLock().lock();
|
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -615,9 +607,6 @@ DatabaseCleaner.Callback {
|
|||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.readLock().unlock();
|
messageLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -779,8 +768,6 @@ DatabaseCleaner.Callback {
|
|||||||
public Collection<MessageHeader> getMessageHeaders(GroupId g)
|
public Collection<MessageHeader> getMessageHeaders(GroupId g)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
messageLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
|
||||||
messageFlagLock.readLock().lock();
|
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -792,9 +779,6 @@ DatabaseCleaner.Callback {
|
|||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageFlagLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.readLock().unlock();
|
messageLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -843,12 +827,15 @@ DatabaseCleaner.Callback {
|
|||||||
|
|
||||||
public Collection<TemporarySecret> getSecrets() throws DbException {
|
public Collection<TemporarySecret> getSecrets() throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
transportLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
windowLock.readLock().lock();
|
windowLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
Collection<TemporarySecret> secrets = db.getSecrets(txn);
|
Collection<TemporarySecret> secrets =
|
||||||
|
db.getSecrets(txn);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
return secrets;
|
return secrets;
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
@@ -858,6 +845,9 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
windowLock.readLock().unlock();
|
windowLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.readLock().unlock();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -882,8 +872,6 @@ DatabaseCleaner.Callback {
|
|||||||
|
|
||||||
public Map<GroupId, Integer> getUnreadMessageCounts() throws DbException {
|
public Map<GroupId, Integer> getUnreadMessageCounts() throws DbException {
|
||||||
messageLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
|
||||||
messageFlagLock.readLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -900,9 +888,6 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageFlagLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.readLock().unlock();
|
messageLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -934,8 +919,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.readLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.readLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -953,9 +936,6 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.readLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.readLock().unlock();
|
messageLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -967,6 +947,8 @@ DatabaseCleaner.Callback {
|
|||||||
public long incrementConnectionCounter(ContactId c, TransportId t,
|
public long incrementConnectionCounter(ContactId c, TransportId t,
|
||||||
long period) throws DbException {
|
long period) throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
transportLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
windowLock.writeLock().lock();
|
windowLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -974,9 +956,10 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
if(!db.containsContactTransport(txn, c, t))
|
if(!db.containsContactTransport(txn, c, t))
|
||||||
throw new NoSuchContactTransportException();
|
throw new NoSuchContactTransportException();
|
||||||
long l = db.incrementConnectionCounter(txn, c, t, period);
|
long counter = db.incrementConnectionCounter(txn, c, t,
|
||||||
|
period);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
return l;
|
return counter;
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
throw e;
|
throw e;
|
||||||
@@ -984,6 +967,9 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
windowLock.writeLock().unlock();
|
windowLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.readLock().unlock();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -1026,15 +1012,13 @@ DatabaseCleaner.Callback {
|
|||||||
transportLock.writeLock().unlock();
|
transportLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
// Call the listeners outside the lock
|
// Call the listeners outside the lock
|
||||||
if(changed) callListeners(new TransportsUpdatedEvent());
|
if(changed) callListeners(new LocalTransportsUpdatedEvent());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receiveAck(ContactId c, Ack a) throws DbException {
|
public void receiveAck(ContactId c, Ack a) throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -1047,10 +1031,7 @@ DatabaseCleaner.Callback {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageLock.readLock().unlock();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -1062,8 +1043,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1081,9 +1060,6 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -1099,8 +1075,7 @@ DatabaseCleaner.Callback {
|
|||||||
* Attempts to store a message received from the given contact, and returns
|
* Attempts to store a message received from the given contact, and returns
|
||||||
* true if it was stored.
|
* true if it was stored.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message write, messageStatus write,
|
* Locking: contact read, message write, subscription read.
|
||||||
* subscription read.
|
|
||||||
*/
|
*/
|
||||||
private boolean storeMessage(T txn, ContactId c, Message m)
|
private boolean storeMessage(T txn, ContactId c, Message m)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
@@ -1115,9 +1090,7 @@ DatabaseCleaner.Callback {
|
|||||||
BitSet request;
|
BitSet request;
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1129,8 +1102,8 @@ DatabaseCleaner.Callback {
|
|||||||
request = new BitSet(offered.size());
|
request = new BitSet(offered.size());
|
||||||
Iterator<MessageId> it = offered.iterator();
|
Iterator<MessageId> it = offered.iterator();
|
||||||
for(int i = 0; it.hasNext(); i++) {
|
for(int i = 0; it.hasNext(); i++) {
|
||||||
// If the message is not in the database, or if
|
// If the message is not in the database, or not
|
||||||
// it is not visible to the contact, request it
|
// visible to the contact, request it
|
||||||
MessageId m = it.next();
|
MessageId m = it.next();
|
||||||
if(!db.setStatusSeenIfVisible(txn, c, m))
|
if(!db.setStatusSeenIfVisible(txn, c, m))
|
||||||
request.set(i);
|
request.set(i);
|
||||||
@@ -1144,10 +1117,7 @@ DatabaseCleaner.Callback {
|
|||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageLock.readLock().unlock();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -1165,8 +1135,7 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
if(!db.containsContact(txn, c))
|
if(!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
long version = a.getVersionNumber();
|
db.setSubscriptionUpdateAcked(txn, c, a.getVersionNumber());
|
||||||
db.setSubscriptionUpdateAcked(txn, c, version);
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
@@ -1202,6 +1171,8 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
// Call the listeners outside the lock
|
||||||
|
callListeners(new RemoteSubscriptionsUpdatedEvent(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void receiveTransportAck(ContactId c, TransportAck a)
|
public void receiveTransportAck(ContactId c, TransportAck a)
|
||||||
@@ -1215,8 +1186,7 @@ DatabaseCleaner.Callback {
|
|||||||
if(!db.containsContact(txn, c))
|
if(!db.containsContact(txn, c))
|
||||||
throw new NoSuchContactException();
|
throw new NoSuchContactException();
|
||||||
TransportId t = a.getId();
|
TransportId t = a.getId();
|
||||||
long version = a.getVersionNumber();
|
db.setTransportUpdateAcked(txn, c, t, a.getVersionNumber());
|
||||||
db.setTransportUpdateAcked(txn, c, t, version);
|
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
@@ -1252,16 +1222,14 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
|
// Call the listeners outside the lock
|
||||||
|
callListeners(new RemoteTransportsUpdatedEvent(c, t.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeContact(ContactId c) throws DbException {
|
public void removeContact(ContactId c) throws DbException {
|
||||||
contactLock.writeLock().lock();
|
contactLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageFlagLock.writeLock().lock();
|
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.writeLock().lock();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1288,12 +1256,6 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.writeLock().unlock();
|
subscriptionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageFlagLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -1304,9 +1266,29 @@ DatabaseCleaner.Callback {
|
|||||||
callListeners(new ContactRemovedEvent(c));
|
callListeners(new ContactRemovedEvent(c));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void removeTransport(TransportId t) throws DbException {
|
||||||
|
transportLock.writeLock().lock();
|
||||||
|
try {
|
||||||
|
T txn = db.startTransaction();
|
||||||
|
try {
|
||||||
|
db.removeTransport(txn, t);
|
||||||
|
db.commitTransaction(txn);
|
||||||
|
} catch(DbException e) {
|
||||||
|
db.abortTransaction(txn);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.writeLock().unlock();
|
||||||
|
}
|
||||||
|
// Call the listeners outside the lock
|
||||||
|
callListeners(new TransportRemovedEvent(t));
|
||||||
|
}
|
||||||
|
|
||||||
public void setConnectionWindow(ContactId c, TransportId t, long period,
|
public void setConnectionWindow(ContactId c, TransportId t, long period,
|
||||||
long centre, byte[] bitmap) throws DbException {
|
long centre, byte[] bitmap) throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
|
try {
|
||||||
|
transportLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
windowLock.writeLock().lock();
|
windowLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1314,7 +1296,8 @@ DatabaseCleaner.Callback {
|
|||||||
try {
|
try {
|
||||||
if(!db.containsContactTransport(txn, c, t))
|
if(!db.containsContactTransport(txn, c, t))
|
||||||
throw new NoSuchContactTransportException();
|
throw new NoSuchContactTransportException();
|
||||||
db.setConnectionWindow(txn, c, t, period, centre, bitmap);
|
db.setConnectionWindow(txn, c, t, period, centre,
|
||||||
|
bitmap);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} catch(DbException e) {
|
} catch(DbException e) {
|
||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
@@ -1323,6 +1306,9 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
windowLock.writeLock().unlock();
|
windowLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
|
} finally {
|
||||||
|
transportLock.readLock().unlock();
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -1362,9 +1348,7 @@ DatabaseCleaner.Callback {
|
|||||||
throws DbException {
|
throws DbException {
|
||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.readLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.readLock().lock();
|
subscriptionLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1384,10 +1368,7 @@ DatabaseCleaner.Callback {
|
|||||||
subscriptionLock.readLock().unlock();
|
subscriptionLock.readLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
messageStatusLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageLock.readLock().unlock();
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
contactLock.readLock().unlock();
|
contactLock.readLock().unlock();
|
||||||
@@ -1474,10 +1455,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.writeLock().lock();
|
contactLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageFlagLock.writeLock().lock();
|
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
subscriptionLock.writeLock().lock();
|
subscriptionLock.writeLock().lock();
|
||||||
try {
|
try {
|
||||||
@@ -1495,12 +1472,6 @@ DatabaseCleaner.Callback {
|
|||||||
} finally {
|
} finally {
|
||||||
subscriptionLock.writeLock().unlock();
|
subscriptionLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageFlagLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -1508,8 +1479,7 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.writeLock().unlock();
|
contactLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
// Call the listeners outside the lock
|
// Call the listeners outside the lock
|
||||||
if(affected != null && !affected.isEmpty())
|
callListeners(new LocalSubscriptionsUpdatedEvent(affected));
|
||||||
callListeners(new SubscriptionsUpdatedEvent(affected));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void checkFreeSpaceAndClean() throws DbException {
|
public void checkFreeSpaceAndClean() throws DbException {
|
||||||
@@ -1536,10 +1506,6 @@ DatabaseCleaner.Callback {
|
|||||||
contactLock.readLock().lock();
|
contactLock.readLock().lock();
|
||||||
try {
|
try {
|
||||||
messageLock.writeLock().lock();
|
messageLock.writeLock().lock();
|
||||||
try {
|
|
||||||
messageFlagLock.writeLock().lock();
|
|
||||||
try {
|
|
||||||
messageStatusLock.writeLock().lock();
|
|
||||||
try {
|
try {
|
||||||
T txn = db.startTransaction();
|
T txn = db.startTransaction();
|
||||||
try {
|
try {
|
||||||
@@ -1550,12 +1516,6 @@ DatabaseCleaner.Callback {
|
|||||||
db.abortTransaction(txn);
|
db.abortTransaction(txn);
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} finally {
|
|
||||||
messageStatusLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
messageFlagLock.writeLock().unlock();
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
messageLock.writeLock().unlock();
|
messageLock.writeLock().unlock();
|
||||||
}
|
}
|
||||||
@@ -1568,7 +1528,7 @@ DatabaseCleaner.Callback {
|
|||||||
/**
|
/**
|
||||||
* Removes the given message (and all associated state) from the database.
|
* Removes the given message (and all associated state) from the database.
|
||||||
* <p>
|
* <p>
|
||||||
* Locking: contact read, message write, messageStatus write.
|
* Locking: contact read, message write.
|
||||||
*/
|
*/
|
||||||
private void removeMessage(T txn, MessageId m) throws DbException {
|
private void removeMessage(T txn, MessageId m) throws DbException {
|
||||||
int sendability = db.getSendability(txn, m);
|
int sendability = db.getSendability(txn, m);
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
private static final String INDEX_MESSAGES_BY_SENDABILITY =
|
private static final String INDEX_MESSAGES_BY_SENDABILITY =
|
||||||
"CREATE INDEX messagesBySendability ON messages (sendability)";
|
"CREATE INDEX messagesBySendability ON messages (sendability)";
|
||||||
|
|
||||||
// Locking: contact read, messageStatus
|
// Locking: contact read, message
|
||||||
private static final String CREATE_MESSAGES_TO_ACK =
|
private static final String CREATE_MESSAGES_TO_ACK =
|
||||||
"CREATE TABLE messagesToAck"
|
"CREATE TABLE messagesToAck"
|
||||||
+ " (messageId HASH NOT NULL,"
|
+ " (messageId HASH NOT NULL,"
|
||||||
@@ -102,7 +102,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " REFERENCES contacts (contactId)"
|
+ " REFERENCES contacts (contactId)"
|
||||||
+ " ON DELETE CASCADE)";
|
+ " ON DELETE CASCADE)";
|
||||||
|
|
||||||
// Locking: contact read, message read, messageStatus
|
// Locking: contact read, message
|
||||||
private static final String CREATE_STATUSES =
|
private static final String CREATE_STATUSES =
|
||||||
"CREATE TABLE statuses"
|
"CREATE TABLE statuses"
|
||||||
+ " (messageId HASH NOT NULL,"
|
+ " (messageId HASH NOT NULL,"
|
||||||
@@ -122,7 +122,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
private static final String INDEX_STATUSES_BY_CONTACT =
|
private static final String INDEX_STATUSES_BY_CONTACT =
|
||||||
"CREATE INDEX statusesByContact ON statuses (contactId)";
|
"CREATE INDEX statusesByContact ON statuses (contactId)";
|
||||||
|
|
||||||
// Locking: message read, messageFlag
|
// Locking: message
|
||||||
private static final String CREATE_FLAGS =
|
private static final String CREATE_FLAGS =
|
||||||
"CREATE TABLE flags"
|
"CREATE TABLE flags"
|
||||||
+ " (messageId HASH NOT NULL,"
|
+ " (messageId HASH NOT NULL,"
|
||||||
@@ -252,7 +252,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " REFERENCES contacts (contactId)"
|
+ " REFERENCES contacts (contactId)"
|
||||||
+ " ON DELETE CASCADE)";
|
+ " ON DELETE CASCADE)";
|
||||||
|
|
||||||
// Locking: contact read, window
|
// Locking: contact read, transport read, window
|
||||||
private static final String CREATE_CONTACT_TRANSPORTS =
|
private static final String CREATE_CONTACT_TRANSPORTS =
|
||||||
"CREATE TABLE contactTransports"
|
"CREATE TABLE contactTransports"
|
||||||
+ " (contactId INT NOT NULL,"
|
+ " (contactId INT NOT NULL,"
|
||||||
@@ -269,7 +269,7 @@ abstract class JdbcDatabase implements Database<Connection> {
|
|||||||
+ " REFERENCES transports (transportId)"
|
+ " REFERENCES transports (transportId)"
|
||||||
+ " ON DELETE CASCADE)";
|
+ " ON DELETE CASCADE)";
|
||||||
|
|
||||||
// Locking: contact read, window
|
// Locking: contact read, transport read, window
|
||||||
private static final String CREATE_SECRETS =
|
private static final String CREATE_SECRETS =
|
||||||
"CREATE TABLE secrets"
|
"CREATE TABLE secrets"
|
||||||
+ " (contactId INT NOT NULL,"
|
+ " (contactId INT NOT NULL,"
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import net.sf.briar.api.db.event.DatabaseEvent;
|
|||||||
import net.sf.briar.api.db.event.DatabaseListener;
|
import net.sf.briar.api.db.event.DatabaseListener;
|
||||||
import net.sf.briar.api.db.event.MessageAddedEvent;
|
import net.sf.briar.api.db.event.MessageAddedEvent;
|
||||||
import net.sf.briar.api.db.event.MessageReceivedEvent;
|
import net.sf.briar.api.db.event.MessageReceivedEvent;
|
||||||
import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent;
|
import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
|
||||||
import net.sf.briar.api.db.event.TransportsUpdatedEvent;
|
import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent;
|
||||||
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
import net.sf.briar.api.plugins.duplex.DuplexTransportConnection;
|
||||||
import net.sf.briar.api.protocol.Ack;
|
import net.sf.briar.api.protocol.Ack;
|
||||||
import net.sf.briar.api.protocol.Message;
|
import net.sf.briar.api.protocol.Message;
|
||||||
@@ -127,13 +127,13 @@ abstract class DuplexConnection implements DatabaseListener {
|
|||||||
} else if(e instanceof MessageAddedEvent) {
|
} else if(e instanceof MessageAddedEvent) {
|
||||||
if(canSendOffer.getAndSet(false))
|
if(canSendOffer.getAndSet(false))
|
||||||
dbExecutor.execute(new GenerateOffer());
|
dbExecutor.execute(new GenerateOffer());
|
||||||
} else if(e instanceof SubscriptionsUpdatedEvent) {
|
} else if(e instanceof LocalSubscriptionsUpdatedEvent) {
|
||||||
Collection<ContactId> affected =
|
Collection<ContactId> affected =
|
||||||
((SubscriptionsUpdatedEvent) e).getAffectedContacts();
|
((LocalSubscriptionsUpdatedEvent) e).getAffectedContacts();
|
||||||
if(affected.contains(contactId)) {
|
if(affected.contains(contactId)) {
|
||||||
dbExecutor.execute(new GenerateSubscriptionUpdate());
|
dbExecutor.execute(new GenerateSubscriptionUpdate());
|
||||||
}
|
}
|
||||||
} else if(e instanceof TransportsUpdatedEvent) {
|
} else if(e instanceof LocalTransportsUpdatedEvent) {
|
||||||
dbExecutor.execute(new GenerateTransportUpdate());
|
dbExecutor.execute(new GenerateTransportUpdate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import net.sf.briar.api.db.event.ContactRemovedEvent;
|
|||||||
import net.sf.briar.api.db.event.DatabaseListener;
|
import net.sf.briar.api.db.event.DatabaseListener;
|
||||||
import net.sf.briar.api.db.event.MessageAddedEvent;
|
import net.sf.briar.api.db.event.MessageAddedEvent;
|
||||||
import net.sf.briar.api.db.event.RatingChangedEvent;
|
import net.sf.briar.api.db.event.RatingChangedEvent;
|
||||||
import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent;
|
import net.sf.briar.api.db.event.LocalSubscriptionsUpdatedEvent;
|
||||||
import net.sf.briar.api.lifecycle.ShutdownManager;
|
import net.sf.briar.api.lifecycle.ShutdownManager;
|
||||||
import net.sf.briar.api.protocol.Ack;
|
import net.sf.briar.api.protocol.Ack;
|
||||||
import net.sf.briar.api.protocol.AuthorId;
|
import net.sf.briar.api.protocol.AuthorId;
|
||||||
@@ -1377,7 +1377,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase {
|
|||||||
oneOf(database).removeVisibility(txn, contactId1, groupId);
|
oneOf(database).removeVisibility(txn, contactId1, groupId);
|
||||||
oneOf(database).commitTransaction(txn);
|
oneOf(database).commitTransaction(txn);
|
||||||
oneOf(listener).eventOccurred(with(any(
|
oneOf(listener).eventOccurred(with(any(
|
||||||
SubscriptionsUpdatedEvent.class)));
|
LocalSubscriptionsUpdatedEvent.class)));
|
||||||
}});
|
}});
|
||||||
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
DatabaseComponent db = createDatabaseComponent(database, cleaner,
|
||||||
shutdown);
|
shutdown);
|
||||||
|
|||||||
Reference in New Issue
Block a user