提交 034abb3c authored 作者: Thomas Mueller's avatar Thomas Mueller

A persistent tree map (work in progress)

上级 af6af2f1
......@@ -48,24 +48,35 @@ public class TestTreeMapStore extends TestBase {
FileUtils.delete(fileName);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
int count = 5;
int count = 10000;
// Profiler p = new Profiler();
// p.startCollecting();
// long t = System.currentTimeMillis();
for (int i = 0; i < count; i++) {
m.put(i, "hello " + i);
assertEquals("hello " + i, m.get(i));
}
// System.out.println("put: " + (System.currentTimeMillis() - t));
// System.out.println(p.getTop(5));
// p = new Profiler();
//p.startCollecting();
// t = System.currentTimeMillis();
s.store();
// System.out.println("store: " + (System.currentTimeMillis() - t));
// System.out.println(p.getTop(5));
m.remove(0);
assertNull(m.get(0));
for (int i = 1; i < count; i++) {
assertEquals("hello " + i, m.get(i));
}
s.close();
// s = BtreeMapStore.open(fileName);
// m = s.openMap("data", Integer.class, String.class);
// assertNull(m.get(0));
// for (int i = 1; i < count; i++) {
// assertEquals("hello " + i, m.get(i));
// }
// s.close();
s = BtreeMapStore.open(fileName);
m = s.openMap("data", Integer.class, String.class);
assertNull(m.get(0));
for (int i = 1; i < count; i++) {
assertEquals("hello " + i, m.get(i));
}
s.close();
}
private void testDefragment() {
......
......@@ -331,57 +331,25 @@ public class BtreeMap<K, V> {
* A cursor to iterate over elements in ascending order.
*/
class Cursor implements Iterator<K> {
Page current;
ArrayList<Page> parents = new ArrayList<Page>();
private ArrayList<Page.CursorPos> parents = new ArrayList<Page.CursorPos>();
private K current;
Cursor(Page root, K from) {
min(root, from);
Page.min(root, parents, from);
fetchNext();
}
private void min(Page p, K key) {
int todo;
// while (n != null) {
// int compare = key == null ? -1 : n.compare(key);
// if (compare == 0) {
// current = n;
// return;
// } else if (compare > 0) {
// n = n.getRight();
// } else {
// parents.add(n);
// n = n.getLeft();
// }
// }
// if (parents.size() == 0) {
// current = null;
// return;
// }
// current = parents.remove(parents.size() - 1);
}
@SuppressWarnings("unchecked")
public K next() {
int todo;
return null;
// Page c = current;
// if (c != null) {
// fetchNext();
// }
// return c == null ? null : (K) c.getKey();
K c = current;
if (c != null) {
fetchNext();
}
return c == null ? null : c;
}
@SuppressWarnings("unchecked")
private void fetchNext() {
int todo;
// Page r = current.getRight();
// if (r != null) {
// min(r, null);
// return;
// }
// if (parents.size() == 0) {
// current = null;
// return;
// }
// current = parents.remove(parents.size() - 1);
current = (K) Page.nextKey(parents);
}
public boolean hasNext() {
......@@ -391,6 +359,7 @@ public class BtreeMap<K, V> {
public void remove() {
throw new UnsupportedOperationException();
}
}
/**
......
......@@ -21,6 +21,7 @@ import java.util.Properties;
import java.util.TreeMap;
import org.h2.dev.store.FilePathCache;
import org.h2.store.fs.FilePath;
import org.h2.store.fs.FileUtils;
import org.h2.util.New;
import org.h2.util.SmallLRUCache;
import org.h2.util.StringUtils;
......@@ -140,7 +141,7 @@ public class BtreeMapStore {
private void open() {
meta = BtreeMap.open(this, "meta", String.class, String.class);
new File(fileName).getParentFile().mkdirs();
FileUtils.createDirectories(FileUtils.getParent(fileName));
try {
log("file open");
file = FilePathCache.wrap(FilePath.get(fileName).open("rw"));
......@@ -546,7 +547,7 @@ public class BtreeMapStore {
try {
long pos = getPosition(id);
file.position(pos);
ByteBuffer buff = ByteBuffer.wrap(new byte[1024]);
ByteBuffer buff = ByteBuffer.wrap(new byte[8 * 1024]);
// TODO read fully; read only required bytes
do {
int len = file.read(buff);
......
......@@ -7,13 +7,14 @@
package org.h2.dev.store.btree;
import java.nio.ByteBuffer;
import java.util.ArrayList;
/**
* A btree page implementation.
*/
class Page {
private static final int MAX_SIZE = 4;
private static final int MAX_SIZE = 20;
private final BtreeMap<?, ?> map;
private long id;
......@@ -55,7 +56,7 @@ class Page {
*/
static Page read(BtreeMap<?, ?> map, long id, ByteBuffer buff) {
Page p = new Page(map);
p.id = id;
p.id = p.storedId = id;
p.read(buff);
return p;
}
......@@ -79,7 +80,7 @@ class Page {
buff.append(" ");
}
if (children != null) {
buff.append("[" + children[i] + "]");
buff.append("[" + children[i] + "] ");
}
if (i < keys.length) {
buff.append(keys[i]);
......@@ -143,6 +144,70 @@ class Page {
return -(low + 1);
}
/**
* A position in a cursor
*/
static class CursorPos {
Page page;
int index;
}
static void min(Page p, ArrayList<CursorPos> parents, Object key) {
int todo;
while (p != null) {
int x = key == null ? 0 : p.findKey(key);
if (p.children != null) {
if (x < 0) {
x = -x - 1;
} else {
x++;
}
p = p.map.readPage(p.children[x]);
CursorPos c = new CursorPos();
c.page = p;
c.index = x;
parents.add(c);
} else {
if (x < 0) {
x = -x - 1;
}
CursorPos c = new CursorPos();
c.page = p;
c.index = x;
parents.add(c);
return;
}
}
}
public static Object nextKey(ArrayList<CursorPos> parents) {
int todoTest;
if (parents.size() == 0) {
return null;
}
while (true) {
// TODO avoid remove/add pairs is possible
CursorPos p = parents.remove(parents.size() - 1);
int index = p.index++;
if (index < p.page.keys.length) {
parents.add(p);
return p.page.keys[index];
}
while (true) {
if (parents.size() == 0) {
return null;
}
p = parents.remove(parents.size() - 1);
index = p.index++;
if (index < p.page.children.length) {
parents.add(p);
min(p.page, parents, null);
break;
}
}
}
}
private int size() {
return keys.length;
}
......@@ -151,7 +216,7 @@ class Page {
return children == null;
}
private Page split(int at) {
private Page splitLeaf(int at) {
int a = at, b = keys.length - a;
Object[] aKeys = new Object[a];
Object[] bKeys = new Object[b];
......@@ -160,22 +225,27 @@ class Page {
keys = aKeys;
Object[] aValues = new Object[a];
Object[] bValues = new Object[b];
bValues = new Object[b];
System.arraycopy(values, 0, aValues, 0, a);
System.arraycopy(values, a, bValues, 0, b);
values = aValues;
long[] bChildren;
if (children == null) {
bChildren = null;
} else {
a = children.length / 2;
b = children.length - a;
long[] aChildren = new long[a];
bChildren = new long[b];
System.arraycopy(children, 0, aChildren, 0, a);
System.arraycopy(children, a, bChildren, 0, b);
children = aChildren;
}
Page newPage = create(map, bKeys, bValues, bChildren);
Page newPage = create(map, bKeys, bValues, null);
return newPage;
}
private Page splitNode(int at) {
int a = at, b = keys.length - a;
Object[] aKeys = new Object[a];
Object[] bKeys = new Object[b - 1];
System.arraycopy(keys, 0, aKeys, 0, a);
System.arraycopy(keys, a + 1, bKeys, 0, b - 1);
keys = aKeys;
long[] aChildren = new long[a + 1];
long[] bChildren = new long[b];
System.arraycopy(children, 0, aChildren, 0, a + 1);
System.arraycopy(children, a + 1, bChildren, 0, b);
children = aChildren;
Page newPage = create(map, bKeys, null, bChildren);
return newPage;
}
......@@ -203,23 +273,40 @@ class Page {
if (parent != null) {
parent.children[parentIndex] = p.id;
}
if (!p.isLeaf()) {
if (p.size() >= MAX_SIZE) {
// TODO almost duplicate code
int pos = p.size() / 2;
Object k = p.keys[pos];
Page split = p.splitNode(pos);
if (parent == null) {
Object[] keys = { k };
long[] children = { p.getId(), split.getId() };
top = create(map, keys, null, children);
p = top;
} else {
parent.insert(parentIndex, k, null, split.getId());
p = parent;
}
}
}
int index = p.findKey(key);
if (p.isLeaf()) {
if (index >= 0) {
p.values[index] = value;
} else {
index = -index - 1;
p.insert(index, key, value, 0);
if (p.size() >= MAX_SIZE) {
int pos = p.size() / 2;
Object k = p.keys[pos];
Page split = p.split(pos);
if (parent == null) {
Object[] keys = { k };
long[] children = { p.getId(), split.getId() };
Page newRoot = create(map, keys, null, children);
return newRoot;
}
break;
}
index = -index - 1;
p.insert(index, key, value, 0);
if (p.size() >= MAX_SIZE) {
int pos = p.size() / 2;
Object k = p.keys[pos];
Page split = p.splitLeaf(pos);
if (parent == null) {
Object[] keys = { k };
long[] children = { p.getId(), split.getId() };
top = create(map, keys, null, children);
} else {
parent.insert(parentIndex, k, null, split.getId());
}
}
......@@ -236,7 +323,6 @@ class Page {
return top;
}
/**
* Remove a key-value pair.
*
......@@ -317,8 +403,8 @@ class Page {
}
if (children != null) {
long[] newChildren = new long[children.length + 1];
copyWithGap(children, newChildren, children.length, index);
newChildren[index] = child;
copyWithGap(children, newChildren, children.length, index + 1);
newChildren[index + 1] = child;
children = newChildren;
}
}
......@@ -407,6 +493,10 @@ class Page {
*/
int lengthIncludingTempChildren() {
int len = length();
if (len > 1024) {
int test;
System.out.println("??");
}
if (children != null) {
int size = children.length;
for (int i = 0; i < size; i++) {
......@@ -508,4 +598,8 @@ class Page {
}
}
public Object getKey(int index) {
return keys[index];
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论