blob: 0fdc6f5ffd43158f5f9e580bd28a0602c09a6351 [file] [log] [blame]
// Copyright (C) 2009 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.cache;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.Weigher;
import com.google.gerrit.extensions.annotations.Exports;
import com.google.gerrit.extensions.config.FactoryModule;
import com.google.gerrit.server.cache.serialize.JavaCacheSerializer;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scopes;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import com.google.inject.util.Types;
import java.lang.reflect.Type;
/** Miniature DSL to support binding {@link Cache} instances in Guice. */
public abstract class CacheModule extends FactoryModule {
public static final String MEMORY_MODULE = "cache-memory";
public static final String PERSISTENT_MODULE = "cache-persistent";
private static final TypeLiteral<Cache<?, ?>> ANY_CACHE = new TypeLiteral<Cache<?, ?>>() {};
/**
* Declare a named in-memory cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @return binding to describe the cache.
*/
protected <K, V> CacheBinding<K, V> cache(String name, Class<K> keyType, Class<V> valType) {
return cache(name, TypeLiteral.get(keyType), TypeLiteral.get(valType));
}
/**
* Declare a named in-memory cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @return binding to describe the cache.
*/
protected <K, V> CacheBinding<K, V> cache(String name, Class<K> keyType, TypeLiteral<V> valType) {
return cache(name, TypeLiteral.get(keyType), valType);
}
/**
* Declare a named in-memory cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @return binding to describe the cache.
*/
protected <K, V> CacheBinding<K, V> cache(
String name, TypeLiteral<K> keyType, TypeLiteral<V> valType) {
CacheProvider<K, V> m =
new CacheProvider<>(this, name, keyType, valType, CacheBackend.CAFFEINE);
bindCache(m, name, keyType, valType);
return m;
}
<K, V> Provider<CacheLoader<K, V>> bindCacheLoader(
CacheProvider<K, V> m, Class<? extends CacheLoader<K, V>> impl) {
Type type =
Types.newParameterizedType(Cache.class, m.keyType().getType(), m.valueType().getType());
Type loadingType =
Types.newParameterizedType(
LoadingCache.class, m.keyType().getType(), m.valueType().getType());
Type loaderType =
Types.newParameterizedType(
CacheLoader.class, m.keyType().getType(), m.valueType().getType());
@SuppressWarnings("unchecked")
Key<LoadingCache<K, V>> key = (Key<LoadingCache<K, V>>) Key.get(type, Names.named(m.name));
@SuppressWarnings("unchecked")
Key<LoadingCache<K, V>> loadingKey =
(Key<LoadingCache<K, V>>) Key.get(loadingType, Names.named(m.name));
@SuppressWarnings("unchecked")
Key<CacheLoader<K, V>> loaderKey =
(Key<CacheLoader<K, V>>) Key.get(loaderType, Names.named(m.name));
bind(loaderKey).to(impl).in(Scopes.SINGLETON);
bind(loadingKey).to(key);
return getProvider(loaderKey);
}
<K, V> Provider<Weigher<K, V>> bindWeigher(
CacheProvider<K, V> m, Class<? extends Weigher<K, V>> impl) {
Type weigherType =
Types.newParameterizedType(Weigher.class, m.keyType().getType(), m.valueType().getType());
@SuppressWarnings("unchecked")
Key<Weigher<K, V>> key = (Key<Weigher<K, V>>) Key.get(weigherType, Names.named(m.name));
bind(key).to(impl).in(Scopes.SINGLETON);
return getProvider(key);
}
/**
* Declare a named in-memory/on-disk cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @return binding to describe the cache.
*/
protected <K, V> PersistentCacheBinding<K, V> persist(
String name, Class<K> keyType, Class<V> valType) {
return persist(name, TypeLiteral.get(keyType), TypeLiteral.get(valType), CacheBackend.CAFFEINE);
}
/**
* Declare a named in-memory/on-disk cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @param backend cache backend.
* @return binding to describe the cache.
*/
protected <K, V> PersistentCacheBinding<K, V> persist(
String name, Class<K> keyType, Class<V> valType, CacheBackend backend) {
return persist(name, TypeLiteral.get(keyType), TypeLiteral.get(valType), backend);
}
/**
* Declare a named in-memory/on-disk cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @return binding to describe the cache.
*/
protected <K, V> PersistentCacheBinding<K, V> persist(
String name, Class<K> keyType, TypeLiteral<V> valType) {
return persist(name, TypeLiteral.get(keyType), valType, CacheBackend.CAFFEINE);
}
/**
* Declare a named in-memory/on-disk cache.
*
* @param <K> type of key used to lookup entries.
* @param <V> type of value stored by the cache.
* @return binding to describe the cache.
*/
protected <K, V> PersistentCacheBinding<K, V> persist(
String name, TypeLiteral<K> keyType, TypeLiteral<V> valType, CacheBackend backend) {
PersistentCacheProvider<K, V> m =
new PersistentCacheProvider<>(this, name, keyType, valType, backend);
bindCache(m, name, keyType, valType);
Type cacheDefType =
Types.newParameterizedType(PersistentCacheDef.class, keyType.getType(), valType.getType());
@SuppressWarnings("unchecked")
Key<PersistentCacheDef<K, V>> cacheDefKey =
(Key<PersistentCacheDef<K, V>>) Key.get(cacheDefType, Names.named(name));
bind(cacheDefKey).toInstance(m);
// TODO(dborowitz): Once default Java serialization is removed, leave no default.
return m.version(0)
.keySerializer(new JavaCacheSerializer<>())
.valueSerializer(new JavaCacheSerializer<>());
}
private <K, V> void bindCache(
CacheProvider<K, V> m, String name, TypeLiteral<K> keyType, TypeLiteral<V> valType) {
Type type = Types.newParameterizedType(Cache.class, keyType.getType(), valType.getType());
Named named = Names.named(name);
@SuppressWarnings("unchecked")
Key<Cache<K, V>> key = (Key<Cache<K, V>>) Key.get(type, named);
bind(key).toProvider(m).asEagerSingleton();
bind(ANY_CACHE).annotatedWith(Exports.named(name)).to(key);
Type cacheDefType =
Types.newParameterizedType(CacheDef.class, keyType.getType(), valType.getType());
@SuppressWarnings("unchecked")
Key<CacheDef<K, V>> cacheDefKey = (Key<CacheDef<K, V>>) Key.get(cacheDefType, named);
bind(cacheDefKey).toInstance(m);
m.maximumWeight(1024);
}
}