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

A persistent tree map (work in progress).

上级 3ff388a0
......@@ -4,9 +4,11 @@
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.dev.store.btree;
package org.h2.test.store;
import java.nio.ByteBuffer;
import org.h2.dev.store.btree.DataType;
import org.h2.dev.store.btree.DataUtils;
/**
* An integer type.
......@@ -21,6 +23,14 @@ class IntegerType implements DataType {
return DataUtils.getVarIntLen((Integer) obj);
}
public int getMaxLength(Object obj) {
return DataUtils.MAX_VAR_INT_LEN;
}
public int getMemory(Object obj) {
return 20;
}
public Integer read(ByteBuffer buff) {
return DataUtils.readVarInt(buff);
}
......
/*
* 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.DataTypeFactory;
import org.h2.dev.store.btree.DataUtils;
import org.h2.util.StringUtils;
/**
* A row type.
*/
public class RowType implements DataType {
private final DataType[] types;
private RowType(DataType[] types) {
this.types = types;
}
public int compare(Object a, Object b) {
if (a == b) {
return 0;
}
Object[] ax = (Object[]) a;
Object[] bx = (Object[]) b;
int al = ax.length;
int bl = bx.length;
int len = Math.min(al, bl);
for (int i = 0; i < len; i++) {
int comp = types[i].compare(ax[i], bx[i]);
if (comp != 0) {
return comp;
}
}
if (len < al) {
return -1;
} else if (len < bl) {
return 1;
}
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;
int result = DataUtils.MAX_VAR_INT_LEN;
for (int i = 0; i < len; i++) {
result += types[i].getMaxLength(x[i]);
}
return result;
}
public int getMemory(Object obj) {
Object[] x = (Object[]) obj;
int len = x.length;
int memory = 0;
for (int i = 0; i < len; i++) {
memory += types[i].getMemory(x[i]);
}
return memory;
}
public Object[] read(ByteBuffer buff) {
int len = DataUtils.readVarInt(buff);
Object[] x = new Object[len];
for (int i = 0; i < len; i++) {
x[i] = types[i].read(buff);
}
return x;
}
public void write(ByteBuffer buff, Object obj) {
Object[] x = (Object[]) obj;
int len = x.length;
DataUtils.writeVarInt(buff, len);
for (int i = 0; i < len; i++) {
types[i].write(buff, x[i]);
}
}
public String asString() {
StringBuilder buff = new StringBuilder();
buff.append('r');
buff.append('(');
for (int i = 0; i < types.length; i++) {
if (i > 0) {
buff.append(',');
}
buff.append(types[i].asString());
}
buff.append(')');
return buff.toString();
}
static RowType fromString(String t, DataTypeFactory factory) {
if (!t.startsWith("r(") || !t.endsWith(")")) {
throw new RuntimeException("Unknown type: " + t);
}
t = t.substring(2, t.length() - 1);
String[] array = StringUtils.arraySplit(t, ',', false);
DataType[] types = new DataType[array.length];
for (int i = 0; i < array.length; i++) {
types[i] = factory.fromString(array[i]);
}
return new RowType(types);
}
}
......@@ -29,6 +29,7 @@ public class TestTreeMapStore extends TestBase {
}
public void test() throws Exception {
testLargeImport();
testBtreeStore();
testDefragment();
testReuseSpace();
......@@ -38,10 +39,39 @@ public class TestTreeMapStore extends TestBase {
testSimple();
}
private void testLargeImport() throws Exception {
String fileName = getBaseDir() + "/testCsv.h3";
int len = 10000;
for (int j = 0; j < 5; j++) {
FileUtils.delete(fileName);
BtreeMapStore s = openStore(fileName);
s.setMaxPageSize(40);
RowType rowType = RowType.fromString("r(i,,)", new TestTypeFactory());
BtreeMap<Integer, Object[]> m = s.openMap("data", new IntegerType(), rowType);
int i = 0;
// long t = System.currentTimeMillis();
for (; i < len;) {
Object[] o = new Object[3];
o[0] = i;
o[1] = "Hello";
o[2] = "World";
m.put(i, o);
i++;
if (i % 10000 == 0) {
s.store();
}
}
s.store();
s.close();
// System.out.println("store time " + (System.currentTimeMillis() - t));
// System.out.println("store size " + FileUtils.size(fileName));
}
}
private void testBtreeStore() {
String fileName = getBaseDir() + "/testBtreeStore.h3";
FileUtils.delete(fileName);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
int count = 2000;
// Profiler p = new Profiler();
......@@ -64,8 +94,9 @@ public class TestTreeMapStore extends TestBase {
for (int i = 1; i < count; i++) {
assertEquals("hello " + i, m.get(i));
}
s.store();
s.close();
s = BtreeMapStore.open(fileName);
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
assertNull(m.get(0));
for (int i = 1; i < count; i++) {
......@@ -87,7 +118,7 @@ public class TestTreeMapStore extends TestBase {
FileUtils.delete(fileName);
long initialLength = 0;
for (int j = 0; j < 20; j++) {
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
for (int i = 0; i < 10; i++) {
m.put(j + i, "Hello " + j);
......@@ -103,9 +134,9 @@ public class TestTreeMapStore extends TestBase {
assertTrue("initial: " + initialLength + " len: " + len, len <= initialLength * 3);
}
}
long len = FileUtils.size(fileName);
// long len = FileUtils.size(fileName);
// System.out.println("len0: " + len);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
for (int i = 0; i < 100; i++) {
m.remove(i);
......@@ -113,13 +144,13 @@ public class TestTreeMapStore extends TestBase {
s.store();
s.compact();
s.close();
len = FileUtils.size(fileName);
// len = FileUtils.size(fileName);
// System.out.println("len1: " + len);
s = BtreeMapStore.open(fileName);
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
s.compact();
s.close();
len = FileUtils.size(fileName);
// len = FileUtils.size(fileName);
// System.out.println("len2: " + len);
}
......@@ -127,14 +158,15 @@ public class TestTreeMapStore extends TestBase {
String fileName = getBaseDir() + "/testReuseSpace.h3";
FileUtils.delete(fileName);
long initialLength = 0;
for (int j = 0; j < 10; j++) {
BtreeMapStore s = BtreeMapStore.open(fileName);
for (int j = 0; j < 20; j++) {
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
for (int i = 0; i < 10; i++) {
m.put(i, "Hello");
}
s.store();
for (int i = 0; i < 10; i++) {
assertEquals("Hello", m.get(i));
m.remove(i);
}
s.store();
......@@ -151,23 +183,25 @@ public class TestTreeMapStore extends TestBase {
private void testRandom() {
String fileName = getBaseDir() + "/testRandom.h3";
FileUtils.delete(fileName);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, Integer> m = s.openMap("data", Integer.class, Integer.class);
TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
Random r = new Random(1);
int operationCount = 1000;
int maxValue = 20;
int operationCount = 10000;
int maxValue = 30;
for (int i = 0; i < operationCount; i++) {
int k = r.nextInt(maxValue);
int v = r.nextInt();
boolean compareAll;
switch (r.nextInt(3)) {
case 0:
log(i + ": put " + k + " = " + v);
m.put(k, v);
map.put(k, v);
compareAll = true;
break;
case 1:
log(i + ": remove " + k);
m.remove(k);
map.remove(k);
compareAll = true;
......@@ -185,10 +219,12 @@ public class TestTreeMapStore extends TestBase {
}
if (compareAll) {
Iterator<Integer> it = m.keyIterator(null);
Iterator<Integer> it2 = map.keySet().iterator();
while (it2.hasNext()) {
Iterator<Integer> itExpected = map.keySet().iterator();
while (itExpected.hasNext()) {
assertTrue(it.hasNext());
assertEquals(it2.next(), it.next());
Integer expected = itExpected.next();
Integer got = it.next();
assertEquals(expected, got);
}
assertFalse(it.hasNext());
}
......@@ -199,7 +235,7 @@ public class TestTreeMapStore extends TestBase {
private void testKeyValueClasses() {
String fileName = getBaseDir() + "/testKeyValueClasses.h3";
FileUtils.delete(fileName);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> is = s.openMap("intString", Integer.class, String.class);
is.put(1, "Hello");
BtreeMap<Integer, Integer> ii = s.openMap("intInt", Integer.class, Integer.class);
......@@ -220,8 +256,9 @@ public class TestTreeMapStore extends TestBase {
} catch (RuntimeException e) {
// expected
}
s.store();
s.close();
s = BtreeMapStore.open(fileName);
s = openStore(fileName);
is = s.openMap("intString", Integer.class, String.class);
assertEquals("Hello", is.get(1));
ii = s.openMap("intInt", Integer.class, Integer.class);
......@@ -236,7 +273,7 @@ public class TestTreeMapStore extends TestBase {
private void testIterate() {
String fileName = getBaseDir() + "/testIterate.h3";
FileUtils.delete(fileName);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
Iterator<Integer> it = m.keyIterator(null);
assertFalse(it.hasNext());
......@@ -269,7 +306,7 @@ public class TestTreeMapStore extends TestBase {
private void testSimple() {
String fileName = getBaseDir() + "/testSimple.h3";
FileUtils.delete(fileName);
BtreeMapStore s = BtreeMapStore.open(fileName);
BtreeMapStore s = openStore(fileName);
BtreeMap<Integer, String> m = s.openMap("data", Integer.class, String.class);
for (int i = 0; i < 3; i++) {
m.put(i, "hello " + i);
......@@ -281,10 +318,10 @@ public class TestTreeMapStore extends TestBase {
for (int i = 1; i < 3; i++) {
assertEquals("hello " + i, m.get(i));
}
s.store();
s.close();
s = BtreeMapStore.open(fileName);
s = openStore(fileName);
m = s.openMap("data", Integer.class, String.class);
assertNull(m.get(0));
for (int i = 1; i < 3; i++) {
......@@ -293,4 +330,19 @@ public class TestTreeMapStore extends TestBase {
s.close();
}
private static BtreeMapStore openStore(String fileName) {
BtreeMapStore store = BtreeMapStore.open(fileName, new TestTypeFactory());
store.setMaxPageSize(10);
return store;
}
/**
* Log the message.
*
* @param msg the message
*/
private static void log(String msg) {
// System.out.println(msg);
}
}
/*
* 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 org.h2.dev.store.btree.DataType;
import org.h2.dev.store.btree.DataTypeFactory;
import org.h2.dev.store.btree.StringType;
/**
* A data type factory.
*/
public class TestTypeFactory implements DataTypeFactory {
public DataType fromString(String s) {
if (s.length() == 0) {
return new StringType();
}
switch (s.charAt(0)) {
case 'i':
return new IntegerType();
case 'r':
return RowType.fromString(s, this);
}
throw new RuntimeException("Unknown data type " + s);
}
public DataType getDataType(Class<?> objectClass) {
if (objectClass == Integer.class) {
return new IntegerType();
}
throw new RuntimeException("Unsupported object class " + objectClass.toString());
}
}
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!--
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
-->
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" /><title>
Javadoc package documentation
</title></head><body style="font: 9pt/130% Tahoma, Arial, Helvetica, sans-serif; font-weight: normal;"><p>
This package contains tests for the map store.
</p></body></html>
\ No newline at end of file
......@@ -17,13 +17,15 @@ import java.util.Iterator;
public class BtreeMap<K, V> {
private final BtreeMapStore store;
private final long id;
private final String name;
private final DataType keyType;
private final DataType valueType;
private Page root;
private BtreeMap(BtreeMapStore store, String name, DataType keyType, DataType valueType) {
private BtreeMap(BtreeMapStore store, long id, String name, DataType keyType, DataType valueType) {
this.store = store;
this.id = id;
this.name = name;
this.keyType = keyType;
this.valueType = valueType;
......@@ -40,8 +42,8 @@ public class BtreeMap<K, V> {
* @param valueClass the value class
* @return the map
*/
static <K, V> BtreeMap<K, V> open(BtreeMapStore store, String name, DataType keyType, DataType valueType) {
return new BtreeMap<K, V>(store, name, keyType, valueType);
static <K, V> BtreeMap<K, V> open(BtreeMapStore store, long id, String name, DataType keyType, DataType valueType) {
return new BtreeMap<K, V>(store, id, name, keyType, valueType);
}
/**
......@@ -51,9 +53,7 @@ public class BtreeMap<K, V> {
* @param data the value
*/
public void put(K key, V data) {
if (!isChanged()) {
store.markChanged(name, this);
}
markChanged();
root = Page.put(this, root, key, data);
}
......@@ -77,23 +77,32 @@ public class BtreeMap<K, V> {
* @param key the key
* @return the value, or null if not found
*/
public Page getPage(K key) {
Page getPage(K key) {
if (root == null) {
return null;
}
return root.findPage(key);
}
/**
* Remove all entries.
*/
public void clear() {
if (root != null) {
markChanged();
root.removeAllRecursive();
root = null;
}
}
/**
* Remove a key-value pair.
*
* @param key the key
*/
public void remove(K key) {
if (!isChanged()) {
store.markChanged(name, this);
}
if (root != null) {
markChanged();
root = Page.remove(root, key);
}
}
......@@ -107,6 +116,12 @@ public class BtreeMap<K, V> {
return root != null && root.getId() < 0;
}
private void markChanged() {
if (!isChanged()) {
store.markChanged(name, this);
}
}
/**
* Compare two keys.
*
......@@ -206,4 +221,12 @@ public class BtreeMap<K, V> {
return name;
}
int getMaxPageSize() {
return store.getMaxPageSize();
}
long getId() {
return id;
}
}
......@@ -11,12 +11,12 @@ import java.io.IOException;
import java.util.Properties;
/**
* A block of data.
* A chunk of data, containing one or multiple pages
*/
class Block {
class Chunk {
/**
* The block id.
* The chunk id.
*/
int id;
......@@ -26,7 +26,7 @@ class Block {
long start;
/**
* The length in bytes.
* The length in bytes (may be larger than the actual value).
*/
long length;
......@@ -45,7 +45,12 @@ class Block {
*/
int collectPriority;
Block(int id) {
/**
* The offset of the meta root.
*/
int metaRootOffset;
Chunk(int id) {
this.id = id;
}
......@@ -55,17 +60,18 @@ class Block {
* @param s the string
* @return the block
*/
static Block fromString(String s) {
Block b = new Block(0);
static Chunk fromString(String s) {
Chunk c = new Chunk(0);
Properties prop = new Properties();
try {
prop.load(new ByteArrayInputStream(s.getBytes("UTF-8")));
b.id = Integer.parseInt(prop.get("id").toString());
b.start = Long.parseLong(prop.get("start").toString());
b.length = Long.parseLong(prop.get("length").toString());
b.entryCount = Integer.parseInt(prop.get("entryCount").toString());
b.liveCount = Integer.parseInt(prop.get("liveCount").toString());
return b;
c.id = Integer.parseInt(prop.get("id").toString());
c.start = Long.parseLong(prop.get("start").toString());
c.length = Long.parseLong(prop.get("length").toString());
c.entryCount = Integer.parseInt(prop.get("entryCount").toString());
c.liveCount = Integer.parseInt(prop.get("liveCount").toString());
c.metaRootOffset = Integer.parseInt(prop.get("metaRoot").toString());
return c;
} catch (IOException e) {
throw new RuntimeException(e);
}
......@@ -80,7 +86,7 @@ class Block {
}
public boolean equals(Object o) {
return o instanceof Block && ((Block) o).id == id;
return o instanceof Chunk && ((Chunk) o).id == id;
}
public String toString() {
......@@ -89,7 +95,8 @@ class Block {
"start:" + start + "\n" +
"length:" + length + "\n" +
"entryCount:" + entryCount + "\n" +
"liveCount:" + liveCount + "\n";
"liveCount:" + liveCount + "\n" +
"metaRoot:" + metaRootOffset + "\n";
}
}
......
......@@ -11,8 +11,11 @@ import java.util.Iterator;
/**
* A cursor to iterate over elements in ascending order.
*
* @param <K> the key type
*/
class Cursor<K> implements Iterator<K> {
private ArrayList<CursorPos> parents = new ArrayList<CursorPos>();
private K current;
......
......@@ -23,20 +23,37 @@ public interface DataType {
int compare(Object a, Object b);
/**
* Get the length in bytes.
* 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.
*
* @param obj the object
* @return the maximum length
*/
int getMaxLength(Object obj);
/**
* Estimate the used memory in bytes.
*
* @param obj the object
* @return the used memory
*/
int getMemory(Object obj);
/**
* Write the object.
*
* @param buff the target buffer
* @param x the value
*/
void write(ByteBuffer buff, Object x);
void write(ByteBuffer buff, Object obj);
/**
* Read an object.
......
......@@ -6,34 +6,18 @@
*/
package org.h2.dev.store.btree;
import java.io.IOException;
import java.io.StringReader;
/**
* A factory for data types.
*/
public class DataTypeFactory {
public interface DataTypeFactory {
/**
* Read the data type.
*
* @param buff the buffer
* @param s the string
* @return the type
*/
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();
}
throw new RuntimeException("Unknown data type " + c);
}
DataType fromString(String s);
/**
* Get the data type object for the given class.
......@@ -41,13 +25,6 @@ public class DataTypeFactory {
* @param objectClass the class
* @return the data type object
*/
static DataType getDataType(Class<?> objectClass) {
if (objectClass == Integer.class) {
return new IntegerType();
} else if (objectClass == String.class) {
return new StringType();
}
throw new RuntimeException("Unsupported object class " + objectClass.toString());
}
DataType getDataType(Class<?> objectClass);
}
......@@ -13,13 +13,18 @@ import java.nio.ByteBuffer;
*/
public class DataUtils {
/**
* The maximum length of a variable size int.
*/
public static final int MAX_VAR_INT_LEN = 5;
/**
* Get the length of the variable size int.
*
* @param x the value
* @return the length in bytes
*/
static int getVarIntLen(int x) {
public static int getVarIntLen(int x) {
if ((x & (-1 << 7)) == 0) {
return 1;
} else if ((x & (-1 << 14)) == 0) {
......@@ -55,7 +60,7 @@ public class DataUtils {
* @param buff the source buffer
* @return the value
*/
static int readVarInt(ByteBuffer buff) {
public static int readVarInt(ByteBuffer buff) {
int b = buff.get();
if (b >= 0) {
return b;
......@@ -111,7 +116,7 @@ public class DataUtils {
* @param buff the target buffer
* @param x the value
*/
static void writeVarInt(ByteBuffer buff, int x) {
public static void writeVarInt(ByteBuffer buff, int x) {
while ((x & ~0x7f) != 0) {
buff.put((byte) (0x80 | (x & 0x7f)));
x >>>= 7;
......@@ -133,4 +138,22 @@ public class DataUtils {
buff.put((byte) x);
}
static void copyWithGap(Object src, Object dst, int oldSize, int gapIndex) {
if (gapIndex > 0) {
System.arraycopy(src, 0, dst, 0, gapIndex);
}
if (gapIndex < oldSize) {
System.arraycopy(src, gapIndex, dst, gapIndex + 1, oldSize - gapIndex);
}
}
static void copyExcept(Object src, Object dst, int oldSize, int removeIndex) {
if (removeIndex > 0 && oldSize > 0) {
System.arraycopy(src, 0, dst, 0, removeIndex);
}
if (removeIndex < oldSize) {
System.arraycopy(src, removeIndex + 1, dst, removeIndex, oldSize - removeIndex - 1);
}
}
}
/*
* 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.dev.store.btree;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.StringReader;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Arrays;
import java.util.Properties;
import org.h2.store.fs.FilePath;
import org.h2.store.fs.FileUtils;
/**
* Convert a database file to a human-readable text dump.
*/
public class Dump {
private static int blockSize = 4 * 1024;
public static void main(String... args) {
String fileName = "test.h3";
for (int i = 0; i < args.length; i++) {
if ("-file".equals(args[i])) {
fileName = args[++i];
}
}
dump(fileName);
}
public static void dump(String fileName) {
if (!FileUtils.exists(fileName)) {
System.out.println("File not found: " + fileName);
return;
}
FileChannel file = null;
try {
file = FilePath.get(fileName).open("r");
long fileLength = file.size();
file.position(0);
byte[] header = new byte[blockSize];
file.read(ByteBuffer.wrap(header));
Properties prop = new Properties();
prop.load(new ByteArrayInputStream(header));
prop.load(new StringReader(new String(header, "UTF-8")));
System.out.println("file " + fileName);
System.out.println(" length " + fileLength);
System.out.println(" " + prop);
ByteBuffer block = ByteBuffer.wrap(new byte[16]);
for (long pos = 0; pos < fileLength;) {
file.position(pos);
block.rewind();
FileUtils.readFully(file, block);
block.rewind();
if (block.get() != 'c') {
pos += blockSize;
continue;
}
int length = block.getInt();
int chunkId = block.getInt();
int metaRootOffset = block.getInt();
System.out.println(" chunk " + chunkId + " at " + pos +
" length " + length + " offset " + metaRootOffset);
ByteBuffer chunk = ByteBuffer.allocate(length);
file.position(pos);
FileUtils.readFully(file, chunk);
int p = block.position();
pos = (pos + length + blockSize) / blockSize * blockSize;
length -= p;
while (length > 0) {
chunk.position(p);
int len = chunk.getInt();
long mapId = chunk.getLong();
int type = chunk.get();
int count = DataUtils.readVarInt(chunk);
if (type == 1) {
long[] children = new long[count];
for (int i = 0; i < count; i++) {
children[i] = chunk.getLong();
}
System.out.println(" map " + mapId + " at " + p + " node, " + count + " children: " + Arrays.toString(children));
} else {
System.out.println(" map " + mapId + " at " + p + " leaf, " + count + " rows");
}
p += len;
length -= len;
}
}
} catch (IOException e) {
System.out.println("ERROR: " + e);
} finally {
try {
file.close();
} catch (IOException e) {
// ignore
}
}
System.out.println();
}
}
......@@ -11,39 +11,67 @@ import java.nio.ByteBuffer;
/**
* A string type.
*/
class StringType implements DataType {
public class StringType implements DataType {
public int compare(Object a, Object b) {
return a.toString().compareTo(b.toString());
}
public int length(Object obj) {
try {
byte[] bytes = obj.toString().getBytes("UTF-8");
return DataUtils.getVarIntLen(bytes.length) + bytes.length;
} catch (Exception e) {
throw new RuntimeException(e);
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;
}
public int getMemory(Object obj) {
return obj.toString().length() * 2 + 48;
}
public String read(ByteBuffer buff) {
int len = DataUtils.readVarInt(buff);
byte[] bytes = new byte[len];
buff.get(bytes);
try {
return new String(bytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
int x = buff.get() & 0xff;
if (x < 0x80) {
chars[i] = (char) x;
} else if (x >= 0xe0) {
chars[i] = (char) (((x & 0xf) << 12) + ((buff.get() & 0x3f) << 6) + (buff.get() & 0x3f));
} else {
chars[i] = (char) (((x & 0x1f) << 6) + (buff.get() & 0x3f));
}
}
return new String(chars);
}
public void write(ByteBuffer buff, Object x) {
try {
byte[] bytes = x.toString().getBytes("UTF-8");
DataUtils.writeVarInt(buff, bytes.length);
buff.put(bytes);
} catch (Exception e) {
throw new RuntimeException(e);
public void write(ByteBuffer buff, Object obj) {
String s = obj.toString();
int len = s.length();
DataUtils.writeVarInt(buff, len);
for (int i = 0; i < len; i++) {
int c = s.charAt(i);
if (c < 0x80) {
buff.put((byte) c);
} else if (c >= 0x800) {
buff.put((byte) (0xe0 | (c >> 12)));
buff.put((byte) (((c >> 6) & 0x3f)));
buff.put((byte) (c & 0x3f));
} else {
buff.put((byte) (0xc0 | (c >> 6)));
buff.put((byte) (c & 0x3f));
}
}
}
......
......@@ -132,7 +132,7 @@ public class StoredMap<K, V> {
/**
* A value type.
*/
static interface ValueType {
interface ValueType {
/**
* Get the length in bytes.
......@@ -170,7 +170,7 @@ public class StoredMap<K, V> {
/**
* A key type.
*/
static interface KeyType extends ValueType {
interface KeyType extends ValueType {
/**
* Compare two keys.
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论