Package com.thinkaurelius.titan.diskstorage.keycolumnvalue

Source Code of com.thinkaurelius.titan.diskstorage.keycolumnvalue.CachedKeyColumnValueStore

package com.thinkaurelius.titan.diskstorage.keycolumnvalue;

import com.codahale.metrics.Counter;
import com.google.common.base.Preconditions;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.Weigher;
import com.thinkaurelius.titan.diskstorage.StaticBuffer;
import com.thinkaurelius.titan.diskstorage.StorageException;
import com.thinkaurelius.titan.diskstorage.TemporaryStorageException;
import com.thinkaurelius.titan.graphdb.configuration.GraphDatabaseConfiguration;
import com.thinkaurelius.titan.util.stats.MetricManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
* Wraps a {@link KeyColumnValueStore} and caches KeySliceQuery results which are marked <i>static</i> and hence do not change.
*
* @author Matthias Broecheler (me@matthiasb.com)
* @see SliceQuery
*      <p/>
*      TODO: generalize cache to check for subsumption instead of equality of KeySliceQuery and allow having a limit
*/

public class CachedKeyColumnValueStore implements KeyColumnValueStore {

    private static final Logger log = LoggerFactory.getLogger(CachedKeyColumnValueStore.class);

    private static final String METRICS_PREFIX = GraphDatabaseConfiguration.METRICS_SYSTEM_PREFIX_DEFAULT
            + "." + CachedKeyColumnValueStore.class.getSimpleName();
    private static final Counter CACHE_RETRIEVAL = MetricManager.INSTANCE.getCounter(METRICS_PREFIX, "retrievals");
    private static final Counter CACHE_MISS = MetricManager.INSTANCE.getCounter(METRICS_PREFIX, "misses");

    private static final long DEFAULT_CACHE_SIZE = 2*1000; //1000 types

    private final KeyColumnValueStore store;
    private final Cache<KeySliceQuery, List<Entry>> cache;

    public CachedKeyColumnValueStore(final KeyColumnValueStore store) {
        this(store, DEFAULT_CACHE_SIZE);
    }

    public CachedKeyColumnValueStore(final KeyColumnValueStore store, long cacheSize) {
        Preconditions.checkNotNull(store);
        this.store = store;
        this.cache = CacheBuilder.newBuilder().weigher(new Weigher<KeySliceQuery, List<Entry>>() {
            @Override
            public int weigh(KeySliceQuery q, List<Entry> r) {
                return 2 + r.size();
            }
        }).maximumWeight(cacheSize)
                .build();
    }

    public static long getGlobalCacheHits() {
        return CACHE_RETRIEVAL.getCount() - CACHE_MISS.getCount();
    }

    public static long getGlobalCacheMisses() {
        return CACHE_MISS.getCount();
    }

    public static void resetGlobalMetrics() {
        // This is at best approximate (especially in the presence of concurrent updates)
        CACHE_MISS.dec(CACHE_MISS.getCount());
        CACHE_RETRIEVAL.dec(CACHE_RETRIEVAL.getCount());
    }

    @Override
    public boolean containsKey(StaticBuffer key, StoreTransaction txh) throws StorageException {
        return store.containsKey(key, txh);
    }

    @Override
    public List<Entry> getSlice(final KeySliceQuery query, final StoreTransaction txh) throws StorageException {
        if (query.isStatic()) {
            try {
                if (log.isDebugEnabled())
                    log.debug("Cache Retrieval on " + store.getName() + ". Attempts: {} | Misses: {}", CACHE_RETRIEVAL.getCount(), CACHE_MISS.getCount());
                CACHE_RETRIEVAL.inc();
                List<Entry> result = cache.get(query, new Callable<List<Entry>>() {
                    @Override
                    public List<Entry> call() throws StorageException {
                        CACHE_MISS.inc();
                        return store.getSlice(query, txh);
                    }
                });
                if (result.isEmpty()) cache.invalidate(query);
                return result;
            } catch (ExecutionException e) {
                Throwable cause = e.getCause();
                if (cause != null && cause instanceof StorageException) {
                    throw (StorageException) cause;
                } else {
                    throw new TemporaryStorageException("Exception while accessing cache", e);
                }
            }
        } else {
            return store.getSlice(query, txh);
        }
    }

    @Override
    public List<List<Entry>> getSlice(List<StaticBuffer> keys, SliceQuery query, StoreTransaction txh) throws StorageException {
        if (query.isStatic() && !query.hasLimit()) {
            List<List<Entry>> results = new ArrayList<List<Entry>>(keys.size());
            for (StaticBuffer key : keys) {
                results.add(getSlice(new KeySliceQuery(key, query), txh));
            }
            return results;
        } else {
            return store.getSlice(keys, query, txh);
        }
    }

    @Override
    public void mutate(StaticBuffer key, List<Entry> additions, List<StaticBuffer> deletions, StoreTransaction txh) throws StorageException {
        store.mutate(key, additions, deletions, txh);
    }

    @Override
    public void acquireLock(StaticBuffer key, StaticBuffer column, StaticBuffer expectedValue, StoreTransaction txh) throws StorageException {
        store.acquireLock(key, column, expectedValue, txh);
    }

    @Override
    public KeyIterator getKeys(KeyRangeQuery keyQuery, StoreTransaction txh) throws StorageException {
        return store.getKeys(keyQuery, txh);
    }

    @Override
    public KeyIterator getKeys(SliceQuery columnQuery, StoreTransaction txh) throws StorageException {
        return store.getKeys(columnQuery, txh);
    }

    @Override
    public StaticBuffer[] getLocalKeyPartition() throws StorageException {
        return store.getLocalKeyPartition();
    }

    @Override
    public String getName() {
        return store.getName();
    }

    @Override
    public void close() throws StorageException {
        store.close();
    }
}
TOP

Related Classes of com.thinkaurelius.titan.diskstorage.keycolumnvalue.CachedKeyColumnValueStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.