📄 delaycache.java
字号:
// You can redistribute this software and/or modify it under the terms of// the Ozone Core License version 1 published by ozone-db.org.//// Copyright (C) 2003-@year@, Leo Mekenkamp. All rights reserved.//// $Id: DelayCache.java,v 1.1.2.2 2004/04/10 10:06:51 per_nyfelt Exp $package org.ozoneDB.core.storage;import java.util.Collection;import java.util.Comparator;import java.util.HashMap;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.LinkedHashSet;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Properties;import java.util.Set;import java.util.Map.Entry;import java.util.SortedSet;import java.util.TreeMap;import java.util.TreeSet;import java.util.logging.Level;import java.util.logging.Logger;import org.ozoneDB.OzoneInternalException;import org.ozoneDB.core.ConfigurationException;/** * <p>A cache with a fixed maximum number of objects in it. This cache grows * until it has reached its maximum, which can be set by maxCapacity. Once that * maximum has been reached, the least recently used object is thrown away when * a new object is put in the cache. This cache has, next to that maximum number * of elements, also a maximum time an element will remain in this cache. If * that time has expired the element will be removed from this cache also. * Reinserting an element (using the same key) causes the time for that element * to be reset.</p> * * <p>Note: every instance creates its own thread for asynchronous removal of * items past their 'best before' time. The trimmed() method on the TrimHandler * is often but not always called asynchronously from that thread.</p> * * @author <a href="mailto:leoATmekenkampD0Tcom">Leo Mekenkamp (mind the anti sp@m)</a> * @version $Id: DelayCache.java,v 1.1.2.2 2004/04/10 10:06:51 per_nyfelt Exp $ */public class DelayCache extends AbstractTrimmingCache implements PropertyConfigurable { private static final Logger log = Logger.getLogger(DelayCache.class.getName()); public static final PropertyInfo DELAY = new PropertyInfo( ".delay", "int", "1000", "time (in ms) that an object can stay in this cache before may be thrown out", new String[] {"100", "10000"} ); public static final PropertyInfo MINSLEEPTIME = new PropertyInfo( ".minSleepTime", "int", "100", "time (in ms) that the thread that does the actual removing will wait at least", new String[] {"100", "10000"} ); public static final PropertyInfo INITIALCAPACITY = new PropertyInfo( ".initialCapacity", "int", "1", "number of objects that this cache reserves space for initially", new String[] {"100", "100000"} ); public static final PropertyInfo LOADFACTOR = new PropertyInfo( ".loadFactor", "float, in range <0, 1>", "0.75", "load factor for this cache; see java.util.LinkedHashMap(int initialCapacity, float loadFactor)", new String[] {"0.5", "0.95"} ); private int delay; private int minSleepTime; private Map keysToEntries; private SortedSet entries; private TrimThread trimThread; private volatile long sleepUntil; private volatile long wakingUpAt; public DelayCache(Properties properties, String prefix) { super(properties, prefix); entries = new TreeSet(); try { float loadFactor = Float.parseFloat(properties.getProperty(prefix + LOADFACTOR.getKey(), LOADFACTOR.getDefaultValue())); log.config(getPrefix() + " using a load factory of " + loadFactor); int initialCapacity = Integer.parseInt(properties.getProperty(prefix + INITIALCAPACITY.getKey(), INITIALCAPACITY.getDefaultValue())); log.config(getPrefix() + " using an initial capacity of " + initialCapacity); keysToEntries = new LinkedHashMap(initialCapacity, loadFactor); setDelay(Integer.parseInt(properties.getProperty(getPrefix() + DELAY.getKey(), DELAY.getDefaultValue()))); log.config(getPrefix() + " using a delay of " + getDelay()); setMinSleepTime(Integer.parseInt(properties.getProperty(getPrefix() + MINSLEEPTIME.getKey(), MINSLEEPTIME.getDefaultValue()))); log.config(getPrefix() + " using a minimum sleep time of " + getMinSleepTime()); } catch (NumberFormatException e) { throw new ConfigurationException(e); } trimThread = new TrimThread(); trimThread.start(); } protected final Map getKeysToEntries() { return keysToEntries; } protected final SortedSet getEntries() { return entries; } public Collection getPropertyInfos() { Collection result = new LinkedList(); result.add(INITIALCAPACITY); result.add(DELAY); result.add(LOADFACTOR); result.add(MINSLEEPTIME); return result; } public Object get(Object key) { synchronized(getSynchronizer()) { TimedEntry entry = (TimedEntry) getKeysToEntries().get(key); return entry == null ? null : entry.value; } } public void put(Object key, Object value) { synchronized(getSynchronizer()) { TimedEntry entry = (TimedEntry) getKeysToEntries().get(key); if (entry != null) { getEntries().remove(entry); entry.touch(); } else { entry = new TimedEntry((Comparable) key, value); getKeysToEntries().put(key, entry); } getEntries().add(entry); } } public Object remove(Object key) { synchronized(getSynchronizer()) { TimedEntry entry = (TimedEntry) getKeysToEntries().remove(key); getEntries().remove(entry); return entry == null ? null : entry.value; } } private void trim() { long now = System.currentTimeMillis(); while (size() > 0) { TimedEntry first = (TimedEntry) getEntries().first(); if (now > first.time + getDelay()) {//System.out.println("TRIMMING! " + (first.time + getDelay() - now)); getEntries().remove(first); if (getTrimHandler() != null) { getTrimHandler().trimming(first.key, first.value); } getKeysToEntries().remove(first.key); } else {//System.out.println("LEAVING! " + (first.time + getDelay() - now)); if (first.time + getDelay() > sleepUntil) { sleepUntil = first.time + getDelay(); } else { sleepUntil = 0; } break; } } } public int size() { synchronized(getSynchronizer()) { return getKeysToEntries().size(); } } public Map copyToMap() { synchronized(getSynchronizer()) { HashMap result = new HashMap(size()); for (Iterator i = getEntries().iterator(); i.hasNext(); ) { TimedEntry entry = (TimedEntry) i.next(); result.put(entry.key, entry.value); } return result; } } public final int getDelay() { // delay is an int, so synchronization is not needed return delay; } public final void setDelay(int delay) { synchronized(getSynchronizer()) { this.delay = delay; trim(); } } public final int getMinSleepTime() { // delay is an int, so synchronization is not needed return minSleepTime; } public final void setMinSleepTime(int minSleepTime) { synchronized(getSynchronizer()) { this.minSleepTime = minSleepTime; trim(); } } protected final class TimedEntry implements Comparable { public long time; public Comparable key; public Object value; public TimedEntry(Comparable key, Object value) { this.key = key; this.value = value; touch(); } public int compareTo(Object o) { TimedEntry other = (TimedEntry) o; int result = (int) (time - other.time); return result != 0 ? result : key.compareTo(other.key); } public boolean equals(Object o) { return compareTo(o) == 0; } public void touch() { time = System.currentTimeMillis(); } } private class TrimThread extends Thread { public TrimThread() { super("delayed trimmer"); setDaemon(true); } public void run() { synchronized(getSynchronizer()) { for (;;) { long now = System.currentTimeMillis(); try { getSynchronizer().wait(Math.max(sleepUntil - now, getMinSleepTime())); } catch (InterruptedException ignore) { } trim(); } } } } }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -