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