提交 670d256c authored 作者: Thomas Mueller's avatar Thomas Mueller

A persistent multi-version map: compact based on estimated size, not page count

上级 3a92ea32
...@@ -577,7 +577,7 @@ public class TestMVStore extends TestBase { ...@@ -577,7 +577,7 @@ public class TestMVStore extends TestBase {
m.put(j + i, "Hello " + j); m.put(j + i, "Hello " + j);
} }
s.store(); s.store();
s.compact(80); // s.compact(80);
s.close(); s.close();
long len = FileUtils.size(fileName); long len = FileUtils.size(fileName);
// System.out.println(" len:" + len); // System.out.println(" len:" + len);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
package org.h2.dev.store.btree; package org.h2.dev.store.btree;
import java.nio.ByteBuffer;
import java.util.HashMap; import java.util.HashMap;
/** /**
...@@ -19,6 +20,7 @@ import java.util.HashMap; ...@@ -19,6 +20,7 @@ import java.util.HashMap;
* 4 bytes: length * 4 bytes: length
* 4 bytes: chunk id (an incrementing number) * 4 bytes: chunk id (an incrementing number)
* 8 bytes: metaRootPos * 8 bytes: metaRootPos
* 8 bytes: maxLengthLive
* [ Page ] * * [ Page ] *
*/ */
public class Chunk { public class Chunk {
...@@ -34,19 +36,19 @@ public class Chunk { ...@@ -34,19 +36,19 @@ public class Chunk {
long start; long start;
/** /**
* The length in bytes (may be larger than the actual value). * The length in bytes.
*/ */
long length; int length;
/** /**
* The entry count. * The sum of the max length of all pages.
*/ */
int entryCount; long maxLength;
/** /**
* The number of life (non-garbage) objects. * The sum of the max length of all pages that are in use.
*/ */
int liveCount; long maxLengthLive;
/** /**
* The garbage collection priority. * The garbage collection priority.
...@@ -67,6 +69,30 @@ public class Chunk { ...@@ -67,6 +69,30 @@ public class Chunk {
this.id = id; this.id = id;
} }
public static Chunk fromHeader(ByteBuffer buff, long start) {
if (buff.get() != 'c') {
throw new RuntimeException("File corrupt");
}
int length = buff.getInt();
int chunkId = buff.getInt();
long metaRootPos = buff.getLong();
long maxLengthLive = buff.getLong();
Chunk c = new Chunk(chunkId);
c.length = length;
c.start = start;
c.metaRootPos = metaRootPos;
c.maxLengthLive = maxLengthLive;
return c;
}
void writeHeader(ByteBuffer buff) {
buff.put((byte) 'c');
buff.putInt(length);
buff.putInt(id);
buff.putLong(metaRootPos);
buff.putLong(maxLengthLive);
}
/** /**
* Build a block from the given string. * Build a block from the given string.
* *
...@@ -78,16 +104,16 @@ public class Chunk { ...@@ -78,16 +104,16 @@ public class Chunk {
int id = Integer.parseInt(map.get("id")); int id = Integer.parseInt(map.get("id"));
Chunk c = new Chunk(id); Chunk c = new Chunk(id);
c.start = Long.parseLong(map.get("start")); c.start = Long.parseLong(map.get("start"));
c.length = Long.parseLong(map.get("length")); c.length = Integer.parseInt(map.get("length"));
c.entryCount = Integer.parseInt(map.get("entryCount")); c.maxLength = Long.parseLong(map.get("maxLength"));
c.liveCount = Integer.parseInt(map.get("liveCount")); c.maxLengthLive = Long.parseLong(map.get("maxLengthLive"));
c.metaRootPos = Long.parseLong(map.get("metaRoot")); c.metaRootPos = Long.parseLong(map.get("metaRoot"));
c.version = Long.parseLong(map.get("version")); c.version = Long.parseLong(map.get("version"));
return c; return c;
} }
public int getFillRate() { public int getFillRate() {
return entryCount == 0 ? 0 : 100 * liveCount / entryCount; return (int) (maxLength == 0 ? 0 : 100 * maxLengthLive / maxLength);
} }
public int hashCode() { public int hashCode() {
...@@ -103,8 +129,8 @@ public class Chunk { ...@@ -103,8 +129,8 @@ public class Chunk {
"id:" + id + "," + "id:" + id + "," +
"start:" + start + "," + "start:" + start + "," +
"length:" + length + "," + "length:" + length + "," +
"entryCount:" + entryCount + "," + "maxLength:" + maxLength + "," +
"liveCount:" + liveCount + "," + "maxLengthLive:" + maxLengthLive + "," +
"metaRoot:" + metaRootPos + "," + "metaRoot:" + metaRootPos + "," +
"version:" + version; "version:" + version;
} }
......
...@@ -80,8 +80,12 @@ public class Dump { ...@@ -80,8 +80,12 @@ public class Dump {
int chunkLength = block.getInt(); int chunkLength = block.getInt();
int chunkId = block.getInt(); int chunkId = block.getInt();
long metaRootPos = block.getLong(); long metaRootPos = block.getLong();
writer.println(" chunk " + chunkId + " at " + pos + long maxLengthLive = block.getLong();
" length " + chunkLength + " root " + metaRootPos); writer.println(" chunk " + chunkId +
" at " + pos +
" length " + chunkLength +
" root " + metaRootPos +
" maxLengthLive " + maxLengthLive);
ByteBuffer chunk = ByteBuffer.allocate(chunkLength); ByteBuffer chunk = ByteBuffer.allocate(chunkLength);
file.position(pos); file.position(pos);
FileUtils.readFully(file, chunk); FileUtils.readFully(file, chunk);
......
...@@ -57,7 +57,7 @@ public class Page { ...@@ -57,7 +57,7 @@ public class Page {
private Page[] childrenPages; private Page[] childrenPages;
private long[] counts; private long[] counts;
private Page(MVMap<?, ?> map, long version) { Page(MVMap<?, ?> map, long version) {
this.map = map; this.map = map;
this.version = version; this.version = version;
} }
...@@ -596,7 +596,7 @@ public class Page { ...@@ -596,7 +596,7 @@ public class Page {
} }
} }
private void read(ByteBuffer buff, int chunkId, int offset, int maxLength) { void read(ByteBuffer buff, int chunkId, int offset, int maxLength) {
int start = buff.position(); int start = buff.position();
int pageLength = buff.getInt(); int pageLength = buff.getInt();
if (pageLength > maxLength) { if (pageLength > maxLength) {
...@@ -661,10 +661,10 @@ public class Page { ...@@ -661,10 +661,10 @@ public class Page {
/** /**
* Store the page and update the position. * Store the page and update the position.
* *
* @param chunk the chunk
* @param buff the target buffer * @param buff the target buffer
* @param chunkId the chunk id
*/ */
private void write(ByteBuffer buff, int chunkId) { private void write(Chunk chunk, ByteBuffer buff) {
int start = buff.position(); int start = buff.position();
buff.putInt(0); buff.putInt(0);
buff.putShort((byte) 0); buff.putShort((byte) 0);
...@@ -707,11 +707,15 @@ public class Page { ...@@ -707,11 +707,15 @@ public class Page {
} }
int pageLength = buff.position() - start; int pageLength = buff.position() - start;
buff.putInt(start, pageLength); buff.putInt(start, pageLength);
int chunkId = chunk.id;
int check = DataUtils.getCheckValue(chunkId) int check = DataUtils.getCheckValue(chunkId)
^ DataUtils.getCheckValue(start) ^ DataUtils.getCheckValue(start)
^ DataUtils.getCheckValue(pageLength); ^ DataUtils.getCheckValue(pageLength);
buff.putShort(start + 4, (short) check); buff.putShort(start + 4, (short) check);
this.pos = DataUtils.getPagePos(chunkId, start, pageLength, type); this.pos = DataUtils.getPagePos(chunkId, start, pageLength, type);
long max = DataUtils.getPageMaxLength(pos);
chunk.maxLength += max;
chunk.maxLengthLive += max;
} }
/** /**
...@@ -748,42 +752,25 @@ public class Page { ...@@ -748,42 +752,25 @@ public class Page {
* Store this page and all children that are changed, in reverse order, and * Store this page and all children that are changed, in reverse order, and
* update the position and the children. * update the position and the children.
* *
* @param chunk the chunk
* @param buff the target buffer * @param buff the target buffer
* @param chunkId the chunk id
* @return the page id * @return the page id
*/ */
long writeTempRecursive(ByteBuffer buff, int chunkId) { long writeTempRecursive(Chunk chunk, ByteBuffer buff) {
if (!isLeaf()) { if (!isLeaf()) {
int len = children.length; int len = children.length;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
Page p = childrenPages[i]; Page p = childrenPages[i];
if (p != null) { if (p != null) {
children[i] = p.writeTempRecursive(buff, chunkId); children[i] = p.writeTempRecursive(chunk, buff);
childrenPages[i] = null; childrenPages[i] = null;
} }
} }
} }
write(buff, chunkId); write(chunk, buff);
return pos; return pos;
} }
/**
* Count the temporary pages recursively.
*
* @return the number of temporary pages
*/
int countTempRecursive() {
int count = 1;
if (!isLeaf()) {
for (Page p : childrenPages) {
if (p != null) {
count += p.countTempRecursive();
}
}
}
return count;
}
long getVersion() { long getVersion() {
return version; return version;
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论