Use persistent cache for GitHub groups Retrieval of GitHub groups is a very expensive operation and causes the start-up of Gerrit to be very sloppy. By using a persistent cache we should avoid to rescan all the GitHub groups when rescanning the users and changes. Change-Id: Ib1c67f17d45ca63c54f5c801859cced42b756b54
diff --git a/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/groups/OrganizationStructure.java b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/groups/OrganizationStructure.java new file mode 100644 index 0000000..d577a62 --- /dev/null +++ b/github-oauth/src/main/java/com/googlesource/gerrit/plugins/github/groups/OrganizationStructure.java
@@ -0,0 +1,55 @@ +// Copyright (C) 2016 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package com.googlesource.gerrit.plugins.github.groups; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + +import com.google.common.base.MoreObjects; + +public class OrganizationStructure implements Serializable { + private static final long serialVersionUID = 1L; + + private HashMap<String, HashSet<String>> teams = new HashMap<>(); + + public Set<String> put(String organisation, String team) { + HashSet<String> userTeams = + MoreObjects.firstNonNull(teams.get(organisation), + new HashSet<String>()); + userTeams.add(team); + return teams.put(organisation, userTeams); + } + + public Set<String> keySet() { + return teams.keySet(); + } + + public Iterable<String> get(String organization) { + return teams.get(organization); + } + + @Override + public String toString() { + return teams + .entrySet() + .stream() + .map( + org -> "Organization " + org.getKey() + " Teams: " + org.getValue()) + .collect(Collectors.joining(" : ")); + } +} \ No newline at end of file
diff --git a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java index 97eeff4..5370f03 100644 --- a/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java +++ b/github-plugin/src/main/java/com/googlesource/gerrit/plugins/github/group/GitHubGroupsCache.java
@@ -18,9 +18,7 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.google.common.collect.HashMultimap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; import com.google.gerrit.reviewdb.client.AccountGroup.UUID; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.cache.CacheModule; @@ -28,9 +26,8 @@ import com.google.inject.Module; import com.google.inject.Provider; import com.google.inject.Singleton; -import com.google.inject.TypeLiteral; import com.google.inject.name.Named; - +import com.googlesource.gerrit.plugins.github.groups.OrganizationStructure; import com.googlesource.gerrit.plugins.github.oauth.GitHubLogin; import com.googlesource.gerrit.plugins.github.oauth.UserScopedProvider; @@ -55,7 +52,7 @@ public static final String EVERYONE_TEAM_NAME = "Everyone"; public static class OrganisationLoader extends - CacheLoader<String, Multimap<String, String>> { + CacheLoader<String, OrganizationStructure> { private static final Logger logger = LoggerFactory .getLogger(OrganisationLoader.class); private final UserScopedProvider<GitHubLogin> ghLoginProvider; @@ -66,8 +63,8 @@ } @Override - public Multimap<String, String> load(String username) throws Exception { - Multimap<String, String> orgsTeams = HashMultimap.create(); + public OrganizationStructure load(String username) throws Exception { + OrganizationStructure orgsTeams = new OrganizationStructure(); GitHubLogin ghLogin = ghLoginProvider.get(username); if (ghLogin == null) { logger.warn("Cannot login to GitHub on behalf of '{}'", username); @@ -87,9 +84,11 @@ return orgsTeams; } - private void loadOrganisationsAndTeams(String username, Multimap<String, String> orgsTeams, - GitHubLogin ghLogin) throws IOException { - logger.debug("Getting list of organisations/teams for user '{}'", username); + private void loadOrganisationsAndTeams(String username, + OrganizationStructure orgsTeams, GitHubLogin ghLogin) + throws IOException { + logger.debug("Getting list of organisations/teams for user '{}'", + username); Map<String, Set<GHTeam>> myOrganisationsLogins = ghLogin.getHub().getMyTeams(); for (Entry<String, Set<GHTeam>> teamsOrg : myOrganisationsLogins @@ -102,8 +101,10 @@ } private void loadOrganisations(String username, - Multimap<String, String> orgsTeams, GitHubLogin ghLogin) throws IOException { - logger.debug("Getting list of public organisations for user '{}'", username); + OrganizationStructure orgsTeams, GitHubLogin ghLogin) + throws IOException { + logger.debug("Getting list of public organisations for user '{}'", + username); Set<String> organisations = ghLogin.getMyOrganisationsLogins(); for (String org : organisations) { orgsTeams.put(org, EVERYONE_TEAM_NAME); @@ -115,20 +116,20 @@ return new CacheModule() { @Override protected void configure() { - cache(ORGS_CACHE_NAME, String.class, - new TypeLiteral<Multimap<String, String>>() {}).expireAfterWrite( - GROUPS_CACHE_TTL_MINS, MINUTES).loader(OrganisationLoader.class); + persist(ORGS_CACHE_NAME, String.class, OrganizationStructure.class) + .expireAfterWrite(GROUPS_CACHE_TTL_MINS, MINUTES).loader( + OrganisationLoader.class); bind(GitHubGroupsCache.class); } }; } - private final LoadingCache<String, Multimap<String, String>> orgTeamsByUsername; + private final LoadingCache<String, OrganizationStructure> orgTeamsByUsername; private final Provider<IdentifiedUser> userProvider; @Inject GitHubGroupsCache( - @Named(ORGS_CACHE_NAME) LoadingCache<String, Multimap<String, String>> byUsername, + @Named(ORGS_CACHE_NAME) LoadingCache<String, OrganizationStructure> byUsername, Provider<IdentifiedUser> userProvider) { this.orgTeamsByUsername = byUsername; this.userProvider = userProvider;