com.fasterxml.jackson.databind.util.LRUMap Maven / Gradle / Ivy
Show all versions of jackson-databind Show documentation
package com.fasterxml.jackson.databind.util;
import java.io.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* Helper for simple bounded maps used for reusing lookup values.
*
* Note that serialization behavior is such that contents are NOT serialized,
* on assumption that all use cases are for caching where persistence
* does not make sense. The only thing serialized is the cache size of Map.
*
* NOTE: since version 2.4.2, this is NOT an LRU-based at all; reason
* being that it is not possible to use JDK components that do LRU _AND_ perform
* well wrt synchronization on multi-core systems. So we choose efficient synchronization
* over potentially more efficient handling of entries.
*
* And yes, there are efficient LRU implementations such as
* concurrentlinkedhashmap;
* but at this point we really try to keep external deps to minimum.
* Plan from Jackson 2.12 is to focus more on pluggability as {@link LookupCache} and
* let users, frameworks, provide their own cache implementations.
*/
public class LRUMap
implements LookupCache, // since 2.12
java.io.Serializable
{
private static final long serialVersionUID = 1L;
protected final transient int _maxEntries;
protected final transient ConcurrentHashMap _map;
public LRUMap(int initialEntries, int maxEntries)
{
// We'll use concurrency level of 4, seems reasonable
_map = new ConcurrentHashMap(initialEntries, 0.8f, 4);
_maxEntries = maxEntries;
}
@Override
public V put(K key, V value) {
if (_map.size() >= _maxEntries) {
// double-locking, yes, but safe here; trying to avoid "clear storms"
synchronized (this) {
if (_map.size() >= _maxEntries) {
clear();
}
}
}
return _map.put(key, value);
}
/**
* @since 2.5
*/
@Override
public V putIfAbsent(K key, V value) {
// not 100% optimal semantically, but better from correctness (never exceeds
// defined maximum) and close enough all in all:
if (_map.size() >= _maxEntries) {
synchronized (this) {
if (_map.size() >= _maxEntries) {
clear();
}
}
}
return _map.putIfAbsent(key, value);
}
// NOTE: key is of type Object only to retain binary backwards-compatibility
@Override
public V get(Object key) { return _map.get(key); }
@Override
public void clear() { _map.clear(); }
@Override
public int size() { return _map.size(); }
/*
/**********************************************************
/* Serializable overrides
/**********************************************************
*/
/**
* Ugly hack, to work through the requirement that _value is indeed final,
* and that JDK serialization won't call ctor(s) if Serializable is implemented.
*
* @since 2.1
*/
protected transient int _jdkSerializeMaxEntries;
private void readObject(ObjectInputStream in) throws IOException {
_jdkSerializeMaxEntries = in.readInt();
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.writeInt(_jdkSerializeMaxEntries);
}
protected Object readResolve() {
return new LRUMap