提交 27be225f authored 作者: Thomas Mueller's avatar Thomas Mueller

A persistent multi-version map (work in progress) - allow reading old versions…

A persistent multi-version map (work in progress) - allow reading old versions after storing; in-memory mode
上级 7b72a44d
...@@ -104,7 +104,7 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> { ...@@ -104,7 +104,7 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
for (int i = 0; i < p.getKeyCount(); i++) { for (int i = 0; i < p.getKeyCount(); i++) {
if (contains(p, i, key)) { if (contains(p, i, key)) {
Page c = p.getChildPage(i); Page c = p.getChildPage(i);
long oldSize = c.getTotalSize(); long oldSize = c.getTotalCount();
Page c2 = remove(c, writeVersion, key); Page c2 = remove(c, writeVersion, key);
if (c2 == null) { if (c2 == null) {
// this child was deleted // this child was deleted
...@@ -114,7 +114,7 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> { ...@@ -114,7 +114,7 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
} }
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.remove(i); p.remove(i);
} else if (oldSize != c2.getTotalSize()) { } else if (oldSize != c2.getTotalCount()) {
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
Object oldBounds = p.getKey(i); Object oldBounds = p.getKey(i);
if (!keyType.isInside(key, oldBounds)) { if (!keyType.isInside(key, oldBounds)) {
...@@ -197,21 +197,22 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> { ...@@ -197,21 +197,22 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
Object[] keys = { key }; Object[] keys = { key };
Object[] values = { value }; Object[] values = { value };
p = Page.create(this, writeVersion, 1, p = Page.create(this, writeVersion, 1,
keys, values, null, null, 1, 0); keys, values, null, null, null, 1, 0);
return p; return p;
} }
if (p.getKeyCount() > maxPageSize) { if (p.getKeyCount() > maxPageSize) {
// only possible if this is the root, else we would have split earlier // only possible if this is the root, else we would have split earlier
// (this requires maxPageSize is fixed) // (this requires maxPageSize is fixed)
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
long totalSize = p.getTotalSize(); long totalCount = p.getTotalCount();
Page split = split(p, writeVersion); Page split = split(p, writeVersion);
Object[] keys = { getBounds(p), getBounds(split) }; Object[] keys = { getBounds(p), getBounds(split) };
long[] children = { p.getPos(), split.getPos(), 0 }; long[] children = { p.getPos(), split.getPos(), 0 };
long[] childrenSize = { p.getTotalSize(), split.getTotalSize(), 0 }; Page[] childrenPages = { p, split, null };
long[] counts = { p.getTotalCount(), split.getTotalCount(), 0 };
p = Page.create(this, writeVersion, 2, p = Page.create(this, writeVersion, 2,
keys, null, children, childrenSize, keys, null, children, childrenPages, counts,
totalSize, 0); totalCount, 0);
// now p is a node; continues // now p is a node; continues
} else if (p.isLeaf()) { } else if (p.isLeaf()) {
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
...@@ -246,7 +247,7 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> { ...@@ -246,7 +247,7 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.setKey(index, getBounds(c)); p.setKey(index, getBounds(c));
p.setChild(index, c); p.setChild(index, c);
p.insertNode(index, getBounds(split), split.getPos(), split.getTotalSize()); p.insertNode(index, getBounds(split), split);
// now we are not sure where to add // now we are not sure where to add
return add(p, writeVersion, key, value, maxPageSize); return add(p, writeVersion, key, value, maxPageSize);
} }
...@@ -360,8 +361,9 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> { ...@@ -360,8 +361,9 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
private Page newPage(boolean leaf, long writeVersion) { private Page newPage(boolean leaf, long writeVersion) {
Object[] values = leaf ? new Object[4] : null; Object[] values = leaf ? new Object[4] : null;
long[] c = leaf ? null : new long[1]; long[] c = leaf ? null : new long[1];
Page[] cp = leaf ? null : new Page[1];
return Page.create(this, writeVersion, 0, return Page.create(this, writeVersion, 0,
new Object[4], values, c, c, 0, 0); new Object[4], values, c, cp, c, 0, 0);
} }
private static void move(Page source, Page target, int sourceIndex) { private static void move(Page source, Page target, int sourceIndex) {
...@@ -370,9 +372,8 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> { ...@@ -370,9 +372,8 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
Object v = source.getValue(sourceIndex); Object v = source.getValue(sourceIndex);
target.insertLeaf(0, k, v); target.insertLeaf(0, k, v);
} else { } else {
long c = source.getChildPage(sourceIndex).getPos(); Page c = source.getChildPage(sourceIndex);
long count = source.getCounts(sourceIndex); target.insertNode(0, k, c);
target.insertNode(0, k, c, count);
} }
source.remove(sourceIndex); source.remove(sourceIndex);
} }
......
...@@ -53,6 +53,7 @@ public class TestBtreeMapStore extends TestBase { ...@@ -53,6 +53,7 @@ public class TestBtreeMapStore extends TestBase {
testRollbackInMemory(); testRollbackInMemory();
testRollbackStored(); testRollbackStored();
testMeta(); testMeta();
testInMemory();
testLargeImport(); testLargeImport();
testBtreeStore(); testBtreeStore();
testDefragment(); testDefragment();
...@@ -95,9 +96,9 @@ public class TestBtreeMapStore extends TestBase { ...@@ -95,9 +96,9 @@ public class TestBtreeMapStore extends TestBase {
s.setRetainChunk(0); s.setRetainChunk(0);
long old2 = s.store(); long old2 = s.store();
// TODO keep old version after storing // the old version is still available
// assertEquals("Hello", mOld.get("1")); assertEquals("Hello", mOld.get("1"));
// assertEquals("World", mOld.get("2")); assertEquals("World", mOld.get("2"));
m.put("1", "Hi"); m.put("1", "Hi");
m.remove("2"); m.remove("2");
...@@ -528,6 +529,36 @@ public class TestBtreeMapStore extends TestBase { ...@@ -528,6 +529,36 @@ public class TestBtreeMapStore extends TestBase {
s.close(); s.close();
} }
private void testInMemory() {
for (int j = 0; j < 1; j++) {
BtreeMapStore s = openStore(null);
// s.setMaxPageSize(10);
// long t;
int len = 100;
// TreeMap<Integer, String> m = new TreeMap<Integer, String>();
// HashMap<Integer, String> m = New.hashMap();
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
// t = System.currentTimeMillis();
for (int i = 0; i < len; i++) {
m.put(i, "Hello World");
}
// System.out.println("put: " + (System.currentTimeMillis() - t));
// t = System.currentTimeMillis();
for (int i = 0; i < len; i++) {
assertEquals("Hello World", m.get(i));
}
// System.out.println("get: " + (System.currentTimeMillis() - t));
// t = System.currentTimeMillis();
for (int i = 0; i < len; i++) {
m.remove(i);
}
// System.out.println("remove: " + (System.currentTimeMillis() - t));
// System.out.println();
assertEquals(0, m.size());
s.close();
}
}
private void testLargeImport() { private void testLargeImport() {
String fileName = getBaseDir() + "/testImport.h3"; String fileName = getBaseDir() + "/testImport.h3";
int len = 1000; int len = 1000;
......
...@@ -75,7 +75,7 @@ public class BtreeMap<K, V> { ...@@ -75,7 +75,7 @@ public class BtreeMap<K, V> {
Object[] keys = { key }; Object[] keys = { key };
Object[] values = { value }; Object[] values = { value };
p = Page.create(this, writeVersion, 1, p = Page.create(this, writeVersion, 1,
keys, values, null, null, 1, 0); keys, values, null, null, null, 1, 0);
return p; return p;
} }
if (p.getKeyCount() > maxPageSize) { if (p.getKeyCount() > maxPageSize) {
...@@ -83,14 +83,15 @@ public class BtreeMap<K, V> { ...@@ -83,14 +83,15 @@ public class BtreeMap<K, V> {
// (this requires maxPageSize is fixed) // (this requires maxPageSize is fixed)
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
int at = p.getKeyCount() / 2; int at = p.getKeyCount() / 2;
long totalSize = p.getTotalSize(); long totalCount = p.getTotalCount();
Object k = p.getKey(at); Object k = p.getKey(at);
Page split = p.split(at); Page split = p.split(at);
Object[] keys = { k }; Object[] keys = { k };
long[] children = { p.getPos(), split.getPos() }; long[] children = { p.getPos(), split.getPos() };
long[] childrenSize = { p.getTotalSize(), split.getTotalSize() }; Page[] childrenPages = { p, split };
long[] counts = { p.getTotalCount(), split.getTotalCount() };
p = Page.create(this, writeVersion, 1, p = Page.create(this, writeVersion, 1,
keys, null, children, childrenSize, totalSize, 0); keys, null, children, childrenPages, counts, totalCount, 0);
// now p is a node; insert continues // now p is a node; insert continues
} else if (p.isLeaf()) { } else if (p.isLeaf()) {
int index = p.binarySearch(key); int index = p.binarySearch(key);
...@@ -119,13 +120,13 @@ public class BtreeMap<K, V> { ...@@ -119,13 +120,13 @@ public class BtreeMap<K, V> {
Page split = c.split(at); Page split = c.split(at);
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.setChild(index, split); p.setChild(index, split);
p.insertNode(index, k, c.getPos(), c.getTotalSize()); p.insertNode(index, k, c);
// now we are not sure where to add // now we are not sure where to add
return put(p, writeVersion, key, value, maxPageSize); return put(p, writeVersion, key, value, maxPageSize);
} }
long oldSize = c.getTotalSize(); long oldSize = c.getTotalCount();
Page c2 = put(c, writeVersion, key, value, maxPageSize); Page c2 = put(c, writeVersion, key, value, maxPageSize);
if (c != c2 || oldSize != c2.getTotalSize()) { if (c != c2 || oldSize != c2.getTotalCount()) {
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.setChild(index, c2); p.setChild(index, c2);
} }
...@@ -354,7 +355,7 @@ public class BtreeMap<K, V> { ...@@ -354,7 +355,7 @@ public class BtreeMap<K, V> {
index++; index++;
} }
Page c = p.getChildPage(index); Page c = p.getChildPage(index);
long oldSize = c.getTotalSize(); long oldCount = c.getTotalCount();
Page c2 = remove(c, writeVersion, key); Page c2 = remove(c, writeVersion, key);
if (c2 == null) { if (c2 == null) {
// this child was deleted // this child was deleted
...@@ -364,7 +365,7 @@ public class BtreeMap<K, V> { ...@@ -364,7 +365,7 @@ public class BtreeMap<K, V> {
removePage(p); removePage(p);
p = p.getChildPage(0); p = p.getChildPage(0);
} }
} else if (oldSize != c2.getTotalSize()) { } else if (oldCount != c2.getTotalCount()) {
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.setChild(index, c2); p.setChild(index, c2);
} }
...@@ -562,7 +563,7 @@ public class BtreeMap<K, V> { ...@@ -562,7 +563,7 @@ public class BtreeMap<K, V> {
} }
public long getSize() { public long getSize() {
return root == null ? 0 : root.getTotalSize(); return root == null ? 0 : root.getTotalCount();
} }
public boolean equals(Object o) { public boolean equals(Object o) {
......
...@@ -11,7 +11,6 @@ import java.io.StringReader; ...@@ -11,7 +11,6 @@ import java.io.StringReader;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet; import java.util.BitSet;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
...@@ -53,7 +52,6 @@ TODO: ...@@ -53,7 +52,6 @@ TODO:
- support large binaries - support large binaries
- support stores that span multiple files (chunks stored in other files) - support stores that span multiple files (chunks stored in other files)
- triggers - triggers
- compare with newest version of IndexedDb
- support database version / schema version - support database version / schema version
- implement more counted b-tree (skip, get positions) - implement more counted b-tree (skip, get positions)
- merge pages if small - merge pages if small
...@@ -83,10 +81,7 @@ public class BtreeMapStore { ...@@ -83,10 +81,7 @@ public class BtreeMapStore {
private int blockSize = 4 * 1024; private int blockSize = 4 * 1024;
private long rootChunkStart; private long rootChunkStart;
private int tempPageId;
private Map<Long, Page> cache = CacheLIRS.newInstance(readCacheSize, 2048); private Map<Long, Page> cache = CacheLIRS.newInstance(readCacheSize, 2048);
private HashMap<Long, Page> temp = New.hashMap();
private Page[] tempCache = new Page[64];
private int lastChunkId; private int lastChunkId;
private HashMap<Integer, Chunk> chunks = New.hashMap(); private HashMap<Integer, Chunk> chunks = New.hashMap();
...@@ -134,7 +129,7 @@ public class BtreeMapStore { ...@@ -134,7 +129,7 @@ public class BtreeMapStore {
/** /**
* Open a tree store. * Open a tree store.
* *
* @param fileName the file name * @param fileName the file name (null for in-memory)
* @param mapFactory the map factory * @param mapFactory the map factory
* @return the store * @return the store
*/ */
...@@ -306,6 +301,9 @@ public class BtreeMapStore { ...@@ -306,6 +301,9 @@ public class BtreeMapStore {
private void open() { private void open() {
meta = new BtreeMap<String, String>(this, 0, "meta", STRING_TYPE, STRING_TYPE, 0); meta = new BtreeMap<String, String>(this, 0, "meta", STRING_TYPE, STRING_TYPE, 0);
if (fileName == null) {
return;
}
FileUtils.createDirectories(FileUtils.getParent(fileName)); FileUtils.createDirectories(FileUtils.getParent(fileName));
try { try {
log("file open"); log("file open");
...@@ -397,8 +395,6 @@ public class BtreeMapStore { ...@@ -397,8 +395,6 @@ public class BtreeMapStore {
for (BtreeMap<?, ?> m : New.arrayList(maps.values())) { for (BtreeMap<?, ?> m : New.arrayList(maps.values())) {
m.close(); m.close();
} }
temp.clear();
Arrays.fill(tempCache, null);
meta = null; meta = null;
compressor = null; compressor = null;
chunks.clear(); chunks.clear();
...@@ -623,21 +619,6 @@ public class BtreeMapStore { ...@@ -623,21 +619,6 @@ public class BtreeMapStore {
return set.size() * blockSize; return set.size() * blockSize;
} }
/**
* Register a page and get the next temporary page id.
*
* @param p the new page
* @return the page id
*/
long registerTempPage(Page p) {
long pos = --tempPageId;
// use -pos so the Long cache can be used
temp.put(-pos, p);
int index = (int) pos & (tempCache.length - 1);
tempCache[index] = p;
return pos;
}
/** /**
* Check whether there are any unsaved changes. * Check whether there are any unsaved changes.
* *
...@@ -833,15 +814,6 @@ public class BtreeMapStore { ...@@ -833,15 +814,6 @@ public class BtreeMapStore {
* @return the page * @return the page
*/ */
Page readPage(BtreeMap<?, ?> map, long pos) { Page readPage(BtreeMap<?, ?> map, long pos) {
if (pos < 0) {
int index = (int) pos & (tempCache.length - 1);
Page p = tempCache[index];
if (p == null || p.getPos() != pos) {
p = temp.get(-pos);
tempCache[index] = p;
}
return p;
}
Page p = cache.get(pos); Page p = cache.get(pos);
if (p == null) { if (p == null) {
long filePos = getFilePosition(pos); long filePos = getFilePosition(pos);
...@@ -1033,9 +1005,6 @@ public class BtreeMapStore { ...@@ -1033,9 +1005,6 @@ public class BtreeMapStore {
m.revertTemp(); m.revertTemp();
} }
mapsChanged.clear(); mapsChanged.clear();
temp.clear();
Arrays.fill(tempCache, null);
tempPageId = 0;
} }
/** /**
......
...@@ -46,6 +46,7 @@ public class Page { ...@@ -46,6 +46,7 @@ public class Page {
private Object[] keys; private Object[] keys;
private Object[] values; private Object[] values;
private long[] children; private long[] children;
private Page[] childrenPages;
private long[] counts; private long[] counts;
private Page(BtreeMap<?, ?> map, long version) { private Page(BtreeMap<?, ?> map, long version) {
...@@ -65,14 +66,15 @@ public class Page { ...@@ -65,14 +66,15 @@ public class Page {
*/ */
public static Page create(BtreeMap<?, ?> map, long version, public static Page create(BtreeMap<?, ?> map, long version,
int keyCount, Object[] keys, int keyCount, Object[] keys,
Object[] values, long[] children, long[] counts, Object[] values, long[] children, Page[] childrenPages, long[] counts,
long totalCount, int sharedFlags) { long totalCount, int sharedFlags) {
Page p = new Page(map, version); Page p = new Page(map, version);
p.pos = map.getStore().registerTempPage(p); // the position is 0
p.keys = keys; p.keys = keys;
p.keyCount = keyCount; p.keyCount = keyCount;
p.values = values; p.values = values;
p.children = children; p.children = children;
p.childrenPages = childrenPages;
p.counts = counts; p.counts = counts;
p.totalCount = totalCount; p.totalCount = totalCount;
p.sharedFlags = sharedFlags; p.sharedFlags = sharedFlags;
...@@ -117,7 +119,8 @@ public class Page { ...@@ -117,7 +119,8 @@ public class Page {
} }
public Page getChildPage(int index) { public Page getChildPage(int index) {
return map.readPage(children[index]); Page p = childrenPages[index];
return p != null ? p : map.readPage(children[index]);
} }
public Object getValue(int x) { public Object getValue(int x) {
...@@ -168,7 +171,7 @@ public class Page { ...@@ -168,7 +171,7 @@ public class Page {
} }
map.getStore().removePage(pos); map.getStore().removePage(pos);
Page newPage = create(map, writeVersion, Page newPage = create(map, writeVersion,
keyCount, keys, values, children, keyCount, keys, values, children, childrenPages,
counts, totalCount, counts, totalCount,
SHARED_KEYS | SHARED_VALUES | SHARED_CHILDREN | SHARED_COUNTS); SHARED_KEYS | SHARED_VALUES | SHARED_CHILDREN | SHARED_COUNTS);
newPage.cachedCompare = cachedCompare; newPage.cachedCompare = cachedCompare;
...@@ -243,29 +246,39 @@ public class Page { ...@@ -243,29 +246,39 @@ public class Page {
sharedFlags &= ~(SHARED_KEYS | SHARED_VALUES); sharedFlags &= ~(SHARED_KEYS | SHARED_VALUES);
totalCount = a; totalCount = a;
Page newPage = create(map, version, b, Page newPage = create(map, version, b,
bKeys, bValues, null, null, bKeys, bValues, null, null, null,
bKeys.length, 0); bKeys.length, 0);
return newPage; return newPage;
} }
private Page splitNode(int at) { private Page splitNode(int at) {
int a = at, b = keyCount - a; int a = at, b = keyCount - a;
Object[] aKeys = new Object[a]; Object[] aKeys = new Object[a];
Object[] bKeys = new Object[b - 1]; Object[] bKeys = new Object[b - 1];
System.arraycopy(keys, 0, aKeys, 0, a); System.arraycopy(keys, 0, aKeys, 0, a);
System.arraycopy(keys, a + 1, bKeys, 0, b - 1); System.arraycopy(keys, a + 1, bKeys, 0, b - 1);
keys = aKeys; keys = aKeys;
keyCount = a; keyCount = a;
long[] aChildren = new long[a + 1]; long[] aChildren = new long[a + 1];
long[] bChildren = new long[b]; long[] bChildren = new long[b];
System.arraycopy(children, 0, aChildren, 0, a + 1); System.arraycopy(children, 0, aChildren, 0, a + 1);
System.arraycopy(children, a + 1, bChildren, 0, b); System.arraycopy(children, a + 1, bChildren, 0, b);
children = aChildren; children = aChildren;
Page[] aChildrenPages = new Page[a + 1];
Page[] bChildrenPages = new Page[b];
System.arraycopy(childrenPages, 0, aChildrenPages, 0, a + 1);
System.arraycopy(childrenPages, a + 1, bChildrenPages, 0, b);
childrenPages = aChildrenPages;
long[] aCounts = new long[a + 1]; long[] aCounts = new long[a + 1];
long[] bCounts = new long[b]; long[] bCounts = new long[b];
System.arraycopy(counts, 0, aCounts, 0, a + 1); System.arraycopy(counts, 0, aCounts, 0, a + 1);
System.arraycopy(counts, a + 1, bCounts, 0, b); System.arraycopy(counts, a + 1, bCounts, 0, b);
counts = aCounts; counts = aCounts;
sharedFlags &= ~(SHARED_KEYS | SHARED_CHILDREN | SHARED_COUNTS); sharedFlags &= ~(SHARED_KEYS | SHARED_CHILDREN | SHARED_COUNTS);
long t = 0; long t = 0;
for (long x : aCounts) { for (long x : aCounts) {
...@@ -277,12 +290,12 @@ public class Page { ...@@ -277,12 +290,12 @@ public class Page {
t += x; t += x;
} }
Page newPage = create(map, version, b - 1, Page newPage = create(map, version, b - 1,
bKeys, null, bChildren, bKeys, null, bChildren, bChildrenPages,
bCounts, t, 0); bCounts, t, 0);
return newPage; return newPage;
} }
public long getTotalSize() { public long getTotalCount() {
if (BtreeMapStore.ASSERT) { if (BtreeMapStore.ASSERT) {
long check = 0; long check = 0;
if (isLeaf()) { if (isLeaf()) {
...@@ -304,17 +317,19 @@ public class Page { ...@@ -304,17 +317,19 @@ public class Page {
if (c.getPos() != children[index]) { if (c.getPos() != children[index]) {
if ((sharedFlags & SHARED_CHILDREN) != 0) { if ((sharedFlags & SHARED_CHILDREN) != 0) {
children = Arrays.copyOf(children, children.length); children = Arrays.copyOf(children, children.length);
childrenPages = Arrays.copyOf(childrenPages, childrenPages.length);
sharedFlags &= ~SHARED_CHILDREN; sharedFlags &= ~SHARED_CHILDREN;
} }
children[index] = c.getPos(); children[index] = c.getPos();
childrenPages[index] = c;
} }
if (c.getTotalSize() != counts[index]) { if (c.getTotalCount() != counts[index]) {
if ((sharedFlags & SHARED_COUNTS) != 0) { if ((sharedFlags & SHARED_COUNTS) != 0) {
counts = Arrays.copyOf(counts, counts.length); counts = Arrays.copyOf(counts, counts.length);
sharedFlags &= ~SHARED_COUNTS; sharedFlags &= ~SHARED_COUNTS;
} }
long oldCount = counts[index]; long oldCount = counts[index];
counts[index] = c.getTotalSize(); counts[index] = c.getTotalCount();
totalCount += counts[index] - oldCount; totalCount += counts[index] - oldCount;
} }
} }
...@@ -340,12 +355,18 @@ public class Page { ...@@ -340,12 +355,18 @@ public class Page {
*/ */
void removeAllRecursive() { void removeAllRecursive() {
if (children != null) { if (children != null) {
for (long c : children) { for (int i = 0, size = children.length; i < size; i++) {
int type = DataUtils.getPageType(c); Page p = childrenPages[i];
if (type == DataUtils.PAGE_TYPE_LEAF) { if (p != null) {
map.getStore().removePage(c); p.removeAllRecursive();
} else { } else {
map.readPage(c).removeAllRecursive(); long c = children[i];
int type = DataUtils.getPageType(c);
if (type == DataUtils.PAGE_TYPE_LEAF) {
map.getStore().removePage(c);
} else {
map.readPage(c).removeAllRecursive();
}
} }
} }
} }
...@@ -374,52 +395,118 @@ public class Page { ...@@ -374,52 +395,118 @@ public class Page {
totalCount++; totalCount++;
} }
public void insertNode(int index, Object key, long child, long count) { public void insertNode(int index, Object key, Page childPage) {
Object[] newKeys = new Object[keyCount + 1]; Object[] newKeys = new Object[keyCount + 1];
DataUtils.copyWithGap(keys, newKeys, keyCount, index); DataUtils.copyWithGap(keys, newKeys, keyCount, index);
newKeys[index] = key; newKeys[index] = key;
keys = newKeys; keys = newKeys;
keyCount++; keyCount++;
long[] newChildren = new long[children.length + 1]; long[] newChildren = new long[children.length + 1];
DataUtils.copyWithGap(children, newChildren, children.length, index); DataUtils.copyWithGap(children, newChildren, children.length, index);
newChildren[index] = child; newChildren[index] = childPage.getPos();
children = newChildren; children = newChildren;
Page[] newChildrenPages = new Page[childrenPages.length + 1];
DataUtils.copyWithGap(childrenPages, newChildrenPages, childrenPages.length, index);
newChildrenPages[index] = childPage;
childrenPages = newChildrenPages;
long[] newCounts = new long[counts.length + 1]; long[] newCounts = new long[counts.length + 1];
DataUtils.copyWithGap(counts, newCounts, counts.length, index); DataUtils.copyWithGap(counts, newCounts, counts.length, index);
newCounts[index] = count; newCounts[index] = childPage.getTotalCount();
counts = newCounts; counts = newCounts;
sharedFlags &= ~(SHARED_KEYS | SHARED_CHILDREN | SHARED_COUNTS); sharedFlags &= ~(SHARED_KEYS | SHARED_CHILDREN | SHARED_COUNTS);
totalCount += count; totalCount += childPage.getTotalCount();
} }
public void remove(int index) { public void remove(int index) {
Object[] newKeys = new Object[keyCount - 1];
int keyIndex = index >= keyCount ? index - 1 : index; int keyIndex = index >= keyCount ? index - 1 : index;
DataUtils.copyExcept(keys, newKeys, keyCount, keyIndex); if ((sharedFlags & SHARED_KEYS) == 0 && keys.length > keyCount - 4) {
keys = newKeys; if (keyIndex < keyCount - 1) {
sharedFlags &= ~SHARED_KEYS; System.arraycopy(keys, keyIndex + 1, keys, keyIndex, keyCount - keyIndex - 1);
}
keys[keyCount - 1] = null;
} else {
Object[] newKeys = new Object[keyCount - 1];
DataUtils.copyExcept(keys, newKeys, keyCount, keyIndex);
keys = newKeys;
sharedFlags &= ~SHARED_KEYS;
}
if (values != null) { if (values != null) {
Object[] newValues = new Object[keyCount - 1]; if ((sharedFlags & SHARED_VALUES) == 0 && values.length > keyCount - 4) {
DataUtils.copyExcept(values, newValues, keyCount, index); if (index < keyCount - 1) {
values = newValues; System.arraycopy(values, index + 1, values, index, keyCount - index - 1);
sharedFlags &= ~SHARED_VALUES; }
values[keyCount - 1] = null;
} else {
Object[] newValues = new Object[keyCount - 1];
DataUtils.copyExcept(values, newValues, keyCount, index);
values = newValues;
sharedFlags &= ~SHARED_VALUES;
}
totalCount--; totalCount--;
} }
keyCount--; keyCount--;
if (children != null) { if (children != null) {
long countOffset = counts[index]; long countOffset = counts[index];
long[] newChildren = new long[children.length - 1]; long[] newChildren = new long[children.length - 1];
DataUtils.copyExcept(children, newChildren, children.length, index); DataUtils.copyExcept(children, newChildren, children.length, index);
children = newChildren; children = newChildren;
Page[] newChildrenPages = new Page[childrenPages.length - 1];
DataUtils.copyExcept(childrenPages, newChildrenPages,
childrenPages.length, index);
childrenPages = newChildrenPages;
long[] newCounts = new long[counts.length - 1]; long[] newCounts = new long[counts.length - 1];
DataUtils.copyExcept(counts, newCounts, DataUtils.copyExcept(counts, newCounts, counts.length, index);
counts.length, index);
counts = newCounts; counts = newCounts;
sharedFlags &= ~(SHARED_CHILDREN | SHARED_COUNTS); sharedFlags &= ~(SHARED_CHILDREN | SHARED_COUNTS);
totalCount -= countOffset; totalCount -= countOffset;
} }
} }
// public void remove(int index) {
// Object[] newKeys = new Object[keyCount - 1];
// int keyIndex = index >= keyCount ? index - 1 : index;
// DataUtils.copyExcept(keys, newKeys, keyCount, keyIndex);
// keys = newKeys;
// sharedFlags &= ~SHARED_KEYS;
// if (values != null) {
// Object[] newValues = new Object[keyCount - 1];
// DataUtils.copyExcept(values, newValues, keyCount, index);
// values = newValues;
// sharedFlags &= ~SHARED_VALUES;
// totalCount--;
// }
// keyCount--;
// if (children != null) {
// long countOffset = counts[index];
//
// long[] newChildren = new long[children.length - 1];
// DataUtils.copyExcept(children, newChildren, children.length, index);
// children = newChildren;
//
// Page[] newChildrenPages = new Page[childrenPages.length - 1];
// DataUtils.copyExcept(childrenPages, newChildrenPages, childrenPages.length, index);
// childrenPages = newChildrenPages;
//
// long[] newCounts = new long[counts.length - 1];
// DataUtils.copyExcept(counts, newCounts,
// counts.length, index);
// counts = newCounts;
//
// sharedFlags &= ~(SHARED_CHILDREN | SHARED_COUNTS);
// totalCount -= countOffset;
// }
// }
private void read(ByteBuffer buff, int chunkId, int offset, int maxLength) { private void read(ByteBuffer buff, int chunkId, int offset, int maxLength) {
int start = buff.position(); int start = buff.position();
int pageLength = buff.getInt(); int pageLength = buff.getInt();
...@@ -464,6 +551,7 @@ public class Page { ...@@ -464,6 +551,7 @@ public class Page {
for (int i = 0; i <= len; i++) { for (int i = 0; i <= len; i++) {
children[i] = buff.getLong(); children[i] = buff.getLong();
} }
childrenPages = new Page[len + 1];
counts = new long[len + 1]; counts = new long[len + 1];
long total = 0; long total = 0;
for (int i = 0; i <= len; i++) { for (int i = 0; i <= len; i++) {
...@@ -550,19 +638,19 @@ public class Page { ...@@ -550,19 +638,19 @@ public class Page {
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
maxLength += map.getKeyType().getMaxLength(keys[i]); maxLength += map.getKeyType().getMaxLength(keys[i]);
} }
if (children != null) { if (isLeaf()) {
for (int i = 0; i < len; i++) {
maxLength += map.getValueType().getMaxLength(values[i]);
}
} else {
maxLength += 8 * len; maxLength += 8 * len;
maxLength += DataUtils.MAX_VAR_LONG_LEN * len; maxLength += DataUtils.MAX_VAR_LONG_LEN * len;
for (int i = 0; i <= len; i++) { for (int i = 0; i <= len; i++) {
long c = children[i]; Page p = childrenPages[i];
if (c < 0) { if (p != null) {
maxLength += map.readPage(c).getMaxLengthTempRecursive(); maxLength += p.getMaxLengthTempRecursive();
} }
} }
} else {
for (int i = 0; i < len; i++) {
maxLength += map.getValueType().getMaxLength(values[i]);
}
} }
return maxLength; return maxLength;
} }
...@@ -576,13 +664,13 @@ public class Page { ...@@ -576,13 +664,13 @@ public class Page {
* @return the page id * @return the page id
*/ */
long writeTempRecursive(ByteBuffer buff, int chunkId) { long writeTempRecursive(ByteBuffer buff, int chunkId) {
if (children != null) { if (!isLeaf()) {
int len = children.length; int len = children.length;
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
long c = children[i]; Page p = childrenPages[i];
if (c < 0) { if (p != null) {
children[i] = map.readPage(c).writeTempRecursive(buff, children[i] = p.writeTempRecursive(buff, chunkId);
chunkId); childrenPages[i] = null;
} }
} }
} }
...@@ -597,12 +685,10 @@ public class Page { ...@@ -597,12 +685,10 @@ public class Page {
*/ */
int countTempRecursive() { int countTempRecursive() {
int count = 1; int count = 1;
if (children != null) { if (!isLeaf()) {
int size = children.length; for (Page p : childrenPages) {
for (int i = 0; i < size; i++) { if (p != null) {
long c = children[i]; count += p.countTempRecursive();
if (c < 0) {
count += map.readPage(c).countTempRecursive();
} }
} }
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论