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

A persistent multi-version map (work in progress): r-tree

上级 b1edabaa
......@@ -19,10 +19,6 @@ class IntegerType implements DataType {
return ((Integer) a).compareTo((Integer) b);
}
public int length(Object obj) {
return DataUtils.getVarIntLen((Integer) obj);
}
public int getMaxLength(Object obj) {
return DataUtils.MAX_VAR_INT_LEN;
}
......
......@@ -46,16 +46,6 @@ public class RowType implements DataType {
return 0;
}
public int length(Object obj) {
Object[] x = (Object[]) obj;
int len = x.length;
int result = DataUtils.getVarIntLen(len);
for (int i = 0; i < len; i++) {
result += types[i].length(x[i]);
}
return result;
}
public int getMaxLength(Object obj) {
Object[] x = (Object[]) obj;
int len = x.length;
......
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 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.store;
/**
* A unique spatial key.
*/
public class SpatialKey {
public float[] min;
public float[] max;
public long id;
public static SpatialKey create(long id, float... minMax) {
SpatialKey k = new SpatialKey();
k.id = id;
int dimensions = minMax.length / 2;
k.min = new float[dimensions];
k.max = new float[dimensions];
for (int i = 0; i < dimensions; i++) {
k.min[i] = minMax[i + i];
k.max[i] = minMax[i + i + 1];
}
return k;
}
public String toString() {
StringBuilder buff = new StringBuilder();
buff.append(id).append(": (");
for (int i = 0; i < min.length; i++) {
if (i > 0) {
buff.append(", ");
}
buff.append(min[i]).append('/').append(max[i]);
}
return buff.append(")").toString();
}
}
/*
* Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
* Version 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.store;
import java.nio.ByteBuffer;
import org.h2.dev.store.btree.DataType;
import org.h2.dev.store.btree.DataUtils;
/**
* A spatial data type. This class supports up to 255 dimensions. Each dimension
* can have a minimum and a maximum value of type float. For each dimension, the
* maximum value is only stored when it is not the same as the minimum.
*/
public class SpatialType implements DataType {
private final int dimensions;
private SpatialType(int dimensions) {
if (dimensions <= 0 || dimensions > 255) {
throw new IllegalArgumentException("Dimensions: " + dimensions);
}
this.dimensions = dimensions;
}
public static SpatialType fromString(String s) {
return new SpatialType(Integer.parseInt(s.substring(1)));
}
@Override
public int compare(Object a, Object b) {
long la = ((SpatialKey) a).id;
long lb = ((SpatialKey) b).id;
return la < lb ? -1 : la > lb ? 1 : 0;
}
public boolean equals(Object a, Object b) {
long la = ((SpatialKey) a).id;
long lb = ((SpatialKey) b).id;
return la == lb;
}
@Override
public int getMaxLength(Object obj) {
return 1 + dimensions * 8 + DataUtils.MAX_VAR_LONG_LEN;
}
@Override
public int getMemory(Object obj) {
return 40 + dimensions * 4;
}
@Override
public void write(ByteBuffer buff, Object obj) {
SpatialKey k = (SpatialKey) obj;
int flags = 0;
for (int i = 0; i < dimensions; i++) {
if (k.min[i] == k.max[i]) {
flags |= 1 << i;
}
}
DataUtils.writeVarInt(buff, flags);
for (int i = 0; i < dimensions; i++) {
buff.putFloat(k.min[i]);
if ((flags & (1 << i)) == 0) {
buff.putFloat(k.max[i]);
}
}
DataUtils.writeVarLong(buff, k.id);
}
@Override
public Object read(ByteBuffer buff) {
SpatialKey k = new SpatialKey();
int flags = DataUtils.readVarInt(buff);
k.min = new float[dimensions];
k.max = new float[dimensions];
for (int i = 0; i < dimensions; i++) {
k.min[i] = buff.getFloat();
if ((flags & (1 << i)) != 0) {
k.max[i] = k.min[i];
} else {
k.max[i] = buff.getFloat();
}
}
k.id = DataUtils.readVarLong(buff);
return k;
}
@Override
public String asString() {
return "s" + dimensions;
}
public boolean isOverlap(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
for (int i = 0; i < dimensions; i++) {
if (a.max[i] < b.min[i] || a.min[i] > b.max[i]) {
return false;
}
}
return true;
}
public SpatialKey copy(SpatialKey old) {
SpatialKey k = new SpatialKey();
k.min = new float[dimensions];
k.max = new float[dimensions];
System.arraycopy(old.min, 0, k.min, 0, dimensions);
System.arraycopy(old.max, 0, k.max, 0, dimensions);
return k;
}
public void increase(SpatialKey bounds, SpatialKey add) {
for (int i = 0; i < dimensions; i++) {
bounds.min[i] = Math.min(bounds.min[i], add.min[i]);
bounds.max[i] = Math.max(bounds.max[i], add.max[i]);
}
}
/**
* Get the area increase by extending a to contain b.
*
* @param objA the bounding box
* @param objB the object
* @return the area
*/
public float getAreaIncrease(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
float areaOld = 1, areaNew = 1;
for (int i = 0; i < dimensions; i++) {
float min = a.min[i];
float max = a.max[i];
areaOld *= max - min;
min = Math.min(min, b.min[i]);
max = Math.max(max, b.max[i]);
areaNew *= max - min;
}
return areaNew - areaOld;
}
public float getCombinedArea(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
float area = 1;
for (int i = 0; i < dimensions; i++) {
float min = Math.min(a.min[i], b.min[i]);
float max = Math.max(a.max[i], b.max[i]);
area *= max - min;
}
return area;
}
/**
* Check whether a contains b.
*
* @param objA the bounding box
* @param objB the object
* @return the area
*/
public boolean contains(Object objA, Object objB) {
SpatialKey a = (SpatialKey) objA;
SpatialKey b = (SpatialKey) objB;
for (int i = 0; i < dimensions; i++) {
if (a.min[i] > b.min[i] || a.max[i] < b.max[i]) {
return false;
}
}
return true;
}
}
......@@ -5,14 +5,27 @@
*/
package org.h2.test.store;
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.Random;
import java.util.TreeMap;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;
import org.h2.dev.store.btree.BtreeMap;
import org.h2.dev.store.btree.BtreeMapStore;
import org.h2.jaqu.bytecode.Null;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
import org.h2.util.New;
/**
* Tests the tree map store.
......@@ -29,6 +42,8 @@ public class TestBtreeMapStore extends TestBase {
}
public void test() {
testRtreeMany();
testRtree();
testCustomMapType();
testTruncateFile();
testFastDelete();
......@@ -45,12 +60,124 @@ public class TestBtreeMapStore extends TestBase {
testSimple();
}
private void testRtreeMany() {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
BtreeMapStore s;
s = openStore(fileName);
// s.setMaxPageSize(100);
RtreeMap<SpatialKey, String> r = s.openMap("data", "r", "s2", "");
Random rand = new Random(1);
for (int i = 0; i < 1000; i++) {
float x = rand.nextFloat(), y = rand.nextFloat();
float p = (float) (rand.nextFloat() * 0.01);
SpatialKey k = SpatialKey.create(i, x - p, x + p, y - p, y + p);
r.put(k, "" + i);
if (i > 0 && i % 10000 == 0) {
render(r, getBaseDir() + "/test.png");
}
}
s.close();
}
private void testRtree() {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
BtreeMapStore s;
s = openStore(fileName);
RtreeMap<SpatialKey, String> r = s.openMap("data", "r", "s2", "");
add(r, "Bern", 46.57, 7.27, 124381);
add(r, "Basel", 47.34, 7.36, 170903);
add(r, "Zurich", 47.22, 8.33, 376008);
add(r, "Lucerne", 47.03, 8.18, 77491);
add(r, "Geneva", 46.12, 6.09, 191803);
add(r, "Lausanne", 46.31, 6.38, 127821);
add(r, "Winterthur", 47.30, 8.45, 102966);
add(r, "St. Gallen", 47.25, 9.22, 73500);
add(r, "Biel/Bienne", 47.08, 7.15, 51203);
add(r, "Lugano", 46.00, 8.57, 54667);
add(r, "Thun", 46.46, 7.38, 42623);
add(r, "Bellinzona", 46.12, 9.01, 17373);
add(r, "Chur", 46.51, 9.32, 33756);
ArrayList<String> list = New.arrayList();
for (SpatialKey x : r.keySet()) {
list.add(r.get(x));
}
Collections.sort(list);
assertEquals("[Basel, Bellinzona, Bern, Biel/Bienne, Chur, Geneva, " +
"Lausanne, Lucerne, Lugano, St. Gallen, Thun, Winterthur, Zurich]",
list.toString());
// render(r, getBaseDir() + "/test.png");
s.close();
}
private static void add(RtreeMap<SpatialKey, String> r, String name, double y, double x, int population) {
int id = r.size();
float a = (float) ((int) x + (x - (int) x) * 5 / 3);
float b = 50 - (float) ((int) y + (y - (int) y) * 5 / 3);
float s = (float) Math.sqrt(population / 10000000.);
SpatialKey k = SpatialKey.create(id, a - s, a + s, b - s, b + s);
r.put(k, name);
}
private static void render(RtreeMap<SpatialKey, String> r, String fileName) {
int width = 1000, height = 500;
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = (Graphics2D) img.getGraphics();
g2d.setBackground(Color.WHITE);
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.BLACK);
SpatialKey b = SpatialKey.create(0, Float.MAX_VALUE, Float.MIN_VALUE,
Float.MAX_VALUE, Float.MIN_VALUE);
for (SpatialKey x : r.keySet()) {
b.min[0] = Math.min(b.min[0], x.min[0]);
b.min[1] = Math.min(b.min[1], x.min[1]);
b.max[0] = Math.max(b.max[0], x.max[0]);
b.max[1] = Math.max(b.max[1], x.max[1]);
}
// System.out.println(b);
for (SpatialKey x : r.keySet()) {
int[] rect = scale(b, x, width, height);
g2d.drawRect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]);
String s = r.get(x);
g2d.drawChars(s.toCharArray(), 0, s.length(), rect[0], rect[1] - 4);
}
g2d.setColor(Color.red);
ArrayList<SpatialKey> list = New.arrayList();
r.addNodeKeys(list, r.getRoot());
for (SpatialKey x : list) {
int[] rect = scale(b, x, width, height);
g2d.drawRect(rect[0], rect[1], rect[2] - rect[0], rect[3] - rect[1]);
}
ImageWriter out = ImageIO.getImageWritersByFormatName("png").next();
try {
out.setOutput(new FileImageOutputStream(new File(fileName)));
out.write(img);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private static int[] scale(SpatialKey b, SpatialKey x, int width, int height) {
int[] rect = {
(int) ((x.min[0] - b.min[0]) * (width * 0.9) / (b.max[0] - b.min[0]) + width * 0.05),
(int) ((x.min[1] - b.min[1]) * (height * 0.9) / (b.max[1] - b.min[1]) + height * 0.05),
(int) ((x.max[0] - b.min[0]) * (width * 0.9) / (b.max[0] - b.min[0]) + width * 0.05),
(int) ((x.max[1] - b.min[1]) * (height * 0.9) / (b.max[1] - b.min[1]) + height * 0.05),
};
return rect;
}
private void testCustomMapType() {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
BtreeMapStore s;
s = openStore(fileName);
SequenceMap<Integer, String> seq = s.openMap("data", "s", "i", "").cast();
SequenceMap<Integer, String> seq = s.openMap("data", "s", "i", "");
StringBuilder buff = new StringBuilder();
for (int x : seq.keySet()) {
buff.append(x).append(';');
......
......@@ -5,6 +5,7 @@
*/
package org.h2.test.store;
import java.nio.ByteBuffer;
import org.h2.dev.store.btree.DataUtils;
import org.h2.test.TestBase;
......@@ -23,11 +24,66 @@ public class TestDataUtils extends TestBase {
}
public void test() throws Exception {
testVarIntVarLong();
testCheckValue();
testPagePos();
testEncodeLength();
}
private void testVarIntVarLong() {
ByteBuffer buff = ByteBuffer.allocate(100);
for (long x = 0; x < 1000; x++) {
testVarIntVarLong(buff, x);
testVarIntVarLong(buff, -x);
}
for (long x = Long.MIN_VALUE, i = 0; i < 1000; x++, i++) {
testVarIntVarLong(buff, x);
}
for (long x = Long.MAX_VALUE, i = 0; i < 1000; x--, i++) {
testVarIntVarLong(buff, x);
}
for (int shift = 0; shift < 64; shift++) {
for (long x = 250; x < 260; x++) {
testVarIntVarLong(buff, x << shift);
testVarIntVarLong(buff, -(x << shift));
}
}
// invalid varInt / varLong
// should work, but not read far too much
for (int i = 0; i < 50; i++) {
buff.put((byte) 255);
}
buff.flip();
assertEquals(-1, DataUtils.readVarInt(buff));
assertEquals(5, buff.position());
buff.rewind();
assertEquals(-1, DataUtils.readVarLong(buff));
assertEquals(10, buff.position());
}
private void testVarIntVarLong(ByteBuffer buff, long x) {
int len;
DataUtils.writeVarLong(buff, x);
len = buff.position();
buff.flip();
long y = DataUtils.readVarLong(buff);
assertEquals(y, x);
assertEquals(len, buff.position());
assertEquals(len, DataUtils.getVarLongLen(x));
buff.clear();
int intX = (int) x;
DataUtils.writeVarInt(buff, intX);
len = buff.position();
buff.flip();
int intY = DataUtils.readVarInt(buff);
assertEquals(intY, intX);
assertEquals(len, buff.position());
assertEquals(len, DataUtils.getVarIntLen(intX));
buff.clear();
}
private void testCheckValue() {
// 0 xor 0 = 0
assertEquals(0, DataUtils.getCheckValue(0));
......
......@@ -22,8 +22,11 @@ public class TestMapFactory implements MapFactory {
long createVersion) {
if (mapType.equals("s")) {
return new SequenceMap<K, V>(store, id, name, keyType, valueType, createVersion);
} else if (mapType.equals("r")) {
return new RtreeMap<K, V>(store, id, name, keyType, valueType, createVersion);
} else {
throw new RuntimeException("Unsupported map type " + mapType);
}
throw new RuntimeException("Unsupported map type " + mapType);
}
@Override
......@@ -36,6 +39,8 @@ public class TestMapFactory implements MapFactory {
return new IntegerType();
case 'r':
return RowType.fromString(s, this);
case 's':
return SpatialType.fromString(s);
}
throw new RuntimeException("Unknown data type " + s);
}
......
......@@ -20,11 +20,14 @@ import java.util.TreeMap;
*/
public class BtreeMap<K, V> {
static final IllegalArgumentException KEY_NOT_FOUND = new IllegalArgumentException(
protected static final IllegalArgumentException KEY_NOT_FOUND = new IllegalArgumentException(
"Key not found");
static final IllegalArgumentException KEY_ALREADY_EXISTS = new IllegalArgumentException(
protected static final IllegalArgumentException KEY_ALREADY_EXISTS = new IllegalArgumentException(
"Key already exists");
protected Page root;
protected BtreeMapStore store;
private final int id;
private final String name;
private final DataType keyType;
......@@ -36,8 +39,6 @@ public class BtreeMap<K, V> {
* before this version.
*/
private final TreeMap<Long, Page> oldRoots = new TreeMap<Long, Page>();
private BtreeMapStore store;
private Page root;
private boolean readOnly;
protected BtreeMap(BtreeMapStore store, int id, String name,
......@@ -79,8 +80,7 @@ public class BtreeMap<K, V> {
* @throws InvalidArgumentException if this key does not exist (without
* stack trace)
*/
private Page set(Page p, long writeVersion, Object key,
Object value) {
protected Page set(Page p, long writeVersion, Object key, Object value) {
if (p == null) {
throw KEY_NOT_FOUND;
}
......@@ -103,7 +103,7 @@ public class BtreeMap<K, V> {
Page c2 = set(c, writeVersion, key, value);
if (c != c2) {
p = p.copyOnWrite(writeVersion);
p.setChild(index, c2.getPos(), c2.getPos());
p.setChild(index, c2);
}
return p;
}
......@@ -120,8 +120,7 @@ public class BtreeMap<K, V> {
* @throws InvalidArgumentException if this key already exists (without
* stack trace)
*/
private Page add(Page p, long writeVersion, Object key,
Object value) {
protected Page add(Page p, long writeVersion, Object key, Object value) {
if (p == null) {
Object[] keys = { key };
Object[] values = { value };
......@@ -167,15 +166,15 @@ public class BtreeMap<K, V> {
Object k = c.getKey(at);
Page split = c.split(at);
p = p.copyOnWrite(writeVersion);
p.setChild(index, c.getPos(), c.getTotalSize());
p.insert(index, k, null, split.getPos(), split.getTotalSize());
p.setChild(index, split);
p.insert(index, k, null, c.getPos(), c.getTotalSize());
// now we are not sure where to add
return add(p, writeVersion, key, value);
}
Page c2 = add(c, writeVersion, key, value);
p = p.copyOnWrite(writeVersion);
// the child might be the same, but not the size
p.setChild(index, c2.getPos(), c2.getTotalSize());
p.setChild(index, c2);
return p;
}
......@@ -201,7 +200,7 @@ public class BtreeMap<K, V> {
* @param parents the stack of parent page positions
* @param key the key
*/
void min(Page p, ArrayList<CursorPos> parents, Object key) {
protected void min(Page p, ArrayList<CursorPos> parents, Object key) {
while (p != null) {
if (!p.isLeaf()) {
int x = key == null ? -1 : p.binarySearch(key);
......@@ -235,7 +234,7 @@ public class BtreeMap<K, V> {
* @param parents the stack of parent page positions
* @return the next key
*/
Object nextKey(ArrayList<CursorPos> parents) {
protected Object nextKey(ArrayList<CursorPos> parents) {
if (parents.size() == 0) {
return null;
}
......@@ -270,7 +269,7 @@ public class BtreeMap<K, V> {
* @param key the key
* @return the value or null
*/
private Object binarySearch(Page p, Object key) {
protected Object binarySearch(Page p, Object key) {
int x = p.binarySearch(key);
if (!p.isLeaf()) {
if (x < 0) {
......@@ -287,7 +286,6 @@ public class BtreeMap<K, V> {
return null;
}
public boolean containsKey(Object key) {
return get(key) != null;
}
......@@ -298,7 +296,7 @@ public class BtreeMap<K, V> {
* @param key the key
* @return the value, or null if not found
*/
Page getPage(K key) {
protected Page getPage(K key) {
if (root == null) {
return null;
}
......@@ -312,7 +310,7 @@ public class BtreeMap<K, V> {
* @param key the key
* @return the page or null
*/
private Page binarySearchPage(Page p, Object key) {
protected Page binarySearchPage(Page p, Object key) {
int x = p.binarySearch(key);
if (!p.isLeaf()) {
if (x < 0) {
......@@ -379,7 +377,6 @@ public class BtreeMap<K, V> {
}
}
/**
* Remove an existing key-value pair.
*
......@@ -389,7 +386,7 @@ public class BtreeMap<K, V> {
* @return the new root page (null if empty)
* @throws InvalidArgumentException if not found (without stack trace)
*/
private Page removeExisting(Page p, long writeVersion, Object key) {
protected Page removeExisting(Page p, long writeVersion, Object key) {
if (p == null) {
throw KEY_NOT_FOUND;
}
......@@ -397,7 +394,7 @@ public class BtreeMap<K, V> {
if (p.isLeaf()) {
if (index >= 0) {
if (p.getKeyCount() == 1) {
store.removePage(p.getPos());
removePage(p);
return null;
}
p = p.copyOnWrite(writeVersion);
......@@ -420,16 +417,16 @@ public class BtreeMap<K, V> {
// this child was deleted
p.remove(index);
if (p.getKeyCount() == 0) {
store.removePage(p.getPos());
removePage(p);
p = p.getChildPage(0);
}
} else {
p.setChild(index, c2.getPos(), c2.getTotalSize());
p.setChild(index, c2);
}
return p;
}
private void markChanged(Page oldRoot) {
protected void markChanged(Page oldRoot) {
if (oldRoot != root) {
long v = store.getCurrentVersion();
if (!oldRoots.containsKey(v)) {
......@@ -530,7 +527,7 @@ public class BtreeMap<K, V> {
*
* @return the root page
*/
Page getRoot() {
public Page getRoot() {
return root;
}
......@@ -585,13 +582,13 @@ public class BtreeMap<K, V> {
return readOnly;
}
private void checkOpen() {
protected void checkOpen() {
if (store == null) {
throw new IllegalStateException("This map is closed");
}
}
private void checkWrite() {
protected void checkWrite() {
if (readOnly) {
checkOpen();
throw new IllegalStateException("This map is read-only");
......@@ -631,9 +628,8 @@ public class BtreeMap<K, V> {
return createVersion;
}
@SuppressWarnings("unchecked")
public <M> M cast() {
return (M) this;
protected void removePage(Page p) {
store.removePage(p.getPos());
}
}
......@@ -38,7 +38,6 @@ header:
blockSize=4096
TODO:
- support custom map types: b-tree, r-tree
- ability to diff / merge versions
- map.getVersion and opening old maps read-only
- limited support for writing to old versions (branches)
......@@ -56,6 +55,9 @@ TODO:
- support large binaries
- support stores that span multiple files (chunks stored in other files)
- triggers
- compare with newest version of IndexedDb
- support database version / schema version
- implement more counted b-tree (skip, get positions)
*/
......@@ -142,8 +144,7 @@ public class BtreeMapStore {
/**
* Open a map.
*
* @param <K> the key type
* @param <V> the value type
* @param <T> the map type
* @param name the name of the map
* @param mapType the map type
* @param keyType the key type
......@@ -151,8 +152,8 @@ public class BtreeMapStore {
* @return the map
*/
@SuppressWarnings("unchecked")
public <K, V> BtreeMap<K, V> openMap(String name, String mapType, String keyType, String valueType) {
BtreeMap<K, V> m = (BtreeMap<K, V>) maps.get(name);
public <T extends BtreeMap<?, ?>> T openMap(String name, String mapType, String keyType, String valueType) {
BtreeMap<?, ?> m = maps.get(name);
if (m == null) {
String identifier = meta.get("map." + name);
int id;
......@@ -178,14 +179,14 @@ public class BtreeMapStore {
DataType k = buildDataType(keyType);
DataType v = buildDataType(valueType);
if (mapType.equals("")) {
m = new BtreeMap<K, V>(this, id, name, k, v, createVersion);
m = new BtreeMap<Object, Object>(this, id, name, k, v, createVersion);
} else {
m = getMapFactory().buildMap(mapType, this, id, name, k, v, createVersion);
}
maps.put(name, m);
m.setRootPos(root);
}
return m;
return (T) m;
}
/**
......@@ -860,7 +861,7 @@ public class BtreeMapStore {
*
* @return the maximum number of entries
*/
int getMaxPageSize() {
public int getMaxPageSize() {
return maxPageSize;
}
......
......@@ -9,16 +9,17 @@ package org.h2.dev.store.btree;
/**
* A position in a cursor
*/
class CursorPos {
public class CursorPos {
/**
* The current page.
*/
Page page;
public Page page;
/**
* The current index.
*/
int index;
public int index;
}
......@@ -22,14 +22,6 @@ public interface DataType {
*/
int compare(Object a, Object b);
/**
* Get the length in bytes used to store an object.
*
* @param obj the object
* @return the length
*/
int length(Object obj);
/**
* Get the maximum length in bytes used to store an object. In many cases,
* this method can be faster than calculating the exact length.
......
......@@ -123,13 +123,14 @@ public class DataUtils {
return x;
}
x &= 0x7f;
for (int s = 7;; s += 7) {
for (int s = 7; s < 64; s += 7) {
long b = buff.get();
x |= (b & 0x7f) << s;
if (b >= 0) {
return x;
break;
}
}
return x;
}
/**
......
......@@ -17,21 +17,6 @@ public class StringType implements DataType {
return a.toString().compareTo(b.toString());
}
public int length(Object obj) {
int plus = 0;
String s = obj.toString();
int len = s.length();
for (int i = 0; i < len; i++) {
char c = s.charAt(i);
if (c >= 0x800) {
plus += 2;
} else if (c >= 0x80) {
plus++;
}
}
return DataUtils.getVarIntLen(len) + len + plus;
}
public int getMaxLength(Object obj) {
return DataUtils.MAX_VAR_INT_LEN + obj.toString().length() * 3;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论