提交 b052ab59 authored 作者: Thomas Mueller's avatar Thomas Mueller

LIRS replacement algorithm

上级 95940109
...@@ -6,10 +6,13 @@ ...@@ -6,10 +6,13 @@
package org.h2.test.store; package org.h2.test.store;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.Random; import java.util.Random;
import org.h2.dev.store.btree.CacheLirs; import org.h2.dev.store.btree.CacheLirs;
import org.h2.test.TestBase; import org.h2.test.TestBase;
import org.h2.upgrade.v1_1.util.Profiler;
import org.h2.util.New; import org.h2.util.New;
/** /**
...@@ -27,14 +30,19 @@ public class TestCache extends TestBase { ...@@ -27,14 +30,19 @@ public class TestCache extends TestBase {
} }
public void test() throws Exception { public void test() throws Exception {
Profiler p = new Profiler();
p.startCollecting();
testEdgeCases(); testEdgeCases();
testSize();
testClear(); testClear();
testGetPutPeekRemove(); testGetPutPeekRemove();
testPruneStack();
testLimitHot(); testLimitHot();
testLimitNonResident(); testLimitNonResident();
testBadHashMethod(); testBadHashMethod();
testScanResistance(); testScanResistance();
testRandomOperations(); testRandomOperations();
System.out.println(p.getTop(5));
} }
private void testEdgeCases() { private void testEdgeCases() {
...@@ -67,6 +75,39 @@ public class TestCache extends TestBase { ...@@ -67,6 +75,39 @@ public class TestCache extends TestBase {
} }
} }
private void testSize() {
verifyMapSize(7, 16);
verifyMapSize(13, 32);
verifyMapSize(25, 64);
verifyMapSize(49, 128);
verifyMapSize(97, 256);
verifyMapSize(193, 512);
verifyMapSize(385, 1024);
verifyMapSize(769, 2048);
CacheLirs<Integer, Integer> test;
test = CacheLirs.newInstance(1000, 1);
for (int j = 0; j < 2000; j++) {
test.put(j, j);
}
// for a cache of size 1000,
// there are 62 cold entries (about 6.25%).
assertEquals(62, test.size() - test.sizeHot());
// at most as many non-resident elements
// as there are entries in the stack
assertEquals(968, test.sizeNonResident());
}
private void verifyMapSize(int elements, int mapSize) {
CacheLirs<Integer, Integer> test;
test = CacheLirs.newInstance(elements - 1, 1);
assertTrue(mapSize > test.sizeMapArray());
test = CacheLirs.newInstance(elements, 1);
assertEquals(mapSize, test.sizeMapArray());
test = CacheLirs.newInstance(elements * 100, 100);
assertEquals(mapSize, test.sizeMapArray());
}
private void testGetPutPeekRemove() { private void testGetPutPeekRemove() {
CacheLirs<Integer, Integer> test = CacheLirs.newInstance(4, 1); CacheLirs<Integer, Integer> test = CacheLirs.newInstance(4, 1);
test.put(1, 10); test.put(1, 10);
...@@ -90,6 +131,10 @@ public class TestCache extends TestBase { ...@@ -90,6 +131,10 @@ public class TestCache extends TestBase {
// 5 is cold; will make 4 non-resident // 5 is cold; will make 4 non-resident
test.put(5, 50); test.put(5, 50);
verify(test, "mem: 4 stack: 5 3 1 2 cold: 5 non-resident: 4"); verify(test, "mem: 4 stack: 5 3 1 2 cold: 5 non-resident: 4");
assertEquals(1, test.getMemory(1));
assertEquals(1, test.getMemory(5));
assertEquals(0, test.getMemory(4));
assertEquals(0, test.getMemory(100));
assertNull(test.peek(4)); assertNull(test.peek(4));
assertNull(test.get(4)); assertNull(test.get(4));
assertEquals(10, test.get(1).intValue()); assertEquals(10, test.get(1).intValue());
...@@ -180,6 +225,25 @@ public class TestCache extends TestBase { ...@@ -180,6 +225,25 @@ public class TestCache extends TestBase {
verify(test, "mem: 4 stack: 6 3 4 cold: 2 non-resident: 5 1"); verify(test, "mem: 4 stack: 6 3 4 cold: 2 non-resident: 5 1");
} }
private void testPruneStack() {
CacheLirs<Integer, Integer> test = CacheLirs.newInstance(5, 1);
for (int i = 0; i < 7; i++) {
test.put(i, i * 10);
}
verify(test, "mem: 5 stack: 6 5 4 3 2 1 cold: 6 non-resident: 5 0");
test.get(4);
test.get(3);
test.get(2);
verify(test, "mem: 5 stack: 2 3 4 6 5 1 cold: 6 non-resident: 5 0");
// this call needs to prune the stack
test.remove(1);
verify(test, "mem: 4 stack: 2 3 4 6 cold: non-resident: 5 0");
test.put(0, 0);
test.put(1, 10);
// the the stack was not pruned, the following will fail
verify(test, "mem: 5 stack: 1 0 2 3 4 cold: 1 non-resident: 6 5");
}
private void testClear() { private void testClear() {
CacheLirs<Integer, Integer> test = CacheLirs.newInstance(40, 10); CacheLirs<Integer, Integer> test = CacheLirs.newInstance(40, 10);
for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
...@@ -319,6 +383,7 @@ public class TestCache extends TestBase { ...@@ -319,6 +383,7 @@ public class TestCache extends TestBase {
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
test.put(-i, -i * 10); test.put(-i, -i * 10);
} }
verify(test, null);
// init with 0..9, ensure those are hot entries // init with 0..9, ensure those are hot entries
for (int i = 0; i < size / 2; i++) { for (int i = 0; i < size / 2; i++) {
test.put(i, i * 10); test.put(i, i * 10);
...@@ -327,6 +392,7 @@ public class TestCache extends TestBase { ...@@ -327,6 +392,7 @@ public class TestCache extends TestBase {
System.out.println("get " + i + " -> " + test); System.out.println("get " + i + " -> " + test);
} }
} }
verify(test, null);
// read 0..9, add 10..19 (cold) // read 0..9, add 10..19 (cold)
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Integer x = test.get(i); Integer x = test.get(i);
...@@ -346,6 +412,7 @@ public class TestCache extends TestBase { ...@@ -346,6 +412,7 @@ public class TestCache extends TestBase {
if (log) { if (log) {
System.out.println("get " + i + " -> " + test); System.out.println("get " + i + " -> " + test);
} }
verify(test, null);
} }
// ensure 0..9 are hot, 10..18 are not resident, 19 is cold // ensure 0..9 are hot, 10..18 are not resident, 19 is cold
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
...@@ -356,6 +423,7 @@ public class TestCache extends TestBase { ...@@ -356,6 +423,7 @@ public class TestCache extends TestBase {
} else { } else {
assertNull(x); assertNull(x);
} }
verify(test, null);
} }
} }
...@@ -401,6 +469,7 @@ public class TestCache extends TestBase { ...@@ -401,6 +469,7 @@ public class TestCache extends TestBase {
System.out.println(" -> " + toString(test)); System.out.println(" -> " + toString(test));
} }
} }
verify(test, null);
} }
} }
...@@ -423,13 +492,28 @@ public class TestCache extends TestBase { ...@@ -423,13 +492,28 @@ public class TestCache extends TestBase {
} }
private <K, V> void verify(CacheLirs<K, V> cache, String expected) { private <K, V> void verify(CacheLirs<K, V> cache, String expected) {
String got = toString(cache); if (expected != null) {
assertEquals(expected, got); String got = toString(cache);
assertEquals(expected, got);
}
int mem = 0; int mem = 0;
for (K k : cache.keySet()) { for (K k : cache.keySet()) {
mem += cache.getMemory(k); mem += cache.getMemory(k);
} }
assertEquals(mem, cache.getUsedMemory()); assertEquals(mem, cache.getUsedMemory());
List<K> stack = cache.keys(false, false);
List<K> cold = cache.keys(true, false);
List<K> nonResident = cache.keys(true, true);
assertEquals(nonResident.size(), cache.sizeNonResident());
HashSet<K> hot = new HashSet<K>(stack);
hot.removeAll(cold);
hot.removeAll(nonResident);
assertEquals(hot.size(), cache.sizeHot());
assertEquals(hot.size() + cold.size(), cache.size());
if (stack.size() > 0) {
K lastStack = stack.get(stack.size() - 1);
assertTrue(hot.contains(lastStack));
}
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论