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