mirror of https://github.com/apache/lucene.git
SOLR-571: autowarmCount on SolrCaches now supports relative percentages
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@938708 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
c3a253ad9c
commit
1e7165f73d
|
@ -139,6 +139,11 @@ New Features
|
|||
* SOLR-1740: ShingleFilterFactory supports the "minShingleSize" and "tokenSeparator"
|
||||
parameters for controlling the minimum shingle size produced by the filter, and
|
||||
the separator string that it uses, respectively. (Steven Rowe via rmuir)
|
||||
|
||||
* SOLR-571: The autowarmCount for LRUCaches (LRUCache and FastLRUCache) now
|
||||
supports "percentages" which get evaluated relative the current size of
|
||||
the cache when warming happens.
|
||||
(Tomas Fernandez Lobbe and hossman)
|
||||
|
||||
Optimizations
|
||||
----------------------
|
||||
|
|
|
@ -43,7 +43,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
|||
* @see org.apache.solr.search.SolrCache
|
||||
* @since solr 1.4
|
||||
*/
|
||||
public class FastLRUCache<K,V> implements SolrCache<K,V> {
|
||||
public class FastLRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V> {
|
||||
|
||||
// contains the statistics objects for all open caches of the same type
|
||||
private List<ConcurrentLRUCache.Stats> statsList;
|
||||
|
@ -51,7 +51,7 @@ public class FastLRUCache<K,V> implements SolrCache<K,V> {
|
|||
private long warmupTime = 0;
|
||||
|
||||
private String name;
|
||||
private int autowarmCount;
|
||||
private AutoWarmCountRef autowarm;
|
||||
private State state;
|
||||
private CacheRegenerator regenerator;
|
||||
private String description = "Concurrent LRU Cache";
|
||||
|
@ -86,8 +86,7 @@ public class FastLRUCache<K,V> implements SolrCache<K,V> {
|
|||
|
||||
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);
|
||||
autowarm = new AutoWarmCountRef((String)args.get("autowarmCount"));
|
||||
str = (String) args.get("cleanupThread");
|
||||
boolean newThread = str == null ? false : Boolean.parseBoolean(str);
|
||||
|
||||
|
@ -97,8 +96,8 @@ public class FastLRUCache<K,V> implements SolrCache<K,V> {
|
|||
|
||||
description = "Concurrent LRU Cache(maxSize=" + limit + ", initialSize=" + initialSize +
|
||||
", minSize="+minLimit + ", acceptableSize="+acceptableLimit+", cleanupThread="+newThread;
|
||||
if (autowarmCount > 0) {
|
||||
description += ", autowarmCount=" + autowarmCount + ", regenerator=" + regenerator;
|
||||
if (autowarm.isAutoWarmingOn()) {
|
||||
description += ", autowarmCount=" + autowarm + ", regenerator=" + regenerator;
|
||||
}
|
||||
description += ')';
|
||||
|
||||
|
@ -154,9 +153,8 @@ public class FastLRUCache<K,V> implements SolrCache<K,V> {
|
|||
long warmingStartTime = System.currentTimeMillis();
|
||||
FastLRUCache other = (FastLRUCache) old;
|
||||
// warm entries
|
||||
if (autowarmCount != 0) {
|
||||
int sz = other.size();
|
||||
if (autowarmCount != -1) sz = Math.min(sz, autowarmCount);
|
||||
if (autowarm.isAutoWarmingOn()) {
|
||||
int sz = autowarm.getWarmCount(other.size());
|
||||
Map items = other.cache.getLatestAccessedItems(sz);
|
||||
Map.Entry[] itemsArr = new Map.Entry[items.size()];
|
||||
int counter = 0;
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.net.URL;
|
|||
/**
|
||||
* @version $Id$
|
||||
*/
|
||||
public class LRUCache<K,V> implements SolrCache<K,V> {
|
||||
public class LRUCache<K,V> extends SolrCacheBase implements SolrCache<K,V> {
|
||||
|
||||
/* An instance of this class will be shared across multiple instances
|
||||
* of an LRUCache at the same time. Make sure everything is thread safe.
|
||||
|
@ -56,7 +56,7 @@ public class LRUCache<K,V> implements SolrCache<K,V> {
|
|||
|
||||
private Map<K,V> map;
|
||||
private String name;
|
||||
private int autowarmCount;
|
||||
private AutoWarmCountRef autowarm;
|
||||
private State state;
|
||||
private CacheRegenerator regenerator;
|
||||
private String description="LRU Cache";
|
||||
|
@ -69,13 +69,10 @@ public class LRUCache<K,V> implements SolrCache<K,V> {
|
|||
final int limit = str==null ? 1024 : Integer.parseInt(str);
|
||||
str = (String)args.get("initialSize");
|
||||
final int initialSize = Math.min(str==null ? 1024 : Integer.parseInt(str), limit);
|
||||
str = (String)args.get("autowarmCount");
|
||||
autowarmCount = str==null ? 0 : Integer.parseInt(str);
|
||||
|
||||
autowarm = new AutoWarmCountRef((String)args.get("autowarmCount"));
|
||||
description = "LRU Cache(maxSize=" + limit + ", initialSize=" + initialSize;
|
||||
if (autowarmCount>0) {
|
||||
description += ", autowarmCount=" + autowarmCount
|
||||
+ ", regenerator=" + regenerator;
|
||||
if (autowarm.isAutoWarmingOn()) {
|
||||
description += ", autowarmCount=" + autowarm + ", regenerator=" + regenerator;
|
||||
}
|
||||
description += ')';
|
||||
|
||||
|
@ -162,13 +159,14 @@ public class LRUCache<K,V> implements SolrCache<K,V> {
|
|||
LRUCache<K,V> other = (LRUCache<K,V>)old;
|
||||
|
||||
// warm entries
|
||||
if (autowarmCount != 0) {
|
||||
if (autowarm.isAutoWarmingOn()) {
|
||||
Object[] keys,vals = null;
|
||||
|
||||
// Don't do the autowarming in the synchronized block, just pull out the keys and values.
|
||||
synchronized (other.map) {
|
||||
int sz = other.map.size();
|
||||
if (autowarmCount!=-1) sz = Math.min(sz,autowarmCount);
|
||||
|
||||
int sz = autowarm.getWarmCount(other.map.size());
|
||||
|
||||
keys = new Object[sz];
|
||||
vals = new Object[sz];
|
||||
|
||||
|
@ -254,7 +252,7 @@ public class LRUCache<K,V> implements SolrCache<K,V> {
|
|||
return Integer.toString(ones) + '.' + tenths;
|
||||
***/
|
||||
}
|
||||
|
||||
|
||||
public NamedList getStatistics() {
|
||||
NamedList lst = new SimpleOrderedMap();
|
||||
synchronized (map) {
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.apache.solr.search;
|
||||
|
||||
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 java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Common base class of reusable functionality for SolrCaches
|
||||
*/
|
||||
public abstract class SolrCacheBase {
|
||||
|
||||
/**
|
||||
* Decides how many things to autowarm based on the size of another cache
|
||||
*/
|
||||
public static class AutoWarmCountRef {
|
||||
|
||||
private final int autoWarmCount;
|
||||
private final int autoWarmPercentage;
|
||||
private final boolean autoWarmByPercentage;
|
||||
private final boolean doAutoWarming;
|
||||
private final String strVal;
|
||||
public AutoWarmCountRef(final String configValue) {
|
||||
try {
|
||||
String input = (null == configValue) ? "0" : configValue.trim();
|
||||
|
||||
// odd undocumented legacy behavior, -1 ment "all" (now "100%")
|
||||
strVal = ("-1".equals(input)) ? "100%" : input;
|
||||
|
||||
if (strVal.indexOf("%") == (strVal.length() - 1)) {
|
||||
autoWarmCount = 0;
|
||||
autoWarmPercentage = Integer.parseInt(strVal.substring(0, strVal.length() - 1));
|
||||
autoWarmByPercentage = true;
|
||||
doAutoWarming = (0 < autoWarmPercentage);
|
||||
} else {
|
||||
autoWarmCount = Integer.parseInt(strVal);
|
||||
autoWarmPercentage = 0;
|
||||
autoWarmByPercentage = false;
|
||||
doAutoWarming = (0 < autoWarmCount);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Can't parse autoWarm value: " + configValue, e);
|
||||
}
|
||||
}
|
||||
public String toString() {
|
||||
return strVal;
|
||||
}
|
||||
public boolean isAutoWarmingOn() {
|
||||
return doAutoWarming;
|
||||
}
|
||||
public int getWarmCount(final int previousCacheSize) {
|
||||
return autoWarmByPercentage ?
|
||||
(previousCacheSize * autoWarmPercentage)/100 :
|
||||
Math.min(previousCacheSize, autoWarmCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import org.apache.solr.common.util.NamedList;
|
|||
import org.apache.solr.common.util.ConcurrentLRUCache;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
@ -35,19 +36,164 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
* @since solr 1.4
|
||||
*/
|
||||
public class TestFastLRUCache extends TestCase {
|
||||
|
||||
public void testPercentageAutowarm() throws IOException {
|
||||
FastLRUCache<Object, Object> fastCache = new FastLRUCache<Object, Object>();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("size", "100");
|
||||
params.put("initialSize", "10");
|
||||
params.put("autowarmCount", "100%");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = fastCache.init(params, null, cr);
|
||||
fastCache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 0; i < 101; i++) {
|
||||
fastCache.put(i + 1, "" + (i + 1));
|
||||
}
|
||||
assertEquals("25", fastCache.get(25));
|
||||
assertEquals(null, fastCache.get(110));
|
||||
NamedList<Serializable> nl = fastCache.getStatistics();
|
||||
assertEquals(2L, nl.get("lookups"));
|
||||
assertEquals(1L, nl.get("hits"));
|
||||
assertEquals(101L, nl.get("inserts"));
|
||||
assertEquals(null, fastCache.get(1)); // first item put in should be the first out
|
||||
FastLRUCache<Object, Object> fastCacheNew = new FastLRUCache<Object, Object>();
|
||||
fastCacheNew.init(params, o, cr);
|
||||
fastCacheNew.warm(null, fastCache);
|
||||
fastCacheNew.setState(SolrCache.State.LIVE);
|
||||
fastCache.close();
|
||||
fastCacheNew.put(103, "103");
|
||||
assertEquals("90", fastCacheNew.get(90));
|
||||
assertEquals("50", fastCacheNew.get(50));
|
||||
nl = fastCacheNew.getStatistics();
|
||||
assertEquals(2L, nl.get("lookups"));
|
||||
assertEquals(2L, nl.get("hits"));
|
||||
assertEquals(1L, nl.get("inserts"));
|
||||
assertEquals(0L, nl.get("evictions"));
|
||||
assertEquals(5L, nl.get("cumulative_lookups"));
|
||||
assertEquals(3L, nl.get("cumulative_hits"));
|
||||
assertEquals(102L, nl.get("cumulative_inserts"));
|
||||
fastCacheNew.close();
|
||||
}
|
||||
|
||||
public void testPercentageAutowarmMultiple() throws IOException {
|
||||
doTestPercentageAutowarm(100, 50, new int[]{51, 55, 60, 70, 80, 99, 100}, new int[]{1, 2, 3, 5, 10, 20, 30, 40, 50});
|
||||
doTestPercentageAutowarm(100, 25, new int[]{76, 80, 99, 100}, new int[]{1, 2, 3, 5, 10, 20, 30, 40, 50, 51, 55, 60, 70});
|
||||
doTestPercentageAutowarm(1000, 10, new int[]{901, 930, 950, 999, 1000}, new int[]{1, 5, 100, 200, 300, 400, 800, 899, 900});
|
||||
doTestPercentageAutowarm(100, 200, new int[]{1, 10, 25, 51, 55, 60, 70, 80, 99, 100}, new int[]{200, 300});
|
||||
doTestPercentageAutowarm(100, 0, new int[]{}, new int[]{1, 10, 25, 51, 55, 60, 70, 80, 99, 100, 200, 300});
|
||||
}
|
||||
|
||||
private void doTestPercentageAutowarm(int limit, int percentage, int[] hits, int[]misses) throws IOException {
|
||||
FastLRUCache<Object, Object> fastCache = new FastLRUCache<Object, Object>();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("size", String.valueOf(limit));
|
||||
params.put("initialSize", "10");
|
||||
params.put("autowarmCount", percentage + "%");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = fastCache.init(params, null, cr);
|
||||
fastCache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 1; i <= limit; i++) {
|
||||
fastCache.put(i, "" + i);//adds numbers from 1 to 100
|
||||
}
|
||||
|
||||
FastLRUCache<Object, Object> fastCacheNew = new FastLRUCache<Object, Object>();
|
||||
fastCacheNew.init(params, o, cr);
|
||||
fastCacheNew.warm(null, fastCache);
|
||||
fastCacheNew.setState(SolrCache.State.LIVE);
|
||||
fastCache.close();
|
||||
|
||||
for(int hit:hits) {
|
||||
assertEquals("The value " + hit + " should be on new cache", String.valueOf(hit), fastCacheNew.get(hit));
|
||||
}
|
||||
|
||||
for(int miss:misses) {
|
||||
assertEquals("The value " + miss + " should NOT be on new cache", null, fastCacheNew.get(miss));
|
||||
}
|
||||
NamedList<Serializable> nl = fastCacheNew.getStatistics();
|
||||
assertEquals(Long.valueOf(hits.length + misses.length), nl.get("lookups"));
|
||||
assertEquals(Long.valueOf(hits.length), nl.get("hits"));
|
||||
fastCacheNew.close();
|
||||
}
|
||||
|
||||
public void testNoAutowarm() throws IOException {
|
||||
FastLRUCache<Object, Object> fastCache = new FastLRUCache<Object, Object>();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("size", "100");
|
||||
params.put("initialSize", "10");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = fastCache.init(params, null, cr);
|
||||
fastCache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 0; i < 101; i++) {
|
||||
fastCache.put(i + 1, "" + (i + 1));
|
||||
}
|
||||
assertEquals("25", fastCache.get(25));
|
||||
assertEquals(null, fastCache.get(110));
|
||||
NamedList<Serializable> nl = fastCache.getStatistics();
|
||||
assertEquals(2L, nl.get("lookups"));
|
||||
assertEquals(1L, nl.get("hits"));
|
||||
assertEquals(101L, nl.get("inserts"));
|
||||
assertEquals(null, fastCache.get(1)); // first item put in should be the first out
|
||||
FastLRUCache<Object, Object> fastCacheNew = new FastLRUCache<Object, Object>();
|
||||
fastCacheNew.init(params, o, cr);
|
||||
fastCacheNew.warm(null, fastCache);
|
||||
fastCacheNew.setState(SolrCache.State.LIVE);
|
||||
fastCache.close();
|
||||
fastCacheNew.put(103, "103");
|
||||
assertEquals(null, fastCacheNew.get(90));
|
||||
assertEquals(null, fastCacheNew.get(50));
|
||||
fastCacheNew.close();
|
||||
}
|
||||
|
||||
public void testFullAutowarm() throws IOException {
|
||||
FastLRUCache<Object, Object> cache = new FastLRUCache<Object, Object>();
|
||||
Map<Object, Object> params = new HashMap<Object, Object>();
|
||||
params.put("size", "100");
|
||||
params.put("initialSize", "10");
|
||||
params.put("autowarmCount", "-1");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = cache.init(params, null, cr);
|
||||
cache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 0; i < 101; i++) {
|
||||
cache.put(i + 1, "" + (i + 1));
|
||||
}
|
||||
assertEquals("25", cache.get(25));
|
||||
assertEquals(null, cache.get(110));
|
||||
|
||||
assertEquals(null, cache.get(1)); // first item put in should be the first out
|
||||
|
||||
|
||||
FastLRUCache<Object, Object> cacheNew = new FastLRUCache<Object, Object>();
|
||||
cacheNew.init(params, o, cr);
|
||||
cacheNew.warm(null, cache);
|
||||
cacheNew.setState(SolrCache.State.LIVE);
|
||||
cache.close();
|
||||
cacheNew.put(103, "103");
|
||||
assertEquals("90", cacheNew.get(90));
|
||||
assertEquals("50", cacheNew.get(50));
|
||||
assertEquals("103", cacheNew.get(103));
|
||||
cacheNew.close();
|
||||
}
|
||||
|
||||
private CacheRegenerator createCodeRegenerator() {
|
||||
CacheRegenerator cr = new CacheRegenerator() {
|
||||
public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache,
|
||||
SolrCache oldCache, Object oldKey, Object oldVal) throws IOException {
|
||||
newCache.put(oldKey, oldVal);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return cr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void testSimple() throws IOException {
|
||||
FastLRUCache sc = new FastLRUCache();
|
||||
Map l = new HashMap();
|
||||
l.put("size", "100");
|
||||
l.put("initialSize", "10");
|
||||
l.put("autowarmCount", "25");
|
||||
CacheRegenerator cr = new CacheRegenerator() {
|
||||
public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache,
|
||||
SolrCache oldCache, Object oldKey, Object oldVal) throws IOException {
|
||||
newCache.put(oldKey, oldVal);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = sc.init(l, null, cr);
|
||||
sc.setState(SolrCache.State.LIVE);
|
||||
for (int i = 0; i < 101; i++) {
|
||||
|
@ -128,13 +274,13 @@ public class TestFastLRUCache extends TestCase {
|
|||
}
|
||||
|
||||
/***
|
||||
public void testPerf() {
|
||||
doPerfTest(1000000, 100000, 200000); // big cache, warmup
|
||||
doPerfTest(2000000, 100000, 200000); // big cache
|
||||
doPerfTest(2000000, 100000, 120000); // smaller key space increases distance between oldest, newest and makes the first passes less effective.
|
||||
doPerfTest(6000000, 1000, 2000); // small cache, smaller hit rate
|
||||
doPerfTest(6000000, 1000, 1200); // small cache, bigger hit rate
|
||||
}
|
||||
public void testPerf() {
|
||||
doPerfTest(1000000, 100000, 200000); // big cache, warmup
|
||||
doPerfTest(2000000, 100000, 200000); // big cache
|
||||
doPerfTest(2000000, 100000, 120000); // smaller key space increases distance between oldest, newest and makes the first passes less effective.
|
||||
doPerfTest(6000000, 1000, 2000); // small cache, smaller hit rate
|
||||
doPerfTest(6000000, 1000, 1200); // small cache, bigger hit rate
|
||||
}
|
||||
***/
|
||||
|
||||
// returns number of puts
|
||||
|
@ -181,11 +327,11 @@ public class TestFastLRUCache extends TestCase {
|
|||
for (int i=0; i<threads.length; i++) {
|
||||
final int seed=i;
|
||||
threads[i] = new Thread() {
|
||||
public void run() {
|
||||
int ret = useCache(sc, numGets/nThreads, maxKey, seed);
|
||||
puts.addAndGet(ret);
|
||||
}
|
||||
};
|
||||
public void run() {
|
||||
int ret = useCache(sc, numGets/nThreads, maxKey, seed);
|
||||
puts.addAndGet(ret);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
for (Thread thread : threads) {
|
||||
|
@ -206,8 +352,8 @@ public class TestFastLRUCache extends TestCase {
|
|||
|
||||
long end = System.currentTimeMillis();
|
||||
System.out.println("time=" + (end-start) + " impl=" +sc.getClass().getSimpleName()
|
||||
+" nThreads= " + nThreads + " size="+cacheSize+" maxKey="+maxKey+" gets="+numGets
|
||||
+" hitRatio="+(1-(((double)puts.get())/numGets)));
|
||||
+" nThreads= " + nThreads + " size="+cacheSize+" maxKey="+maxKey+" gets="+numGets
|
||||
+" hitRatio="+(1-(((double)puts.get())/numGets)));
|
||||
}
|
||||
|
||||
void perfTestBoth(int nThreads, int numGets, int cacheSize, int maxKey) {
|
||||
|
@ -216,27 +362,27 @@ public class TestFastLRUCache extends TestCase {
|
|||
}
|
||||
|
||||
/***
|
||||
public void testCachePerf() {
|
||||
// warmup
|
||||
perfTestBoth(2, 100000, 100000, 120000);
|
||||
perfTestBoth(1, 2000000, 100000, 100000); // big cache, 100% hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 100000); // big cache, 100% hit ratio
|
||||
perfTestBoth(1, 2000000, 100000, 120000); // big cache, bigger hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 120000); // big cache, bigger hit ratio
|
||||
perfTestBoth(1, 2000000, 100000, 200000); // big cache, ~50% hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 200000); // big cache, ~50% hit ratio
|
||||
perfTestBoth(1, 2000000, 100000, 1000000); // big cache, ~10% hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 1000000); // big cache, ~10% hit ratio
|
||||
public void testCachePerf() {
|
||||
// warmup
|
||||
perfTestBoth(2, 100000, 100000, 120000);
|
||||
perfTestBoth(1, 2000000, 100000, 100000); // big cache, 100% hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 100000); // big cache, 100% hit ratio
|
||||
perfTestBoth(1, 2000000, 100000, 120000); // big cache, bigger hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 120000); // big cache, bigger hit ratio
|
||||
perfTestBoth(1, 2000000, 100000, 200000); // big cache, ~50% hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 200000); // big cache, ~50% hit ratio
|
||||
perfTestBoth(1, 2000000, 100000, 1000000); // big cache, ~10% hit ratio
|
||||
perfTestBoth(2, 2000000, 100000, 1000000); // big cache, ~10% hit ratio
|
||||
|
||||
perfTestBoth(1, 2000000, 1000, 1000); // small cache, ~100% hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 1000); // small cache, ~100% hit ratio
|
||||
perfTestBoth(1, 2000000, 1000, 1200); // small cache, bigger hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 1200); // small cache, bigger hit ratio
|
||||
perfTestBoth(1, 2000000, 1000, 2000); // small cache, ~50% hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 2000); // small cache, ~50% hit ratio
|
||||
perfTestBoth(1, 2000000, 1000, 10000); // small cache, ~10% hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 10000); // small cache, ~10% hit ratio
|
||||
}
|
||||
perfTestBoth(1, 2000000, 1000, 1000); // small cache, ~100% hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 1000); // small cache, ~100% hit ratio
|
||||
perfTestBoth(1, 2000000, 1000, 1200); // small cache, bigger hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 1200); // small cache, bigger hit ratio
|
||||
perfTestBoth(1, 2000000, 1000, 2000); // small cache, ~50% hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 2000); // small cache, ~50% hit ratio
|
||||
perfTestBoth(1, 2000000, 1000, 10000); // small cache, ~10% hit ratio
|
||||
perfTestBoth(2, 2000000, 1000, 10000); // small cache, ~10% hit ratio
|
||||
}
|
||||
***/
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package org.apache.solr.search;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
|
||||
/**
|
||||
* Test for <code>org.apache.solr.search.LRUCache</code>
|
||||
*/
|
||||
public class TestLRUCache extends TestCase {
|
||||
|
||||
public void testFullAutowarm() throws IOException {
|
||||
LRUCache<Object, Object> lruCache = new LRUCache<Object, Object>();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("size", "100");
|
||||
params.put("initialSize", "10");
|
||||
params.put("autowarmCount", "100%");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = lruCache.init(params, null, cr);
|
||||
lruCache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 0; i < 101; i++) {
|
||||
lruCache.put(i + 1, "" + (i + 1));
|
||||
}
|
||||
assertEquals("25", lruCache.get(25));
|
||||
assertEquals(null, lruCache.get(110));
|
||||
assertEquals(null, lruCache.get(1)); // first item put in should be the first out
|
||||
LRUCache<Object, Object> lruCacheNew = new LRUCache<Object, Object>();
|
||||
lruCacheNew.init(params, o, cr);
|
||||
lruCacheNew.warm(null, lruCache);
|
||||
lruCacheNew.setState(SolrCache.State.LIVE);
|
||||
lruCache.close();
|
||||
lruCacheNew.put(103, "103");
|
||||
assertEquals("90", lruCacheNew.get(90));
|
||||
assertEquals("50", lruCacheNew.get(50));
|
||||
lruCacheNew.close();
|
||||
}
|
||||
|
||||
public void testPercentageAutowarm() throws IOException {
|
||||
doTestPercentageAutowarm(100, 50, new int[]{51, 55, 60, 70, 80, 99, 100}, new int[]{1, 2, 3, 5, 10, 20, 30, 40, 50});
|
||||
doTestPercentageAutowarm(100, 25, new int[]{76, 80, 99, 100}, new int[]{1, 2, 3, 5, 10, 20, 30, 40, 50, 51, 55, 60, 70});
|
||||
doTestPercentageAutowarm(1000, 10, new int[]{901, 930, 950, 999, 1000}, new int[]{1, 5, 100, 200, 300, 400, 800, 899, 900});
|
||||
doTestPercentageAutowarm(10, 10, new int[]{10}, new int[]{1, 5, 9, 100, 200, 300, 400, 800, 899, 900});
|
||||
}
|
||||
|
||||
private void doTestPercentageAutowarm(int limit, int percentage, int[] hits, int[]misses) throws IOException {
|
||||
LRUCache<Object, Object> lruCache = new LRUCache<Object, Object>();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("size", String.valueOf(limit));
|
||||
params.put("initialSize", "10");
|
||||
params.put("autowarmCount", percentage + "%");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = lruCache.init(params, null, cr);
|
||||
lruCache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 1; i <= limit; i++) {
|
||||
lruCache.put(i, "" + i);//adds numbers from 1 to 100
|
||||
}
|
||||
|
||||
LRUCache<Object, Object> lruCacheNew = new LRUCache<Object, Object>();
|
||||
lruCacheNew.init(params, o, cr);
|
||||
lruCacheNew.warm(null, lruCache);
|
||||
lruCacheNew.setState(SolrCache.State.LIVE);
|
||||
lruCache.close();
|
||||
|
||||
for(int hit:hits) {
|
||||
assertEquals("The value " + hit + " should be on new cache", String.valueOf(hit), lruCacheNew.get(hit));
|
||||
}
|
||||
|
||||
for(int miss:misses) {
|
||||
assertEquals("The value " + miss + " should NOT be on new cache", null, lruCacheNew.get(miss));
|
||||
}
|
||||
lruCacheNew.close();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testNoAutowarm() throws IOException {
|
||||
LRUCache<Object, Object> lruCache = new LRUCache<Object, Object>();
|
||||
Map<String, String> params = new HashMap<String, String>();
|
||||
params.put("size", "100");
|
||||
params.put("initialSize", "10");
|
||||
CacheRegenerator cr = createCodeRegenerator();
|
||||
Object o = lruCache.init(params, null, cr);
|
||||
lruCache.setState(SolrCache.State.LIVE);
|
||||
for (int i = 0; i < 101; i++) {
|
||||
lruCache.put(i + 1, "" + (i + 1));
|
||||
}
|
||||
assertEquals("25", lruCache.get(25));
|
||||
assertEquals(null, lruCache.get(110));
|
||||
NamedList<Serializable> nl = lruCache.getStatistics();
|
||||
assertEquals(2L, nl.get("lookups"));
|
||||
assertEquals(1L, nl.get("hits"));
|
||||
assertEquals(101L, nl.get("inserts"));
|
||||
assertEquals(null, lruCache.get(1)); // first item put in should be the first out
|
||||
LRUCache<Object, Object> lruCacheNew = new LRUCache<Object, Object>();
|
||||
lruCacheNew.init(params, o, cr);
|
||||
lruCacheNew.warm(null, lruCache);
|
||||
lruCacheNew.setState(SolrCache.State.LIVE);
|
||||
lruCache.close();
|
||||
lruCacheNew.put(103, "103");
|
||||
assertEquals(null, lruCacheNew.get(90));
|
||||
assertEquals(null, lruCacheNew.get(50));
|
||||
lruCacheNew.close();
|
||||
}
|
||||
|
||||
private CacheRegenerator createCodeRegenerator() {
|
||||
CacheRegenerator cr = new CacheRegenerator() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public boolean regenerateItem(SolrIndexSearcher newSearcher, SolrCache newCache,
|
||||
SolrCache oldCache, Object oldKey, Object oldVal) throws IOException {
|
||||
newCache.put(oldKey, oldVal);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return cr;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue