package org.cache2k.benchmark.impl2015; /* * #%L * Benchmarks: implementation variants * %% * Copyright (C) 2013 - 2017 headissue GmbH, Munich * %% * 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. * #L% */ /** * Straight forward CLOCK implementation. This is probably the simplest * eviction algorithm around. Interestingly it produces good results. * * @author Jens Wilke; created: 2013-12-01 */ public class ClockCache<K, T> extends LockFreeCache<ClockCache.Entry, K, T> { long hits; int runCnt; int scan24hCnt; int scanCnt; int size; Entry hand; @Override public long getHitCnt() { return hits + sumUpListHits(hand); } private int sumUpListHits(Entry e) { if (e == null) { return 0; } int cnt = 0; Entry _head = e; do { cnt += e.hitCnt; e = (Entry) e.prev; } while (e != _head); return cnt; } @Override protected void initializeHeapCache() { super.initializeHeapCache(); size = 0; hand = null; } @Override protected void iterateAllEntriesRemoveAndCancelTimer() { Entry e, _head; int _count = 0; e = _head = hand; long _hits = 0; if (e != null) { do { _hits += e.hitCnt; e.removedFromList(); cancelExpiryTimer(e); _count++; e = (Entry) e.prev; } while (e != _head); hits += _hits; } } @Override protected void removeEntryFromReplacementList(Entry e) { hand = removeFromCyclicList(hand, e); hits += e.hitCnt; size--; } private int getListSize() { return size; } @Override protected void recordHit(Entry e) { e.hitCnt++; } @Override protected void insertIntoReplacementList(Entry e) { size++; hand = insertIntoTailCyclicList(hand, e); } @Override protected Entry newEntry() { return new Entry(); } /** * Run to evict an entry. */ @Override protected Entry findEvictionCandidate() { runCnt++; int _scanCnt = 0; while (hand.hitCnt > 0) { _scanCnt++; hits += hand.hitCnt; hand.hitCnt = 0; hand = (Entry) hand.next; } if (_scanCnt > size) { scan24hCnt++; } scanCnt += _scanCnt; return hand; } @Override protected IntegrityState getIntegrityState() { synchronized (lock) { return super.getIntegrityState() .checkEquals("getListSize() + evictedButInHashCnt == getSize()", getListSize() + evictedButInHashCnt, getLocalSize()) .check("checkCyclicListIntegrity(hand)", checkCyclicListIntegrity(hand)) .checkEquals("getCyclicListEntryCount(hand) == size", getCyclicListEntryCount(hand), size); } } @Override protected String getExtraStatistics() { return ", clockRunCnt=" + runCnt + ", scanCnt=" + scanCnt + ", scan24hCnt=" + scan24hCnt; } static class Entry<K, T> extends org.cache2k.benchmark.impl2015.Entry<Entry, K, T> { int hitCnt; } }