Load list of private groups in a single DB transaction

This commit is contained in:
Torsten Grote
2020-12-17 13:11:13 -03:00
parent 9048392d4e
commit fd86b73626
4 changed files with 87 additions and 46 deletions

View File

@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.crypto.CryptoExecutor; import org.briarproject.bramble.api.crypto.CryptoExecutor;
import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator; import org.briarproject.bramble.api.crypto.PasswordStrengthEstimator;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.keyagreement.KeyAgreementTask; import org.briarproject.bramble.api.keyagreement.KeyAgreementTask;
@@ -85,6 +86,8 @@ public interface AndroidComponent
@DatabaseExecutor @DatabaseExecutor
Executor databaseExecutor(); Executor databaseExecutor();
TransactionManager transactionManager();
MessageTracker messageTracker(); MessageTracker messageTracker();
LifecycleManager lifecycleManager(); LifecycleManager lifecycleManager();

View File

@@ -4,6 +4,8 @@ import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchGroupException; import org.briarproject.bramble.api.db.NoSuchGroupException;
import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.db.TransactionManager;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
@@ -55,6 +57,7 @@ class GroupListControllerImpl extends DbControllerImpl
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(GroupListControllerImpl.class.getName()); Logger.getLogger(GroupListControllerImpl.class.getName());
private final TransactionManager db;
private final PrivateGroupManager groupManager; private final PrivateGroupManager groupManager;
private final GroupInvitationManager groupInvitationManager; private final GroupInvitationManager groupInvitationManager;
private final ContactManager contactManager; private final ContactManager contactManager;
@@ -67,11 +70,14 @@ class GroupListControllerImpl extends DbControllerImpl
@Inject @Inject
GroupListControllerImpl(@DatabaseExecutor Executor dbExecutor, GroupListControllerImpl(@DatabaseExecutor Executor dbExecutor,
LifecycleManager lifecycleManager, PrivateGroupManager groupManager, LifecycleManager lifecycleManager,
TransactionManager db,
PrivateGroupManager groupManager,
GroupInvitationManager groupInvitationManager, GroupInvitationManager groupInvitationManager,
ContactManager contactManager, ContactManager contactManager,
AndroidNotificationManager notificationManager, EventBus eventBus) { AndroidNotificationManager notificationManager, EventBus eventBus) {
super(dbExecutor, lifecycleManager); super(dbExecutor, lifecycleManager);
this.db = db;
this.groupManager = groupManager; this.groupManager = groupManager;
this.groupInvitationManager = groupInvitationManager; this.groupInvitationManager = groupInvitationManager;
this.contactManager = contactManager; this.contactManager = contactManager;
@@ -140,32 +146,7 @@ class GroupListControllerImpl extends DbControllerImpl
ResultExceptionHandler<Collection<GroupItem>, DbException> handler) { ResultExceptionHandler<Collection<GroupItem>, DbException> handler) {
runOnDbThread(() -> { runOnDbThread(() -> {
try { try {
long start = now(); db.transaction(true, txn -> loadGroups(txn, handler));
Collection<PrivateGroup> groups =
groupManager.getPrivateGroups();
List<GroupItem> items = new ArrayList<>(groups.size());
Map<AuthorId, AuthorInfo> authorInfos = new HashMap<>();
for (PrivateGroup g : groups) {
try {
GroupId id = g.getId();
AuthorId authorId = g.getCreator().getId();
AuthorInfo authorInfo;
if (authorInfos.containsKey(authorId)) {
authorInfo = authorInfos.get(authorId);
} else {
authorInfo = contactManager.getAuthorInfo(authorId);
authorInfos.put(authorId, authorInfo);
}
GroupCount count = groupManager.getGroupCount(id);
boolean dissolved = groupManager.isDissolved(id);
items.add(
new GroupItem(g, authorInfo, count, dissolved));
} catch (NoSuchGroupException e) {
// Continue
}
}
logDuration(LOG, "Loading groups", start);
handler.onResult(items);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
handler.onException(e); handler.onException(e);
@@ -173,6 +154,36 @@ class GroupListControllerImpl extends DbControllerImpl
}); });
} }
@DatabaseExecutor
private void loadGroups(Transaction txn,
ResultExceptionHandler<Collection<GroupItem>, DbException> handler)
throws DbException {
long start = now();
Collection<PrivateGroup> groups = groupManager.getPrivateGroups(txn);
List<GroupItem> items = new ArrayList<>(groups.size());
Map<AuthorId, AuthorInfo> authorInfos = new HashMap<>();
for (PrivateGroup g : groups) {
try {
GroupId id = g.getId();
AuthorId authorId = g.getCreator().getId();
AuthorInfo authorInfo;
if (authorInfos.containsKey(authorId)) {
authorInfo = authorInfos.get(authorId);
} else {
authorInfo = contactManager.getAuthorInfo(txn, authorId);
authorInfos.put(authorId, authorInfo);
}
GroupCount count = groupManager.getGroupCount(txn, id);
boolean dissolved = groupManager.isDissolved(txn, id);
items.add(new GroupItem(g, authorInfo, count, dissolved));
} catch (NoSuchGroupException e) {
// Continue
}
}
logDuration(LOG, "Loading groups", start);
handler.onResult(items);
}
@Override @Override
public void removeGroup(GroupId g, ExceptionHandler<DbException> handler) { public void removeGroup(GroupId g, ExceptionHandler<DbException> handler) {
runOnDbThread(() -> { runOnDbThread(() -> {

View File

@@ -66,6 +66,11 @@ public interface PrivateGroupManager {
*/ */
void markGroupDissolved(Transaction txn, GroupId g) throws DbException; void markGroupDissolved(Transaction txn, GroupId g) throws DbException;
/**
* Returns true if the given private group has been dissolved.
*/
boolean isDissolved(Transaction txn, GroupId g) throws DbException;
/** /**
* Returns true if the given private group has been dissolved. * Returns true if the given private group has been dissolved.
*/ */
@@ -91,6 +96,12 @@ public interface PrivateGroupManager {
*/ */
Collection<PrivateGroup> getPrivateGroups() throws DbException; Collection<PrivateGroup> getPrivateGroups() throws DbException;
/**
* Returns all private groups the user is a member of.
*/
Collection<PrivateGroup> getPrivateGroups(Transaction txn)
throws DbException;
/** /**
* Returns the text of the private group message with the given ID. * Returns the text of the private group message with the given ID.
*/ */
@@ -111,6 +122,11 @@ public interface PrivateGroupManager {
*/ */
boolean isMember(Transaction txn, GroupId g, Author a) throws DbException; boolean isMember(Transaction txn, GroupId g, Author a) throws DbException;
/**
* Returns the group count for the given private group.
*/
GroupCount getGroupCount(Transaction txn, GroupId g) throws DbException;
/** /**
* Returns the group count for the given private group. * Returns the group count for the given private group.
*/ */

View File

@@ -270,22 +270,31 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
} }
@Override @Override
public Collection<PrivateGroup> getPrivateGroups() throws DbException { public Collection<PrivateGroup> getPrivateGroups(Transaction txn)
Collection<Group> groups; throws DbException {
Transaction txn = db.startTransaction(true); Collection<Group> groups = db.getGroups(txn, CLIENT_ID, MAJOR_VERSION);
Collection<PrivateGroup> privateGroups = new ArrayList<>(groups.size());
try { try {
groups = db.getGroups(txn, CLIENT_ID, MAJOR_VERSION);
db.commitTransaction(txn);
} finally {
db.endTransaction(txn);
}
try {
Collection<PrivateGroup> privateGroups =
new ArrayList<>(groups.size());
for (Group g : groups) { for (Group g : groups) {
privateGroups.add(privateGroupFactory.parsePrivateGroup(g)); privateGroups.add(privateGroupFactory.parsePrivateGroup(g));
} }
return privateGroups; } catch (FormatException e) {
throw new DbException(e);
}
return privateGroups;
}
@Override
public Collection<PrivateGroup> getPrivateGroups() throws DbException {
return db.transactionWithResult(true, this::getPrivateGroups);
}
@Override
public boolean isDissolved(Transaction txn, GroupId g) throws DbException {
try {
BdfDictionary meta =
clientHelper.getGroupMetadataAsDictionary(txn, g);
return meta.getBoolean(GROUP_KEY_DISSOLVED);
} catch (FormatException e) { } catch (FormatException e) {
throw new DbException(e); throw new DbException(e);
} }
@@ -293,12 +302,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
@Override @Override
public boolean isDissolved(GroupId g) throws DbException { public boolean isDissolved(GroupId g) throws DbException {
try { return db.transactionWithResult(true, txn -> isDissolved(txn, g));
BdfDictionary meta = clientHelper.getGroupMetadataAsDictionary(g);
return meta.getBoolean(GROUP_KEY_DISSOLVED);
} catch (FormatException e) {
throw new DbException(e);
}
} }
@Override @Override
@@ -403,7 +407,8 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
PrivateGroup privateGroup = getPrivateGroup(txn, g); PrivateGroup privateGroup = getPrivateGroup(txn, g);
for (Entry<Author, Visibility> m : authors.entrySet()) { for (Entry<Author, Visibility> m : authors.entrySet()) {
Author a = m.getKey(); Author a = m.getKey();
AuthorInfo authorInfo = contactManager.getAuthorInfo(txn, a.getId()); AuthorInfo authorInfo =
contactManager.getAuthorInfo(txn, a.getId());
Status status = authorInfo.getStatus(); Status status = authorInfo.getStatus();
Visibility v = m.getValue(); Visibility v = m.getValue();
ContactId c = null; ContactId c = null;
@@ -450,6 +455,12 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
return false; return false;
} }
@Override
public GroupCount getGroupCount(Transaction txn, GroupId g)
throws DbException {
return messageTracker.getGroupCount(txn, g);
}
@Override @Override
public GroupCount getGroupCount(GroupId g) throws DbException { public GroupCount getGroupCount(GroupId g) throws DbException {
return messageTracker.getGroupCount(g); return messageTracker.getGroupCount(g);