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

A persistent multi-version map (work in progress)

上级 1217a01e
...@@ -19,11 +19,6 @@ import java.util.TreeMap; ...@@ -19,11 +19,6 @@ import java.util.TreeMap;
*/ */
public class BtreeMap<K, V> { public class BtreeMap<K, V> {
protected static final IllegalArgumentException KEY_NOT_FOUND = new IllegalArgumentException(
"Key not found");
protected static final IllegalArgumentException KEY_ALREADY_EXISTS = new IllegalArgumentException(
"Key already exists");
protected Page root; protected Page root;
protected BtreeMapStore store; protected BtreeMapStore store;
...@@ -59,76 +54,32 @@ public class BtreeMap<K, V> { ...@@ -59,76 +54,32 @@ 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;
if (containsKey(key)) { root = put(oldRoot, store.getCurrentVersion(), key, data, store.getMaxPageSize());
root = set(root, store.getCurrentVersion(), key, data);
} else {
root = add(root, store.getCurrentVersion(), key, data);
}
markChanged(oldRoot); markChanged(oldRoot);
} }
/** /**
* Update a value for an existing key. * Add or update a key-value pair.
*
* @param map the map
* @param p the page (may not be null)
* @param writeVersion the write version
* @param key the key
* @param value the value
* @return the root page
* @throws InvalidArgumentException if this key does not exist (without
* stack trace)
*/
protected Page set(Page p, long writeVersion, Object key, Object value) {
if (p == null) {
throw KEY_NOT_FOUND;
}
int index = p.binarySearch(key);
if (p.isLeaf()) {
if (index < 0) {
throw KEY_NOT_FOUND;
}
p = p.copyOnWrite(writeVersion);
p.setValue(index, value);
return p;
}
// it is a node
if (index < 0) {
index = -index - 1;
} else {
index++;
}
Page c = p.getChildPage(index);
Page c2 = set(c, writeVersion, key, value);
if (c != c2) {
p = p.copyOnWrite(writeVersion);
p.setChild(index, c2);
}
return p;
}
/**
* Add a new key-value pair.
* *
* @param map the map * @param map the map
* @param p the page (may be null) * @param p the page (may be null)
* @param writeVersion the write version * @param writeVersion the write version
* @param key the key * @param key the key
* @param value the value * @param value the value (may not be null)
* @param maxPageSize the maximum page size
* @return the root page * @return the root page
* @throws InvalidArgumentException if this key already exists (without
* stack trace)
*/ */
protected Page add(Page p, long writeVersion, Object key, Object value) { protected Page put(Page p, long writeVersion, Object key, Object value, int maxPageSize) {
if (p == null) { if (p == null) {
Object[] keys = { key }; Object[] keys = { key };
Object[] values = { value }; Object[] values = { value };
p = Page.create(this, writeVersion, keys, values, null, null, 1); p = Page.create(this, writeVersion, 1,
keys, values, null, null, 1, 0);
return p; return p;
} }
if (p.getKeyCount() >= store.getMaxPageSize()) { if (p.getKeyCount() > maxPageSize) {
// only possible if this is the root, // only possible if this is the root, else we would have split earlier
// otherwise we would have split earlier // (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 totalSize = p.getTotalSize();
...@@ -137,17 +88,18 @@ public class BtreeMap<K, V> { ...@@ -137,17 +88,18 @@ public class BtreeMap<K, V> {
Object[] keys = { k }; Object[] keys = { k };
long[] children = { p.getPos(), split.getPos() }; long[] children = { p.getPos(), split.getPos() };
long[] childrenSize = { p.getTotalSize(), split.getTotalSize() }; long[] childrenSize = { p.getTotalSize(), split.getTotalSize() };
p = Page.create(this, writeVersion, keys, null, children, childrenSize, p = Page.create(this, writeVersion, 1,
totalSize); keys, null, children, childrenSize, totalSize, 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);
if (index >= 0) {
throw KEY_ALREADY_EXISTS;
}
index = -index - 1;
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.insert(index, key, value, 0, 0); if (index < 0) {
index = -index - 1;
p.insertLeaf(index, key, value);
} else {
p.setValue(index, value);
}
return p; return p;
} }
// p is a node // p is a node
...@@ -158,7 +110,7 @@ public class BtreeMap<K, V> { ...@@ -158,7 +110,7 @@ public class BtreeMap<K, V> {
index++; index++;
} }
Page c = p.getChildPage(index); Page c = p.getChildPage(index);
if (c.getKeyCount() >= store.getMaxPageSize()) { if (c.getKeyCount() >= maxPageSize) {
// split on the way down // split on the way down
c = c.copyOnWrite(writeVersion); c = c.copyOnWrite(writeVersion);
int at = c.getKeyCount() / 2; int at = c.getKeyCount() / 2;
...@@ -166,14 +118,16 @@ public class BtreeMap<K, V> { ...@@ -166,14 +118,16 @@ 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.insert(index, k, null, c.getPos(), c.getTotalSize()); p.insertNode(index, k, c.getPos(), c.getTotalSize());
// now we are not sure where to add // now we are not sure where to add
return add(p, writeVersion, key, value); return put(p, writeVersion, key, value, maxPageSize);
} }
Page c2 = add(c, writeVersion, key, value); long oldSize = c.getTotalSize();
Page c2 = put(c, writeVersion, key, value, maxPageSize);
if (c != c2 || oldSize != c2.getTotalSize()) {
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
// the child might be the same, but not the size
p.setChild(index, c2); p.setChild(index, c2);
}
return p; return p;
} }
...@@ -364,26 +318,22 @@ public class BtreeMap<K, V> { ...@@ -364,26 +318,22 @@ public class BtreeMap<K, V> {
*/ */
public void remove(K key) { public void remove(K key) {
checkWrite(); checkWrite();
if (containsKey(key)) {
Page oldRoot = root; Page oldRoot = root;
root = removeExisting(root, store.getCurrentVersion(), key); if (oldRoot != null) {
root = remove(oldRoot, store.getCurrentVersion(), key);
markChanged(oldRoot); markChanged(oldRoot);
} }
} }
/** /**
* Remove an existing key-value pair. * Remove a key-value pair.
* *
* @param p the page (may not be null) * @param p the page (may not be null)
* @param writeVersion the write version * @param writeVersion the write version
* @param key the key * @param key the key
* @return the new root page (null if empty) * @return the new root page (null if empty)
* @throws InvalidArgumentException if not found (without stack trace)
*/ */
protected Page removeExisting(Page p, long writeVersion, Object key) { protected Page remove(Page p, long writeVersion, Object key) {
if (p == null) {
throw KEY_NOT_FOUND;
}
int index = p.binarySearch(key); int index = p.binarySearch(key);
if (p.isLeaf()) { if (p.isLeaf()) {
if (index >= 0) { if (index >= 0) {
...@@ -393,8 +343,6 @@ public class BtreeMap<K, V> { ...@@ -393,8 +343,6 @@ public class BtreeMap<K, V> {
} }
p = p.copyOnWrite(writeVersion); p = p.copyOnWrite(writeVersion);
p.remove(index); p.remove(index);
} else {
throw KEY_NOT_FOUND;
} }
return p; return p;
} }
...@@ -405,16 +353,18 @@ public class BtreeMap<K, V> { ...@@ -405,16 +353,18 @@ public class BtreeMap<K, V> {
index++; index++;
} }
Page c = p.getChildPage(index); Page c = p.getChildPage(index);
Page c2 = removeExisting(c, writeVersion, key); long oldSize = c.getTotalSize();
p = p.copyOnWrite(writeVersion); Page c2 = remove(c, writeVersion, key);
if (c2 == null) { if (c2 == null) {
// this child was deleted // this child was deleted
p = p.copyOnWrite(writeVersion);
p.remove(index); p.remove(index);
if (p.getKeyCount() == 0) { if (p.getKeyCount() == 0) {
removePage(p); removePage(p);
p = p.getChildPage(0); p = p.getChildPage(0);
} }
} else { } else if (oldSize != c2.getTotalSize()) {
p = p.copyOnWrite(writeVersion);
p.setChild(index, c2); p.setChild(index, c2);
} }
return p; return p;
......
...@@ -11,6 +11,7 @@ import java.io.StringReader; ...@@ -11,6 +11,7 @@ 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;
...@@ -56,6 +57,7 @@ TODO: ...@@ -56,6 +57,7 @@ TODO:
- compare with newest version of IndexedDb - 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
*/ */
...@@ -64,7 +66,7 @@ TODO: ...@@ -64,7 +66,7 @@ TODO:
*/ */
public class BtreeMapStore { public class BtreeMapStore {
public static final boolean ASSERT = true; public static final boolean ASSERT = false;
private static final StringType STRING_TYPE = new StringType(); private static final StringType STRING_TYPE = new StringType();
...@@ -82,6 +84,7 @@ public class BtreeMapStore { ...@@ -82,6 +84,7 @@ public class BtreeMapStore {
private int tempPageId; 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 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();
...@@ -367,6 +370,7 @@ public class BtreeMapStore { ...@@ -367,6 +370,7 @@ public class BtreeMapStore {
m.close(); m.close();
} }
temp.clear(); temp.clear();
Arrays.fill(tempCache, null);
meta = null; meta = null;
compressor = null; compressor = null;
chunks.clear(); chunks.clear();
...@@ -598,9 +602,11 @@ public class BtreeMapStore { ...@@ -598,9 +602,11 @@ public class BtreeMapStore {
* @return the page id * @return the page id
*/ */
long registerTempPage(Page p) { long registerTempPage(Page p) {
long id = --tempPageId; long pos = --tempPageId;
temp.put(id, p); temp.put(pos, p);
return id; int index = (int) pos & (tempCache.length - 1);
tempCache[index] = p;
return pos;
} }
/** /**
...@@ -799,7 +805,13 @@ public class BtreeMapStore { ...@@ -799,7 +805,13 @@ public class BtreeMapStore {
*/ */
Page readPage(BtreeMap<?, ?> map, long pos) { Page readPage(BtreeMap<?, ?> map, long pos) {
if (pos < 0) { if (pos < 0) {
return temp.get(pos); 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) {
...@@ -993,6 +1005,7 @@ public class BtreeMapStore { ...@@ -993,6 +1005,7 @@ public class BtreeMapStore {
} }
mapsChanged.clear(); mapsChanged.clear();
temp.clear(); temp.clear();
Arrays.fill(tempCache, null);
tempPageId = 0; tempPageId = 0;
} }
......
...@@ -9,6 +9,7 @@ package org.h2.dev.store.btree; ...@@ -9,6 +9,7 @@ package org.h2.dev.store.btree;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel; import java.nio.channels.FileChannel;
import java.util.Arrays;
import org.h2.compress.Compressor; import org.h2.compress.Compressor;
/** /**
...@@ -24,15 +25,28 @@ import org.h2.compress.Compressor; ...@@ -24,15 +25,28 @@ import org.h2.compress.Compressor;
*/ */
public class Page { public class Page {
private static final int SHARED_KEYS = 1, SHARED_VALUES = 2, SHARED_CHILDREN = 4, SHARED_COUNTS = 8;
private final BtreeMap<?, ?> map; private final BtreeMap<?, ?> map;
private final long version; private final long version;
private long pos; private long pos;
private long totalCount;
private int keyCount;
/**
* The last result of a find operation is cached.
*/
private int cachedCompare;
/**
* Which arrays are shared with another version of this page.
*/
private int sharedFlags;
private Object[] keys; private Object[] keys;
private Object[] values; private Object[] values;
private long[] children; private long[] children;
private long[] counts; private long[] counts;
private int cachedCompare;
private long totalCount;
private Page(BtreeMap<?, ?> map, long version) { private Page(BtreeMap<?, ?> map, long version) {
this.map = map; this.map = map;
...@@ -49,16 +63,19 @@ public class Page { ...@@ -49,16 +63,19 @@ public class Page {
* @param children the children * @param children the children
* @return the page * @return the page
*/ */
public static Page create(BtreeMap<?, ?> map, long version, Object[] keys, public static Page create(BtreeMap<?, ?> map, long version,
int keyCount, Object[] keys,
Object[] values, long[] children, long[] counts, Object[] values, long[] children, long[] counts,
long totalCount) { long totalCount, int sharedFlags) {
Page p = new Page(map, version); Page p = new Page(map, version);
p.pos = map.getStore().registerTempPage(p); p.pos = map.getStore().registerTempPage(p);
p.keys = keys; p.keys = keys;
p.keyCount = keyCount;
p.values = values; p.values = values;
p.children = children; p.children = children;
p.counts = counts; p.counts = counts;
p.totalCount = totalCount; p.totalCount = totalCount;
p.sharedFlags = sharedFlags;
return p; return p;
} }
...@@ -70,8 +87,8 @@ public class Page { ...@@ -70,8 +87,8 @@ public class Page {
* @param buff the source buffer * @param buff the source buffer
* @return the page * @return the page
*/ */
static Page read(FileChannel file, BtreeMap<?, ?> map, long filePos, static Page read(FileChannel file, BtreeMap<?, ?> map,
long pos) { long filePos, long pos) {
int maxLength = DataUtils.getPageMaxLength(pos), length = maxLength; int maxLength = DataUtils.getPageMaxLength(pos), length = maxLength;
ByteBuffer buff; ByteBuffer buff;
try { try {
...@@ -108,7 +125,7 @@ public class Page { ...@@ -108,7 +125,7 @@ public class Page {
} }
public int getKeyCount() { public int getKeyCount() {
return keys.length; return keyCount;
} }
public boolean isLeaf() { public boolean isLeaf() {
...@@ -127,14 +144,14 @@ public class Page { ...@@ -127,14 +144,14 @@ public class Page {
public String toString() { public String toString() {
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
buff.append("pos: ").append(pos).append("\n"); buff.append("pos: ").append(pos).append("\n");
for (int i = 0; i <= keys.length; i++) { for (int i = 0; i <= keyCount; i++) {
if (i > 0) { if (i > 0) {
buff.append(" "); buff.append(" ");
} }
if (children != null) { if (children != null) {
buff.append("[" + children[i] + "] "); buff.append("[" + children[i] + "] ");
} }
if (i < keys.length) { if (i < keyCount) {
buff.append(keys[i]); buff.append(keys[i]);
if (values != null) { if (values != null) {
buff.append(':'); buff.append(':');
...@@ -150,8 +167,10 @@ public class Page { ...@@ -150,8 +167,10 @@ public class Page {
return this; return this;
} }
map.getStore().removePage(pos); map.getStore().removePage(pos);
Page newPage = create(map, writeVersion, keys, values, children, Page newPage = create(map, writeVersion,
counts, totalCount); keyCount, keys, values, children,
counts, totalCount,
SHARED_KEYS | SHARED_VALUES | SHARED_CHILDREN | SHARED_COUNTS);
newPage.cachedCompare = cachedCompare; newPage.cachedCompare = cachedCompare;
return newPage; return newPage;
} }
...@@ -167,7 +186,7 @@ public class Page { ...@@ -167,7 +186,7 @@ public class Page {
* @return the value or null * @return the value or null
*/ */
public int binarySearch(Object key) { public int binarySearch(Object key) {
int low = 0, high = keys.length - 1; int low = 0, high = keyCount - 1;
int x = cachedCompare - 1; int x = cachedCompare - 1;
if (x < 0 || x > high) { if (x < 0 || x > high) {
x = (low + high) >>> 1; x = (low + high) >>> 1;
...@@ -188,7 +207,7 @@ public class Page { ...@@ -188,7 +207,7 @@ public class Page {
return -(low + 1); return -(low + 1);
// regular binary search (without caching) // regular binary search (without caching)
// int low = 0, high = keys.length - 1; // int low = 0, high = keyCount - 1;
// while (low <= high) { // while (low <= high) {
// int x = (low + high) >>> 1; // int x = (low + high) >>> 1;
// int compare = map.compare(key, keys[x]); // int compare = map.compare(key, keys[x]);
...@@ -208,31 +227,35 @@ public class Page { ...@@ -208,31 +227,35 @@ public class Page {
} }
private Page splitLeaf(int at) { private Page splitLeaf(int at) {
int a = at, b = keys.length - a; int a = at, b = keyCount - a;
Object[] aKeys = new Object[a]; Object[] aKeys = new Object[a];
Object[] bKeys = new Object[b]; Object[] bKeys = new Object[b];
System.arraycopy(keys, 0, aKeys, 0, a); System.arraycopy(keys, 0, aKeys, 0, a);
System.arraycopy(keys, a, bKeys, 0, b); System.arraycopy(keys, a, bKeys, 0, b);
keys = aKeys; keys = aKeys;
keyCount = a;
Object[] aValues = new Object[a]; Object[] aValues = new Object[a];
Object[] bValues = new Object[b]; Object[] bValues = new Object[b];
bValues = new Object[b]; bValues = new Object[b];
System.arraycopy(values, 0, aValues, 0, a); System.arraycopy(values, 0, aValues, 0, a);
System.arraycopy(values, a, bValues, 0, b); System.arraycopy(values, a, bValues, 0, b);
values = aValues; values = aValues;
totalCount = keys.length; sharedFlags &= ~(SHARED_KEYS | SHARED_VALUES);
Page newPage = create(map, version, bKeys, bValues, null, null, totalCount = a;
bKeys.length); Page newPage = create(map, version, b,
bKeys, bValues, null, null,
bKeys.length, 0);
return newPage; return newPage;
} }
private Page splitNode(int at) { private Page splitNode(int at) {
int a = at, b = keys.length - 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;
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);
...@@ -243,6 +266,7 @@ public class Page { ...@@ -243,6 +266,7 @@ public class Page {
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);
long t = 0; long t = 0;
for (long x : aCounts) { for (long x : aCounts) {
t += x; t += x;
...@@ -252,8 +276,9 @@ public class Page { ...@@ -252,8 +276,9 @@ public class Page {
for (long x : bCounts) { for (long x : bCounts) {
t += x; t += x;
} }
Page newPage = create(map, version, bKeys, null, bChildren, Page newPage = create(map, version, b - 1,
bCounts, t); bKeys, null, bChildren,
bCounts, t, 0);
return newPage; return newPage;
} }
...@@ -261,7 +286,7 @@ public class Page { ...@@ -261,7 +286,7 @@ public class Page {
if (BtreeMapStore.ASSERT) { if (BtreeMapStore.ASSERT) {
long check = 0; long check = 0;
if (isLeaf()) { if (isLeaf()) {
check = keys.length; check = keyCount;
} else { } else {
for (long x : counts) { for (long x : counts) {
check += x; check += x;
...@@ -277,37 +302,37 @@ public class Page { ...@@ -277,37 +302,37 @@ public class Page {
public void setChild(int index, Page c) { public void setChild(int index, Page c) {
if (c.getPos() != children[index]) { if (c.getPos() != children[index]) {
long[] newChildren = new long[children.length]; if ((sharedFlags & SHARED_CHILDREN) != 0) {
System.arraycopy(children, 0, newChildren, 0, newChildren.length); children = Arrays.copyOf(children, children.length);
newChildren[index] = c.getPos(); sharedFlags &= ~SHARED_CHILDREN;
children = newChildren; }
children[index] = c.getPos();
} }
if (c.getTotalSize() != counts[index]) { if (c.getTotalSize() != counts[index]) {
long[] newCounts = new long[counts.length]; if ((sharedFlags & SHARED_COUNTS) != 0) {
System.arraycopy(counts, 0, newCounts, 0, counts = Arrays.copyOf(counts, counts.length);
newCounts.length); sharedFlags &= ~SHARED_COUNTS;
newCounts[index] = c.getTotalSize(); }
totalCount += newCounts[index] - counts[index]; long oldCount = counts[index];
counts = newCounts; counts[index] = c.getTotalSize();
totalCount += counts[index] - oldCount;
} }
} }
public void setKey(int index, Object key) { public void setKey(int index, Object key) {
// create a copy - not required if already cloned once in this version, if ((sharedFlags & SHARED_KEYS) != 0) {
// but avoid unnecessary cloning would require a "modified" flag keys = Arrays.copyOf(keys, keys.length);
Object[] newKeys = new Object[keys.length]; sharedFlags &= ~SHARED_KEYS;
System.arraycopy(keys, 0, newKeys, 0, newKeys.length); }
newKeys[index] = key; keys[index] = key;
keys = newKeys;
} }
public void setValue(int index, Object value) { public void setValue(int index, Object value) {
// create a copy - not required if already cloned once in this version, if ((sharedFlags & SHARED_VALUES) != 0) {
// but avoid unnecessary cloning would require a "modified" flag values = Arrays.copyOf(values, values.length);
Object[] newValues = new Object[values.length]; sharedFlags &= ~SHARED_VALUES;
System.arraycopy(values, 0, newValues, 0, newValues.length); }
newValues[index] = value; values[index] = value;
values = newValues;
} }
/** /**
...@@ -327,20 +352,34 @@ public class Page { ...@@ -327,20 +352,34 @@ public class Page {
map.getStore().removePage(pos); map.getStore().removePage(pos);
} }
public void insert(int index, Object key, Object value, long child, public void insertLeaf(int index, Object key, Object value) {
long count) { if (((sharedFlags & SHARED_KEYS) == 0) && keys.length > keyCount + 1) {
Object[] newKeys = new Object[keys.length + 1]; if (index < keyCount) {
DataUtils.copyWithGap(keys, newKeys, keys.length, index); System.arraycopy(keys, index, keys, index + 1, keyCount - index);
newKeys[index] = key; System.arraycopy(values, index, values, index + 1, keyCount - index);
}
} else {
int len = keyCount + 6;
Object[] newKeys = new Object[len];
DataUtils.copyWithGap(keys, newKeys, keyCount, index);
keys = newKeys; keys = newKeys;
if (values != null) { Object[] newValues = new Object[len];
Object[] newValues = new Object[values.length + 1]; DataUtils.copyWithGap(values, newValues, keyCount, index);
DataUtils.copyWithGap(values, newValues, values.length, index);
newValues[index] = value;
values = newValues; values = newValues;
}
keys[index] = key;
values[index] = value;
keyCount++;
sharedFlags &= ~(SHARED_KEYS | SHARED_VALUES);
totalCount++; totalCount++;
} }
if (children != null) {
public void insertNode(int index, Object key, long child, long count) {
Object[] newKeys = new Object[keyCount + 1];
DataUtils.copyWithGap(keys, newKeys, keyCount, index);
newKeys[index] = key;
keys = newKeys;
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] = child;
...@@ -349,21 +388,24 @@ public class Page { ...@@ -349,21 +388,24 @@ public class Page {
DataUtils.copyWithGap(counts, newCounts, counts.length, index); DataUtils.copyWithGap(counts, newCounts, counts.length, index);
newCounts[index] = count; newCounts[index] = count;
counts = newCounts; counts = newCounts;
sharedFlags &= ~(SHARED_KEYS | SHARED_CHILDREN | SHARED_COUNTS);
totalCount += count; totalCount += count;
} }
}
public void remove(int index) { public void remove(int index) {
Object[] newKeys = new Object[keys.length - 1]; Object[] newKeys = new Object[keyCount - 1];
int keyIndex = index >= keys.length ? index - 1 : index; int keyIndex = index >= keyCount ? index - 1 : index;
DataUtils.copyExcept(keys, newKeys, keys.length, keyIndex); DataUtils.copyExcept(keys, newKeys, keyCount, keyIndex);
keys = newKeys; keys = newKeys;
sharedFlags &= ~SHARED_KEYS;
if (values != null) { if (values != null) {
Object[] newValues = new Object[values.length - 1]; Object[] newValues = new Object[keyCount - 1];
DataUtils.copyExcept(values, newValues, values.length, index); DataUtils.copyExcept(values, newValues, keyCount, index);
values = newValues; values = newValues;
sharedFlags &= ~SHARED_VALUES;
totalCount--; totalCount--;
} }
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];
...@@ -373,6 +415,7 @@ public class Page { ...@@ -373,6 +415,7 @@ public class Page {
DataUtils.copyExcept(counts, newCounts, DataUtils.copyExcept(counts, newCounts,
counts.length, index); counts.length, index);
counts = newCounts; counts = newCounts;
sharedFlags &= ~(SHARED_CHILDREN | SHARED_COUNTS);
totalCount -= countOffset; totalCount -= countOffset;
} }
} }
...@@ -399,6 +442,7 @@ public class Page { ...@@ -399,6 +442,7 @@ public class Page {
} }
int len = DataUtils.readVarInt(buff); int len = DataUtils.readVarInt(buff);
keys = new Object[len]; keys = new Object[len];
keyCount = len;
int type = buff.get(); int type = buff.get();
boolean node = (type & 1) == DataUtils.PAGE_TYPE_NODE; boolean node = (type & 1) == DataUtils.PAGE_TYPE_NODE;
boolean compressed = (type & DataUtils.PAGE_COMPRESSED) != 0; boolean compressed = (type & DataUtils.PAGE_COMPRESSED) != 0;
...@@ -448,7 +492,7 @@ public class Page { ...@@ -448,7 +492,7 @@ public class Page {
buff.putInt(0); buff.putInt(0);
buff.putShort((byte) 0); buff.putShort((byte) 0);
DataUtils.writeVarInt(buff, map.getId()); DataUtils.writeVarInt(buff, map.getId());
int len = keys.length; int len = keyCount;
DataUtils.writeVarInt(buff, len); DataUtils.writeVarInt(buff, len);
Compressor compressor = map.getStore().getCompressor(); Compressor compressor = map.getStore().getCompressor();
int type = children != null ? DataUtils.PAGE_TYPE_NODE int type = children != null ? DataUtils.PAGE_TYPE_NODE
...@@ -502,7 +546,7 @@ public class Page { ...@@ -502,7 +546,7 @@ public class Page {
// length, check, map id, key length, type // length, check, map id, key length, type
int maxLength = 4 + 2 + DataUtils.MAX_VAR_INT_LEN int maxLength = 4 + 2 + DataUtils.MAX_VAR_INT_LEN
+ DataUtils.MAX_VAR_INT_LEN + 1; + DataUtils.MAX_VAR_INT_LEN + 1;
int len = keys.length; int len = keyCount;
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]);
} }
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论