You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by er...@apache.org on 2012/01/12 22:18:50 UTC

svn commit: r1230790 [1/2] - in /lucene/dev/trunk/solr/core/src: java/org/apache/solr/search/LFUCache.java java/org/apache/solr/util/ConcurrentLFUCache.java test-files/solr/conf/solrconfig-caching.xml test/org/apache/solr/search/TestLFUCache.java

Author: erick
Date: Thu Jan 12 21:18:50 2012
New Revision: 1230790

URL: http://svn.apache.org/viewvc?rev=1230790&view=rev
Log:
Fixing up where I messed up on previous checkin for SOLR-2906

Modified:
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/LFUCache.java
    lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/ConcurrentLFUCache.java
    lucene/dev/trunk/solr/core/src/test-files/solr/conf/solrconfig-caching.xml
    lucene/dev/trunk/solr/core/src/test/org/apache/solr/search/TestLFUCache.java

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/LFUCache.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/LFUCache.java?rev=1230790&r1=1230789&r2=1230790&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/LFUCache.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/search/LFUCache.java Thu Jan 12 21:18:50 2012
@@ -288,592 +288,3 @@ public class LFUCache<K, V> implements S
     return name + getStatistics().toString();
   }
 }
-
-
-
-package org.apache.solr.search;
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.util.ConcurrentLFUCache;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * SolrCache based on ConcurrentLFUCache implementation.
- * <p/>
- * This implementation does not use a separate cleanup thread. Instead it uses the calling thread
- * itself to do the cleanup when the size of the cache exceeds certain limits.
- * <p/>
- * Also see <a href="http://wiki.apache.org/solr/SolrCaching">SolrCaching</a>
- * <p/>
- * <b>This API is experimental and subject to change</b>
- *
- * @version $Id: LFUCache.java 1170772 2011-09-14 19:09:56Z sarowe $
- * @see org.apache.solr.util.ConcurrentLFUCache
- * @see org.apache.solr.search.SolrCache
- * @since solr 3.6
- */
-public class LFUCache<K, V> implements SolrCache<K, V> {
-
-  // contains the statistics objects for all open caches of the same type
-  private List<ConcurrentLFUCache.Stats> statsList;
-
-  private long warmupTime = 0;
-
-  private String name;
-  private int autowarmCount;
-  private State state;
-  private CacheRegenerator regenerator;
-  private String description = "Concurrent LFU Cache";
-  private ConcurrentLFUCache<K, V> cache;
-  private int showItems = 0;
-  private Boolean timeDecay = true;
-
-  public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
-    state = State.CREATED;
-    this.regenerator = regenerator;
-    name = (String) args.get("name");
-    String str = (String) args.get("size");
-    int limit = str == null ? 1024 : Integer.parseInt(str);
-    int minLimit;
-    str = (String) args.get("minSize");
-    if (str == null) {
-      minLimit = (int) (limit * 0.9);
-    } else {
-      minLimit = Integer.parseInt(str);
-    }
-    if (minLimit == 0) minLimit = 1;
-    if (limit <= minLimit) limit = minLimit + 1;
-
-    int acceptableSize;
-    str = (String) args.get("acceptableSize");
-    if (str == null) {
-      acceptableSize = (int) (limit * 0.95);
-    } else {
-      acceptableSize = Integer.parseInt(str);
-    }
-    // acceptable limit should be somewhere between minLimit and limit
-    acceptableSize = Math.max(minLimit, acceptableSize);
-
-    str = (String) args.get("initialSize");
-    final int initialSize = str == null ? limit : Integer.parseInt(str);
-    str = (String) args.get("autowarmCount");
-    autowarmCount = str == null ? 0 : Integer.parseInt(str);
-    str = (String) args.get("cleanupThread");
-    boolean newThread = str == null ? false : Boolean.parseBoolean(str);
-
-    str = (String) args.get("showItems");
-    showItems = str == null ? 0 : Integer.parseInt(str);
-
-    // Don't make this "efficient" by removing the test, default is true and omitting the param will make it false.
-    str = (String) args.get("timeDecay");
-    timeDecay = (str == null) ? true : Boolean.parseBoolean(str);
-
-    description = "Concurrent LFU Cache(maxSize=" + limit + ", initialSize=" + initialSize +
-        ", minSize=" + minLimit + ", acceptableSize=" + acceptableSize + ", cleanupThread=" + newThread +
-        ", timeDecay=" + Boolean.toString(timeDecay);
-    if (autowarmCount > 0) {
-      description += ", autowarmCount=" + autowarmCount + ", regenerator=" + regenerator;
-    }
-    description += ')';
-
-    cache = new ConcurrentLFUCache<K, V>(limit, minLimit, acceptableSize, initialSize, newThread, false, null, timeDecay);
-    cache.setAlive(false);
-
-    statsList = (List<ConcurrentLFUCache.Stats>) persistence;
-    if (statsList == null) {
-      // must be the first time a cache of this type is being created
-      // Use a CopyOnWriteArrayList since puts are very rare and iteration may be a frequent operation
-      // because it is used in getStatistics()
-      statsList = new CopyOnWriteArrayList<ConcurrentLFUCache.Stats>();
-
-      // the first entry will be for cumulative stats of caches that have been closed.
-      statsList.add(new ConcurrentLFUCache.Stats());
-    }
-    statsList.add(cache.getStats());
-    return statsList;
-  }
-
-  public String name() {
-    return name;
-  }
-
-  public int size() {
-    return cache.size();
-
-  }
-
-  public V put(K key, V value) {
-    return cache.put(key, value);
-  }
-
-  public V get(K key) {
-    return cache.get(key);
-  }
-
-  public void clear() {
-    cache.clear();
-  }
-
-  public void setState(State state) {
-    this.state = state;
-    cache.setAlive(state == State.LIVE);
-  }
-
-  public State getState() {
-    return state;
-  }
-
-  public void warm(SolrIndexSearcher searcher, SolrCache old) throws IOException {
-    if (regenerator == null) return;
-    long warmingStartTime = System.currentTimeMillis();
-    LFUCache other = (LFUCache) old;
-    // warm entries
-    if (autowarmCount != 0) {
-      int sz = other.size();
-      if (autowarmCount != -1) sz = Math.min(sz, autowarmCount);
-      Map items = other.cache.getMostUsedItems(sz);
-      Map.Entry[] itemsArr = new Map.Entry[items.size()];
-      int counter = 0;
-      for (Object mapEntry : items.entrySet()) {
-        itemsArr[counter++] = (Map.Entry) mapEntry;
-      }
-      for (int i = itemsArr.length - 1; i >= 0; i--) {
-        try {
-          boolean continueRegen = regenerator.regenerateItem(searcher,
-              this, old, itemsArr[i].getKey(), itemsArr[i].getValue());
-          if (!continueRegen) break;
-        } catch (Throwable e) {
-          SolrException.log(log, "Error during auto-warming of key:" + itemsArr[i].getKey(), e);
-        }
-      }
-    }
-    warmupTime = System.currentTimeMillis() - warmingStartTime;
-  }
-
-
-  public void close() {
-    // add the stats to the cumulative stats object (the first in the statsList)
-    statsList.get(0).add(cache.getStats());
-    statsList.remove(cache.getStats());
-    cache.destroy();
-  }
-
-  //////////////////////// SolrInfoMBeans methods //////////////////////
-  public String getName() {
-    return LFUCache.class.getName();
-  }
-
-  public String getVersion() {
-    return SolrCore.version;
-  }
-
-  public String getDescription() {
-    return description;
-  }
-
-  public Category getCategory() {
-    return Category.CACHE;
-  }
-
-  public String getSourceId() {
-    return "$Id: LFUCache.java 1170772 2011-09-14 19:09:56Z sarowe $";
-  }
-
-  public String getSource() {
-    return "$URL: http://svn.apache.org/repos/asf/lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/search/LFUCache.java $";
-  }
-
-  public URL[] getDocs() {
-    return null;
-  }
-
-  // returns a ratio, not a percent.
-  private static String calcHitRatio(long lookups, long hits) {
-    if (lookups == 0) return "0.00";
-    if (lookups == hits) return "1.00";
-    int hundredths = (int) (hits * 100 / lookups);   // rounded down
-    if (hundredths < 10) return "0.0" + hundredths;
-    return "0." + hundredths;
-  }
-
-  public NamedList getStatistics() {
-    NamedList<Serializable> lst = new SimpleOrderedMap<Serializable>();
-    if (cache == null) return lst;
-    ConcurrentLFUCache.Stats stats = cache.getStats();
-    long lookups = stats.getCumulativeLookups();
-    long hits = stats.getCumulativeHits();
-    long inserts = stats.getCumulativePuts();
-    long evictions = stats.getCumulativeEvictions();
-    long size = stats.getCurrentSize();
-
-    lst.add("lookups", lookups);
-    lst.add("hits", hits);
-    lst.add("hitratio", calcHitRatio(lookups, hits));
-    lst.add("inserts", inserts);
-    lst.add("evictions", evictions);
-    lst.add("size", size);
-
-    lst.add("warmupTime", warmupTime);
-    lst.add("timeDecay", timeDecay);
-
-    long clookups = 0;
-    long chits = 0;
-    long cinserts = 0;
-    long cevictions = 0;
-
-    // NOTE: It is safe to iterate on a CopyOnWriteArrayList
-    for (ConcurrentLFUCache.Stats statistiscs : statsList) {
-      clookups += statistiscs.getCumulativeLookups();
-      chits += statistiscs.getCumulativeHits();
-      cinserts += statistiscs.getCumulativePuts();
-      cevictions += statistiscs.getCumulativeEvictions();
-    }
-    lst.add("cumulative_lookups", clookups);
-    lst.add("cumulative_hits", chits);
-    lst.add("cumulative_hitratio", calcHitRatio(clookups, chits));
-    lst.add("cumulative_inserts", cinserts);
-    lst.add("cumulative_evictions", cevictions);
-
-    if (showItems != 0) {
-      Map items = cache.getMostUsedItems(showItems == -1 ? Integer.MAX_VALUE : showItems);
-      for (Map.Entry e : (Set<Map.Entry>) items.entrySet()) {
-        Object k = e.getKey();
-        Object v = e.getValue();
-
-        String ks = "item_" + k;
-        String vs = v.toString();
-        lst.add(ks, vs);
-      }
-
-    }
-
-    return lst;
-  }
-
-  @Override
-  public String toString() {
-    return name + getStatistics().toString();
-  }
-}
-
-
-
-package org.apache.solr.search;
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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.
- */
-
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.util.NamedList;
-import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.util.ConcurrentLFUCache;
-
-import java.io.IOException;
-import java.io.Serializable;
-import java.net.URL;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * SolrCache based on ConcurrentLFUCache implementation.
- * <p/>
- * This implementation does not use a separate cleanup thread. Instead it uses the calling thread
- * itself to do the cleanup when the size of the cache exceeds certain limits.
- * <p/>
- * Also see <a href="http://wiki.apache.org/solr/SolrCaching">SolrCaching</a>
- * <p/>
- * <b>This API is experimental and subject to change</b>
- *
- * @version $Id: LFUCache.java 1170772 2011-09-14 19:09:56Z sarowe $
- * @see org.apache.solr.util.ConcurrentLFUCache
- * @see org.apache.solr.search.SolrCache
- * @since solr 3.6
- */
-public class LFUCache<K, V> implements SolrCache<K, V> {
-
-  // contains the statistics objects for all open caches of the same type
-  private List<ConcurrentLFUCache.Stats> statsList;
-
-  private long warmupTime = 0;
-
-  private String name;
-  private int autowarmCount;
-  private State state;
-  private CacheRegenerator regenerator;
-  private String description = "Concurrent LFU Cache";
-  private ConcurrentLFUCache<K, V> cache;
-  private int showItems = 0;
-  private Boolean timeDecay = true;
-
-  public Object init(Map args, Object persistence, CacheRegenerator regenerator) {
-    state = State.CREATED;
-    this.regenerator = regenerator;
-    name = (String) args.get("name");
-    String str = (String) args.get("size");
-    int limit = str == null ? 1024 : Integer.parseInt(str);
-    int minLimit;
-    str = (String) args.get("minSize");
-    if (str == null) {
-      minLimit = (int) (limit * 0.9);
-    } else {
-      minLimit = Integer.parseInt(str);
-    }
-    if (minLimit == 0) minLimit = 1;
-    if (limit <= minLimit) limit = minLimit + 1;
-
-    int acceptableSize;
-    str = (String) args.get("acceptableSize");
-    if (str == null) {
-      acceptableSize = (int) (limit * 0.95);
-    } else {
-      acceptableSize = Integer.parseInt(str);
-    }
-    // acceptable limit should be somewhere between minLimit and limit
-    acceptableSize = Math.max(minLimit, acceptableSize);
-
-    str = (String) args.get("initialSize");
-    final int initialSize = str == null ? limit : Integer.parseInt(str);
-    str = (String) args.get("autowarmCount");
-    autowarmCount = str == null ? 0 : Integer.parseInt(str);
-    str = (String) args.get("cleanupThread");
-    boolean newThread = str == null ? false : Boolean.parseBoolean(str);
-
-    str = (String) args.get("showItems");
-    showItems = str == null ? 0 : Integer.parseInt(str);
-
-    // Don't make this "efficient" by removing the test, default is true and omitting the param will make it false.
-    str = (String) args.get("timeDecay");
-    timeDecay = (str == null) ? true : Boolean.parseBoolean(str);
-
-    description = "Concurrent LFU Cache(maxSize=" + limit + ", initialSize=" + initialSize +
-        ", minSize=" + minLimit + ", acceptableSize=" + acceptableSize + ", cleanupThread=" + newThread +
-        ", timeDecay=" + Boolean.toString(timeDecay);
-    if (autowarmCount > 0) {
-      description += ", autowarmCount=" + autowarmCount + ", regenerator=" + regenerator;
-    }
-    description += ')';
-
-    cache = new ConcurrentLFUCache<K, V>(limit, minLimit, acceptableSize, initialSize, newThread, false, null, timeDecay);
-    cache.setAlive(false);
-
-    statsList = (List<ConcurrentLFUCache.Stats>) persistence;
-    if (statsList == null) {
-      // must be the first time a cache of this type is being created
-      // Use a CopyOnWriteArrayList since puts are very rare and iteration may be a frequent operation
-      // because it is used in getStatistics()
-      statsList = new CopyOnWriteArrayList<ConcurrentLFUCache.Stats>();
-
-      // the first entry will be for cumulative stats of caches that have been closed.
-      statsList.add(new ConcurrentLFUCache.Stats());
-    }
-    statsList.add(cache.getStats());
-    return statsList;
-  }
-
-  public String name() {
-    return name;
-  }
-
-  public int size() {
-    return cache.size();
-
-  }
-
-  public V put(K key, V value) {
-    return cache.put(key, value);
-  }
-
-  public V get(K key) {
-    return cache.get(key);
-  }
-
-  public void clear() {
-    cache.clear();
-  }
-
-  public void setState(State state) {
-    this.state = state;
-    cache.setAlive(state == State.LIVE);
-  }
-
-  public State getState() {
-    return state;
-  }
-
-  public void warm(SolrIndexSearcher searcher, SolrCache old) throws IOException {
-    if (regenerator == null) return;
-    long warmingStartTime = System.currentTimeMillis();
-    LFUCache other = (LFUCache) old;
-    // warm entries
-    if (autowarmCount != 0) {
-      int sz = other.size();
-      if (autowarmCount != -1) sz = Math.min(sz, autowarmCount);
-      Map items = other.cache.getMostUsedItems(sz);
-      Map.Entry[] itemsArr = new Map.Entry[items.size()];
-      int counter = 0;
-      for (Object mapEntry : items.entrySet()) {
-        itemsArr[counter++] = (Map.Entry) mapEntry;
-      }
-      for (int i = itemsArr.length - 1; i >= 0; i--) {
-        try {
-          boolean continueRegen = regenerator.regenerateItem(searcher,
-              this, old, itemsArr[i].getKey(), itemsArr[i].getValue());
-          if (!continueRegen) break;
-        } catch (Throwable e) {
-          SolrException.log(log, "Error during auto-warming of key:" + itemsArr[i].getKey(), e);
-        }
-      }
-    }
-    warmupTime = System.currentTimeMillis() - warmingStartTime;
-  }
-
-
-  public void close() {
-    // add the stats to the cumulative stats object (the first in the statsList)
-    statsList.get(0).add(cache.getStats());
-    statsList.remove(cache.getStats());
-    cache.destroy();
-  }
-
-  //////////////////////// SolrInfoMBeans methods //////////////////////
-  public String getName() {
-    return LFUCache.class.getName();
-  }
-
-  public String getVersion() {
-    return SolrCore.version;
-  }
-
-  public String getDescription() {
-    return description;
-  }
-
-  public Category getCategory() {
-    return Category.CACHE;
-  }
-
-  public String getSourceId() {
-    return "$Id: LFUCache.java 1170772 2011-09-14 19:09:56Z sarowe $";
-  }
-
-  public String getSource() {
-    return "$URL: http://svn.apache.org/repos/asf/lucene/dev/branches/branch_3x/solr/core/src/java/org/apache/solr/search/LFUCache.java $";
-  }
-
-  public URL[] getDocs() {
-    return null;
-  }
-
-  // returns a ratio, not a percent.
-  private static String calcHitRatio(long lookups, long hits) {
-    if (lookups == 0) return "0.00";
-    if (lookups == hits) return "1.00";
-    int hundredths = (int) (hits * 100 / lookups);   // rounded down
-    if (hundredths < 10) return "0.0" + hundredths;
-    return "0." + hundredths;
-  }
-
-  public NamedList getStatistics() {
-    NamedList<Serializable> lst = new SimpleOrderedMap<Serializable>();
-    if (cache == null) return lst;
-    ConcurrentLFUCache.Stats stats = cache.getStats();
-    long lookups = stats.getCumulativeLookups();
-    long hits = stats.getCumulativeHits();
-    long inserts = stats.getCumulativePuts();
-    long evictions = stats.getCumulativeEvictions();
-    long size = stats.getCurrentSize();
-
-    lst.add("lookups", lookups);
-    lst.add("hits", hits);
-    lst.add("hitratio", calcHitRatio(lookups, hits));
-    lst.add("inserts", inserts);
-    lst.add("evictions", evictions);
-    lst.add("size", size);
-
-    lst.add("warmupTime", warmupTime);
-    lst.add("timeDecay", timeDecay);
-
-    long clookups = 0;
-    long chits = 0;
-    long cinserts = 0;
-    long cevictions = 0;
-
-    // NOTE: It is safe to iterate on a CopyOnWriteArrayList
-    for (ConcurrentLFUCache.Stats statistiscs : statsList) {
-      clookups += statistiscs.getCumulativeLookups();
-      chits += statistiscs.getCumulativeHits();
-      cinserts += statistiscs.getCumulativePuts();
-      cevictions += statistiscs.getCumulativeEvictions();
-    }
-    lst.add("cumulative_lookups", clookups);
-    lst.add("cumulative_hits", chits);
-    lst.add("cumulative_hitratio", calcHitRatio(clookups, chits));
-    lst.add("cumulative_inserts", cinserts);
-    lst.add("cumulative_evictions", cevictions);
-
-    if (showItems != 0) {
-      Map items = cache.getMostUsedItems(showItems == -1 ? Integer.MAX_VALUE : showItems);
-      for (Map.Entry e : (Set<Map.Entry>) items.entrySet()) {
-        Object k = e.getKey();
-        Object v = e.getValue();
-
-        String ks = "item_" + k;
-        String vs = v.toString();
-        lst.add(ks, vs);
-      }
-
-    }
-
-    return lst;
-  }
-
-  @Override
-  public String toString() {
-    return name + getStatistics().toString();
-  }
-}
-
-
-

