Do not exceed index.maxTerms when querying group index by subgroups The optimisation of the GroupIncludeCacheImpl introduced by Ic73e01e933cb did not check for the underlying indexing backend maxTerms settings when loading the cache. Use the index.maxTerms configuration and use it to partition the input groupIds by several queries of maximum index.maxTerms per query, keeping the external behaviour and fixing Gerrit setups where the number of groups exceeds the index.maxTerms configuration setting. Bug: Issue 368553867 Release-Notes: Fix support for a number of groups higher than the index.maxTerms Change-Id: I070bbf117ea4cb6d29bbac3ddeb98a37e07ee9c1
diff --git a/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java b/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java index fc6087b..5134643 100644 --- a/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java +++ b/java/com/google/gerrit/server/account/GroupIncludeCacheImpl.java
@@ -23,11 +23,13 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.flogger.FluentLogger; import com.google.gerrit.entities.Account; import com.google.gerrit.entities.AccountGroup; import com.google.gerrit.entities.InternalGroup; +import com.google.gerrit.index.IndexConfig; import com.google.gerrit.proto.Protos; import com.google.gerrit.server.cache.CacheModule; import com.google.gerrit.server.cache.proto.Cache.AllExternalGroupsProto; @@ -45,9 +47,11 @@ import com.google.inject.Singleton; import com.google.inject.TypeLiteral; import com.google.inject.name.Named; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -62,6 +66,8 @@ private static final String EXTERNAL_NAME = "groups_external"; private static final String PERSISTED_EXTERNAL_NAME = "groups_external_persisted"; + private final IndexConfig indexConfig; + public static Module module() { return new CacheModule() { @Override @@ -115,10 +121,12 @@ LoadingCache<Account.Id, ImmutableSet<AccountGroup.UUID>> groupsWithMember, @Named(PARENT_GROUPS_NAME) LoadingCache<AccountGroup.UUID, ImmutableSet<AccountGroup.UUID>> parentGroups, - @Named(EXTERNAL_NAME) LoadingCache<String, ImmutableList<AccountGroup.UUID>> external) { + @Named(EXTERNAL_NAME) LoadingCache<String, ImmutableList<AccountGroup.UUID>> external, + IndexConfig indexConfig) { this.groupsWithMember = groupsWithMember; this.parentGroups = parentGroups; this.external = external; + this.indexConfig = indexConfig; } @Override @@ -145,7 +153,10 @@ public Collection<AccountGroup.UUID> parentGroupsOf(Set<AccountGroup.UUID> groupIds) { try { Set<AccountGroup.UUID> parents = new HashSet<>(); - parentGroups.getAll(groupIds).values().forEach(p -> parents.addAll(p)); + for (List<AccountGroup.UUID> groupIdsBatch : + Lists.partition(new ArrayList<>(groupIds), indexConfig.maxTerms())) { + parentGroups.getAll(groupIdsBatch).values().forEach(p -> parents.addAll(p)); + } return parents; } catch (ExecutionException e) { logger.atWarning().withCause(e).log("Cannot load included groups");