001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright notice. All rights reserved.
003: */
004: package com.tc.object.cache;
005:
006: import com.tc.text.PrettyPrinter;
007:
008: import gnu.trove.TLinkedList;
009:
010: import java.util.Collection;
011: import java.util.Collections;
012: import java.util.HashSet;
013:
014: public class ClockEvictionPolicy implements EvictionPolicy {
015:
016: // private static final TCLogger logger = new LossyTCLogger(TCLogging.getLogger(ClockEvictionPolicy.class), 1000);
017:
018: private final TLinkedList cache = new TLinkedList();
019: private final int capacity;
020: private Cacheable hand = null;
021: private final int evictionSize;
022: private Cacheable save;
023:
024: public ClockEvictionPolicy(int size) {
025: this (size, (int) ((size * 0.1)));
026: }
027:
028: public ClockEvictionPolicy(int capacity, int evictionSize) {
029: this .capacity = capacity;
030: this .evictionSize = (evictionSize <= 0 ? 1 : evictionSize);
031: }
032:
033: public synchronized boolean add(Cacheable obj) {
034: if (hand == null) {
035: cache.addLast(obj);
036: } else {
037: cache.addBefore(hand, obj);
038: }
039: markReferenced(obj);
040: return isCacheFull();
041: }
042:
043: private boolean isCacheFull() {
044: if (capacity <= 0 || cache.size() <= capacity) {
045: return false;
046: } else {
047: return true;
048: }
049: }
050:
051: public synchronized Collection getRemovalCandidates(int maxCount) {
052: if (capacity > 0) {
053: if (!isCacheFull())
054: return Collections.EMPTY_LIST;
055: if (maxCount <= 0 || maxCount > evictionSize) {
056: maxCount = evictionSize;
057: }
058: } else if (maxCount <= 0) {
059: // disallow negetative maxCount when capacity is negative
060: throw new AssertionError(
061: "Please specify maxcount > 0 as capacity is set to : "
062: + capacity + " Max Count = " + maxCount);
063: }
064: Collection rv = new HashSet();
065: int count = Math.min(cache.size(), maxCount);
066: while (cache.size() - rv.size() > capacity && count > 0
067: && moveHand()) {
068: rv.add(hand);
069: count--;
070: }
071: erasePosition();
072: return rv;
073: }
074:
075: private void erasePosition() {
076: this .save = null;
077: }
078:
079: private void markPosition() {
080: this .save = this .hand;
081: }
082:
083: public synchronized void remove(Cacheable obj) {
084: if (hand != null && obj == hand) {
085: hand = (Cacheable) hand.getPrevious();
086: }
087: cache.remove(obj);
088: }
089:
090: public void markReferenced(Cacheable obj) {
091: obj.markAccessed();
092: }
093:
094: public PrettyPrinter prettyPrint(PrettyPrinter out) {
095: return null;
096: }
097:
098: private boolean moveHand() {
099: boolean found = false;
100: while (!found) {
101: if (hand == null || hand.getNext() == null) {
102: hand = (Cacheable) cache.getFirst();
103: } else {
104: this .hand = (Cacheable) hand.getNext();
105: }
106: if (hand.recentlyAccessed()) {
107: hand.clearAccessed();
108: } else if (hand.canEvict()) {
109: found = true;
110: break;
111: }
112: if (hand == save) {
113: // logger.info("Cache Evictor : Couldnt find any more ! - cache.size () = " + cache.size());
114: break;
115: }
116: if (save == null) {
117: markPosition();
118: }
119: }
120: return found;
121: }
122:
123: public int getCacheCapacity() {
124: return capacity;
125: }
126: }
|