Modified: lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/ConcurrentLFUCache.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/ConcurrentLFUCache.java?rev=1230790&r1=1230789&r2=1230790&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/ConcurrentLFUCache.java (original)
+++ lucene/dev/trunk/solr/core/src/java/org/apache/solr/util/ConcurrentLFUCache.java Thu Jan 12 21:18:50 2012
@@ -473,953 +473,3 @@ public class ConcurrentLFUCache<K, V> {
     }
   }
 }
-package org.apache.solr.util;
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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
- * 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.
- */
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.ref.WeakReference;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * A LFU cache implementation based upon ConcurrentHashMap.
- * <p/>
- * This is not a terribly efficient implementation.  The tricks used in the
- * LRU version were not directly usable, perhaps it might be possible to
- * rewrite them with LFU in mind.
- * <p/>
- * <b>This API is experimental and subject to change</b>
- *
- * @version $Id: ConcurrentLFUCache.java 1170772 2011-09-14 19:09:56Z sarowe $
- * @since solr 1.6
- */
-public class ConcurrentLFUCache<K, V> {
-  private static Logger log = LoggerFactory.getLogger(ConcurrentLFUCache.class);
-
-  private final ConcurrentHashMap<Object, CacheEntry<K, V>> map;
-  private final int upperWaterMark, lowerWaterMark;
-  private final ReentrantLock markAndSweepLock = new ReentrantLock(true);
-  private boolean isCleaning = false;  // not volatile... piggybacked on other volatile vars
-  private final boolean newThreadForCleanup;
-  private volatile boolean islive = true;
-  private final Stats stats = new Stats();
-  private final int acceptableWaterMark;
-  private long lowHitCount = 0;  // not volatile, only accessed in the cleaning method
-  private final EvictionListener<K, V> evictionListener;
-  private CleanupThread cleanupThread;
-  private final boolean timeDecay;
-
-  public ConcurrentLFUCache(int upperWaterMark, final int lowerWaterMark, int acceptableSize,
-                            int initialSize, boolean runCleanupThread, boolean runNewThreadForCleanup,
-                            EvictionListener<K, V> evictionListener, boolean timeDecay) {
-    if (upperWaterMark < 1) throw new IllegalArgumentException("upperWaterMark must be > 0");
-    if (lowerWaterMark >= upperWaterMark)
-      throw new IllegalArgumentException("lowerWaterMark must be  < upperWaterMark");
-    map = new ConcurrentHashMap<Object, CacheEntry<K, V>>(initialSize);
-    newThreadForCleanup = runNewThreadForCleanup;
-    this.upperWaterMark = upperWaterMark;
-    this.lowerWaterMark = lowerWaterMark;
-    this.acceptableWaterMark = acceptableSize;
-    this.evictionListener = evictionListener;
-    this.timeDecay = timeDecay;
-    if (runCleanupThread) {
-      cleanupThread = new CleanupThread(this);
-      cleanupThread.start();
-    }
-  }
-
-  public ConcurrentLFUCache(int size, int lowerWatermark) {
-    this(size, lowerWatermark, (int) Math.floor((lowerWatermark + size) / 2),
-        (int) Math.ceil(0.75 * size), false, false, null, true);
-  }
-
-  public void setAlive(boolean live) {
-    islive = live;
-  }
-
-  public V get(K key) {
-    CacheEntry<K, V> e = map.get(key);
-    if (e == null) {
-      if (islive) stats.missCounter.incrementAndGet();
-      return null;
-    }
-    if (islive) {
-      e.lastAccessed = stats.accessCounter.incrementAndGet();
-      e.hits.incrementAndGet();
-    }
-    return e.value;
-  }
-
-  public V remove(K key) {
-    CacheEntry<K, V> cacheEntry = map.remove(key);
-    if (cacheEntry != null) {
-      stats.size.decrementAndGet();
-      return cacheEntry.value;
-    }
-    return null;
-  }
-
-  public V put(K key, V val) {
-    if (val == null) return null;
-    CacheEntry<K, V> e = new CacheEntry<K, V>(key, val, stats.accessCounter.incrementAndGet());
-    CacheEntry<K, V> oldCacheEntry = map.put(key, e);
-    int currentSize;
-    if (oldCacheEntry == null) {
-      currentSize = stats.size.incrementAndGet();
-    } else {
-      currentSize = stats.size.get();
-    }
-    if (islive) {
-      stats.putCounter.incrementAndGet();
-    } else {
-      stats.nonLivePutCounter.incrementAndGet();
-    }
-
-    // Check if we need to clear out old entries from the cache.
-    // isCleaning variable is checked instead of markAndSweepLock.isLocked()
-    // for performance because every put invokation will check until
-    // the size is back to an acceptable level.
-    //
-    // There is a race between the check and the call to markAndSweep, but
-    // it's unimportant because markAndSweep actually aquires the lock or returns if it can't.
-    //
-    // Thread safety note: isCleaning read is piggybacked (comes after) other volatile reads
-    // in this method.
-    if (currentSize > upperWaterMark && !isCleaning) {
-      if (newThreadForCleanup) {
-        new Thread() {
-          @Override
-          public void run() {
-            markAndSweep();
-          }
-        }.start();
-      } else if (cleanupThread != null) {
-        cleanupThread.wakeThread();
-      } else {
-        markAndSweep();
-      }
-    }
-    return oldCacheEntry == null ? null : oldCacheEntry.value;
-  }
-
-  /**
-   * Removes items from the cache to bring the size down
-   * to an acceptable value ('acceptableWaterMark').
-   * <p/>
-   * It is done in two stages. In the first stage, least recently used items are evicted.
-   * If, after the first stage, the cache size is still greater than 'acceptableSize'
-   * config parameter, the second stage takes over.
-   * <p/>
-   * The second stage is more intensive and tries to bring down the cache size
-   * to the 'lowerWaterMark' config parameter.
-   */
-  private void markAndSweep() {
-    if (!markAndSweepLock.tryLock()) return;
-    try {
-      long lowHitCount = this.lowHitCount;
-      isCleaning = true;
-      this.lowHitCount = lowHitCount;     // volatile write to make isCleaning visible
-
-      int sz = stats.size.get();
-
-      int wantToRemove = sz - lowerWaterMark;
-
-      TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
-
-      for (CacheEntry<K, V> ce : map.values()) {
-        // set hitsCopy to avoid later Atomic reads
-        ce.hitsCopy = ce.hits.get();
-        ce.lastAccessedCopy = ce.lastAccessed;
-        if (timeDecay) {
-          ce.hits.set(ce.hitsCopy >>> 1);
-        }
-
-        if (tree.size() < wantToRemove) {
-          tree.add(ce);
-        } else {
-          // If the hits are not equal, we can remove before adding
-          // which is slightly faster
-          if (ce.hitsCopy < tree.first().hitsCopy) {
-            tree.remove(tree.first());
-            tree.add(ce);
-          } else if (ce.hitsCopy == tree.first().hitsCopy) {
-            tree.add(ce);
-            tree.remove(tree.first());
-          }
-        }
-      }
-
-      for (CacheEntry<K, V> e : tree) {
-        evictEntry(e.key);
-      }
-    } finally {
-      isCleaning = false;  // set before markAndSweep.unlock() for visibility
-      markAndSweepLock.unlock();
-    }
-  }
-
-  private void evictEntry(K key) {
-    CacheEntry<K, V> o = map.remove(key);
-    if (o == null) return;
-    stats.size.decrementAndGet();
-    stats.evictionCounter.incrementAndGet();
-    if (evictionListener != null) evictionListener.evictedEntry(o.key, o.value);
-  }
-
-  /**
-   * Returns 'n' number of least used entries present in this cache.
-   * <p/>
-   * This uses a TreeSet to collect the 'n' least used items ordered by ascending hitcount
-   * and returns a LinkedHashMap containing 'n' or less than 'n' entries.
-   *
-   * @param n the number of items needed
-   * @return a LinkedHashMap containing 'n' or less than 'n' entries
-   */
-  public Map<K, V> getLeastUsedItems(int n) {
-    Map<K, V> result = new LinkedHashMap<K, V>();
-    if (n <= 0)
-      return result;
-    TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
-    // we need to grab the lock since we are changing the copy variables
-    markAndSweepLock.lock();
-    try {
-      for (Map.Entry<Object, CacheEntry<K, V>> entry : map.entrySet()) {
-        CacheEntry ce = entry.getValue();
-        ce.hitsCopy = ce.hits.get();
-        ce.lastAccessedCopy = ce.lastAccessed;
-        if (tree.size() < n) {
-          tree.add(ce);
-        } else {
-          // If the hits are not equal, we can remove before adding
-          // which is slightly faster
-          if (ce.hitsCopy < tree.first().hitsCopy) {
-            tree.remove(tree.first());
-            tree.add(ce);
-          } else if (ce.hitsCopy == tree.first().hitsCopy) {
-            tree.add(ce);
-            tree.remove(tree.first());
-          }
-        }
-      }
-    } finally {
-      markAndSweepLock.unlock();
-    }
-    for (CacheEntry<K, V> e : tree) {
-      result.put(e.key, e.value);
-    }
-    return result;
-  }
-
-  /**
-   * Returns 'n' number of most used entries present in this cache.
-   * <p/>
-   * This uses a TreeSet to collect the 'n' most used items ordered by descending hitcount
-   * and returns a LinkedHashMap containing 'n' or less than 'n' entries.
-   *
-   * @param n the number of items needed
-   * @return a LinkedHashMap containing 'n' or less than 'n' entries
-   */
-  public Map<K, V> getMostUsedItems(int n) {
-    Map<K, V> result = new LinkedHashMap<K, V>();
-    if (n <= 0)
-      return result;
-    TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
-    // we need to grab the lock since we are changing the copy variables
-    markAndSweepLock.lock();
-    try {
-      for (Map.Entry<Object, CacheEntry<K, V>> entry : map.entrySet()) {
-        CacheEntry<K, V> ce = entry.getValue();
-        ce.hitsCopy = ce.hits.get();
-        ce.lastAccessedCopy = ce.lastAccessed;
-        if (tree.size() < n) {
-          tree.add(ce);
-        } else {
-          // If the hits are not equal, we can remove before adding
-          // which is slightly faster
-          if (ce.hitsCopy > tree.last().hitsCopy) {
-            tree.remove(tree.last());
-            tree.add(ce);
-          } else if (ce.hitsCopy == tree.last().hitsCopy) {
-            tree.add(ce);
-            tree.remove(tree.last());
-          }
-        }
-      }
-    } finally {
-      markAndSweepLock.unlock();
-    }
-    for (CacheEntry<K, V> e : tree) {
-      result.put(e.key, e.value);
-    }
-    return result;
-  }
-
-  public int size() {
-    return stats.size.get();
-  }
-
-  public void clear() {
-    map.clear();
-  }
-
-  public Map<Object, CacheEntry<K, V>> getMap() {
-    return map;
-  }
-
-  private static class CacheEntry<K, V> implements Comparable<CacheEntry<K, V>> {
-    K key;
-    V value;
-    volatile AtomicLong hits = new AtomicLong(0);
-    long hitsCopy = 0;
-    volatile long lastAccessed = 0;
-    long lastAccessedCopy = 0;
-
-    public CacheEntry(K key, V value, long lastAccessed) {
-      this.key = key;
-      this.value = value;
-      this.lastAccessed = lastAccessed;
-    }
-
-    public int compareTo(CacheEntry<K, V> that) {
-      if (this.hitsCopy == that.hitsCopy) {
-        if (this.lastAccessedCopy == that.lastAccessedCopy) {
-          return 0;
-        }
-        return this.lastAccessedCopy < that.lastAccessedCopy ? 1 : -1;
-      }
-      return this.hitsCopy < that.hitsCopy ? 1 : -1;
-    }
-
-    @Override
-    public int hashCode() {
-      return value.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      return value.equals(obj);
-    }
-
-    @Override
-    public String toString() {
-      return "key: " + key + " value: " + value + " hits:" + hits.get();
-    }
-  }
-
-  private boolean isDestroyed = false;
-
-  public void destroy() {
-    try {
-      if (cleanupThread != null) {
-        cleanupThread.stopThread();
-      }
-    } finally {
-      isDestroyed = true;
-    }
-  }
-
-  public Stats getStats() {
-    return stats;
-  }
-
-
-  public static class Stats {
-    private final AtomicLong accessCounter = new AtomicLong(0),
-        putCounter = new AtomicLong(0),
-        nonLivePutCounter = new AtomicLong(0),
-        missCounter = new AtomicLong();
-    private final AtomicInteger size = new AtomicInteger();
-    private AtomicLong evictionCounter = new AtomicLong();
-
-    public long getCumulativeLookups() {
-      return (accessCounter.get() - putCounter.get() - nonLivePutCounter.get()) + missCounter.get();
-    }
-
-    public long getCumulativeHits() {
-      return accessCounter.get() - putCounter.get() - nonLivePutCounter.get();
-    }
-
-    public long getCumulativePuts() {
-      return putCounter.get();
-    }
-
-    public long getCumulativeEvictions() {
-      return evictionCounter.get();
-    }
-
-    public int getCurrentSize() {
-      return size.get();
-    }
-
-    public long getCumulativeNonLivePuts() {
-      return nonLivePutCounter.get();
-    }
-
-    public long getCumulativeMisses() {
-      return missCounter.get();
-    }
-
-    public void add(Stats other) {
-      accessCounter.addAndGet(other.accessCounter.get());
-      putCounter.addAndGet(other.putCounter.get());
-      nonLivePutCounter.addAndGet(other.nonLivePutCounter.get());
-      missCounter.addAndGet(other.missCounter.get());
-      evictionCounter.addAndGet(other.evictionCounter.get());
-      size.set(Math.max(size.get(), other.size.get()));
-    }
-  }
-
-  public static interface EvictionListener<K, V> {
-    public void evictedEntry(K key, V value);
-  }
-
-  private static class CleanupThread extends Thread {
-    private WeakReference<ConcurrentLFUCache> cache;
-
-    private boolean stop = false;
-
-    public CleanupThread(ConcurrentLFUCache c) {
-      cache = new WeakReference<ConcurrentLFUCache>(c);
-    }
-
-    @Override
-    public void run() {
-      while (true) {
-        synchronized (this) {
-          if (stop) break;
-          try {
-            this.wait();
-          } catch (InterruptedException e) {
-          }
-        }
-        if (stop) break;
-        ConcurrentLFUCache c = cache.get();
-        if (c == null) break;
-        c.markAndSweep();
-      }
-    }
-
-    void wakeThread() {
-      synchronized (this) {
-        this.notify();
-      }
-    }
-
-    void stopThread() {
-      synchronized (this) {
-        stop = true;
-        this.notify();
-      }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable {
-    try {
-      if (!isDestroyed) {
-        log.error("ConcurrentLFUCache was not destroyed prior to finalize(), indicates a bug -- POSSIBLE RESOURCE LEAK!!!");
-        destroy();
-      }
-    } finally {
-      super.finalize();
-    }
-  }
-}
-package org.apache.solr.util;
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You 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
- * 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.
- */
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.lang.ref.WeakReference;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * A LFU cache implementation based upon ConcurrentHashMap.
- * <p/>
- * This is not a terribly efficient implementation.  The tricks used in the
- * LRU version were not directly usable, perhaps it might be possible to
- * rewrite them with LFU in mind.
- * <p/>
- * <b>This API is experimental and subject to change</b>
- *
- * @version $Id: ConcurrentLFUCache.java 1170772 2011-09-14 19:09:56Z sarowe $
- * @since solr 1.6
- */
-public class ConcurrentLFUCache<K, V> {
-  private static Logger log = LoggerFactory.getLogger(ConcurrentLFUCache.class);
-
-  private final ConcurrentHashMap<Object, CacheEntry<K, V>> map;
-  private final int upperWaterMark, lowerWaterMark;
-  private final ReentrantLock markAndSweepLock = new ReentrantLock(true);
-  private boolean isCleaning = false;  // not volatile... piggybacked on other volatile vars
-  private final boolean newThreadForCleanup;
-  private volatile boolean islive = true;
-  private final Stats stats = new Stats();
-  private final int acceptableWaterMark;
-  private long lowHitCount = 0;  // not volatile, only accessed in the cleaning method
-  private final EvictionListener<K, V> evictionListener;
-  private CleanupThread cleanupThread;
-  private final boolean timeDecay;
-
-  public ConcurrentLFUCache(int upperWaterMark, final int lowerWaterMark, int acceptableSize,
-                            int initialSize, boolean runCleanupThread, boolean runNewThreadForCleanup,
-                            EvictionListener<K, V> evictionListener, boolean timeDecay) {
-    if (upperWaterMark < 1) throw new IllegalArgumentException("upperWaterMark must be > 0");
-    if (lowerWaterMark >= upperWaterMark)
-      throw new IllegalArgumentException("lowerWaterMark must be  < upperWaterMark");
-    map = new ConcurrentHashMap<Object, CacheEntry<K, V>>(initialSize);
-    newThreadForCleanup = runNewThreadForCleanup;
-    this.upperWaterMark = upperWaterMark;
-    this.lowerWaterMark = lowerWaterMark;
-    this.acceptableWaterMark = acceptableSize;
-    this.evictionListener = evictionListener;
-    this.timeDecay = timeDecay;
-    if (runCleanupThread) {
-      cleanupThread = new CleanupThread(this);
-      cleanupThread.start();
-    }
-  }
-
-  public ConcurrentLFUCache(int size, int lowerWatermark) {
-    this(size, lowerWatermark, (int) Math.floor((lowerWatermark + size) / 2),
-        (int) Math.ceil(0.75 * size), false, false, null, true);
-  }
-
-  public void setAlive(boolean live) {
-    islive = live;
-  }
-
-  public V get(K key) {
-    CacheEntry<K, V> e = map.get(key);
-    if (e == null) {
-      if (islive) stats.missCounter.incrementAndGet();
-      return null;
-    }
-    if (islive) {
-      e.lastAccessed = stats.accessCounter.incrementAndGet();
-      e.hits.incrementAndGet();
-    }
-    return e.value;
-  }
-
-  public V remove(K key) {
-    CacheEntry<K, V> cacheEntry = map.remove(key);
-    if (cacheEntry != null) {
-      stats.size.decrementAndGet();
-      return cacheEntry.value;
-    }
-    return null;
-  }
-
-  public V put(K key, V val) {
-    if (val == null) return null;
-    CacheEntry<K, V> e = new CacheEntry<K, V>(key, val, stats.accessCounter.incrementAndGet());
-    CacheEntry<K, V> oldCacheEntry = map.put(key, e);
-    int currentSize;
-    if (oldCacheEntry == null) {
-      currentSize = stats.size.incrementAndGet();
-    } else {
-      currentSize = stats.size.get();
-    }
-    if (islive) {
-      stats.putCounter.incrementAndGet();
-    } else {
-      stats.nonLivePutCounter.incrementAndGet();
-    }
-
-    // Check if we need to clear out old entries from the cache.
-    // isCleaning variable is checked instead of markAndSweepLock.isLocked()
-    // for performance because every put invokation will check until
-    // the size is back to an acceptable level.
-    //
-    // There is a race between the check and the call to markAndSweep, but
-    // it's unimportant because markAndSweep actually aquires the lock or returns if it can't.
-    //
-    // Thread safety note: isCleaning read is piggybacked (comes after) other volatile reads
-    // in this method.
-    if (currentSize > upperWaterMark && !isCleaning) {
-      if (newThreadForCleanup) {
-        new Thread() {
-          @Override
-          public void run() {
-            markAndSweep();
-          }
-        }.start();
-      } else if (cleanupThread != null) {
-        cleanupThread.wakeThread();
-      } else {
-        markAndSweep();
-      }
-    }
-    return oldCacheEntry == null ? null : oldCacheEntry.value;
-  }
-
-  /**
-   * Removes items from the cache to bring the size down
-   * to an acceptable value ('acceptableWaterMark').
-   * <p/>
-   * It is done in two stages. In the first stage, least recently used items are evicted.
-   * If, after the first stage, the cache size is still greater than 'acceptableSize'
-   * config parameter, the second stage takes over.
-   * <p/>
-   * The second stage is more intensive and tries to bring down the cache size
-   * to the 'lowerWaterMark' config parameter.
-   */
-  private void markAndSweep() {
-    if (!markAndSweepLock.tryLock()) return;
-    try {
-      long lowHitCount = this.lowHitCount;
-      isCleaning = true;
-      this.lowHitCount = lowHitCount;     // volatile write to make isCleaning visible
-
-      int sz = stats.size.get();
-
-      int wantToRemove = sz - lowerWaterMark;
-
-      TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
-
-      for (CacheEntry<K, V> ce : map.values()) {
-        // set hitsCopy to avoid later Atomic reads
-        ce.hitsCopy = ce.hits.get();
-        ce.lastAccessedCopy = ce.lastAccessed;
-        if (timeDecay) {
-          ce.hits.set(ce.hitsCopy >>> 1);
-        }
-
-        if (tree.size() < wantToRemove) {
-          tree.add(ce);
-        } else {
-          // If the hits are not equal, we can remove before adding
-          // which is slightly faster
-          if (ce.hitsCopy < tree.first().hitsCopy) {
-            tree.remove(tree.first());
-            tree.add(ce);
-          } else if (ce.hitsCopy == tree.first().hitsCopy) {
-            tree.add(ce);
-            tree.remove(tree.first());
-          }
-        }
-      }
-
-      for (CacheEntry<K, V> e : tree) {
-        evictEntry(e.key);
-      }
-    } finally {
-      isCleaning = false;  // set before markAndSweep.unlock() for visibility
-      markAndSweepLock.unlock();
-    }
-  }
-
-  private void evictEntry(K key) {
-    CacheEntry<K, V> o = map.remove(key);
-    if (o == null) return;
-    stats.size.decrementAndGet();
-    stats.evictionCounter.incrementAndGet();
-    if (evictionListener != null) evictionListener.evictedEntry(o.key, o.value);
-  }
-
-  /**
-   * Returns 'n' number of least used entries present in this cache.
-   * <p/>
-   * This uses a TreeSet to collect the 'n' least used items ordered by ascending hitcount
-   * and returns a LinkedHashMap containing 'n' or less than 'n' entries.
-   *
-   * @param n the number of items needed
-   * @return a LinkedHashMap containing 'n' or less than 'n' entries
-   */
-  public Map<K, V> getLeastUsedItems(int n) {
-    Map<K, V> result = new LinkedHashMap<K, V>();
-    if (n <= 0)
-      return result;
-    TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
-    // we need to grab the lock since we are changing the copy variables
-    markAndSweepLock.lock();
-    try {
-      for (Map.Entry<Object, CacheEntry<K, V>> entry : map.entrySet()) {
-        CacheEntry ce = entry.getValue();
-        ce.hitsCopy = ce.hits.get();
-        ce.lastAccessedCopy = ce.lastAccessed;
-        if (tree.size() < n) {
-          tree.add(ce);
-        } else {
-          // If the hits are not equal, we can remove before adding
-          // which is slightly faster
-          if (ce.hitsCopy < tree.first().hitsCopy) {
-            tree.remove(tree.first());
-            tree.add(ce);
-          } else if (ce.hitsCopy == tree.first().hitsCopy) {
-            tree.add(ce);
-            tree.remove(tree.first());
-          }
-        }
-      }
-    } finally {
-      markAndSweepLock.unlock();
-    }
-    for (CacheEntry<K, V> e : tree) {
-      result.put(e.key, e.value);
-    }
-    return result;
-  }
-
-  /**
-   * Returns 'n' number of most used entries present in this cache.
-   * <p/>
-   * This uses a TreeSet to collect the 'n' most used items ordered by descending hitcount
-   * and returns a LinkedHashMap containing 'n' or less than 'n' entries.
-   *
-   * @param n the number of items needed
-   * @return a LinkedHashMap containing 'n' or less than 'n' entries
-   */
-  public Map<K, V> getMostUsedItems(int n) {
-    Map<K, V> result = new LinkedHashMap<K, V>();
-    if (n <= 0)
-      return result;
-    TreeSet<CacheEntry> tree = new TreeSet<CacheEntry>();
-    // we need to grab the lock since we are changing the copy variables
-    markAndSweepLock.lock();
-    try {
-      for (Map.Entry<Object, CacheEntry<K, V>> entry : map.entrySet()) {
-        CacheEntry<K, V> ce = entry.getValue();
-        ce.hitsCopy = ce.hits.get();
-        ce.lastAccessedCopy = ce.lastAccessed;
-        if (tree.size() < n) {
-          tree.add(ce);
-        } else {
-          // If the hits are not equal, we can remove before adding
-          // which is slightly faster
-          if (ce.hitsCopy > tree.last().hitsCopy) {
-            tree.remove(tree.last());
-            tree.add(ce);
-          } else if (ce.hitsCopy == tree.last().hitsCopy) {
-            tree.add(ce);
-            tree.remove(tree.last());
-          }
-        }
-      }
-    } finally {
-      markAndSweepLock.unlock();
-    }
-    for (CacheEntry<K, V> e : tree) {
-      result.put(e.key, e.value);
-    }
-    return result;
-  }
-
-  public int size() {
-    return stats.size.get();
-  }
-
-  public void clear() {
-    map.clear();
-  }
-
-  public Map<Object, CacheEntry<K, V>> getMap() {
-    return map;
-  }
-
-  private static class CacheEntry<K, V> implements Comparable<CacheEntry<K, V>> {
-    K key;
-    V value;
-    volatile AtomicLong hits = new AtomicLong(0);
-    long hitsCopy = 0;
-    volatile long lastAccessed = 0;
-    long lastAccessedCopy = 0;
-
-    public CacheEntry(K key, V value, long lastAccessed) {
-      this.key = key;
-      this.value = value;
-      this.lastAccessed = lastAccessed;
-    }
-
-    public int compareTo(CacheEntry<K, V> that) {
-      if (this.hitsCopy == that.hitsCopy) {
-        if (this.lastAccessedCopy == that.lastAccessedCopy) {
-          return 0;
-        }
-        return this.lastAccessedCopy < that.lastAccessedCopy ? 1 : -1;
-      }
-      return this.hitsCopy < that.hitsCopy ? 1 : -1;
-    }
-
-    @Override
-    public int hashCode() {
-      return value.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      return value.equals(obj);
-    }
-
-    @Override
-    public String toString() {
-      return "key: " + key + " value: " + value + " hits:" + hits.get();
-    }
-  }
-
-  private boolean isDestroyed = false;
-
-  public void destroy() {
-    try {
-      if (cleanupThread != null) {
-        cleanupThread.stopThread();
-      }
-    } finally {
-      isDestroyed = true;
-    }
-  }
-
-  public Stats getStats() {
-    return stats;
-  }
-
-
-  public static class Stats {
-    private final AtomicLong accessCounter = new AtomicLong(0),
-        putCounter = new AtomicLong(0),
-        nonLivePutCounter = new AtomicLong(0),
-        missCounter = new AtomicLong();
-    private final AtomicInteger size = new AtomicInteger();
-    private AtomicLong evictionCounter = new AtomicLong();
-
-    public long getCumulativeLookups() {
-      return (accessCounter.get() - putCounter.get() - nonLivePutCounter.get()) + missCounter.get();
-    }
-
-    public long getCumulativeHits() {
-      return accessCounter.get() - putCounter.get() - nonLivePutCounter.get();
-    }
-
-    public long getCumulativePuts() {
-      return putCounter.get();
-    }
-
-    public long getCumulativeEvictions() {
-      return evictionCounter.get();
-    }
-
-    public int getCurrentSize() {
-      return size.get();
-    }
-
-    public long getCumulativeNonLivePuts() {
-      return nonLivePutCounter.get();
-    }
-
-    public long getCumulativeMisses() {
-      return missCounter.get();
-    }
-
-    public void add(Stats other) {
-      accessCounter.addAndGet(other.accessCounter.get());
-      putCounter.addAndGet(other.putCounter.get());
-      nonLivePutCounter.addAndGet(other.nonLivePutCounter.get());
-      missCounter.addAndGet(other.missCounter.get());
-      evictionCounter.addAndGet(other.evictionCounter.get());
-      size.set(Math.max(size.get(), other.size.get()));
-    }
-  }
-
-  public static interface EvictionListener<K, V> {
-    public void evictedEntry(K key, V value);
-  }
-
-  private static class CleanupThread extends Thread {
-    private WeakReference<ConcurrentLFUCache> cache;
-
-    private boolean stop = false;
-
-    public CleanupThread(ConcurrentLFUCache c) {
-      cache = new WeakReference<ConcurrentLFUCache>(c);
-    }
-
-    @Override
-    public void run() {
-      while (true) {
-        synchronized (this) {
-          if (stop) break;
-          try {
-            this.wait();
-          } catch (InterruptedException e) {
-          }
-        }
-        if (stop) break;
-        ConcurrentLFUCache c = cache.get();
-        if (c == null) break;
-        c.markAndSweep();
-      }
-    }
-
-    void wakeThread() {
-      synchronized (this) {
-        this.notify();
-      }
-    }
-
-    void stopThread() {
-      synchronized (this) {
-        stop = true;
-        this.notify();
-      }
-    }
-  }
-
-  @Override
-  protected void finalize() throws Throwable {
-    try {
-      if (!isDestroyed) {
-        log.error("ConcurrentLFUCache was not destroyed prior to finalize(), indicates a bug -- POSSIBLE RESOURCE LEAK!!!");
-        destroy();
-      }
-    } finally {
-      super.finalize();
-    }
-  }
-}

Modified: lucene/dev/trunk/solr/core/src/test-files/solr/conf/solrconfig-caching.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/solr/core/src/test-files/solr/conf/solrconfig-caching.xml?rev=1230790&r1=1230789&r2=1230790&view=diff
==============================================================================
--- lucene/dev/trunk/solr/core/src/test-files/solr/conf/solrconfig-caching.xml (original)
+++ lucene/dev/trunk/solr/core/src/test-files/solr/conf/solrconfig-caching.xml Thu Jan 12 21:18:50 2012
@@ -34,78 +34,4 @@
            size="10"
            initialSize="9" />
   </query>
-</config>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You 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.
-  -->
-<config>
-  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
-  <query>
-    <cache name="lfuCacheDecayFalse"
-           class="solr.search.LFUCache"
-           size="10"
-           initialSize="9"
-           timeDecay="false" />
-
-    <cache name="lfuCacheDecayTrue"
-           class="solr.search.LFUCache"
-           size="10"
-           initialSize="9"
-           timeDecay="true" />
-
-    <cache name="lfuCacheDecayDefault"
-           class="solr.search.LFUCache"
-           size="10"
-           initialSize="9" />
-  </query>
-</config>
-<!--
-  Licensed to the Apache Software Foundation (ASF) under one or more
-  contributor license agreements.  See the NOTICE file distributed with
-  this work for additional information regarding copyright ownership.
-  The ASF licenses this file to You 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.
-  -->
-<config>
-  <luceneMatchVersion>${tests.luceneMatchVersion:LUCENE_CURRENT}</luceneMatchVersion>
-  <query>
-    <cache name="lfuCacheDecayFalse"
-           class="solr.search.LFUCache"
-           size="10"
-           initialSize="9"
-           timeDecay="false" />
-
-    <cache name="lfuCacheDecayTrue"
-           class="solr.search.LFUCache"
-           size="10"
-           initialSize="9"
-           timeDecay="true" />
-
-    <cache name="lfuCacheDecayDefault"
-           class="solr.search.LFUCache"
-           size="10"
-           initialSize="9" />
-  </query>
 </config>
\ No newline at end of file