blob: 952c218de3f630042a9ef39fa8a0d1fd2f6566f7 [file] [log] [blame]
package org.apache.lucene.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
* 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.lucene.util.LuceneTestCase;
public class TestDoubleBarrelLRUCache extends LuceneTestCase {
private void testCache(DoubleBarrelLRUCache<CloneableInteger,Object> cache, int n) throws Exception {
Object dummy = new Object();
for (int i = 0; i < n; i++) {
cache.put(new CloneableInteger(i), dummy);
}
// access every 2nd item in cache
for (int i = 0; i < n; i+=2) {
assertNotNull(cache.get(new CloneableInteger(i)));
}
// add n/2 elements to cache, the ones that weren't
// touched in the previous loop should now be thrown away
for (int i = n; i < n + (n / 2); i++) {
cache.put(new CloneableInteger(i), dummy);
}
// access every 4th item in cache
for (int i = 0; i < n; i+=4) {
assertNotNull(cache.get(new CloneableInteger(i)));
}
// add 3/4n elements to cache, the ones that weren't
// touched in the previous loops should now be thrown away
for (int i = n; i < n + (n * 3 / 4); i++) {
cache.put(new CloneableInteger(i), dummy);
}
// access every 4th item in cache
for (int i = 0; i < n; i+=4) {
assertNotNull(cache.get(new CloneableInteger(i)));
}
}
public void testLRUCache() throws Exception {
final int n = 100;
testCache(new DoubleBarrelLRUCache<CloneableInteger,Object>(n), n);
}
private class CacheThread extends Thread {
private final CloneableObject[] objs;
private final DoubleBarrelLRUCache<CloneableObject,Object> c;
private final long endTime;
volatile boolean failed;
public CacheThread(DoubleBarrelLRUCache<CloneableObject,Object> c,
CloneableObject[] objs, long endTime) {
this.c = c;
this.objs = objs;
this.endTime = endTime;
}
@Override
public void run() {
try {
long count = 0;
long miss = 0;
long hit = 0;
final int limit = objs.length;
while(true) {
final CloneableObject obj = objs[(int) ((count/2) % limit)];
Object v = c.get(obj);
if (v == null) {
c.put(new CloneableObject(obj), obj);
miss++;
} else {
assert obj == v;
hit++;
}
if ((++count % 10000) == 0) {
if (System.currentTimeMillis() >= endTime) {
break;
}
}
}
addResults(miss, hit);
} catch (Throwable t) {
failed = true;
throw new RuntimeException(t);
}
}
}
long totMiss, totHit;
void addResults(long miss, long hit) {
totMiss += miss;
totHit += hit;
}
public void testThreadCorrectness() throws Exception {
final int NUM_THREADS = 4;
final int CACHE_SIZE = 512;
final int OBJ_COUNT = 3*CACHE_SIZE;
DoubleBarrelLRUCache<CloneableObject,Object> c = new DoubleBarrelLRUCache<CloneableObject,Object>(1024);
CloneableObject[] objs = new CloneableObject[OBJ_COUNT];
for(int i=0;i<OBJ_COUNT;i++) {
objs[i] = new CloneableObject(new Object());
}
final CacheThread[] threads = new CacheThread[NUM_THREADS];
final long endTime = System.currentTimeMillis()+1000L;
for(int i=0;i<NUM_THREADS;i++) {
threads[i] = new CacheThread(c, objs, endTime);
threads[i].start();
}
for(int i=0;i<NUM_THREADS;i++) {
threads[i].join();
assert !threads[i].failed;
}
//System.out.println("hits=" + totHit + " misses=" + totMiss);
}
private static class CloneableObject extends DoubleBarrelLRUCache.CloneableKey {
private Object value;
public CloneableObject(Object value) {
this.value = value;
}
@Override
public boolean equals(Object other) {
return this.value.equals(((CloneableObject) other).value);
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public Object clone() {
return new CloneableObject(value);
}
}
protected static class CloneableInteger extends DoubleBarrelLRUCache.CloneableKey {
private Integer value;
public CloneableInteger(Integer value) {
this.value = value;
}
@Override
public boolean equals(Object other) {
return this.value.equals(((CloneableInteger) other).value);
}
@Override
public int hashCode() {
return value.hashCode();
}
@Override
public Object clone() {
return new CloneableInteger(value);
}
}
}