in commons-jcs3-core/src/main/java/org/apache/commons/jcs3/utils/struct/AbstractLRUMap.java [318:389]
public V put(final K key, final V value)
{
putCnt++;
LRUElementDescriptor<K, V> old = null;
final LRUElementDescriptor<K, V> me = new LRUElementDescriptor<>(key, value);
lock.lock();
try
{
list.addFirst( me );
old = map.put(key, me);
// If the node was the same as an existing node, remove it.
if ( old != null && key.equals(old.getKey()))
{
list.remove( old );
}
}
finally
{
lock.unlock();
}
// If the element limit is reached, we need to spool
if (shouldRemove())
{
log.debug( "In memory limit reached, removing least recently used." );
// The spool will put them in a disk event queue, so there is no
// need to pre-queue the queuing. This would be a bit wasteful
// and wouldn't save much time in this synchronous call.
while (shouldRemove())
{
lock.lock();
try
{
final LRUElementDescriptor<K, V> last = list.getLast();
if (last == null) {
verifyCache();
throw new Error("update: last is null!");
}
processRemovedLRU(last.getKey(), last.getPayload());
if (map.remove(last.getKey()) == null)
{
log.warn("update: remove failed for key: {0}",
last::getKey);
verifyCache();
}
list.removeLast();
}
finally
{
lock.unlock();
}
}
log.debug( "update: After spool map size: {0}", map::size);
if ( map.size() != list.size() )
{
log.error("update: After spool, size mismatch: map.size() = {0}, "
+ "linked list size = {1}",
map::size, list::size);
}
}
if ( old != null )
{
return old.getPayload();
}
return null;
}