
org.postgresql.util.LruCache Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of postgresql Show documentation
Show all versions of postgresql Show documentation
PostgreSQL JDBC Driver JDBC4
/*
* Copyright (c) 2015, PostgreSQL Global Development Group
* See the LICENSE file in the project root for more information.
*/
package org.postgresql.util;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Caches values in simple least-recently-accessed order.
*/
public class LruCache implements Gettable {
/**
* Action that is invoked when the entry is removed from the cache.
*
* @param type of the cache entry
*/
public interface EvictAction {
void evict(Value value) throws SQLException;
}
/**
* When the entry is not present in cache, this create action is used to create one.
*
* @param type of the cache entry
*/
public interface CreateAction {
Value create(Key key) throws SQLException;
}
private final EvictAction onEvict;
private final CreateAction createAction;
private final int maxSizeEntries;
private final long maxSizeBytes;
private long currentSize;
private final Map cache;
private class LimitedMap extends LinkedHashMap {
LimitedMap(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor, accessOrder);
}
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
// Avoid creating iterators if size constraints not violated
if (size() <= maxSizeEntries && currentSize <= maxSizeBytes) {
return false;
}
Iterator> it = entrySet().iterator();
while (it.hasNext()) {
if (size() <= maxSizeEntries && currentSize <= maxSizeBytes) {
return false;
}
Map.Entry entry = it.next();
evictValue(entry.getValue());
long valueSize = entry.getValue().getSize();
if (valueSize > 0) {
// just in case
currentSize -= valueSize;
}
it.remove();
}
return false;
}
}
private void evictValue(Value value) {
try {
onEvict.evict(value);
} catch (SQLException e) {
/* ignore */
}
}
public LruCache(int maxSizeEntries, long maxSizeBytes, boolean accessOrder) {
this(maxSizeEntries, maxSizeBytes, accessOrder, NOOP_CREATE_ACTION, NOOP_EVICT_ACTION);
}
public LruCache(int maxSizeEntries, long maxSizeBytes, boolean accessOrder,
CreateAction createAction,
EvictAction onEvict) {
this.maxSizeEntries = maxSizeEntries;
this.maxSizeBytes = maxSizeBytes;
this.createAction = createAction;
this.onEvict = onEvict;
this.cache = new LimitedMap(16, 0.75f, accessOrder);
}
/**
* Returns an entry from the cache.
*
* @param key cache key
* @return entry from cache or null if cache does not contain given key.
*/
public synchronized Value get(Key key) {
return cache.get(key);
}
/**
* Borrows an entry from the cache.
*
* @param key cache key
* @return entry from cache or newly created entry if cache does not contain given key.
* @throws SQLException if entry creation fails
*/
public synchronized Value borrow(Key key) throws SQLException {
Value value = cache.remove(key);
if (value == null) {
return createAction.create(key);
}
currentSize -= value.getSize();
return value;
}
/**
* Returns given value to the cache.
*
* @param key key
* @param value value
*/
public synchronized void put(Key key, Value value) {
long valueSize = value.getSize();
if (maxSizeBytes == 0 || maxSizeEntries == 0 || valueSize * 2 > maxSizeBytes) {
// Just destroy the value if cache is disabled or if entry would consume more than a half of
// the cache
evictValue(value);
return;
}
currentSize += valueSize;
Value prev = cache.put(key, value);
if (prev == null) {
return;
}
// This should be a rare case
currentSize -= prev.getSize();
if (prev != value) {
evictValue(prev);
}
}
/**
* Puts all the values from the given map into the cache.
*
* @param m The map containing entries to put into the cache
*/
public synchronized void putAll(Map m) {
for (Map.Entry entry : m.entrySet()) {
this.put(entry.getKey(), entry.getValue());
}
}
public static final CreateAction NOOP_CREATE_ACTION = new CreateAction() {
@Override
public Object create(Object o) throws SQLException {
return null;
}
};
public static final EvictAction NOOP_EVICT_ACTION = new EvictAction() {
@Override
public void evict(Object o) throws SQLException {
return;
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy