mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
Merge branch 'transactional-db' into 'master'
Transactional DB interface See merge request briar/briar!945
This commit is contained in:
@@ -76,6 +76,19 @@ public interface DatabaseComponent {
|
|||||||
*/
|
*/
|
||||||
void endTransaction(Transaction txn);
|
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,
|
* Stores a contact associated with the given local and remote pseudonyms,
|
||||||
* and returns an ID for the contact.
|
* and returns an ID for the contact.
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
|
public interface DbCallable<R, E extends Exception> {
|
||||||
|
|
||||||
|
R call(Transaction txn) throws DbException, E;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.briarproject.bramble.api.db;
|
||||||
|
|
||||||
|
public interface DbRunnable<E extends Exception> {
|
||||||
|
|
||||||
|
void run(Transaction txn) throws DbException, E;
|
||||||
|
}
|
||||||
@@ -9,7 +9,9 @@ import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
|
|||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||||
import org.briarproject.bramble.api.db.ContactExistsException;
|
import org.briarproject.bramble.api.db.ContactExistsException;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
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.DbException;
|
||||||
|
import org.briarproject.bramble.api.db.DbRunnable;
|
||||||
import org.briarproject.bramble.api.db.Metadata;
|
import org.briarproject.bramble.api.db.Metadata;
|
||||||
import org.briarproject.bramble.api.db.MigrationListener;
|
import org.briarproject.bramble.api.db.MigrationListener;
|
||||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||||
@@ -166,6 +168,31 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
|
|||||||
for (Event e : transaction.getEvents()) eventBus.broadcast(e);
|
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) {
|
private T unbox(Transaction transaction) {
|
||||||
if (transaction.isCommitted()) throw new IllegalStateException();
|
if (transaction.isCommitted()) throw new IllegalStateException();
|
||||||
return txnClass.cast(transaction.unbox());
|
return txnClass.cast(transaction.unbox());
|
||||||
|
|||||||
@@ -94,14 +94,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
|||||||
@Override
|
@Override
|
||||||
public Forum addForum(String name) throws DbException {
|
public Forum addForum(String name) throws DbException {
|
||||||
Forum f = forumFactory.createForum(name);
|
Forum f = forumFactory.createForum(name);
|
||||||
|
db.transaction(false, txn -> db.addGroup(txn, f.getGroup()));
|
||||||
Transaction txn = db.startTransaction(false);
|
|
||||||
try {
|
|
||||||
db.addGroup(txn, f.getGroup());
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,15 +105,11 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeForum(Forum f) throws DbException {
|
public void removeForum(Forum f) throws DbException {
|
||||||
Transaction txn = db.startTransaction(false);
|
db.transaction(false, txn -> {
|
||||||
try {
|
|
||||||
for (RemoveForumHook hook : removeHooks)
|
for (RemoveForumHook hook : removeHooks)
|
||||||
hook.removingForum(txn, f);
|
hook.removingForum(txn, f);
|
||||||
db.removeGroup(txn, f.getGroup());
|
db.removeGroup(txn, f.getGroup());
|
||||||
db.commitTransaction(txn);
|
});
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -131,45 +120,35 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
|||||||
p = forumPostFactory.createPost(groupId, timestamp, parentId,
|
p = forumPostFactory.createPost(groupId, timestamp, parentId,
|
||||||
author, body);
|
author, body);
|
||||||
} catch (GeneralSecurityException | FormatException e) {
|
} catch (GeneralSecurityException | FormatException e) {
|
||||||
throw new RuntimeException(e);
|
throw new AssertionError(e);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ForumPostHeader addLocalPost(ForumPost p) throws DbException {
|
public ForumPostHeader addLocalPost(ForumPost p) throws DbException {
|
||||||
Transaction txn = db.startTransaction(false);
|
db.transaction(false, txn -> {
|
||||||
try {
|
try {
|
||||||
BdfDictionary meta = new BdfDictionary();
|
BdfDictionary meta = new BdfDictionary();
|
||||||
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp());
|
meta.put(KEY_TIMESTAMP, p.getMessage().getTimestamp());
|
||||||
if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent());
|
if (p.getParent() != null) meta.put(KEY_PARENT, p.getParent());
|
||||||
Author a = p.getAuthor();
|
Author a = p.getAuthor();
|
||||||
meta.put(KEY_AUTHOR, clientHelper.toList(a));
|
meta.put(KEY_AUTHOR, clientHelper.toList(a));
|
||||||
meta.put(KEY_LOCAL, true);
|
meta.put(KEY_LOCAL, true);
|
||||||
meta.put(MSG_KEY_READ, true);
|
meta.put(MSG_KEY_READ, true);
|
||||||
clientHelper.addLocalMessage(txn, p.getMessage(), meta, true);
|
clientHelper.addLocalMessage(txn, p.getMessage(), meta, true);
|
||||||
messageTracker.trackOutgoingMessage(txn, p.getMessage());
|
messageTracker.trackOutgoingMessage(txn, p.getMessage());
|
||||||
db.commitTransaction(txn);
|
} catch (FormatException e) {
|
||||||
} catch (FormatException e) {
|
throw new AssertionError(e);
|
||||||
throw new RuntimeException(e);
|
}
|
||||||
} finally {
|
});
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return new ForumPostHeader(p.getMessage().getId(), p.getParent(),
|
return new ForumPostHeader(p.getMessage().getId(), p.getParent(),
|
||||||
p.getMessage().getTimestamp(), p.getAuthor(), OURSELVES, true);
|
p.getMessage().getTimestamp(), p.getAuthor(), OURSELVES, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Forum getForum(GroupId g) throws DbException {
|
public Forum getForum(GroupId g) throws DbException {
|
||||||
Forum forum;
|
return db.transactionWithResult(true, txn -> getForum(txn, g));
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
|
||||||
forum = getForum(txn, g);
|
|
||||||
db.commitTransaction(txn);
|
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
|
||||||
return forum;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -184,15 +163,9 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<Forum> getForums() throws DbException {
|
public Collection<Forum> getForums() throws DbException {
|
||||||
|
Collection<Group> groups = db.transactionWithResult(true, txn ->
|
||||||
|
db.getGroups(txn, CLIENT_ID, MAJOR_VERSION));
|
||||||
try {
|
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<>();
|
List<Forum> forums = new ArrayList<>();
|
||||||
for (Group g : groups) forums.add(parseForum(g));
|
for (Group g : groups) forums.add(parseForum(g));
|
||||||
return forums;
|
return forums;
|
||||||
@@ -218,36 +191,35 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
|
|||||||
@Override
|
@Override
|
||||||
public Collection<ForumPostHeader> getPostHeaders(GroupId g)
|
public Collection<ForumPostHeader> getPostHeaders(GroupId g)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
|
|
||||||
Collection<ForumPostHeader> headers = new ArrayList<>();
|
|
||||||
Transaction txn = db.startTransaction(true);
|
|
||||||
try {
|
try {
|
||||||
Map<MessageId, BdfDictionary> metadata =
|
return db.transactionWithResult(true, txn -> {
|
||||||
clientHelper.getMessageMetadataAsDictionary(txn, g);
|
Collection<ForumPostHeader> headers = new ArrayList<>();
|
||||||
// get all authors we need to get the status for
|
Map<MessageId, BdfDictionary> metadata =
|
||||||
Set<AuthorId> authors = new HashSet<>();
|
clientHelper.getMessageMetadataAsDictionary(txn, g);
|
||||||
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
|
// get all authors we need to get the status for
|
||||||
BdfList authorList = entry.getValue().getList(KEY_AUTHOR);
|
Set<AuthorId> authors = new HashSet<>();
|
||||||
Author a = clientHelper.parseAndValidateAuthor(authorList);
|
for (Entry<MessageId, BdfDictionary> entry :
|
||||||
authors.add(a.getId());
|
metadata.entrySet()) {
|
||||||
}
|
BdfList authorList = entry.getValue().getList(KEY_AUTHOR);
|
||||||
// get statuses for all authors
|
Author a = clientHelper.parseAndValidateAuthor(authorList);
|
||||||
Map<AuthorId, Status> statuses = new HashMap<>();
|
authors.add(a.getId());
|
||||||
for (AuthorId id : authors) {
|
}
|
||||||
statuses.put(id, identityManager.getAuthorStatus(txn, id));
|
// get statuses for all authors
|
||||||
}
|
Map<AuthorId, Status> statuses = new HashMap<>();
|
||||||
// Parse the metadata
|
for (AuthorId id : authors) {
|
||||||
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
|
statuses.put(id, identityManager.getAuthorStatus(txn, id));
|
||||||
BdfDictionary meta = entry.getValue();
|
}
|
||||||
headers.add(getForumPostHeader(txn, entry.getKey(), meta,
|
// Parse the metadata
|
||||||
statuses));
|
for (Entry<MessageId, BdfDictionary> entry :
|
||||||
}
|
metadata.entrySet()) {
|
||||||
db.commitTransaction(txn);
|
BdfDictionary meta = entry.getValue();
|
||||||
return headers;
|
headers.add(getForumPostHeader(txn, entry.getKey(), meta,
|
||||||
|
statuses));
|
||||||
|
}
|
||||||
|
return headers;
|
||||||
|
});
|
||||||
} catch (FormatException e) {
|
} catch (FormatException e) {
|
||||||
throw new DbException(e);
|
throw new DbException(e);
|
||||||
} finally {
|
|
||||||
db.endTransaction(txn);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user