Merge branch 'stable-3.4' into stable-3.5
* stable-3.4:
Add an option to periodically warm the project_list cache
Release-Notes: skip
Change-Id: Id4a92ff775a0ccbad15ed54daf753a83bcba4adc
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 9d4de83..0ce5dae 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1313,6 +1313,21 @@
+
Default is the number of CPUs.
+[[cache.project_list.interval]]cache.project_list.interval::
++
+The link:#schedule-configuration-interval[interval] for running
+the project_list cache warmer.
+
+By default, if `cache.project_list.maxAge` is set, `interval` will be set to
+half its value. If `cache.project_list.maxAge` is not set or `interval` is set
+to `-1`, it is disabled.
+
+[[cache.project_list.startTime]]cache.project_list.startTime::
++
+The link:#schedule-configuration-startTime[start time] for running
+the project_list cache warmer.
+
+Default is 00:00 if the project_list cache warmer is enabled.
[[capability]]
=== Section capability
diff --git a/java/com/google/gerrit/server/project/PeriodicProjectListCacheWarmer.java b/java/com/google/gerrit/server/project/PeriodicProjectListCacheWarmer.java
new file mode 100644
index 0000000..caffb45
--- /dev/null
+++ b/java/com/google/gerrit/server/project/PeriodicProjectListCacheWarmer.java
@@ -0,0 +1,100 @@
+// Copyright (C) 2022 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.google.gerrit.server.project;
+
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+
+import com.google.common.flogger.FluentLogger;
+import com.google.gerrit.extensions.events.LifecycleListener;
+import com.google.gerrit.server.config.GerritServerConfig;
+import com.google.gerrit.server.config.ScheduleConfig;
+import com.google.gerrit.server.git.WorkQueue;
+import com.google.inject.Inject;
+import java.time.Duration;
+import org.eclipse.jgit.lib.Config;
+
+public class PeriodicProjectListCacheWarmer implements Runnable {
+ private static final FluentLogger logger = FluentLogger.forEnclosingClass();
+
+ public static class LifeCycle implements LifecycleListener {
+ protected final Config config;
+ protected final WorkQueue queue;
+ protected final PeriodicProjectListCacheWarmer runner;
+
+ @Inject
+ LifeCycle(
+ @GerritServerConfig Config config, WorkQueue queue, PeriodicProjectListCacheWarmer runner) {
+ this.config = config;
+ this.queue = queue;
+ this.runner = runner;
+ }
+
+ @Override
+ public void start() {
+ long interval = -1L;
+ String intervalString = config.getString("cache", ProjectCacheImpl.CACHE_LIST, "interval");
+ if (!"-1".equals(intervalString)) {
+ long maxAge =
+ config.getTimeUnit("cache", ProjectCacheImpl.CACHE_LIST, "maxAge", -1L, MILLISECONDS);
+ interval =
+ config.getTimeUnit(
+ "cache",
+ ProjectCacheImpl.CACHE_LIST,
+ "interval",
+ getHalfDuration(maxAge),
+ MILLISECONDS);
+ }
+
+ if (interval == -1L) {
+ logger.atWarning().log("project_list cache warmer is disabled");
+ return;
+ }
+
+ String startTime = config.getString("cache", ProjectCacheImpl.CACHE_LIST, "startTime");
+ if (startTime == null) {
+ startTime = "00:00";
+ }
+
+ runner.run();
+ queue.scheduleAtFixedRate(runner, ScheduleConfig.Schedule.createOrFail(interval, startTime));
+ }
+
+ @Override
+ public void stop() {
+ // handled by WorkQueue.stop() already
+ }
+
+ private long getHalfDuration(long duration) {
+ if (duration < 0) {
+ return duration;
+ }
+ return Duration.ofMillis(duration).dividedBy(2L).toMillis();
+ }
+ }
+
+ protected final ProjectCache cache;
+
+ @Inject
+ PeriodicProjectListCacheWarmer(ProjectCache cache) {
+ this.cache = cache;
+ }
+
+ @Override
+ public void run() {
+ logger.atFine().log("Loading project_list cache");
+ cache.all();
+ logger.atFine().log("Finished loading project_list cache");
+ }
+}
diff --git a/java/com/google/gerrit/server/project/ProjectCacheImpl.java b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
index 7e7c7be..15b5b42 100644
--- a/java/com/google/gerrit/server/project/ProjectCacheImpl.java
+++ b/java/com/google/gerrit/server/project/ProjectCacheImpl.java
@@ -95,7 +95,7 @@
public static final String PERSISTED_CACHE_NAME = "persisted_projects";
- private static final String CACHE_LIST = "project_list";
+ public static final String CACHE_LIST = "project_list";
public static Module module() {
return new CacheModule() {
@@ -147,6 +147,13 @@
listener().to(ProjectCacheWarmer.class);
}
});
+ install(
+ new LifecycleModule() {
+ @Override
+ protected void configure() {
+ listener().to(PeriodicProjectListCacheWarmer.LifeCycle.class);
+ }
+ });
}
};
}