001: package ri.cache.eviction;
002:
003: import java.util.ArrayList;
004: import java.util.Collections;
005: import java.util.Comparator;
006: import java.util.HashMap;
007: import java.util.Map;
008:
009: import javax.cache.Cache;
010: import javax.cache.CacheEntry;
011:
012: public class BatchLRUEvictionStrategy<K, V> extends
013: AbstractEvictionStrategy<K, V> {
014:
015: private final int low;
016: private final int timeout;
017:
018: public BatchLRUEvictionStrategy(int lowWaterMark, int idleTimeout) {
019: low = lowWaterMark;
020: timeout = idleTimeout;
021: }
022:
023: public CacheEntry<K, V> createEntry(K key, V value, long ttl) {
024: return new Entry<K, V>(key, value, ttl);
025: }
026:
027: public Map evict(Cache<K, V> c) {
028: ArrayList<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(
029: c.entrySet());
030: Map m = new HashMap();
031:
032: Collections.sort(list, new EntryComparator());
033:
034: // remove all the expired and timed out
035: long now = System.currentTimeMillis();
036: for (int i = list.size(); --i >= 0;) {
037: Entry e = (Entry) list.get(i);
038: if (e.getExpirationTime() > now
039: || e.getLastAccessTime() + timeout < now) {
040: list.remove(i);
041: m.put(e.getKey(), e.getValue());
042: } else {
043: break;
044: }
045: }
046:
047: // remove the rest until we get to our low water mark
048: for (int i = list.size(); --i >= low;) {
049: Entry e = (Entry) list.remove(i);
050: m.put(e.getKey(), e.getValue());
051: }
052:
053: return m;
054: }
055:
056: public class EntryComparator implements Comparator {
057: public int compare(Object o1, Object o2) {
058: Entry e1 = (Entry) o1;
059: Entry e2 = (Entry) o2;
060:
061: // worst is expired
062: long now = System.currentTimeMillis();
063: if (e1.getExpirationTime() > now
064: && e2.getExpirationTime() <= now)
065: return -1;
066: if (e2.getExpirationTime() > now
067: && e1.getExpirationTime() <= now)
068: return 1;
069: if (e1.getExpirationTime() > now
070: && e2.getExpirationTime() > now)
071: return 0;
072:
073: // next worse is idle timeout
074: long idleTime = now - timeout;
075: if (e1.getLastAccessTime() > idleTime
076: && e2.getLastAccessTime() <= idleTime)
077: return -1;
078: if (e2.getLastAccessTime() > idleTime
079: && e1.getLastAccessTime() <= idleTime)
080: return 1;
081: if (e1.getLastAccessTime() > idleTime
082: && e2.getLastAccessTime() > idleTime)
083: return 0;
084:
085: // only then actually sort
086: long diff = e2.getLastAccessTime() - e1.getLastAccessTime();
087: if (diff > 0)
088: return 1;
089: if (diff < 0)
090: return -1;
091: return 0;
092: }
093: }
094:
095: private static class Entry<K, V> extends AbstractCacheEntry<K, V> {
096: public Entry(K key, V value, long ttl) {
097: super (key, value, ttl);
098: }
099:
100: public void discard() {
101: }
102: }
103:
104: }
|