Unverified 提交 07e4ef94 authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1310 from h2database/lisr-weak

Use weak references in LIRS cache
package org.h2.test.db;
import org.h2.mvstore.cache.CacheLongKeyLIRS;
import org.h2.test.TestBase;
import org.h2.test.TestDb;
import java.util.Random;
/**
* Class TestLIRSMemoryConsumption.
* <UL>
* <LI> 8/5/18 10:57 PM initial creation
* </UL>
*
* @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/
public class TestLIRSMemoryConsumption extends TestDb {
/**
* Run just this test.
*
* @param a
* ignored
*/
public static void main(String... a) throws Exception {
TestBase.createCaller().init().test();
}
@Override
public void test() {
testMemoryConsumption();
System.out.println("-----------------------");
testMemoryConsumption();
System.out.println("-----------------------");
testMemoryConsumption();
}
private void testMemoryConsumption() {
int size = 1_000_000;
Random rng = new Random();
CacheLongKeyLIRS.Config config = new CacheLongKeyLIRS.Config();
for (int mb = 1; mb <= 16; mb *= 2) {
config.maxMemory = mb * 1024 * 1024;
CacheLongKeyLIRS<Object> cache = new CacheLongKeyLIRS<>(config);
long memoryUsedInitial = getMemUsedKb();
for (int i = 0; i < size; i++) {
cache.put(i, createValue(i), getValueSize(i));
}
for (int i = 0; i < size; i++) {
int key;
int mode = rng.nextInt(4);
switch(mode) {
default:
case 0:
key = rng.nextInt(10);
break;
case 1:
key = rng.nextInt(100);
break;
case 2:
key = rng.nextInt(10_000);
break;
case 3:
key = rng.nextInt(1_000_000);
break;
}
Object val = cache.get(key);
if (val == null) {
cache.put(key, createValue(key), getValueSize(key));
}
}
eatMemory(1);
freeMemory();
cache.trimNonResidentQueue();
long memoryUsed = getMemUsedKb();
int sizeHot = cache.sizeHot();
int sizeResident = cache.size();
int sizeNonResident = cache.sizeNonResident();
long hits = cache.getHits();
long misses = cache.getMisses();
System.out.println(mb + " | " +
(memoryUsed - memoryUsedInitial + 512) / 1024 + " | " +
(sizeResident+sizeNonResident) + " | " +
sizeHot + " | " + (sizeResident - sizeHot) + " | " + sizeNonResident +
" | " + (hits * 100 / (hits + misses)) );
}
}
private Object createValue(long key) {
// return new Object();
return new byte[2540];
}
private int getValueSize(long key) {
// return 16;
return 2560;
}
private long getMemUsedKb() {
Runtime rt = Runtime.getRuntime();
long memory = Long.MAX_VALUE;
for (int i = 0; i < 8; i++) {
rt.gc();
long memNow = (rt.totalMemory() - rt.freeMemory()) / 1024;
if (memNow >= memory) {
break;
}
memory = memNow;
try { Thread.sleep(1000); } catch (InterruptedException e) {/**/}
}
return memory;
}
}
......@@ -46,28 +46,37 @@ public class TestCacheLongKeyLIRS extends TestBase {
testRandomOperations();
}
private static void testRandomSmallCache() {
private void testRandomSmallCache() {
Random r = new Random(1);
for (int i = 0; i < 10000; i++) {
int j = 0;
StringBuilder buff = new StringBuilder();
CacheLongKeyLIRS<Integer> test = createCache(1 + r.nextInt(10));
int maxSize = 1 + r.nextInt(10);
buff.append("size:").append(maxSize).append('\n');
CacheLongKeyLIRS<Integer> test = createCache(maxSize);
for (; j < 30; j++) {
int key = r.nextInt(5);
switch (r.nextInt(3)) {
case 0:
int memory = r.nextInt(5) + 1;
buff.append("add ").append(key).append(' ').
append(memory).append('\n');
test.put(key, j, memory);
break;
case 1:
buff.append("remove ").append(key).append('\n');
test.remove(key);
break;
case 2:
buff.append("get ").append(key).append('\n');
test.get(key);
String lastState = toString(test);
try {
int key = r.nextInt(5);
switch (r.nextInt(3)) {
case 0:
int memory = r.nextInt(5) + 1;
buff.append("add ").append(key).append(' ').
append(memory).append('\n');
test.put(key, j, memory);
break;
case 1:
buff.append("remove ").append(key).append('\n');
test.remove(key);
break;
case 2:
buff.append("get ").append(key).append('\n');
test.get(key);
}
verify(test, null);
} catch (Throwable ex) {
println(i + "\n" + buff + "\n" + lastState + "\n" + toString(test));
throw ex;
}
}
}
......@@ -108,8 +117,8 @@ public class TestCacheLongKeyLIRS extends TestBase {
test.put(j, j);
}
// for a cache of size 1000,
// there are 63 cold entries (about 6.25%).
assertEquals(63, test.size() - test.sizeHot());
// there are 32 cold entries (about 1/32).
assertEquals(32, test.size() - test.sizeHot());
// at most as many non-resident elements
// as there are entries in the stack
assertEquals(1000, test.size());
......@@ -164,22 +173,22 @@ public class TestCacheLongKeyLIRS extends TestBase {
assertEquals(1, test.getMemory(5));
assertEquals(0, test.getMemory(4));
assertEquals(0, test.getMemory(100));
assertNull(test.peek(4));
assertNull(test.get(4));
assertNotNull(test.peek(4));
assertNotNull(test.get(4));
assertEquals(10, test.get(1).intValue());
assertEquals(20, test.get(2).intValue());
assertEquals(30, test.get(3).intValue());
verify(test, "mem: 4 stack: 3 2 1 cold: 5 non-resident: 4");
verify(test, "mem: 5 stack: 3 2 1 cold: 4 5 non-resident:");
assertEquals(50, test.get(5).intValue());
verify(test, "mem: 4 stack: 5 3 2 1 cold: 5 non-resident: 4");
verify(test, "mem: 5 stack: 5 3 2 1 cold: 5 4 non-resident:");
assertEquals(50, test.get(5).intValue());
verify(test, "mem: 4 stack: 5 3 2 cold: 1 non-resident: 4");
verify(test, "mem: 5 stack: 5 3 2 cold: 1 4 non-resident:");
// remove
assertEquals(50, test.remove(5).intValue());
assertNull(test.remove(5));
verify(test, "mem: 3 stack: 3 2 1 cold: non-resident: 4");
assertNull(test.remove(4));
verify(test, "mem: 4 stack: 3 2 1 cold: 4 non-resident:");
assertNotNull(test.remove(4));
verify(test, "mem: 3 stack: 3 2 1 cold: non-resident:");
assertNull(test.remove(4));
verify(test, "mem: 3 stack: 3 2 1 cold: non-resident:");
......@@ -195,7 +204,7 @@ public class TestCacheLongKeyLIRS extends TestBase {
verify(test, "mem: 3 stack: 4 3 2 cold: non-resident: 1");
assertEquals(20, test.remove(2).intValue());
assertFalse(test.containsKey(1));
assertNull(test.remove(1));
assertEquals(10, test.remove(1).intValue());
assertFalse(test.containsKey(1));
verify(test, "mem: 2 stack: 4 3 cold: non-resident:");
test.put(1, 10);
......@@ -226,7 +235,7 @@ public class TestCacheLongKeyLIRS extends TestBase {
// 1 was non-resident, so this should make it hot
test.put(1, 10);
verify(test, "mem: 4 stack: 1 5 4 3 cold: 2 non-resident: 5");
assertFalse(test.containsValue(50));
assertTrue(test.containsValue(50));
test.remove(2);
test.remove(3);
test.remove(4);
......@@ -324,7 +333,7 @@ public class TestCacheLongKeyLIRS extends TestBase {
}
assertEquals(100, test.size());
assertEquals(200, test.sizeNonResident());
assertEquals(90, test.sizeHot());
assertEquals(96, test.sizeHot());
}
private void testLimitNonResident() {
......@@ -332,8 +341,8 @@ public class TestCacheLongKeyLIRS extends TestBase {
for (int i = 0; i < 20; i++) {
test.put(i, 10 * i);
}
verify(test, "mem: 4 stack: 19 18 17 16 15 14 13 12 11 10 3 2 1 " +
"cold: 19 non-resident: 18 17 16 15 14 13 12 11 10");
verify(test, "mem: 4 stack: 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 " +
"cold: 19 non-resident: 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 0");
}
private void testLimitMemory() {
......@@ -344,10 +353,10 @@ public class TestCacheLongKeyLIRS extends TestBase {
verify(test, "mem: 4 stack: 4 3 2 1 cold: 4 non-resident: 0");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
test.put(6, 60, 3);
verify(test, "mem: 4 stack: 6 4 3 cold: 6 non-resident: 2 1 4");
verify(test, "mem: 4 stack: 6 4 3 cold: 6 non-resident: 2 1 4 0");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
test.put(7, 70, 3);
verify(test, "mem: 4 stack: 7 6 3 cold: 7 non-resident: 6 2 1");
verify(test, "mem: 4 stack: 7 6 4 3 cold: 7 non-resident: 6 2 1 4 0");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
test.put(8, 80, 4);
verify(test, "mem: 4 stack: 8 cold: non-resident:");
......@@ -369,7 +378,7 @@ public class TestCacheLongKeyLIRS extends TestBase {
test.put(i, i * 10);
test.get(i);
if (log) {
System.out.println("get " + i + " -> " + test);
println("get " + i + " -> " + test);
}
}
verify(test, null);
......@@ -394,14 +403,13 @@ public class TestCacheLongKeyLIRS extends TestBase {
}
verify(test, null);
}
// ensure 0..9 are hot, 10..17 are not resident, 18..19 are cold
for (int i = 0; i < size; i++) {
Integer x = test.get(i);
if (i < size / 2 || i == size - 1 || i == size - 2) {
assertNotNull("i: " + i, x);
assertEquals(i * 10, x.intValue());
} else {
assertNull(x);
}
verify(test, null);
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论