// Copyright (C) 2012 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.h2; import com.google.common.base.Strings; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.cache.Weigher; import com.google.gerrit.lifecycle.LifecycleModule; import com.google.gerrit.server.cache.CacheBinding; import com.google.gerrit.server.cache.ForwardingRemovalListener; import com.google.gerrit.server.cache.MemoryCacheFactory; import com.google.gerrit.server.cache.PersistentCacheFactory; import com.google.gerrit.server.cache.h2.H2CacheImpl.ValueHolder; import com.google.gerrit.server.config.ConfigUtil; import com.google.gerrit.server.config.GerritServerConfig; import com.google.inject.Inject; import org.eclipse.jgit.lib.Config; import java.util.concurrent.TimeUnit; public class DefaultCacheFactory implements MemoryCacheFactory { public static class Module extends LifecycleModule { @Override protected void configure() { factory(ForwardingRemovalListener.Factory.class); bind(DefaultCacheFactory.class); bind(MemoryCacheFactory.class).to(DefaultCacheFactory.class); bind(PersistentCacheFactory.class).to(H2CacheFactory.class); listener().to(H2CacheFactory.class); } } private final Config cfg; private final ForwardingRemovalListener.Factory forwardingRemovalListenerFactory; @Inject public DefaultCacheFactory(@GerritServerConfig Config config, ForwardingRemovalListener.Factory forwardingRemovalListenerFactory) { this.cfg = config; this.forwardingRemovalListenerFactory = forwardingRemovalListenerFactory; } @Override public <K, V> Cache<K, V> build(CacheBinding<K, V> def) { return create(def, false).build(); } @Override public <K, V> LoadingCache<K, V> build( CacheBinding<K, V> def, CacheLoader<K, V> loader) { return create(def, false).build(loader); } @SuppressWarnings("unchecked") <K, V> CacheBuilder<K, V> create( CacheBinding<K, V> def, boolean unwrapValueHolder) { CacheBuilder<K,V> builder = newCacheBuilder(); builder.recordStats(); builder.maximumWeight(cfg.getLong( "cache", def.name(), "memoryLimit", def.maximumWeight())); builder = builder.removalListener(forwardingRemovalListenerFactory.create(def.name())); Weigher<K, V> weigher = def.weigher(); if (weigher != null && unwrapValueHolder) { final Weigher<K, V> impl = weigher; weigher = (Weigher<K, V>) new Weigher<K, ValueHolder<V>> () { @Override public int weigh(K key, ValueHolder<V> value) { return impl.weigh(key, value.value); } }; } else if (weigher == null) { weigher = unitWeight(); } builder.weigher(weigher); Long age = def.expireAfterWrite(TimeUnit.SECONDS); if (has(def.name(), "maxAge")) { builder.expireAfterWrite(ConfigUtil.getTimeUnit(cfg, "cache", def.name(), "maxAge", age != null ? age : 0, TimeUnit.SECONDS), TimeUnit.SECONDS); } else if (age != null) { builder.expireAfterWrite(age, TimeUnit.SECONDS); } return builder; } private boolean has(String name, String var) { return !Strings.isNullOrEmpty(cfg.getString("cache", name, var)); } @SuppressWarnings("unchecked") private static <K, V> CacheBuilder<K, V> newCacheBuilder() { return (CacheBuilder<K, V>) CacheBuilder.newBuilder(); } private static <K, V> Weigher<K, V> unitWeight() { return new Weigher<K, V>() { @Override public int weigh(K key, V value) { return 1; } }; } }