/** {@inheritDoc} */ @Override public void onEntryAccessed(boolean rmv, EvictableEntry<K, V> entry) { if (!rmv) { if (!entry.isCached()) return; if (touch(entry)) shrink(); } else { Node<EvictableEntry<K, V>> node = entry.removeMeta(); if (node != null) { queue.unlinkx(node); memSize.add(-entry.size()); } } }
/** * Tries to remove one item from queue. * * @return number of bytes that was free. {@code -1} if queue is empty. */ private int shrink0() { EvictableEntry<K, V> entry = queue.poll(); if (entry == null) return -1; int size = 0; Node<EvictableEntry<K, V>> meta = entry.removeMeta(); if (meta != null) { size = entry.size(); memSize.add(-size); if (!entry.evict()) touch(entry); } return size; }
/** * @param entry Entry to touch. * @return {@code True} if new node has been added to queue by this call. */ private boolean touch(EvictableEntry<K, V> entry) { Node<EvictableEntry<K, V>> node = entry.meta(); // Entry has not been enqueued yet. if (node == null) { while (true) { node = queue.offerLastx(entry); if (entry.putMetaIfAbsent(node) != null) { // Was concurrently added, need to clear it from queue. queue.unlinkx(node); // Queue has not been changed. return false; } else if (node.item() != null) { if (!entry.isCached()) { // Was concurrently evicted, need to clear it from queue. queue.unlinkx(node); return false; } memSize.add(entry.size()); return true; } // If node was unlinked by concurrent shrink() call, we must repeat the whole cycle. else if (!entry.removeMeta(node)) return false; } } else if (queue.unlinkx(node)) { // Move node to tail. Node<EvictableEntry<K, V>> newNode = queue.offerLastx(entry); if (!entry.replaceMeta(node, newNode)) // Was concurrently added, need to clear it from queue. queue.unlinkx(newNode); } // Entry is already in queue. return false; }