Add intersection to GroupMembership
Support slower group backends by allowing a lookup of a lot of
groups at once to use intersection(). This method signature allows
the backend to filter the input query set and return the subset of
groups that the user is a member of.
Using a batch style interface can decrease latency when resolving
a large number of external groups identified through the internal
group system's nested includes feature.
Change-Id: I6926a3373589f439c8d694d36cdbe5fa8396a040
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
index d536c09..d7a97fb 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/GroupMembership.java
@@ -40,6 +40,20 @@
boolean containsAnyOf(Iterable<AccountGroup.UUID> groupIds);
/**
+ * Returns a set containing an input member of {@code contains(id)} is true.
+ * <p>
+ * This is batch form of contains that returns specific group information.
+ * Implementors may implement the method as:
+ *
+ * <pre>
+ * Set<AccountGroup.UUID> r = Sets.newHashSet();
+ * for (AccountGroup.UUID id : groupIds)
+ * if (contains(id)) r.add(id);
+ * </pre>
+ */
+ Set<AccountGroup.UUID> intersection(Iterable<AccountGroup.UUID> groupIds);
+
+ /**
* Returns the set of groups that can be determined by the implementation.
* This may not return all groups the {@link #contains(AccountGroup.UUID)}
* would return {@code true} for, but will at least contain all top level
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java
index d448fff..75b7f32 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/IncludingGroupMembership.java
@@ -70,6 +70,17 @@
return findIncludedGroup(query);
}
+ @Override
+ public Set<AccountGroup.UUID> intersection(Iterable<AccountGroup.UUID> groupIds) {
+ Set<AccountGroup.UUID> r = Sets.newHashSet();
+ for (AccountGroup.UUID id : groupIds) {
+ if (contains(id)) {
+ r.add(id);
+ }
+ }
+ return r;
+ }
+
private boolean findIncludedGroup(Set<AccountGroup.UUID> query) {
boolean found = false;
while (!found && !groupQueue.isEmpty()) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
index 346f406..118940f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/ListGroupMembership.java
@@ -24,7 +24,6 @@
* GroupMembership over an explicit list.
*/
public class ListGroupMembership implements GroupMembership {
-
private final Set<AccountGroup.UUID> groups;
public ListGroupMembership(Iterable<AccountGroup.UUID> groupIds) {
@@ -47,6 +46,11 @@
}
@Override
+ public Set<AccountGroup.UUID> intersection(Iterable<AccountGroup.UUID> groupIds) {
+ return Sets.intersection(ImmutableSet.copyOf(groupIds), groups);
+ }
+
+ @Override
public Set<AccountGroup.UUID> getKnownGroups() {
return Sets.newHashSet(groups);
}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java b/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java
index 1f670f6..d9c9257 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/account/UniversalGroupBackend.java
@@ -156,13 +156,33 @@
return false;
}
- @Override
- public Set<AccountGroup.UUID> getKnownGroups() {
- Set<AccountGroup.UUID> groups = Sets.newHashSet();
- for (GroupMembership m : memberships.values()) {
- groups.addAll(m.getKnownGroups());
- }
- return groups;
- }
+ @Override
+ public Set<AccountGroup.UUID> intersection(Iterable<AccountGroup.UUID> uuids) {
+ Multimap<GroupMembership, AccountGroup.UUID> lookups =
+ ArrayListMultimap.create();
+ for (AccountGroup.UUID uuid : uuids) {
+ GroupMembership m = membership(uuid);
+ if (m == null) {
+ log.warn("Unknown GroupMembership for UUID: " + uuid);
+ continue;
+ }
+ lookups.put(m, uuid);
+ }
+ Set<AccountGroup.UUID> groups = Sets.newHashSet();
+ for (Map.Entry<GroupMembership, Collection<AccountGroup.UUID>> entry
+ : lookups.asMap().entrySet()) {
+ groups.addAll(entry.getKey().intersection(entry.getValue()));
+ }
+ return groups;
+ }
+
+ @Override
+ public Set<AccountGroup.UUID> getKnownGroups() {
+ Set<AccountGroup.UUID> groups = Sets.newHashSet();
+ for (GroupMembership m : memberships.values()) {
+ groups.addAll(m.getKnownGroups());
+ }
+ return groups;
+ }
}
}