Implement group backends cache warm-up

Group backends typically come with their own cache for saving
preciouses roundtrips to fetch groups from remote systems.

Group lookup in LDAP may take a few seconds and on GitHub may even
cause a blockage of API calls because of traffic overload.

Warming up group caches from backends avoid floods of calls and threads
accumulating when the server needs to be restarted during peak hours.

Change-Id: Ifefcee686e18ecdb812f3eed614ffd5672d3db53
diff --git a/admin/warm-cache-1.0.groovy b/admin/warm-cache-1.0.groovy
index 5b1d75b..dae00dd 100644
--- a/admin/warm-cache-1.0.groovy
+++ b/admin/warm-cache-1.0.groovy
@@ -16,6 +16,7 @@
 import com.google.gerrit.extensions.annotations.*
 import com.google.gerrit.server.project.*
 import com.google.gerrit.server.account.*
+import com.google.gerrit.server.IdentifiedUser
 import com.google.gerrit.reviewdb.client.AccountGroup
 import com.google.gerrit.reviewdb.server.ReviewDb
 import com.google.inject.*
@@ -30,11 +31,15 @@
 }
 
 @Export("projects")
+@CommandMetaData(description = "Warm-up project_list and projects caches")
 class WarmProjectsCache extends BaseSshCommand {
 
   @Inject
   ProjectCache cache
 
+  @Inject
+  GroupCache groupCache
+
   public void run() {
     println "Loading project list ..."
     def start = System.currentTimeMillis()
@@ -135,5 +140,36 @@
   }
 }
 
-commands = [ WarmProjectsCache, WarmGroupsCache, WarmAccountsCache ]
+@Export("groups-backends")
+class WarmGroupsBackendsCache extends WarmAccountsCache {
+
+  @Inject
+  IdentifiedUser.GenericFactory userFactory
+
+  public void run() {
+    println "Loading groups ..."
+    def start = System.currentTimeMillis()
+    def allAccounts = db.get().accounts().all()
+    def loaded = 0
+    def allGroupsUUIDs = new HashSet<AccountGroup.UUID>()
+    def lastDisplay = 0
+
+    for (account in allAccounts) {
+      def user = userFactory.create(account.accountId)
+      def groupsUUIDs = user?.getEffectiveGroups()?.getKnownGroups()
+      if (groupsUUIDs != null) { allGroupsUUIDs.addAll(groupsUUIDs) }
+
+      loaded = allGroupsUUIDs.size()
+      if (loaded.intdiv(1000) > lastDisplay) {
+        println "$loaded groups"
+        lastDisplay = loaded.intdiv(1000)
+      }
+    }
+
+    def elapsed = (System.currentTimeMillis()-start)/1000
+    println "$loaded groups loaded in $elapsed secs"
+  }
+}
+
+commands = [ WarmProjectsCache, WarmGroupsCache, WarmAccountsCache, WarmGroupsBackendsCache ]