提交 6ab864dc authored 作者: Thomas Mueller's avatar Thomas Mueller

A persistent tree map (work in progress).

上级 e920b890
......@@ -29,6 +29,7 @@ public class TestBtreeMapStore extends TestBase {
}
public void test() {
testTruncateFile();
testFastDelete();
testRollbackInMemory();
testRollbackStored();
......@@ -43,6 +44,29 @@ public class TestBtreeMapStore extends TestBase {
testSimple();
}
private void testTruncateFile() {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
BtreeMapStore s;
BtreeMap<Integer, String> m;
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
for (int i = 0; i < 1000; i++) {
m.put(i, "Hello World");
}
s.store();
s.close();
long len = FileUtils.size(fileName);
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
m.clear();
s.store();
s.compact(100);
s.close();
long len2 = FileUtils.size(fileName);
assertTrue(len2 < len);
}
private void testFastDelete() {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
......@@ -53,7 +77,9 @@ public class TestBtreeMapStore extends TestBase {
m = s.openMap("data", Integer.class, String.class);
for (int i = 0; i < 1000; i++) {
m.put(i, "Hello World");
assertEquals(i + 1, m.size());
}
assertEquals(1000, m.size());
s.store();
assertEquals(3, s.getWriteCount());
s.close();
......@@ -61,6 +87,7 @@ public class TestBtreeMapStore extends TestBase {
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
m.clear();
assertEquals(0, m.size());
s.store();
// ensure only nodes are read, but not leaves
assertEquals(4, s.getReadCount());
......@@ -76,7 +103,7 @@ public class TestBtreeMapStore extends TestBase {
assertEquals(-1, s.getRetainChunk());
s.setRetainChunk(0);
assertEquals(0, s.getRetainChunk());
assertEquals(0, s.getCurrentVersion());
assertEquals(1, s.getCurrentVersion());
assertFalse(s.hasUnsavedChanges());
BtreeMap<String, String> m = s.openMap("data", String.class, String.class);
assertTrue(s.hasUnsavedChanges());
......@@ -86,12 +113,14 @@ public class TestBtreeMapStore extends TestBase {
s.rollbackTo(1);
assertEquals("Hello", m.get("1"));
long v2 = s.store();
assertEquals(2, v2);
assertEquals(3, s.getCurrentVersion());
assertFalse(s.hasUnsavedChanges());
s.close();
s = openStore(fileName);
assertEquals(3, s.getCurrentVersion());
s.setRetainChunk(0);
assertEquals(2, s.getCurrentVersion());
meta = s.getMetaMap();
m = s.openMap("data", String.class, String.class);
m0 = s.openMap("data0", String.class, String.class);
......@@ -101,6 +130,7 @@ public class TestBtreeMapStore extends TestBase {
m1.put("1", "Hallo");
assertEquals("Hallo", m.get("1"));
assertEquals("Hallo", m1.get("1"));
assertTrue(s.hasUnsavedChanges());
s.rollbackTo(v2);
assertFalse(s.hasUnsavedChanges());
assertNull(meta.get("map.data1"));
......@@ -111,7 +141,7 @@ public class TestBtreeMapStore extends TestBase {
s = openStore(fileName);
s.setRetainChunk(0);
assertEquals(2, s.getCurrentVersion());
assertEquals(3, s.getCurrentVersion());
meta = s.getMetaMap();
assertTrue(meta.get("map.data") != null);
assertTrue(meta.get("map.data0") != null);
......@@ -123,10 +153,10 @@ public class TestBtreeMapStore extends TestBase {
assertFalse(m0.isReadOnly());
m.put("1", "Hallo");
s.commit();
assertEquals(3, s.getCurrentVersion());
assertEquals(4, s.getCurrentVersion());
long v4 = s.store();
assertEquals(4, v4);
assertEquals(4, s.getCurrentVersion());
assertEquals(5, s.getCurrentVersion());
s.close();
s = openStore(fileName);
......@@ -155,8 +185,14 @@ public class TestBtreeMapStore extends TestBase {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
BtreeMapStore s = openStore(fileName);
assertEquals(1, s.getCurrentVersion());
s.setMaxPageSize(5);
BtreeMap<String, String> m = s.openMap("data", String.class, String.class);
s.rollbackTo(0);
assertTrue(m.isClosed());
assertEquals(1, s.getCurrentVersion());
m = s.openMap("data", String.class, String.class);
BtreeMap<String, String> m0 = s.openMap("data0", String.class, String.class);
BtreeMap<String, String> m2 = s.openMap("data2", String.class, String.class);
m.put("1", "Hello");
......@@ -165,6 +201,7 @@ public class TestBtreeMapStore extends TestBase {
}
long v1 = s.commit();
assertEquals(1, v1);
assertEquals(2, s.getCurrentVersion());
BtreeMap<String, String> m1 = s.openMap("data1", String.class, String.class);
assertEquals("Test", m2.get("1"));
m.put("1", "Hallo");
......@@ -174,6 +211,7 @@ public class TestBtreeMapStore extends TestBase {
assertEquals("Hallo", m.get("1"));
assertEquals("Hallo", m1.get("1"));
s.rollbackTo(v1);
assertEquals(2, s.getCurrentVersion());
for (int i = 0; i < 10; i++) {
assertEquals("Test", m2.get("" + i));
}
......@@ -195,11 +233,11 @@ public class TestBtreeMapStore extends TestBase {
data.put("1", "Hello");
data.put("2", "World");
s.store();
assertEquals("1/0//", m.get("map.data"));
assertEquals("1/1//", m.get("map.data"));
assertTrue(m.containsKey("chunk.1"));
data.put("1", "Hallo");
s.store();
assertEquals("1/0//", m.get("map.data"));
assertEquals("1/1//", m.get("map.data"));
assertTrue(m.get("root.1").length() > 0);
assertTrue(m.containsKey("chunk.1"));
assertTrue(m.containsKey("chunk.2"));
......@@ -295,7 +333,7 @@ public class TestBtreeMapStore extends TestBase {
m.put(j + i, "Hello " + j);
}
s.store();
s.compact();
s.compact(80);
s.close();
long len = FileUtils.size(fileName);
// System.out.println(" len:" + len);
......@@ -313,13 +351,13 @@ public class TestBtreeMapStore extends TestBase {
m.remove(i);
}
s.store();
s.compact();
s.compact(80);
s.close();
// len = FileUtils.size(fileName);
// System.out.println("len1: " + len);
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
s.compact();
s.compact(80);
s.close();
// len = FileUtils.size(fileName);
// System.out.println("len2: " + len);
......
......@@ -6,7 +6,9 @@
*/
package org.h2.dev.store.btree;
import java.util.AbstractSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;
/**
......@@ -22,6 +24,11 @@ public class BtreeMap<K, V> {
private final DataType keyType;
private final DataType valueType;
private final long createVersion;
/**
* The map of old roots. The key is the new version, the value is the root
* before this version.
*/
private final TreeMap<Long, Page> oldRoots = new TreeMap<Long, Page>();
private BtreeMapStore store;
private Page root;
......@@ -45,7 +52,11 @@ public class BtreeMap<K, V> {
public void put(K key, V data) {
checkWrite();
Page oldRoot = root;
root = Page.put(this, root, store.getCurrentVersion(), key, data);
if (containsKey(key)) {
root = Page.set(this, root, store.getCurrentVersion(), key, data);
} else {
root = Page.add(this, root, store.getCurrentVersion(), key, data);
}
markChanged(oldRoot);
}
......@@ -56,7 +67,7 @@ public class BtreeMap<K, V> {
* @return the value, or null if not found
*/
@SuppressWarnings("unchecked")
public V get(K key) {
public V get(Object key) {
checkOpen();
if (root == null) {
return null;
......@@ -64,7 +75,7 @@ public class BtreeMap<K, V> {
return (V) root.find(key);
}
public boolean containsKey(K key) {
public boolean containsKey(Object key) {
return get(key) != null;
}
......@@ -102,7 +113,7 @@ public class BtreeMap<K, V> {
if (root != null) {
root.removeAllRecursive();
}
store.removeMap(id);
store.removeMap(name);
close();
}
......@@ -118,22 +129,25 @@ public class BtreeMap<K, V> {
}
/**
* Remove a key-value pair.
* Remove a key-value pair, if the key exists.
*
* @param key the key
*/
public void remove(K key) {
checkWrite();
if (root != null) {
if (containsKey(key)) {
Page oldRoot = root;
root = Page.remove(root, store.getCurrentVersion(), key);
root = Page.removeExisting(root, store.getCurrentVersion(), key);
markChanged(oldRoot);
}
}
private void markChanged(Page oldRoot) {
if (oldRoot != root) {
oldRoots.put(store.getCurrentVersion(), oldRoot);
long v = store.getCurrentVersion();
if (!oldRoots.containsKey(v)) {
oldRoots.put(v, oldRoot);
}
store.markChanged(this);
}
}
......@@ -201,6 +215,28 @@ public class BtreeMap<K, V> {
return new Cursor<K>(root, from);
}
public Set<K> keySet() {
checkOpen();
return new AbstractSet<K>() {
@Override
public Iterator<K> iterator() {
return new Cursor<K>(getRoot(), null);
}
@Override
public int size() {
return BtreeMap.this.size();
}
@Override
public boolean contains(Object o) {
return BtreeMap.this.containsKey(o);
}
};
}
/**
* Get the root page.
*
......@@ -229,7 +265,7 @@ public class BtreeMap<K, V> {
void rollbackTo(long version) {
checkWrite();
if (version <= createVersion) {
if (version < createVersion) {
remove();
} else {
// iterating in ascending order, and pick the last version -
......@@ -238,7 +274,7 @@ public class BtreeMap<K, V> {
Long newestOldVersion = null;
for (Iterator<Long> it = oldRoots.keySet().iterator(); it.hasNext();) {
Long x = it.next();
if (x >= version) {
if (x > version) {
if (newestOldVersion == null) {
newestOldVersion = x;
root = oldRoots.get(x);
......@@ -249,6 +285,10 @@ public class BtreeMap<K, V> {
}
}
void stored() {
oldRoots.clear();
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
......@@ -286,6 +326,15 @@ public class BtreeMap<K, V> {
return id;
}
public int size() {
long size = getSize();
return size > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) size;
}
public long getSize() {
return root == null ? 0 : root.getTotalSize();
}
public boolean equals(Object o) {
return this == o;
}
......
......@@ -35,6 +35,11 @@ public class DataUtils {
*/
public static final int MAX_VAR_INT_LEN = 5;
/**
* The maximum length of a variable size long.
*/
public static final int MAX_VAR_LONG_LEN = 10;
/**
* Get the length of the variable size int.
*
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论