提交 89f239ba authored 作者: Thomas Mueller Graf's avatar Thomas Mueller Graf

LIRS cache: make the non-resident queue size configurable

上级 fac08d62
...@@ -322,15 +322,11 @@ public class MVStore { ...@@ -322,15 +322,11 @@ public class MVStore {
o = config.get("cacheSize"); o = config.get("cacheSize");
int mb = o == null ? 16 : (Integer) o; int mb = o == null ? 16 : (Integer) o;
if (mb > 0) { if (mb > 0) {
long maxMemoryBytes = mb * 1024L * 1024L; CacheLongKeyLIRS.Config cc = new CacheLongKeyLIRS.Config();
int segmentCount = 16; cc.maxMemory = mb * 1024L * 1024L;
int stackMoveDistance = 8; cache = new CacheLongKeyLIRS<Page>(cc);
cache = new CacheLongKeyLIRS<Page>( cc.maxMemory /= 4;
maxMemoryBytes, cacheChunkRef = new CacheLongKeyLIRS<PageChildren>(cc);
segmentCount, stackMoveDistance);
cacheChunkRef = new CacheLongKeyLIRS<PageChildren>(
maxMemoryBytes / 4,
segmentCount, stackMoveDistance);
} }
o = config.get("autoCommitBufferSize"); o = config.get("autoCommitBufferSize");
int kb = o == null ? 1024 : (Integer) o; int kb = o == null ? 1024 : (Integer) o;
......
...@@ -55,35 +55,23 @@ public class CacheLongKeyLIRS<V> { ...@@ -55,35 +55,23 @@ public class CacheLongKeyLIRS<V> {
private final int segmentShift; private final int segmentShift;
private final int segmentMask; private final int segmentMask;
private final int stackMoveDistance; private final int stackMoveDistance;
private final double nonResidentQueueSize;
/**
* Create a new cache with the given number of entries, and the default
* settings (16 segments, and stack move distance of 8.
*
* @param maxMemory the maximum memory to use (1 or larger)
*/
public CacheLongKeyLIRS(long maxMemory) {
this(maxMemory, 16, 8);
}
/** /**
* Create a new cache with the given memory size. * Create a new cache with the given memory size.
* *
* @param maxMemory the maximum memory to use (1 or larger) * @param config the configuration
* @param segmentCount the number of cache segments (must be a power of 2)
* @param stackMoveDistance how many other item are to be moved to the top
* of the stack before the current item is moved
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public CacheLongKeyLIRS(long maxMemory, public CacheLongKeyLIRS(Config config) {
int segmentCount, int stackMoveDistance) { setMaxMemory(config.maxMemory);
setMaxMemory(maxMemory); this.nonResidentQueueSize = config.nonResidentQueueSize;
DataUtils.checkArgument( DataUtils.checkArgument(
Integer.bitCount(segmentCount) == 1, Integer.bitCount(config.segmentCount) == 1,
"The segment count must be a power of 2, is {0}", segmentCount); "The segment count must be a power of 2, is {0}", config.segmentCount);
this.segmentCount = segmentCount; this.segmentCount = config.segmentCount;
this.segmentMask = segmentCount - 1; this.segmentMask = segmentCount - 1;
this.stackMoveDistance = stackMoveDistance; this.stackMoveDistance = config.stackMoveDistance;
segments = new Segment[segmentCount]; segments = new Segment[segmentCount];
clear(); clear();
// use the high bits for the segment // use the high bits for the segment
...@@ -97,7 +85,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -97,7 +85,7 @@ public class CacheLongKeyLIRS<V> {
long max = Math.max(1, maxMemory / segmentCount); long max = Math.max(1, maxMemory / segmentCount);
for (int i = 0; i < segmentCount; i++) { for (int i = 0; i < segmentCount; i++) {
segments[i] = new Segment<V>( segments[i] = new Segment<V>(
max, stackMoveDistance, 8); max, stackMoveDistance, 8, nonResidentQueueSize);
} }
} }
...@@ -543,6 +531,12 @@ public class CacheLongKeyLIRS<V> { ...@@ -543,6 +531,12 @@ public class CacheLongKeyLIRS<V> {
*/ */
private final int mask; private final int mask;
/**
* The number of entries in the non-resident queue, as a factor of the
* number of entries in the map.
*/
private final double nonResidentQueueSize;
/** /**
* The stack of recently referenced elements. This includes all hot * The stack of recently referenced elements. This includes all hot
* entries, and the recently referenced cold entries. Resident cold * entries, and the recently referenced cold entries. Resident cold
...@@ -584,10 +578,13 @@ public class CacheLongKeyLIRS<V> { ...@@ -584,10 +578,13 @@ public class CacheLongKeyLIRS<V> {
* @param stackMoveDistance the number of other entries to be moved to * @param stackMoveDistance the number of other entries to be moved to
* the top of the stack before moving an entry to the top * the top of the stack before moving an entry to the top
* @param len the number of hash table buckets (must be a power of 2) * @param len the number of hash table buckets (must be a power of 2)
* @param nonResidentQueueSize the non-resident queue size factor
*/ */
Segment(long maxMemory, int stackMoveDistance, int len) { Segment(long maxMemory, int stackMoveDistance, int len,
double nonResidentQueueSize) {
setMaxMemory(maxMemory); setMaxMemory(maxMemory);
this.stackMoveDistance = stackMoveDistance; this.stackMoveDistance = stackMoveDistance;
this.nonResidentQueueSize = nonResidentQueueSize;
// the bit mask has all bits set // the bit mask has all bits set
mask = len - 1; mask = len - 1;
...@@ -614,7 +611,7 @@ public class CacheLongKeyLIRS<V> { ...@@ -614,7 +611,7 @@ public class CacheLongKeyLIRS<V> {
* @param len the number of hash table buckets (must be a power of 2) * @param len the number of hash table buckets (must be a power of 2)
*/ */
Segment(Segment<V> old, int len) { Segment(Segment<V> old, int len) {
this(old.maxMemory, old.stackMoveDistance, len); this(old.maxMemory, old.stackMoveDistance, len, old.nonResidentQueueSize);
hits = old.hits; hits = old.hits;
misses = old.misses; misses = old.misses;
Entry<V> s = old.stack.stackPrev; Entry<V> s = old.stack.stackPrev;
...@@ -907,7 +904,8 @@ public class CacheLongKeyLIRS<V> { ...@@ -907,7 +904,8 @@ public class CacheLongKeyLIRS<V> {
e.memory = 0; e.memory = 0;
addToQueue(queue2, e); addToQueue(queue2, e);
// the size of the non-resident-cold entries needs to be limited // the size of the non-resident-cold entries needs to be limited
while (queue2Size + queue2Size > stackSize) { int maxQueue2Size = (int) (nonResidentQueueSize * mapSize);
while (queue2Size > maxQueue2Size) {
e = queue2.queuePrev; e = queue2.queuePrev;
int hash = getHash(e.key); int hash = getHash(e.key);
remove(e.key, hash); remove(e.key, hash);
...@@ -1151,4 +1149,32 @@ public class CacheLongKeyLIRS<V> { ...@@ -1151,4 +1149,32 @@ public class CacheLongKeyLIRS<V> {
} }
/**
* The cache configuration.
*/
public static class Config {
/**
* The maximum memory to use (1 or larger).
*/
public long maxMemory = 1;
/**
* The number of cache segments (must be a power of 2).
*/
public int segmentCount = 16;
/**
* How many other item are to be moved to the top of the stack before the current item is moved.
*/
public int stackMoveDistance = 32;
/**
* The number of entries in the non-resident queue, as a factor of the
* number of entries in the map.
*/
public double nonResidentQueueSize = 0.5;
}
} }
...@@ -38,9 +38,15 @@ public class FilePathCache extends FilePathWrapper { ...@@ -38,9 +38,15 @@ public class FilePathCache extends FilePathWrapper {
private static final int CACHE_BLOCK_SIZE = 4 * 1024; private static final int CACHE_BLOCK_SIZE = 4 * 1024;
private final FileChannel base; private final FileChannel base;
// 1 MB cache size
private final CacheLongKeyLIRS<ByteBuffer> cache = private final CacheLongKeyLIRS<ByteBuffer> cache;
new CacheLongKeyLIRS<ByteBuffer>(1024 * 1024);
{
CacheLongKeyLIRS.Config cc = new CacheLongKeyLIRS.Config();
// 1 MB cache size
cc.maxMemory = 1024 * 1024;
cache = new CacheLongKeyLIRS<ByteBuffer>(cc);
}
FileCache(FileChannel base) { FileCache(FileChannel base) {
this.base = base; this.base = base;
......
...@@ -32,7 +32,9 @@ public class TestCacheConcurrentLIRS extends TestBase { ...@@ -32,7 +32,9 @@ public class TestCacheConcurrentLIRS extends TestBase {
} }
private void testConcurrent() { private void testConcurrent() {
final CacheLongKeyLIRS<Integer> test = new CacheLongKeyLIRS<Integer>(100); CacheLongKeyLIRS.Config cc = new CacheLongKeyLIRS.Config();
cc.maxMemory = 100;
final CacheLongKeyLIRS<Integer> test = new CacheLongKeyLIRS<Integer>(cc);
int threadCount = 8; int threadCount = 8;
final CountDownLatch wait = new CountDownLatch(1); final CountDownLatch wait = new CountDownLatch(1);
final AtomicBoolean stopped = new AtomicBoolean(); final AtomicBoolean stopped = new AtomicBoolean();
......
...@@ -110,11 +110,11 @@ public class TestCacheLongKeyLIRS extends TestBase { ...@@ -110,11 +110,11 @@ public class TestCacheLongKeyLIRS extends TestBase {
test.put(j, j); test.put(j, j);
} }
// for a cache of size 1000, // for a cache of size 1000,
// there are 62 cold entries (about 6.25%). // there are 63 cold entries (about 6.25%).
assertEquals(62, test.size() - test.sizeHot()); assertEquals(63, test.size() - test.sizeHot());
// at most as many non-resident elements // at most as many non-resident elements
// as there are entries in the stack // as there are entries in the stack
assertEquals(968, test.sizeNonResident()); assertEquals(999, test.sizeNonResident());
} }
private void verifyMapSize(int elements, int expectedMapSize) { private void verifyMapSize(int elements, int expectedMapSize) {
...@@ -344,13 +344,13 @@ public class TestCacheLongKeyLIRS extends TestBase { ...@@ -344,13 +344,13 @@ public class TestCacheLongKeyLIRS extends TestBase {
verify(test, "mem: 4 stack: 4 3 2 1 cold: 4 non-resident: 0"); verify(test, "mem: 4 stack: 4 3 2 1 cold: 4 non-resident: 0");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4); assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
test.put(6, 60, 3); test.put(6, 60, 3);
verify(test, "mem: 4 stack: 6 3 cold: 6 non-resident:"); verify(test, "mem: 4 stack: 6 3 cold: 6 non-resident: 2 1");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4); assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
test.put(7, 70, 3); test.put(7, 70, 3);
verify(test, "mem: 4 stack: 7 6 3 cold: 7 non-resident: 6"); verify(test, "mem: 4 stack: 7 6 3 cold: 7 non-resident: 6 2");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4); assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
test.put(8, 80, 4); test.put(8, 80, 4);
verify(test, "mem: 4 stack: 8 cold: non-resident:"); verify(test, "mem: 4 stack: 8 cold: non-resident: 3");
assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4); assertTrue("" + test.getUsedMemory(), test.getUsedMemory() <= 4);
} }
...@@ -497,7 +497,11 @@ public class TestCacheLongKeyLIRS extends TestBase { ...@@ -497,7 +497,11 @@ public class TestCacheLongKeyLIRS extends TestBase {
} }
private static <V> CacheLongKeyLIRS<V> createCache(int maxSize) { private static <V> CacheLongKeyLIRS<V> createCache(int maxSize) {
return new CacheLongKeyLIRS<V>(maxSize, 1, 0); CacheLongKeyLIRS.Config cc = new CacheLongKeyLIRS.Config();
cc.maxMemory = maxSize;
cc.segmentCount = 1;
cc.stackMoveDistance = 0;
return new CacheLongKeyLIRS<V>(cc);
} }
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论