org.eclipse.rdf4j.sail.nativerdf.ConcurrentCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rdf4j-sail-nativerdf Show documentation
Show all versions of rdf4j-sail-nativerdf Show documentation
Sail implementation that stores data directly to disk in dedicated file formats.
/*******************************************************************************
* Copyright (c) 2018 Eclipse RDF4J contributors, Aduna, 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
* http://www.eclipse.org/org/documents/edl-v10.php.
*******************************************************************************/
package org.eclipse.rdf4j.sail.nativerdf;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
/**
* Limited-size concurrent cache. The actual cleanup to keep the size limited is done once per
* CLEANUP_INTERVAL
invocations of the protected method cleanUp
. cleanUp
method
* is called every time by put
The maximum size is maintained approximately. Cleanup is not done if size is
* less than capacity + CLEANUP_INTERVAL / 2
.
*
* @author Oleg Mirzov
*/
public class ConcurrentCache {
private static final int CLEANUP_INTERVAL = 1024;
private static final float LOAD_FACTOR = 0.75f;
private final int capacity;
private volatile int cleanupTick = 0;
protected final ConcurrentHashMap cache;
public ConcurrentCache(int capacity) {
this.capacity = capacity;
this.cache = new ConcurrentHashMap<>((int) (capacity / LOAD_FACTOR), LOAD_FACTOR);
}
public V get(Object key) {
return cache.get(key);
}
public V put(K key, V value) {
cleanUp();
return cache.put(key, value);
}
public void clear() {
cache.clear();
}
/**
* @param key the key of the node to test for removal and do finalization on
* @return true if removal is approved
*/
protected boolean onEntryRemoval(K key) {
// Hook method, doing nothing by default
return true;
}
protected void cleanUp() {
// This is not thread-safe, but the worst that can happen is that we may (rarely) get slightly longer
// cleanup intervals or run cleanUp twice
cleanupTick++;
if (cleanupTick <= CLEANUP_INTERVAL) {
return;
}
cleanupTick %= CLEANUP_INTERVAL;
synchronized (cache) {
final int size = cache.size();
if (size < capacity + CLEANUP_INTERVAL / 2) {
return;
}
Iterator iter = cache.keySet().iterator();
float removeEachTh = (float) size / (size - capacity);
for (int i = 0; iter.hasNext(); i++) {
K key = iter.next();
if (i % removeEachTh < 1) {
cache.computeIfPresent(key, (k, v) -> onEntryRemoval(k) ? null : v);
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy