Allow creation of persistent caches after server is started

2e1cb2b849 switches from Ehcache to Guava
for providing caching in Gerrit and claims that one of the advantages of
using Guava is that it enables caches to be build at any time, rather
than only at server startup. Therefore, I guess it is OK to remove the
precondition check which prevents creation of caches once the server was
started.

This enables plugins to create own persistent caches when they are
installed.

Change-Id: I28b1a140c58f9967e6d1dacd61ddd021b48c8ad5
This commit is contained in:
Saša Živkov
2014-02-25 16:28:16 +01:00
parent 29e3289a37
commit 218c6b69c2
3 changed files with 38 additions and 11 deletions

View File

@@ -14,20 +14,22 @@
package com.google.gerrit.server.cache.h2;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.registration.DynamicMap;
import com.google.gerrit.server.cache.CacheBinding;
import com.google.gerrit.server.cache.PersistentCacheFactory;
import com.google.gerrit.server.cache.h2.H2CacheImpl.SqlStore;
import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.plugins.Plugin;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.TypeLiteral;
@@ -37,6 +39,7 @@ import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
@@ -50,15 +53,16 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
private final Config config;
private final File cacheDir;
private final List<H2CacheImpl<?, ?>> caches;
private final DynamicMap<Cache<?, ?>> cacheMap;
private final ExecutorService executor;
private final ScheduledExecutorService cleanup;
private volatile boolean started;
@Inject
H2CacheFactory(
DefaultCacheFactory defaultCacheFactory,
@GerritServerConfig Config cfg,
SitePaths site) {
SitePaths site,
DynamicMap<Cache<?, ?>> cacheMap) {
defaultFactory = defaultCacheFactory;
config = cfg;
@@ -79,6 +83,7 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
}
caches = Lists.newLinkedList();
this.cacheMap = cacheMap;
if (cacheDir != null) {
executor = Executors.newFixedThreadPool(
@@ -100,7 +105,6 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
@Override
public void start() {
started = true;
if (executor != null) {
for (final H2CacheImpl<?, ?> cache : caches) {
executor.execute(new Runnable() {
@@ -141,15 +145,16 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
log.warn("Interrupted waiting for disk cache to shutdown");
}
}
synchronized (caches) {
for (H2CacheImpl<?, ?> cache : caches) {
cache.stop();
}
}
}
@SuppressWarnings({"unchecked", "cast"})
@Override
public <K, V> Cache<K, V> build(CacheBinding<K, V> def) {
Preconditions.checkState(!started, "cache must be built before start");
long limit = config.getLong("cache", def.name(), "diskLimit", 128 << 20);
if (cacheDir == null || limit <= 0) {
@@ -160,7 +165,9 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
H2CacheImpl<K, V> cache = new H2CacheImpl<K, V>(
executor, store, def.keyType(),
(Cache<K, ValueHolder<V>>) defaultFactory.create(def, true).build());
synchronized (caches) {
caches.add(cache);
}
return cache;
}
@@ -169,7 +176,6 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
public <K, V> LoadingCache<K, V> build(
CacheBinding<K, V> def,
CacheLoader<K, V> loader) {
Preconditions.checkState(!started, "cache must be built before start");
long limit = config.getLong("cache", def.name(), "diskLimit", 128 << 20);
if (cacheDir == null || limit <= 0) {
@@ -187,6 +193,19 @@ class H2CacheFactory implements PersistentCacheFactory, LifecycleListener {
return cache;
}
@Override
public void onStop(Plugin plugin) {
synchronized (caches) {
for (Map.Entry<String, Provider<Cache<?, ?>>> entry :
cacheMap.byPlugin(plugin.getName()).entrySet()) {
Cache<?, ?> cache = entry.getValue().get();
if (caches.remove(cache)) {
((H2CacheImpl<?, ?>) cache).stop();
}
}
}
}
private <V, K> SqlStore<K, V> newSqlStore(
String name,
TypeLiteral<K> keyType,

View File

@@ -17,6 +17,7 @@ package com.google.gerrit.server.cache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.gerrit.server.plugins.Plugin;
public interface PersistentCacheFactory {
<K, V> Cache<K, V> build(CacheBinding<K, V> def);
@@ -24,4 +25,6 @@ public interface PersistentCacheFactory {
<K, V> LoadingCache<K, V> build(
CacheBinding<K, V> def,
CacheLoader<K, V> loader);
void onStop(Plugin plugin);
}

View File

@@ -31,6 +31,7 @@ import com.google.gerrit.extensions.events.LifecycleListener;
import com.google.gerrit.extensions.systemstatus.ServerInformation;
import com.google.gerrit.extensions.webui.JavaScriptPlugin;
import com.google.gerrit.server.PluginUser;
import com.google.gerrit.server.cache.PersistentCacheFactory;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -90,6 +91,7 @@ public class PluginLoader implements LifecycleListener {
private final Provider<PluginCleanerTask> cleaner;
private final PluginScannerThread scanner;
private final Provider<String> urlProvider;
private final PersistentCacheFactory persistentCacheFactory;
private final boolean remoteAdmin;
@Inject
@@ -99,7 +101,8 @@ public class PluginLoader implements LifecycleListener {
PluginUser.Factory puf,
Provider<PluginCleanerTask> pct,
@GerritServerConfig Config cfg,
@CanonicalWebUrl Provider<String> provider) {
@CanonicalWebUrl Provider<String> provider,
PersistentCacheFactory cacheFactory) {
pluginsDir = sitePaths.plugins_dir;
dataDir = sitePaths.data_dir;
tmpDir = sitePaths.tmp_dir;
@@ -113,6 +116,7 @@ public class PluginLoader implements LifecycleListener {
cleanupHandles = Maps.newConcurrentMap();
cleaner = pct;
urlProvider = provider;
persistentCacheFactory = cacheFactory;
remoteAdmin =
cfg.getBoolean("plugins", null, "allowRemoteAdmin", false);
@@ -228,6 +232,7 @@ public class PluginLoader implements LifecycleListener {
}
synchronized private void unloadPlugin(Plugin plugin) {
persistentCacheFactory.onStop(plugin);
String name = plugin.getName();
log.info(String.format("Unloading plugin %s", name));
plugin.stop(env);