提交 dc1ae239 authored 作者: Thomas Mueller's avatar Thomas Mueller

A persistent tree map (work in progress).

上级 767ed8d3
...@@ -103,6 +103,7 @@ import org.h2.test.server.TestAutoServer; ...@@ -103,6 +103,7 @@ import org.h2.test.server.TestAutoServer;
import org.h2.test.server.TestNestedLoop; import org.h2.test.server.TestNestedLoop;
import org.h2.test.server.TestWeb; import org.h2.test.server.TestWeb;
import org.h2.test.server.TestInit; import org.h2.test.server.TestInit;
import org.h2.test.store.TestTreeMapStore;
import org.h2.test.synth.TestBtreeIndex; import org.h2.test.synth.TestBtreeIndex;
import org.h2.test.synth.TestCrashAPI; import org.h2.test.synth.TestCrashAPI;
import org.h2.test.synth.TestDiskFull; import org.h2.test.synth.TestDiskFull;
...@@ -164,7 +165,6 @@ import org.h2.test.unit.TestStreams; ...@@ -164,7 +165,6 @@ import org.h2.test.unit.TestStreams;
import org.h2.test.unit.TestStringCache; import org.h2.test.unit.TestStringCache;
import org.h2.test.unit.TestStringUtils; import org.h2.test.unit.TestStringUtils;
import org.h2.test.unit.TestTools; import org.h2.test.unit.TestTools;
import org.h2.test.unit.TestTreeMapStore;
import org.h2.test.unit.TestUtils; import org.h2.test.unit.TestUtils;
import org.h2.test.unit.TestValue; import org.h2.test.unit.TestValue;
import org.h2.test.unit.TestValueHashMap; import org.h2.test.unit.TestValueHashMap;
...@@ -661,6 +661,10 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -661,6 +661,10 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
} }
private void testUnit() { private void testUnit() {
// store
new TestTreeMapStore().runTest(this);
// unit
new TestAutoReconnect().runTest(this); new TestAutoReconnect().runTest(this);
new TestCache().runTest(this); new TestCache().runTest(this);
new TestClearReferences().runTest(this); new TestClearReferences().runTest(this);
...@@ -703,7 +707,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1` ...@@ -703,7 +707,6 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestStringCache().runTest(this); new TestStringCache().runTest(this);
new TestStringUtils().runTest(this); new TestStringUtils().runTest(this);
new TestTools().runTest(this); new TestTools().runTest(this);
new TestTreeMapStore().runTest(this);
new TestTraceSystem().runTest(this); new TestTraceSystem().runTest(this);
new TestUpgrade().runTest(this); new TestUpgrade().runTest(this);
new TestUtils().runTest(this); new TestUtils().runTest(this);
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* 1.0, and under the Eclipse Public License, Version 1.0 * 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html). Initial Developer: H2 Group * (http://h2database.com/html/license.html). Initial Developer: H2 Group
*/ */
package org.h2.test.unit; package org.h2.test.store;
import java.util.Iterator; import java.util.Iterator;
import java.util.Random; import java.util.Random;
......
...@@ -29,23 +29,6 @@ public class BtreeMap<K, V> { ...@@ -29,23 +29,6 @@ public class BtreeMap<K, V> {
this.valueType = valueType; this.valueType = valueType;
} }
/**
* Open a map.
*
* @param <K> the key type
* @param <V> the value type
* @param store the tree store
* @param name the name of the map
* @param keyClass the key class
* @param valueClass the value class
* @return the map
*/
static <K, V> BtreeMap<K, V> open(BtreeMapStore store, String name, Class<K> keyClass, Class<V> valueClass) {
DataType keyType = DataTypeFactory.getDataType(keyClass);
DataType valueType = DataTypeFactory.getDataType(valueClass);
return new BtreeMap<K, V>(store, name, keyType, valueType);
}
/** /**
* Open a map. * Open a map.
* *
......
...@@ -51,8 +51,6 @@ todo: ...@@ -51,8 +51,6 @@ todo:
- encode length in pos (1=32, 2=128, 3=512,...) - encode length in pos (1=32, 2=128, 3=512,...)
- don't use any 't' blocks
- floating header (avoid duplicate header) - floating header (avoid duplicate header)
for each chunk, store chunk (a counter) for each chunk, store chunk (a counter)
for each page, store chunk id and offset to root for each page, store chunk id and offset to root
...@@ -65,6 +63,8 @@ todo: ...@@ -65,6 +63,8 @@ todo:
*/ */
public class BtreeMapStore { public class BtreeMapStore {
private static final StringType STRING_TYPE = new StringType();
private final String fileName; private final String fileName;
private FileChannel file; private FileChannel file;
private int pageSize = 4 * 1024; private int pageSize = 4 * 1024;
...@@ -115,11 +115,15 @@ public class BtreeMapStore { ...@@ -115,11 +115,15 @@ public class BtreeMapStore {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
BtreeMap<K, V> m = (BtreeMap<K, V>) maps.get(name); BtreeMap<K, V> m = (BtreeMap<K, V>) maps.get(name);
if (m == null) { if (m == null) {
String root = meta.get("map." + name); String root = meta.get("root." + name);
m = BtreeMap.open(this, name, keyClass, valueClass); DataType keyType = getDataType(keyClass);
DataType valueType = getDataType(valueClass);
m = BtreeMap.open(this, name, keyType, valueType);
maps.put(name, m); maps.put(name, m);
if (root != null) { if (root == null) {
root = StringUtils.arraySplit(root, ',', false)[0]; String info = m.getKeyType().asString() + "/" + m.getValueType().asString();
meta.put("map." + name, info);
} else {
if (!root.equals("0")) { if (!root.equals("0")) {
m.setRoot(Long.parseLong(root)); m.setRoot(Long.parseLong(root));
} }
...@@ -128,6 +132,20 @@ public class BtreeMapStore { ...@@ -128,6 +132,20 @@ public class BtreeMapStore {
return m; return m;
} }
private DataType getDataType(Class<?> clazz) {
if (clazz == String.class) {
return STRING_TYPE;
}
return DataTypeFactory.getDataType(clazz);
}
private DataType getDataType(String s) {
if (s.equals("")) {
return STRING_TYPE;
}
return DataTypeFactory.fromString(s);
}
/** /**
* Mark a map as changed. * Mark a map as changed.
* *
...@@ -141,7 +159,7 @@ public class BtreeMapStore { ...@@ -141,7 +159,7 @@ public class BtreeMapStore {
} }
private void open() { private void open() {
meta = BtreeMap.open(this, "meta", String.class, String.class); meta = BtreeMap.open(this, "meta", STRING_TYPE, STRING_TYPE);
FileUtils.createDirectories(FileUtils.getParent(fileName)); FileUtils.createDirectories(FileUtils.getParent(fileName));
try { try {
log("file open"); log("file open");
...@@ -258,8 +276,7 @@ public class BtreeMapStore { ...@@ -258,8 +276,7 @@ public class BtreeMapStore {
// as we don't know the exact positions and entry counts // as we don't know the exact positions and entry counts
int lenEstimate = 1 + 8; int lenEstimate = 1 + 8;
for (BtreeMap<?, ?> m : mapsChanged.values()) { for (BtreeMap<?, ?> m : mapsChanged.values()) {
meta.put("map." + m.getName(), String.valueOf(Long.MAX_VALUE) + meta.put("root." + m.getName(), String.valueOf(Long.MAX_VALUE));
"," + m.getKeyType().getName() + "," + m.getValueType().getName());
Page p = m.getRoot(); Page p = m.getRoot();
if (p != null) { if (p != null) {
lenEstimate += p.lengthIncludingTempChildren(); lenEstimate += p.lengthIncludingTempChildren();
...@@ -304,7 +321,7 @@ public class BtreeMapStore { ...@@ -304,7 +321,7 @@ public class BtreeMapStore {
for (BtreeMap<?, ?> m : mapsChanged.values()) { for (BtreeMap<?, ?> m : mapsChanged.values()) {
Page r = m.getRoot(); Page r = m.getRoot();
long p = r == null ? 0 : pageId; long p = r == null ? 0 : pageId;
meta.put("map." + m.getName(), String.valueOf(p) + "," + m.getKeyType().getName() + "," + m.getValueType().getName()); meta.put("root." + m.getName(), "" + p);
if (r != null) { if (r != null) {
pageId = r.updatePageIds(pageId); pageId = r.updatePageIds(pageId);
} }
...@@ -488,16 +505,15 @@ public class BtreeMapStore { ...@@ -488,16 +505,15 @@ public class BtreeMapStore {
long oldMetaRootId = readMetaRootId(move.start); long oldMetaRootId = readMetaRootId(move.start);
long offset = getPosition(oldMetaRootId); long offset = getPosition(oldMetaRootId);
log(" meta:" + move.id + "/" + offset + " start: " + move.start); log(" meta:" + move.id + "/" + offset + " start: " + move.start);
BtreeMap<String, String> oldMeta = BtreeMap.open(this, "old-meta", String.class, String.class); BtreeMap<String, String> oldMeta = BtreeMap.open(this, "old-meta", STRING_TYPE, STRING_TYPE);
oldMeta.setRoot(oldMetaRootId); oldMeta.setRoot(oldMetaRootId);
Iterator<String> it = oldMeta.keyIterator(null); Iterator<String> it = oldMeta.keyIterator(null);
ArrayList<Integer> oldBlocks = New.arrayList(); ArrayList<Integer> oldBlocks = New.arrayList();
while (it.hasNext()) { while (it.hasNext()) {
String k = it.next(); String k = it.next();
String v = oldMeta.get(k); String s = oldMeta.get(k);
log(" " + k + " " + v.replace('\n', ' ')); log(" " + k + " " + s.replace('\n', ' '));
if (k.startsWith("block.")) { if (k.startsWith("block.")) {
String s = oldMeta.get(k);
Block b = Block.fromString(s); Block b = Block.fromString(s);
if (!blocks.containsKey(b.id)) { if (!blocks.containsKey(b.id)) {
oldBlocks.add(b.id); oldBlocks.add(b.id);
...@@ -512,11 +528,11 @@ public class BtreeMapStore { ...@@ -512,11 +528,11 @@ public class BtreeMapStore {
if (!maps.containsKey(k)) { if (!maps.containsKey(k)) {
continue; continue;
} }
String[] d = StringUtils.arraySplit(v, ',', false); String[] types = StringUtils.arraySplit(s, '/', false);
DataType kt = DataTypeFactory.getDataType(d[1]); DataType kt = getDataType(types[0]);
DataType vt = DataTypeFactory.getDataType(d[2]); DataType vt = getDataType(types[1]);
long oldDataRoot = Long.parseLong(oldMeta.get("root." + k));
BtreeMap<?, ?> oldData = BtreeMap.open(this, "old-" + k, kt, vt); BtreeMap<?, ?> oldData = BtreeMap.open(this, "old-" + k, kt, vt);
long oldDataRoot = Long.parseLong(d[0]);
if (oldDataRoot == 0) { if (oldDataRoot == 0) {
// no rows // no rows
} else { } else {
......
...@@ -9,9 +9,9 @@ package org.h2.dev.store.btree; ...@@ -9,9 +9,9 @@ package org.h2.dev.store.btree;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
/** /**
* A value type. * A data type.
*/ */
interface DataType { public interface DataType {
/** /**
* Compare two keys. * Compare two keys.
...@@ -47,11 +47,11 @@ interface DataType { ...@@ -47,11 +47,11 @@ interface DataType {
Object read(ByteBuffer buff); Object read(ByteBuffer buff);
/** /**
* Get the tag name of the class. * Get the string representation of this type.
* *
* @return the tag name * @return the string
*/ */
String getName(); String asString();
} }
...@@ -6,24 +6,33 @@ ...@@ -6,24 +6,33 @@
*/ */
package org.h2.dev.store.btree; package org.h2.dev.store.btree;
import java.io.IOException;
import java.io.StringReader;
/** /**
* A factory for data types. * A factory for data types.
*/ */
public class DataTypeFactory { public class DataTypeFactory {
/** /**
* Get the class with the given name. * Read the data type.
* *
* @param name the name * @param buff the buffer
* @return the data type * @return the type
*/ */
static DataType getDataType(String name) { static DataType fromString(String s) {
if (name.equals("i")) { StringReader r = new StringReader(s);
char c;
try {
c = (char) r.read();
} catch (IOException e) {
throw new RuntimeException(e);
}
switch (c) {
case 'i':
return new IntegerType(); return new IntegerType();
} else if (name.equals("s")) {
return new StringType();
} }
throw new RuntimeException("Unknown data type name " + name); throw new RuntimeException("Unknown data type " + c);
} }
/** /**
......
...@@ -29,7 +29,7 @@ class IntegerType implements DataType { ...@@ -29,7 +29,7 @@ class IntegerType implements DataType {
DataUtils.writeVarInt(buff, (Integer) x); DataUtils.writeVarInt(buff, (Integer) x);
} }
public String getName() { public String asString() {
return "i"; return "i";
} }
......
...@@ -47,8 +47,8 @@ class StringType implements DataType { ...@@ -47,8 +47,8 @@ class StringType implements DataType {
} }
} }
public String getName() { public String asString() {
return "s"; return "";
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论