org.locationtech.geogig.di.caching.CacheFactory.java Source code

Java tutorial

Introduction

Here is the source code for org.locationtech.geogig.di.caching.CacheFactory.java

Source

/* Copyright (c) 2013-2014 Boundless and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/edl-v10.html
 *
 * Contributors:
 * Gabriel Roldan (Boundless) - initial implementation
 */
package org.locationtech.geogig.di.caching;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import org.locationtech.geogig.api.ObjectId;
import org.locationtech.geogig.api.RevObject;
import org.locationtech.geogig.api.porcelain.ConfigException;
import org.locationtech.geogig.storage.ConfigDatabase;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Optional;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheStats;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.Provider;

abstract class CacheFactory {

    private static final Logger LOGGER = LoggerFactory.getLogger(CacheFactory.class);

    private volatile Cache<ObjectId, RevObject> cache;

    private final Provider<ConfigDatabase> configDb;

    private final String configKeywordPrefix;

    public CacheFactory(final String configKeywordPrefix, final Provider<ConfigDatabase> configDb) {
        this.configKeywordPrefix = configKeywordPrefix;
        this.configDb = configDb;
    }

    public Cache<ObjectId, RevObject> get() {
        if (cache == null) {
            createCache();
        }
        return cache;
    }

    protected synchronized void createCache() {
        if (cache != null) {
            return;
        }
        if (!cacheIsEnabled()) {
            this.cache = NO_CACHE;
            return;
        }
        final int maxSize = getConfig("maxSize", 50_000);
        final int concurrencyLevel = getConfig("concurrencyLevel", 4);

        final int expireSeconds = getConfig("expireSeconds", 300);
        final int initialCapacity = getConfig("initialCapacity", 10 * 1000);
        CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder();
        cacheBuilder = cacheBuilder.maximumSize(maxSize);
        cacheBuilder.expireAfterAccess(expireSeconds, TimeUnit.SECONDS);
        cacheBuilder.initialCapacity(initialCapacity);
        cacheBuilder.concurrencyLevel(concurrencyLevel);
        cacheBuilder.softValues();

        try {
            this.cache = cacheBuilder.build();
        } catch (RuntimeException e) {
            LOGGER.error(
                    "Error configuring cache '{}' with maxSize: {}, expireSeconds: {}, initialCapacity: {}, concurrencyLevel: {}",
                    configKeywordPrefix, maxSize, expireSeconds, initialCapacity, concurrencyLevel, e);

            throw e;
        }

        LOGGER.debug(
                "Cache '{}' configured with maxSize: {}, expireSeconds: {}, initialCapacity: {}, concurrencyLevel: {}",
                configKeywordPrefix, maxSize, expireSeconds, initialCapacity, concurrencyLevel);

    }

    private boolean cacheIsEnabled() {
        LOGGER.debug("checking if cache {} is enabled...", configKeywordPrefix);
        final boolean enabled = getConfig("enabled", Boolean.TRUE);
        if (!enabled) {
            LOGGER.debug("Cache {} is disabled", configKeywordPrefix);
        }
        return enabled;
    }

    @SuppressWarnings("unchecked")
    private <T> T getConfig(final String keyword, final T defaultValue) {
        final String kw = configKeywordPrefix + "." + keyword;
        ConfigDatabase configDatabase = configDb.get();
        try {
            Optional<? extends Object> value = configDatabase.get(kw, defaultValue.getClass());
            if (value.isPresent()) {
                LOGGER.trace("Got cache config property {} = {}", kw, value.get());
                return (T) value.get();
            }
        } catch (ConfigException e) {
            return defaultValue;
        }
        return defaultValue;
    }

    private static final Cache<ObjectId, RevObject> NO_CACHE = new Cache<ObjectId, RevObject>() {

        @Override
        public RevObject getIfPresent(Object key) {
            return null;
        }

        @Override
        public RevObject get(ObjectId key, Callable<? extends RevObject> valueLoader) throws ExecutionException {
            try {
                return valueLoader.call();
            } catch (Exception e) {
                throw new ExecutionException(e);
            }
        }

        @Override
        public ImmutableMap<ObjectId, RevObject> getAllPresent(Iterable<?> keys) {
            return ImmutableMap.of();
        }

        @Override
        public void put(ObjectId key, RevObject value) {
            // do nothing
        }

        @Override
        public void putAll(Map<? extends ObjectId, ? extends RevObject> m) {
            // do nothing
        }

        @Override
        public void invalidate(Object key) {
            // do nothing
        }

        @Override
        public void invalidateAll(Iterable<?> keys) {
            // do nothing
        }

        @Override
        public void invalidateAll() {
            // do nothing
        }

        @Override
        public long size() {
            return 0;
        }

        @Override
        public CacheStats stats() {
            return new CacheStats(0, 0, 0, 0, 0, 0);
        }

        @Override
        public ConcurrentMap<ObjectId, RevObject> asMap() {
            return Maps.newConcurrentMap();
        }

        @Override
        public void cleanUp() {
            // do nothing
        }
    };
}