private CacheRegion<? extends Comparable, ?> getLeastUsedRegion(Set<CacheRegion> checkedRegions) { CacheRegion<? extends Comparable, ?> leastUsed = null; for(CacheRegion<? extends Comparable, ?> region: getRegions()) { LOG.debug("Checking region: {}", region); if(!checkedRegions.contains(region)) { LOG.debug("Region available: {}", region.memorySize()); if(leastUsed == null || leastUsed.lastRegionAccess() > region.lastRegionAccess()) { leastUsed = region; } } } return leastUsed; }
public <T extends Comparable<T>> void registerRegion(CacheRegion<T, ? extends CacheEntry> region) { regionMap.putIfAbsent(region.name(), region); }
@Override public long getCachedBlocks() { return memoryRegion.size(); }
@RequestMapping(value = "/Caches", method = RequestMethod.GET, produces = "application/json") public RestEntity loadModel() throws RestException { GlobalCachingMemoryManager cachingMemoryManager = GlobalCachingMemoryManager.getGlobalInstance(); List<CacheBucket> buckets = new ArrayList<>(); for(CacheRegion region : cachingMemoryManager.getRegions()) { buckets.add(new CacheBucket(region.name(), region.size(), region.memorySize())); } return new CacheBucketCollection(buckets); } }
@Override public long getTotalMemoryUsage() { return memoryRegion.memorySize(); }
@Override public IndexBlock loadBlock(long position) throws JasDBStorageException { StatRecord loadBlockRecord = StatisticsMonitor.createRecord("btreeplus:persister:loadblock"); try { IndexBlockEntry blockEntry = memoryRegion.getEntry(position); if(blockEntry != null) { blockEntry.requestToken(); lockManager.registerBlockUsage(blockEntry.getValue()); return blockEntry.getValue(); } else { DataBlock dataBlock = dataBlockFactory.loadBlock(position); BlockTypes type = BlockTypes.getByTypeDef(dataBlock.getHeader().getInt(BLOCK_TYPE_HEADER_INDEX)); IndexBlock block = blockFactories.get(type).loadBlock(dataBlock); //it could happen the block was loaded concurrently, the cache putEntry will return the correct block entry blockEntry = new IndexBlockEntry(this, block); blockEntry = memoryRegion.putEntry(position, blockEntry); blockEntry.requestToken(); lockManager.registerBlockUsage(blockEntry.getValue()); return block; } } finally { loadBlockRecord.stop(); } }
@Override public void releaseBlock(IndexBlock block) { memoryRegion.getEntry(block.getPosition()).releaseToken(); }
public void flushAndCloseBlock(IndexBlock block) throws JasDBStorageException { persistBlock(block); memoryRegion.removeEntry(block.getPosition()); }
public void checkMemoryState(Set<CacheRegion> ignoreRegions) { long memorySize = calculateMemorySize(); if(memorySize > maximumMemory) { LOG.debug("Current memory size: {}", memorySize); LOG.debug("Maximum memory: {}", maximumMemory); long reduceSize = memorySize - maximumMemory; LOG.info("Memory overflow: {} bytes more than allowed limit", reduceSize); CacheRegion<? extends Comparable, ?> leastUsed = getLeastUsedRegion(ignoreRegions); if(leastUsed != null) { long actualReduce = leastUsed.reduceBy(reduceSize); LOG.debug("Reduced region: {} by: {} bytes", leastUsed, actualReduce); if(actualReduce < reduceSize) { ignoreRegions.add(leastUsed); LOG.debug("Reduce was not sufficient to meet reduce size: {} was actually: {}", reduceSize, actualReduce); checkMemoryState(ignoreRegions); } } else { LOG.warn("Could not reduce memory footprint further, no more reducable regions available, current memory footprint: {}", calculateMemorySize()); } } }
@Override public void close() throws JasDBStorageException { flush(); memoryRegion.clear(); GlobalCachingMemoryManager.getGlobalInstance().unregisterRegion(keyInfo.getKeyName()); }
@Override public IndexBlock createBlock(BlockTypes blockType, long parentBlock) throws JasDBStorageException { StatRecord blockCreateTimer = StatisticsMonitor.createRecord("btreeplus:persister:createblock"); lock.lock(); try { IndexBlock block = blockFactories.get(blockType).createBlock(parentBlock, dataBlockFactory.getBlockWithSpace(false)); block.getDataBlock().getHeader().putInt(BLOCK_TYPE_HEADER_INDEX, blockType.getTypeDef()); IndexBlockEntry entry = new IndexBlockEntry(this, block); entry.requestToken(); memoryRegion.putEntry(block.getPosition(), entry); lockManager.registerBlockUsage(block); return block; } finally { lock.unlock(); blockCreateTimer.stop(); } }
public long calculateMemorySize() { long total = 0; for(CacheRegion<? extends Comparable, ?> region: regionMap.values()) { total += region.memorySize(); } return total; }