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;