Merge branch 'transactional-db' into 'master'

Transactional DB interface

See merge request briar/briar!945
This commit is contained in:
akwizgran
2018-10-05 15:19:40 +00:00
5 changed files with 100 additions and 76 deletions

View File

@@ -76,6 +76,19 @@ public interface DatabaseComponent {
*/
void endTransaction(Transaction txn);
/**
* Runs the given task within a transaction.
*/
<E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E;
/**
* Runs the given task within a transaction and returns the result of the
* task.
*/
<R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E;
/**
* Stores a contact associated with the given local and remote pseudonyms,
* and returns an ID for the contact.

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.db;
public interface DbCallable<R, E extends Exception> {
R call(Transaction txn) throws DbException, E;
}

View File

@@ -0,0 +1,6 @@
package org.briarproject.bramble.api.db;
public interface DbRunnable<E extends Exception> {
void run(Transaction txn) throws DbException, E;
}

View File

@@ -9,7 +9,9 @@ import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.ContactExistsException;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbCallable;
import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.DbRunnable;
import org.briarproject.bramble.api.db.Metadata;
import org.briarproject.bramble.api.db.MigrationListener;
import org.briarproject.bramble.api.db.NoSuchContactException;
@@ -166,6 +168,31 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
}
@Override
public <E extends Exception> void transaction(boolean readOnly,
DbRunnable<E> task) throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
task.run(txn);
commitTransaction(txn);
} finally {
endTransaction(txn);
}
}
@Override
public <R, E extends Exception> R transactionWithResult(boolean readOnly,
DbCallable<R, E> task) throws DbException, E {
Transaction txn = startTransaction(readOnly);
try {
R result = task.call(txn);
commitTransaction(txn);
return result;
} finally {
endTransaction(txn);
}
}
private T unbox(Transaction transaction) {
if (transaction.isCommitted()) throw new IllegalStateException();
return txnClass.cast(transaction.unbox());

View File

@@ -94,14 +94,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@Override
public Forum addForum(String name) throws DbException {
Forum f = forumFactory.createForum(name);
Transaction txn = db.startTransaction(false);
try {
db.addGroup(txn, f.getGroup());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> db.addGroup(txn, f.getGroup()));
return f;
}
@@ -112,15 +105,11 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@Override
public void removeForum(Forum f) throws DbException {
Transaction txn = db.startTransaction(false);
try {
db.transaction(false, txn -> {
for (RemoveForumHook hook : removeHooks)
hook.removingForum(txn, f);
db.removeGroup(txn, f.getGroup());
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
});
}
@Override
@@ -131,45 +120,35 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
p = forumPostFactory.createPost(groupId, timestamp, parentId,
author, body);
} catch (GeneralSecurityException | FormatException e) {
throw new RuntimeException(e);
throw new AssertionError(e);
}
return p;
}
@Override
public ForumPostHeader addLocalPost(ForumPost p) throws DbException {
Transaction txn = db.startTransaction(false);
try {
BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp());
if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent());
Author a = p.getAuthor();
meta.put(KEY_AUTHOR, clientHelper.toList(a));
meta.put(KEY_LOCAL, true);
meta.put(MSG_KEY_READ, true);
clientHelper.addLocalMessage(txn, p.getMessage(), meta, true);
messageTracker.trackOutgoingMessage(txn, p.getMessage());
db.commitTransaction(txn);
} catch (FormatException e) {
throw new RuntimeException(e);
} finally {
db.endTransaction(txn);
}
db.transaction(false, txn -> {
try {
BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp());
if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent());
Author a = p.getAuthor();
meta.put(KEY_AUTHOR, clientHelper.toList(a));
meta.put(KEY_LOCAL, true);
meta.put(MSG_KEY_READ, true);
clientHelper.addLocalMessage(txn, p.getMessage(), meta, true);
messageTracker.trackOutgoingMessage(txn, p.getMessage());
} catch (FormatException e) {
throw new AssertionError(e);
}
});
return new ForumPostHeader(p.getMessage().getId(), p.getParent(),
p.getMessage().getTimestamp(), p.getAuthor(), OURSELVES, true);
}
@Override
public Forum getForum(GroupId g) throws DbException {
Forum forum;
Transaction txn = db.startTransaction(true);
try {
forum = getForum(txn, g);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
return forum;
return db.transactionWithResult(true, txn -> getForum(txn, g));
}
@Override
@@ -184,15 +163,9 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@Override
public Collection<Forum> getForums() throws DbException {
Collection<Group> groups = db.transactionWithResult(true, txn ->
db.getGroups(txn, CLIENT_ID, MAJOR_VERSION));
try {
Collection<Group> groups;
Transaction txn = db.startTransaction(true);
try {
groups = db.getGroups(txn, CLIENT_ID, MAJOR_VERSION);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
List<Forum> forums = new ArrayList<>();
for (Group g : groups) forums.add(parseForum(g));
return forums;
@@ -218,36 +191,35 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
@Override
public Collection<ForumPostHeader> getPostHeaders(GroupId g)
throws DbException {
Collection<ForumPostHeader> headers = new ArrayList<>();
Transaction txn = db.startTransaction(true);
try {
Map<MessageId, BdfDictionary> metadata =
clientHelper.getMessageMetadataAsDictionary(txn, g);
// get all authors we need to get the status for
Set<AuthorId> authors = new HashSet<>();
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfList authorList = entry.getValue().getList(KEY_AUTHOR);
Author a = clientHelper.parseAndValidateAuthor(authorList);
authors.add(a.getId());
}
// get statuses for all authors
Map<AuthorId, Status> statuses = new HashMap<>();
for (AuthorId id : authors) {
statuses.put(id, identityManager.getAuthorStatus(txn, id));
}
// Parse the metadata
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfDictionary meta = entry.getValue();
headers.add(getForumPostHeader(txn, entry.getKey(), meta,
statuses));
}
db.commitTransaction(txn);
return headers;
return db.transactionWithResult(true, txn -> {
Collection<ForumPostHeader> headers = new ArrayList<>();
Map<MessageId, BdfDictionary> metadata =
clientHelper.getMessageMetadataAsDictionary(txn, g);
// get all authors we need to get the status for
Set<AuthorId> authors = new HashSet<>();
for (Entry<MessageId, BdfDictionary> entry :
metadata.entrySet()) {
BdfList authorList = entry.getValue().getList(KEY_AUTHOR);
Author a = clientHelper.parseAndValidateAuthor(authorList);
authors.add(a.getId());
}
// get statuses for all authors
Map<AuthorId, Status> statuses = new HashMap<>();
for (AuthorId id : authors) {
statuses.put(id, identityManager.getAuthorStatus(txn, id));
}
// Parse the metadata
for (Entry<MessageId, BdfDictionary> entry :
metadata.entrySet()) {
BdfDictionary meta = entry.getValue();
headers.add(getForumPostHeader(txn, entry.getKey(), meta,
statuses));
}
return headers;
});
} catch (FormatException e) {
throw new DbException(e);
} finally {
db.endTransaction(txn);
}
}