001package org.cache2k.impl; 002 003/* 004 * #%L 005 * cache2k core package 006 * %% 007 * Copyright (C) 2000 - 2015 headissue GmbH, Munich 008 * %% 009 * This program is free software: you can redistribute it and/or modify 010 * it under the terms of the GNU General Public License as 011 * published by the Free Software Foundation, either version 3 of the 012 * License, or (at your option) any later version. 013 * 014 * This program is distributed in the hope that it will be useful, 015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 017 * GNU General Public License for more details. 018 * 019 * You should have received a copy of the GNU General Public 020 * License along with this program. If not, see 021 * <http://www.gnu.org/licenses/gpl-3.0.html>. 022 * #L% 023 */ 024 025/** 026 * Straight forward CLOCK implementation. This is probably the simplest 027 * eviction algorithm around. Interestingly it produces good results. 028 * 029 * @author Jens Wilke; created: 2013-12-01 030 */ 031public class ClockCache<K, T> extends LockFreeCache<ClockCache.Entry, K, T> { 032 033 long hits; 034 int runCnt; 035 int scan24hCnt; 036 int scanCnt; 037 int size; 038 039 Entry hand; 040 041 @Override 042 public long getHitCnt() { 043 return hits + sumUpListHits(hand); 044 } 045 046 private int sumUpListHits(Entry e) { 047 if (e == null) { return 0; } 048 int cnt = 0; 049 Entry _head = e; 050 do { 051 cnt += e.hitCnt; 052 e = (Entry) e.prev; 053 } while (e != _head); 054 return cnt; 055 } 056 057 @Override 058 protected void initializeHeapCache() { 059 super.initializeHeapCache(); 060 size = 0; 061 hand = null; 062 } 063 064 @Override 065 protected void removeEntryFromReplacementList(Entry e) { 066 hand = removeFromCyclicList(hand, e); 067 size--; 068 } 069 070 private int getListSize() { 071 return size; 072 } 073 074 @Override 075 protected void recordHit(Entry e) { 076 e.hitCnt++; 077 } 078 079 @Override 080 protected void insertIntoReplacementList(Entry e) { 081 size++; 082 hand = insertIntoTailCyclicList(hand, e); 083 } 084 085 @Override 086 protected Entry newEntry() { 087 return new Entry(); 088 } 089 090 /** 091 * Run to evict an entry. 092 */ 093 @Override 094 protected Entry findEvictionCandidate() { 095 runCnt++; 096 int _scanCnt = 0; 097 098 while (hand.hitCnt > 0) { 099 _scanCnt++; 100 hits += hand.hitCnt; 101 hand.hitCnt = 0; 102 hand = (Entry) hand.next; 103 } 104 if (_scanCnt > size) { 105 scan24hCnt++; 106 } 107 scanCnt += _scanCnt; 108 return hand; 109 } 110 111 @Override 112 protected IntegrityState getIntegrityState() { 113 synchronized (lock) { 114 return super.getIntegrityState() 115 .checkEquals("getListSize() + evictedButInHashCnt == getSize()", getListSize() + evictedButInHashCnt, getLocalSize()) 116 .check("checkCyclicListIntegrity(hand)", checkCyclicListIntegrity(hand)) 117 .checkEquals("getCyclicListEntryCount(hand) == size", getCyclicListEntryCount(hand), size); 118 } 119 } 120 121 @Override 122 protected String getExtraStatistics() { 123 return ", clockRunCnt=" + runCnt + 124 ", scanCnt=" + scanCnt + 125 ", scan24hCnt=" + scan24hCnt; 126 } 127 128 static class Entry<K, T> extends org.cache2k.impl.Entry<Entry, K, T> { 129 130 int hitCnt; 131 132 } 133 134}