Update element caching to use Guava cache implementation

This commit is contained in:
Michael Lieberman
2014-12-24 11:34:59 -05:00
parent 0526fb68e4
commit 9117cab1ae
4 changed files with 157 additions and 126 deletions

View File

@@ -145,8 +145,8 @@ public class AccumuloGraph implements Graph, KeyIndexableGraph, IndexableGraph {
BatchWriter vertexBW;
BatchWriter edgeBW;
LruElementCache<Vertex> vertexCache;
LruElementCache<Edge> edgeCache;
ElementCache<Vertex> vertexCache;
ElementCache<Edge> edgeCache;
public AccumuloGraph(Configuration cfg) {
this(new AccumuloGraphConfiguration(cfg));
@@ -162,12 +162,12 @@ public class AccumuloGraph implements Graph, KeyIndexableGraph, IndexableGraph {
this.config = config;
if (config.getVertexCacheEnabled()) {
vertexCache = new LruElementCache<Vertex>(config.getVertexCacheSize(),
vertexCache = new ElementCache<Vertex>(config.getVertexCacheSize(),
config.getVertexCacheTimeout());
}
if (config.getEdgeCacheEnabled()) {
edgeCache = new LruElementCache<Edge>(config.getEdgeCacheSize(),
edgeCache = new ElementCache<Edge>(config.getEdgeCacheSize(),
config.getEdgeCacheTimeout());
}

View File

@@ -0,0 +1,50 @@
/******************************************************************************
* COPYRIGHT NOTICE *
* Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory *
* All rights reserved. *
* *
* This material may only be used, modified, or reproduced by or for the *
* U.S. Government pursuant to the license rights granted under FAR clause *
* 52.227-14 or DFARS clauses 252.227-7013/7014. *
* *
* For any other permissions, please contact the Legal Office at JHU/APL. *
******************************************************************************/
package edu.jhuapl.tinkerpop;
import java.util.concurrent.TimeUnit;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.tinkerpop.blueprints.Element;
/**
* Simple cache for retrieved graph elements,
* backed by Guava's cache implementation.
*/
public class ElementCache<T extends Element> {
private Cache<Object, T> cache;
public ElementCache(int size, int timeout) {
cache = CacheBuilder.newBuilder()
.maximumSize(size)
.expireAfterAccess(timeout, TimeUnit.MILLISECONDS)
.build();
}
public void cache(T element) {
cache.put(element.getId(), element);
}
public T retrieve(Object id) {
return cache.getIfPresent(id);
}
public void remove(Object id) {
cache.invalidate(id);
}
public void clear() {
cache.invalidateAll();
}
}

View File

@@ -1,122 +0,0 @@
/* Copyright 2014 The Johns Hopkins University Applied Physics Laboratory
*
* 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 edu.jhuapl.tinkerpop;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.util.LinkedHashMap;
import java.util.Map;
import com.tinkerpop.blueprints.Element;
class LruElementCache<T extends Element> extends LinkedHashMap<String,LruElementCache<T>.Entry> implements Runnable {
private static final long serialVersionUID = 1435352624360026357L;
ReferenceQueue<T> queue;
Integer maxCapacity;
int timeout;
public LruElementCache(int timeout) {
super(32, .75f, true);
this.maxCapacity = null;
init(timeout);
}
public LruElementCache(int maxCapacity, int timeout) {
super(maxCapacity + 1, 1f, true);
this.maxCapacity = maxCapacity;
init(timeout);
}
private void init(int timeout) {
this.timeout = timeout;
this.queue = new ReferenceQueue<T>();
Thread t = new Thread(this, "lru-cache-reaper-" + System.identityHashCode(this));
t.setPriority(Thread.MIN_PRIORITY);
t.setDaemon(true);
t.start();
}
@Override
protected boolean removeEldestEntry(Map.Entry<String,LruElementCache<T>.Entry> eldest) {
if (maxCapacity != null) {
return size() > maxCapacity;
} else {
// no cap on size, but see if eldest has timed out or been gc'ed
// already...
return eldest.getValue().getElement() == null;
}
}
@Override
public synchronized Entry remove(Object id) {
return super.remove(id);
}
public synchronized void cache(T element) {
Entry entry = new Entry(element, queue, timeout);
put(element.getId().toString(), entry);
}
public synchronized T retrieve(String id) {
LruElementCache<T>.Entry entry = get(id);
if (entry == null) {
// not cached...
return null;
}
T element = (T) entry.getElement();
if (element == null) {
// gc'ed or timed out; either way...
remove(id);
}
return element;
}
@Override
public void run() {
while (true) {
try {
Entry entry = (Entry) queue.remove();
synchronized (this) {
remove(entry.id);
}
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
}
}
final class Entry extends SoftReference<T> {
String id;
long timeout;
public Entry(T element, ReferenceQueue<T> queue, int timeout) {
super(element, queue);
this.id = element.getId().toString();
this.timeout = System.currentTimeMillis() + timeout;
}
public T getElement() {
if (System.currentTimeMillis() <= timeout) {
return get();
} else {
return null;
}
}
}
}

View File

@@ -0,0 +1,103 @@
/******************************************************************************
* COPYRIGHT NOTICE *
* Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory *
* All rights reserved. *
* *
* This material may only be used, modified, or reproduced by or for the *
* U.S. Government pursuant to the license rights granted under FAR clause *
* 52.227-14 or DFARS clauses 252.227-7013/7014. *
* *
* For any other permissions, please contact the Legal Office at JHU/APL. *
******************************************************************************/
package edu.jhuapl.tinkerpop;
import org.junit.Test;
import static org.junit.Assert.*;
import com.tinkerpop.blueprints.Edge;
import com.tinkerpop.blueprints.Element;
import com.tinkerpop.blueprints.Graph;
import com.tinkerpop.blueprints.GraphFactory;
import com.tinkerpop.blueprints.Vertex;
public class ElementCacheTest {
@Test
public void testElementCacheSize() throws Exception {
AccumuloGraphConfiguration cfg = AccumuloGraphTestUtils
.generateGraphConfig("elementCacheSize");
Graph graph = GraphFactory.open(cfg.getConfiguration());
Vertex[] verts = new Vertex[10];
for (int i = 0; i < verts.length; i++) {
verts[i] = graph.addVertex(i);
}
Edge[] edges = new Edge[9];
for (int i = 0; i < edges.length; i++) {
edges[i] = graph.addEdge(null,
verts[0], verts[i+1], "edge");
}
sizeTests(verts);
sizeTests(edges);
graph.shutdown();
}
private void sizeTests(Element[] elts) {
ElementCache<Element> cache =
new ElementCache<Element>(3, 120000);
for (Element e : elts) {
cache.cache(e);
}
for (Element e : elts) {
cache.cache(e);
}
int total = 0;
for (Element e : elts) {
if (cache.retrieve(e.getId()) != null) {
total++;
}
}
assertTrue(total < elts.length);
cache.clear();
for (Element e : elts) {
assertNull(cache.retrieve(e.getId()));
}
}
@Test
public void testElementCacheTimeout() throws Exception {
AccumuloGraphConfiguration cfg = AccumuloGraphTestUtils
.generateGraphConfig("elementCacheTimeout");
Graph graph = GraphFactory.open(cfg.getConfiguration());
ElementCache<Element> cache =
new ElementCache<Element>(10, 2000);
Vertex v1 = graph.addVertex(1);
Vertex v2 = graph.addVertex(2);
assertNull(cache.retrieve(1));
assertNull(cache.retrieve(2));
cache.cache(v1);
assertNotNull(cache.retrieve(v1.getId()));
Thread.sleep(3000);
assertNull(cache.retrieve(v1.getId()));
Edge e = graph.addEdge(null, v1, v2, "label");
assertNull(cache.retrieve(e.getId()));
cache.cache(e);
assertNotNull(cache.retrieve(e.getId()));
Thread.sleep(3000);
assertNull(cache.retrieve(e.getId()));
graph.shutdown();
}
}