提交 2d531580 authored 作者: Thomas Mueller's avatar Thomas Mueller

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

上级 ecf54428
......@@ -13,6 +13,7 @@ import org.h2.dev.store.btree.Cursor;
import org.h2.dev.store.btree.CursorPos;
import org.h2.dev.store.btree.DataType;
import org.h2.dev.store.btree.Page;
import org.h2.util.New;
/**
* An r-tree implementation. It uses the quadratic split algorithm.
......@@ -23,6 +24,7 @@ import org.h2.dev.store.btree.Page;
public class RtreeMap<K, V> extends BtreeMap<K, V> {
private final SpatialType keyType;
private boolean quadraticSplit;
RtreeMap(BtreeMapStore store, int id, String name, DataType keyType,
DataType valueType, long createVersion) {
......@@ -43,10 +45,6 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
return keyType.contains(p.getKey(index), key);
}
private float getAreaIncrease(Page p, int index, Object key) {
return keyType.getAreaIncrease(p.getKey(index), key);
}
/**
* Get the object for the given key. An exact match is required.
*
......@@ -101,18 +99,27 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
return null;
}
protected Page set(Page p, long writeVersion, Object key, Object value) {
if (p == null) {
throw KEY_NOT_FOUND;
}
protected Page remove(Page p, long writeVersion, Object key) {
if (!p.isLeaf()) {
for (int i = 0; i < p.getKeyCount(); i++) {
if (contains(p, i, key)) {
Page c = p.getChildPage(i);
Page c2 = set(c, writeVersion, key, value);
if (c != c2) {
long oldSize = c.getTotalSize();
Page c2 = remove(c, writeVersion, key);
if (c2 == null) {
// this child was deleted
p.remove(i);
if (p.getKeyCount() == 0) {
removePage(p);
return null;
}
} else if (oldSize != c2.getTotalSize()) {
p = p.copyOnWrite(writeVersion);
setChildUpdateBox(p, i, c2, key);
Object oldBounds = p.getKey(i);
if (!keyType.isInside(key, oldBounds)) {
p.setKey(i, getBounds(c));
}
p.setChild(i, c2);
break;
}
}
......@@ -120,8 +127,12 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
} else {
for (int i = 0; i < p.getKeyCount(); i++) {
if (keyType.equals(p.getKey(i), key)) {
if (p.getKeyCount() == 1) {
removePage(p);
return null;
}
p = p.copyOnWrite(writeVersion);
p.setValue(i, value);
p.remove(i);
break;
}
}
......@@ -129,26 +140,34 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
return p;
}
protected Page removeExisting(Page p, long writeVersion, Object key) {
if (p == null) {
throw KEY_NOT_FOUND;
private Object getBounds(Page x) {
Object bounds = keyType.createBoundingBox(x.getKey(0));
for (int i = 1; i < x.getKeyCount(); i++) {
keyType.increaseBounds(bounds, x.getKey(i));
}
return bounds;
}
public void put(K key, V data) {
checkWrite();
Page oldRoot = root;
if (get(key) != null) {
root = set(root, store.getCurrentVersion(), key, data);
} else {
root = add(root, store.getCurrentVersion(), key, data, store.getMaxPageSize());
}
markChanged(oldRoot);
}
protected Page set(Page p, long writeVersion, Object key, Object value) {
if (!p.isLeaf()) {
for (int i = 0; i < p.getKeyCount(); i++) {
if (contains(p, i, key)) {
Page c = p.getChildPage(i);
long oldSize = c.getTotalSize();
Page c2 = removeExisting(c, writeVersion, key);
if (c2 == null) {
// this child was deleted
p.remove(i);
if (p.getKeyCount() == 0) {
removePage(p);
return null;
}
} else if (oldSize != c2.getTotalSize()) {
Page c2 = set(c, writeVersion, key, value);
if (c != c2) {
p = p.copyOnWrite(writeVersion);
setChildUpdateBox(p, i, c2, key);
p.setChild(i, c2);
break;
}
}
......@@ -156,12 +175,8 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
} else {
for (int i = 0; i < p.getKeyCount(); i++) {
if (keyType.equals(p.getKey(i), key)) {
if (p.getKeyCount() == 1) {
removePage(p);
return null;
}
p = p.copyOnWrite(writeVersion);
p.remove(i);
p.setValue(i, value);
break;
}
}
......@@ -169,153 +184,202 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
return p;
}
/**
* Set the child and update the bounding box if required. The bounding box
* is only updated if the key touches or is outside the old bounding box.
*
* @param p the parent (this page is changed)
* @param index the child index
* @param c the child page
* @param key the new or old key
*/
private void setChildUpdateBox(Page p, int index, Page c, Object key) {
Object oldBounds = p.getKey(index);
if (key == null || !keyType.isInside(key, oldBounds)) {
p.setKey(index, getBounds(c));
}
p.setChild(index, c);
}
private Object getBounds(Page x) {
Object bounds = keyType.createBoundingBox(x.getKey(0));
for (int i = 1; i < x.getKeyCount(); i++) {
keyType.increaseBounds(bounds, x.getKey(i));
}
return bounds;
public void add(K key, V data) {
checkWrite();
Page oldRoot = root;
root = add(root, store.getCurrentVersion(), key, data, store.getMaxPageSize());
markChanged(oldRoot);
}
protected Page add(Page p, long writeVersion, Object key, Object value) {
protected Page add(Page p, long writeVersion, Object key, Object value, int maxPageSize) {
if (p == null) {
Object[] keys = { key };
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;
}
if (p.getKeyCount() >= store.getMaxPageSize()) {
// only possible if this is the root,
// otherwise we would have split earlier
if (p.getKeyCount() > maxPageSize) {
// only possible if this is the root, else we would have split earlier
// (this requires maxPageSize is fixed)
p = p.copyOnWrite(writeVersion);
long totalSize = p.getTotalSize();
Page split = split(p, writeVersion);
Object[] keys = { getBounds(p), getBounds(split) };
long[] children = { p.getPos(), split.getPos(), 0 };
long[] childrenSize = { p.getTotalSize(), split.getTotalSize(), 0 };
p = Page.create(this, writeVersion, keys, null, children, childrenSize,
totalSize);
// now p is a node; insert continues
p = Page.create(this, writeVersion, 2,
keys, null, children, childrenSize,
totalSize, 0);
// now p is a node; continues
} else if (p.isLeaf()) {
for (int i = 0; i < p.getKeyCount(); i++) {
if (keyType.equals(p.getKey(i), key)) {
throw KEY_ALREADY_EXISTS;
}
}
p = p.copyOnWrite(writeVersion);
p.insert(p.getKeyCount(), key, value, 0, 0);
p.insertLeaf(p.getKeyCount(), key, value);
return p;
}
// p is a node
float min = Float.MAX_VALUE;
int index = 0;
int index = -1;
for (int i = 0; i < p.getKeyCount(); i++) {
float areaIncrease = getAreaIncrease(p, i, key);
if (areaIncrease < min) {
if (contains(p, i, key)) {
index = i;
min = areaIncrease;
break;
}
}
if (index < 0) {
// a new entry, we don't know where to add yet
float min = Float.MAX_VALUE;
for (int i = 0; i < p.getKeyCount(); i++) {
Object k = p.getKey(i);
float areaIncrease = keyType.getAreaIncrease(k, key);
if (areaIncrease < min) {
index = i;
min = areaIncrease;
}
}
}
Page c = p.getChildPage(index);
if (c.getKeyCount() >= store.getMaxPageSize()) {
if (c.getKeyCount() >= maxPageSize) {
// split on the way down
c = c.copyOnWrite(writeVersion);
Page split = split(c, writeVersion);
p = p.copyOnWrite(writeVersion);
setChildUpdateBox(p, index, c, null);
p.insert(index, getBounds(split), null, split.getPos(), split.getTotalSize());
p.setKey(index, getBounds(c));
p.setChild(index, c);
p.insertNode(index, getBounds(split), split.getPos(), split.getTotalSize());
// now we are not sure where to add
return add(p, writeVersion, key, value);
return add(p, writeVersion, key, value, maxPageSize);
}
Page c2 = add(c, writeVersion, key, value);
Page c2 = add(c, writeVersion, key, value, maxPageSize);
p = p.copyOnWrite(writeVersion);
// the child might be the same, but maybe not the bounding box
setChildUpdateBox(p, index, c2, key);
Object bounds = p.getKey(index);
keyType.increaseBounds(bounds, key);
p.setKey(index, bounds);
p.setChild(index, c2);
return p;
}
private Page split(Page p, long writeVersion) {
// quadratic algorithm
Object[] values = p.isLeaf() ? new Object[0] : null;
long[] c = p.isLeaf() ? null : new long[1];
Page split = Page.create(this, writeVersion, new Object[0],
values, c, c, 0);
Page newP = Page.create(this, writeVersion, new Object[0],
values, c, c, 0);
float largest = Float.MIN_VALUE;
int iBest = 0, jBest = 0;
// if (p.getTotalSize() > 10000) {
// return
// }
return quadraticSplit | p.getTotalSize() > 10000 ?
splitQuadratic(p, writeVersion) :
splitLinear(p, writeVersion);
}
public static int splitLin, splitQuad;
private Page splitLinear(Page p, long writeVersion) {
ArrayList<Object> keys = New.arrayList();
for (int i = 0; i < p.getKeyCount(); i++) {
Object oi = p.getKey(i);
for (int j = 0; j < p.getKeyCount(); j++) {
if (i == j) {
keys.add(p.getKey(i));
}
int[] extremes = keyType.getExtremes(keys);
if (extremes == null) {
splitQuad++;
return splitQuadratic(p, writeVersion);
}
splitLin++;
Page splitA = newPage(p.isLeaf(), writeVersion);
Page splitB = newPage(p.isLeaf(), writeVersion);
move(p, splitA, extremes[0]);
if (extremes[1] > extremes[0]) {
extremes[1]--;
}
move(p, splitB, extremes[1]);
Object boundsA = keyType.createBoundingBox(splitA.getKey(0));
Object boundsB = keyType.createBoundingBox(splitB.getKey(0));
while (p.getKeyCount() > 0) {
Object o = p.getKey(0);
float a = keyType.getAreaIncrease(boundsA, o);
float b = keyType.getAreaIncrease(boundsB, o);
if (a < b) {
keyType.increaseBounds(boundsA, o);
move(p, splitA, 0);
} else {
keyType.increaseBounds(boundsB, o);
move(p, splitB, 0);
}
}
while (splitB.getKeyCount() > 0) {
move(splitB, p, 0);
}
return splitA;
}
private Page splitQuadratic(Page p, long writeVersion) {
Page splitA = newPage(p.isLeaf(), writeVersion);
Page splitB = newPage(p.isLeaf(), writeVersion);
float largest = Float.MIN_VALUE;
int ia = 0, ib = 0;
for (int a = 0; a < p.getKeyCount(); a++) {
Object objA = p.getKey(a);
for (int b = 0; b < p.getKeyCount(); b++) {
if (a == b) {
continue;
}
Object oj = p.getKey(j);
float area = keyType.getCombinedArea(oi, oj);
Object objB = p.getKey(b);
float area = keyType.getCombinedArea(objA, objB);
if (area > largest) {
largest = area;
iBest = i;
jBest = j;
ia = a;
ib = b;
}
}
}
move(p, newP, iBest);
if (iBest < jBest) {
jBest--;
move(p, splitA, ia);
if (ia < ib) {
ib--;
}
move(p, split, jBest);
move(p, splitB, ib);
Object boundsA = keyType.createBoundingBox(splitA.getKey(0));
Object boundsB = keyType.createBoundingBox(splitB.getKey(0));
while (p.getKeyCount() > 0) {
float diff = 0, bestA = 0, bestB = 0;
int best = 0;
Object ba = getBounds(newP);
Object bb = getBounds(split);
for (int i = 0; i < p.getKeyCount(); i++) {
Object o = p.getKey(i);
float a = keyType.getAreaIncrease(ba, o);
float b = keyType.getAreaIncrease(bb, o);
float d = Math.abs(a - b);
float incA = keyType.getAreaIncrease(boundsA, o);
float incB = keyType.getAreaIncrease(boundsB, o);
float d = Math.abs(incA - incB);
if (d > diff) {
diff = d;
bestA = a;
bestB = b;
bestA = incA;
bestB = incB;
best = i;
}
}
if (bestA < bestB) {
move(p, newP, best);
keyType.increaseBounds(boundsA, p.getKey(best));
move(p, splitA, best);
} else {
move(p, split, best);
keyType.increaseBounds(boundsB, p.getKey(best));
move(p, splitB, best);
}
}
while (newP.getKeyCount() > 0) {
move(newP, p, 0);
while (splitB.getKeyCount() > 0) {
move(splitB, p, 0);
}
return split;
return splitA;
}
private Page newPage(boolean leaf, long writeVersion) {
Object[] values = leaf ? new Object[4] : null;
long[] c = leaf ? null : new long[1];
return Page.create(this, writeVersion, 0,
new Object[4], values, c, c, 0, 0);
}
private static void move(Page source, Page target, int sourceIndex) {
Object k = source.getKey(sourceIndex);
Object v = source.isLeaf() ? source.getValue(sourceIndex) : null;
long c = source.isLeaf() ? 0 : source.getChildPage(sourceIndex).getPos();
long count = source.isLeaf() ? 0 : source.getCounts(sourceIndex);
target.insert(0, k, v, c, count);
if (source.isLeaf()) {
Object v = source.getValue(sourceIndex);
target.insertLeaf(0, k, v);
} else {
long c = source.getChildPage(sourceIndex).getPos();
long count = source.getCounts(sourceIndex);
target.insertNode(0, k, c, count);
}
source.remove(sourceIndex);
}
......@@ -337,7 +401,10 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
* @param key the key
*/
protected CursorPos min(Page p, Cursor<K, V> cursor, Object key) {
while (p != null) {
if (p == null) {
return null;
}
while (true) {
CursorPos c = new CursorPos();
c.page = p;
if (p.isLeaf()) {
......@@ -346,7 +413,6 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
cursor.push(c);
p = p.getChildPage(0);
}
return null;
}
/**
......@@ -380,4 +446,12 @@ public class RtreeMap<K, V> extends BtreeMap<K, V> {
}
}
public boolean isQuadraticSplit() {
return quadraticSplit;
}
public void setQuadraticSplit(boolean quadraticSplit) {
this.quadraticSplit = quadraticSplit;
}
}
......@@ -7,6 +7,7 @@
package org.h2.test.store;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import org.h2.dev.store.btree.DataType;
import org.h2.dev.store.btree.DataUtils;
......@@ -126,10 +127,15 @@ public class SpatialType implements DataType {
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);
float min = a.min(0);
float max = a.max(0);
float areaOld = max - min;
min = Math.min(min, b.min(0));
max = Math.max(max, b.max(0));
float areaNew = max - min;
for (int i = 1; i < dimensions; i++) {
min = a.min(i);
max = a.max(i);
areaOld *= max - min;
min = Math.min(min, b.min(i));
max = Math.max(max, b.max(i));
......@@ -197,4 +203,65 @@ public class SpatialType implements DataType {
return new SpatialKey(0, minMax);
}
/**
* Get the most extreme pair (elements that are as far apart as possible).
* This method is used to split a page (linear split). If no extreme objects
* could be found, this method returns null.
*
* @param list the objects
* @return the indexes of the extremes
*/
public int[] getExtremes(ArrayList<Object> list) {
SpatialKey bounds = (SpatialKey) createBoundingBox(list.get(0));
SpatialKey boundsInner = (SpatialKey) createBoundingBox(bounds);
for (int i = 0; i < dimensions; i++) {
float t = boundsInner.min(i);
boundsInner.setMin(i, boundsInner.max(i));
boundsInner.setMax(i, t);
}
for (int i = 0; i < list.size(); i++) {
Object o = list.get(i);
increaseBounds(bounds, o);
increaseMaxInnerBounds(boundsInner, o);
}
double best = 0;
int bestDim = 0;
for (int i = 0; i < dimensions; i++) {
float inner = boundsInner.max(i) - boundsInner.min(i);
if (inner < 0) {
continue;
}
float outer = bounds.max(i) - bounds.min(i);
float d = inner / outer;
if (d > best) {
best = d;
bestDim = i;
}
}
if (best <= 0) {
return null;
}
float min = boundsInner.min(bestDim);
float max = boundsInner.max(bestDim);
int firstIndex = -1, lastIndex = -1;
for (int i = 0; i < list.size() && (firstIndex < 0 || lastIndex < 0); i++) {
SpatialKey o = (SpatialKey) list.get(i);
if (firstIndex < 0 && o.max(bestDim) == min) {
firstIndex = i;
} else if (lastIndex < 0 && o.min(bestDim) == max) {
lastIndex = i;
}
}
return new int[] { firstIndex, lastIndex };
}
private void increaseMaxInnerBounds(Object bounds, Object add) {
SpatialKey b = (SpatialKey) bounds;
SpatialKey a = (SpatialKey) add;
for (int i = 0; i < dimensions; i++) {
b.setMin(i, Math.min(b.min(i), a.max(i)));
b.setMax(i, Math.max(b.max(i), a.min(i)));
}
}
}
......@@ -14,6 +14,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.TreeMap;
......@@ -26,6 +27,7 @@ import org.h2.jaqu.bytecode.Null;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
import org.h2.util.New;
import org.h2.util.Profiler;
/**
* Tests the tree map store.
......@@ -42,8 +44,16 @@ public class TestBtreeMapStore extends TestBase {
}
public void test() {
testRtreeMany();
// testRtreeMany();
// System.out.println("lin: " + RtreeMap.splitLin + " quad:" + RtreeMap.splitQuad);
// testRtreeMany();
// System.out.println("lin: " + RtreeMap.splitLin + " quad:" + RtreeMap.splitQuad);
// testRtreeMany();
// System.out.println("lin: " + RtreeMap.splitLin + " quad:" + RtreeMap.splitQuad);
// if(true) return;
//
testRtree();
testRandomRtree();
testCustomMapType();
testTruncateFile();
testFastDelete();
......@@ -61,37 +71,113 @@ public class TestBtreeMapStore extends TestBase {
}
private void testRtreeMany() {
// quadratic:
// add: 796
// query: 161
// remove: 194
// linear: 50
// add: 345
// query: 244
// remove: 259
// MyTest
// add:197
// query:236
// delete:669
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
BtreeMapStore s;
s = openStore(fileName);
// s.setMaxPageSize(50);
s.setMaxPageSize(50);
RtreeMap<SpatialKey, String> r = s.openMap("data", "r", "s2", "");
// r.setQuadraticSplit(true);
Random rand = new Random(1);
int len = 1000;
int len = 1000000;
long t = System.currentTimeMillis();
Profiler prof = new Profiler();
//prof.startCollecting();
for (int i = 0; i < len; 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 % 100) == 0) {
s.store();
}
float p = (float) (rand.nextFloat() * 0.000001);
SpatialKey k = new SpatialKey(i, x - p, x + p, y - p, y + p);
r.add(k, "" + i);
if (i > 0 && (i % 10000) == 0) {
render(r, getBaseDir() + "/test.png");
s.store();
System.out.println("store " + i);
}
// if (i > 0 && (i % 10000) == 0) {
// render(r, getBaseDir() + "/test.png");
// }
}
//System.out.println(prof.getTop(5));
// quadratic
// add: 77967
// query: 39521
// remove: 22292
// linear
// add: 46136
// query: 65454
// remove: 35514
// > 10000 quadratic
// add: 54660
// query: 62946
System.out.println("add: " + (System.currentTimeMillis() - t));
s.store();
s.close();
s = openStore(fileName);
r = s.openMap("data", "r", "s2", "");
t = System.currentTimeMillis();
rand = new Random(1);
for (int i = 0; i < len; 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);
float p = (float) (rand.nextFloat() * 0.000001);
SpatialKey k = new SpatialKey(i, x - p, x + p, y - p, y + p);
assertEquals("" + i, r.get(k));
}
System.out.println("query: " + (System.currentTimeMillis() - t));
assertEquals(len, r.size());
int count = 0;
for (SpatialKey k : r.keySet()) {
assertTrue(r.get(k) != null);
count++;
}
assertEquals(len, count);
t = System.currentTimeMillis();
//Profiler prof = new Profiler();
//prof.startCollecting();
rand = new Random(1);
for (int i = 0; i < len; i++) {
float x = rand.nextFloat(), y = rand.nextFloat();
float p = (float) (rand.nextFloat() * 0.000001);
SpatialKey k = new SpatialKey(i, x - p, x + p, y - p, y + p);
r.remove(k);
}
assertEquals(0, r.size());
// System.out.println(prof.getTop(5));
System.out.println("remove: " + (System.currentTimeMillis() - t));
}
private void testRtree() {
......@@ -130,7 +216,7 @@ public class TestBtreeMapStore extends TestBase {
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);
SpatialKey k = new SpatialKey(id, a - s, a + s, b - s, b + s);
r.put(k, name);
}
......@@ -145,13 +231,13 @@ public class TestBtreeMapStore extends TestBase {
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setColor(Color.BLACK);
SpatialKey b = SpatialKey.create(0, Float.MAX_VALUE, Float.MIN_VALUE,
SpatialKey b = new SpatialKey(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]);
b.setMin(0, Math.min(b.min(0), x.min(0)));
b.setMin(1, Math.min(b.min(1), x.min(1)));
b.setMax(0, Math.max(b.max(0), x.max(0)));
b.setMax(1, Math.max(b.max(1), x.max(1)));
}
// System.out.println(b);
for (SpatialKey x : r.keySet()) {
......@@ -178,14 +264,55 @@ public class TestBtreeMapStore extends TestBase {
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),
(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 testRandomRtree() {
String fileName = getBaseDir() + "/testRandom.h3";
FileUtils.delete(fileName);
BtreeMapStore s = openStore(fileName);
RtreeMap<SpatialKey, String> m = s.openMap("data", "r", "s2", "");
HashMap<SpatialKey, String> map = new HashMap<SpatialKey, String>();
Random rand = new Random(1);
int operationCount = 1000;
int maxValue = 30;
for (int i = 0; i < operationCount; i++) {
int key = rand.nextInt(maxValue);
Random rk = new Random(key);
float x = rk.nextFloat(), y = rk.nextFloat();
float p = (float) (rk.nextFloat() * 0.000001);
SpatialKey k = new SpatialKey(key, x - p, x + p, y - p, y + p);
String v = "" + rand.nextInt();
switch (rand.nextInt(3)) {
case 0:
log(i + ": put " + k + " = " + v + " " + m.size());
m.put(k, v);
map.put(k, v);
break;
case 1:
log(i + ": remove " + k + " " + m.size());
m.remove(k);
map.remove(k);
break;
default:
String a = map.get(k);
String b = m.get(k);
if (a == null || b == null) {
assertTrue(a == b);
} else {
assertEquals(a, b);
}
break;
}
assertEquals(map.size(), m.size());
}
s.close();
}
private void testCustomMapType() {
String fileName = getBaseDir() + "/testMeta.h3";
FileUtils.delete(fileName);
......@@ -412,9 +539,10 @@ public class TestBtreeMapStore extends TestBase {
// s.setCompressor(null);
s.setMaxPageSize(40);
BtreeMap<Integer, Object[]> m = s.openMap("data", "", "i", "r(i,,)");
int i = 0;
// Profiler prof = new Profiler();
// prof.startCollecting();
// long t = System.currentTimeMillis();
for (; i < len;) {
for (int i = 0; i < len;) {
Object[] o = new Object[3];
o[0] = i;
o[1] = "Hello World";
......@@ -427,6 +555,7 @@ public class TestBtreeMapStore extends TestBase {
}
s.store();
s.close();
// System.out.println(prof.getTop(5));
// System.out.println("store time " + (System.currentTimeMillis() - t));
// System.out.println("store size " + FileUtils.size(fileName));
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论