package org.wonderdb.cache.impl; /******************************************************************************* * Copyright 2013 Vilas Athavale * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *******************************************************************************/ import java.util.List; import org.apache.log4j.Logger; import org.wonderdb.cache.Cacheable; public class CacheEvictor<Key, Data> implements Runnable { boolean finish = false; CacheBean cacheBean = null; CacheState cacheState = null; CacheLock cacheLock = null; boolean eagerCleanup = true; CacheEntryPinner pinner = CacheEntryPinner.getInstance(); MemoryCacheMap<Key, Data> cacheMap = null; CacheHandler<Key, Data> cacheHandler = null; public CacheEvictor(boolean eagerCleanup, CacheBean cacheBean, CacheState cacheState, CacheLock cacheLock, MemoryCacheMap<Key, Data> cacheMap, CacheHandler<Key, Data> cacheHandler) { this.eagerCleanup = eagerCleanup; this.cacheBean = cacheBean; this.cacheState = cacheState; this.cacheLock = cacheLock; this.cacheMap = cacheMap; this.cacheHandler = cacheHandler; } public void finish() { finish = true; cacheLock.notifyStartCleanup(); cacheLock.notifyEagerCleanup(); } public void run() { long lastRunTime = Long.MAX_VALUE; int size = cacheMap.listSize; long objCountAfterRun = cacheBean.getCleanupLowWaterMark(); if (eagerCleanup) { objCountAfterRun = cacheBean.getCleanupHighWaterMark(); } int bucket = 0; while (true) { if (finish) { return; } if (eagerCleanup) { cacheLock.waitOnEagerCleanup(); } else { cacheLock.waitOnStartCleanup(); } if (finish) { Logger.getLogger(getClass()).info("ending cleanup thread"); return; } if (cacheState.getTotalCount() <= objCountAfterRun) { continue; } while (true) { List<Cacheable<Key, Data>> list = cacheMap.getBucket(bucket, true); // Set<Object> pinnedBlocks = new HashSet<>(); try { for (int j = 0; j < list.size(); j++) { Cacheable<Key, Data> e = list.get(j); if (!pinner.isPinned(e.getPtr()) && !cacheMap.isChanged(e.getPtr())) { // CacheEntryPinner.getInstance().pin(e.getPtr(), pinnedBlocks); if (eagerCleanup) { Cacheable<Key, Data> ref = cacheHandler.removeForEvict(e.getPtr()); // if (pinner.isPinned(e.getPtr()) || cacheMap.isChanged(e.getPtr())) { // cacheMap.addIfAbsent(ref); // } } else { if (e.getLastAccessTime() < lastRunTime) { Cacheable<Key, Data> ref = cacheHandler.removeForEvict(e.getPtr()); // if (pinner.isPinned(e.getPtr()) || cacheMap.isChanged(e.getPtr())) { // cacheMap.addIfAbsent(ref); // } } } } } } finally { cacheMap.returnBucket(bucket, true); bucket = ++bucket % size; // CacheEntryPinner.getInstance().unpin(pinnedBlocks, pinnedBlocks); } if (cacheState.getTotalCount() <= objCountAfterRun) { break; } lastRunTime = System.currentTimeMillis(); } } } }