@Override public Cacheable getBlock( BlockCacheKey key, boolean caching, boolean repeat, boolean updateCacheMetrics) { CacheablePair contentBlock = backingMap.get(key); if (contentBlock == null) { if (!repeat && updateCacheMetrics) stats.miss(caching); return null; } if (updateCacheMetrics) stats.hit(caching); // If lock cannot be obtained, that means we're undergoing eviction. try { contentBlock.recentlyAccessed.set(System.nanoTime()); synchronized (contentBlock) { if (contentBlock.serializedData == null) { // concurrently evicted LOG.warn("Concurrent eviction of " + key); return null; } return contentBlock.deserializer.deserialize( contentBlock.serializedData.asReadOnlyBuffer()); } } catch (Throwable t) { LOG.error("Deserializer threw an exception. This may indicate a bug.", t); return null; } }
private void doEviction(BlockCacheKey key, CacheablePair evictedBlock) { long evictedHeap = 0; synchronized (evictedBlock) { if (evictedBlock.serializedData == null) { // someone else already freed return; } evictedHeap = evictedBlock.heapSize(); ByteBuffer bb = evictedBlock.serializedData; evictedBlock.serializedData = null; backingStore.free(bb); // We have to do this callback inside the synchronization here. // Otherwise we can have the following interleaving: // Thread A calls getBlock(): // SlabCache directs call to this SingleSizeCache // It gets the CacheablePair object // Thread B runs eviction // doEviction() is called and sets serializedData = null, here. // Thread A sees the null serializedData, and returns null // Thread A calls cacheBlock on the same block, and gets // "already cached" since the block is still in backingStore if (actionWatcher != null) { actionWatcher.onEviction(key, this); } } stats.evicted(); size.addAndGet(-1 * evictedHeap); }
/** * Evicts the block * * @param key the key of the entry we are going to evict * @return the evicted ByteBuffer */ public boolean evictBlock(BlockCacheKey key) { stats.evict(); CacheablePair evictedBlock = backingMap.remove(key); if (evictedBlock != null) { doEviction(key, evictedBlock); } return evictedBlock != null; }
public long getEvictedCount() { return stats.getEvictedCount(); }
public void logStats() { long milliseconds = this.timeSinceLastAccess.get() / 1000000; LOG.info( "For Slab of size " + this.blockSize + ": " + this.getOccupiedSize() / this.blockSize + " occupied, out of a capacity of " + this.numBlocks + " blocks. HeapSize is " + StringUtils.humanReadableInt(this.heapSize()) + " bytes." + ", " + "churnTime=" + StringUtils.formatTime(milliseconds)); LOG.info( "Slab Stats: " + "accesses=" + stats.getRequestCount() + ", " + "hits=" + stats.getHitCount() + ", " + "hitRatio=" + (stats.getHitCount() == 0 ? "0" : (StringUtils.formatPercent(stats.getHitRatio(), 2) + "%, ")) + "cachingAccesses=" + stats.getRequestCachingCount() + ", " + "cachingHits=" + stats.getHitCachingCount() + ", " + "cachingHitsRatio=" + (stats.getHitCachingCount() == 0 ? "0" : (StringUtils.formatPercent(stats.getHitCachingRatio(), 2) + "%, ")) + "evictions=" + stats.getEvictionCount() + ", " + "evicted=" + stats.getEvictedCount() + ", " + "evictedPerRun=" + stats.evictedPerEviction()); }