Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
ccaa8179
提交
ccaa8179
authored
12 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
A persistent multi-version map (work in progress): r-tree
上级
b1edabaa
显示空白字符变更
内嵌
并排
正在显示
15 个修改的文件
包含
876 行增加
和
151 行删除
+876
-151
IntegerType.java
h2/src/test/org/h2/test/store/IntegerType.java
+0
-4
RowType.java
h2/src/test/org/h2/test/store/RowType.java
+0
-10
RtreeMap.java
h2/src/test/org/h2/test/store/RtreeMap.java
+345
-1
SpatialKey.java
h2/src/test/org/h2/test/store/SpatialKey.java
+43
-0
SpatialType.java
h2/src/test/org/h2/test/store/SpatialType.java
+177
-0
TestBtreeMapStore.java
h2/src/test/org/h2/test/store/TestBtreeMapStore.java
+128
-1
TestDataUtils.java
h2/src/test/org/h2/test/store/TestDataUtils.java
+56
-0
TestMapFactory.java
h2/src/test/org/h2/test/store/TestMapFactory.java
+6
-1
BtreeMap.java
h2/src/tools/org/h2/dev/store/btree/BtreeMap.java
+26
-30
BtreeMapStore.java
h2/src/tools/org/h2/dev/store/btree/BtreeMapStore.java
+9
-8
CursorPos.java
h2/src/tools/org/h2/dev/store/btree/CursorPos.java
+4
-3
DataType.java
h2/src/tools/org/h2/dev/store/btree/DataType.java
+0
-8
DataUtils.java
h2/src/tools/org/h2/dev/store/btree/DataUtils.java
+3
-2
Page.java
h2/src/tools/org/h2/dev/store/btree/Page.java
+79
-68
StringType.java
h2/src/tools/org/h2/dev/store/btree/StringType.java
+0
-15
没有找到文件。
h2/src/test/org/h2/test/store/IntegerType.java
浏览文件 @
ccaa8179
...
...
@@ -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
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/RowType.java
浏览文件 @
ccaa8179
...
...
@@ -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
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/RtreeMap.java
浏览文件 @
ccaa8179
...
...
@@ -6,21 +6,365 @@
*/
package
org
.
h2
.
test
.
store
;
import
java.util.ArrayList
;
import
org.h2.dev.store.btree.BtreeMap
;
import
org.h2.dev.store.btree.BtreeMapStore
;
import
org.h2.dev.store.btree.CursorPos
;
import
org.h2.dev.store.btree.DataType
;
import
org.h2.dev.store.btree.Page
;
/**
* A
stored r-tree
.
* A
n r-tree implementation
.
*
* @param <K> the key class
* @param <V> the value class
*/
public
class
RtreeMap
<
K
,
V
>
extends
BtreeMap
<
K
,
V
>
{
private
final
SpatialType
keyType
;
RtreeMap
(
BtreeMapStore
store
,
int
id
,
String
name
,
DataType
keyType
,
DataType
valueType
,
long
createVersion
)
{
super
(
store
,
id
,
name
,
keyType
,
valueType
,
createVersion
);
this
.
keyType
=
(
SpatialType
)
keyType
;
}
@SuppressWarnings
(
"unchecked"
)
public
V
get
(
Object
key
)
{
checkOpen
();
if
(
root
==
null
)
{
return
null
;
}
return
(
V
)
getSpatial
(
root
,
key
);
}
private
boolean
overlap
(
Page
p
,
int
index
,
Object
key
)
{
return
keyType
.
isOverlap
(
p
.
getKey
(
index
),
key
);
}
private
boolean
contains
(
Page
p
,
int
index
,
Object
key
)
{
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.
*
* @param p the page
* @param key the key
* @return the value, or null if not found
*/
protected
Object
getSpatial
(
Page
p
,
Object
key
)
{
if
(!
p
.
isLeaf
())
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
contains
(
p
,
i
,
key
))
{
Object
o
=
getSpatial
(
p
.
getChildPage
(
i
),
key
);
if
(
o
!=
null
)
{
return
o
;
}
}
}
}
else
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
keyType
.
equals
(
p
.
getKey
(
i
),
key
))
{
return
p
.
getValue
(
i
);
}
}
}
return
null
;
}
protected
Page
getPage
(
K
key
)
{
if
(
root
==
null
)
{
return
null
;
}
return
getPageSpatial
(
root
,
key
);
}
protected
Page
getPageSpatial
(
Page
p
,
Object
key
)
{
if
(!
p
.
isLeaf
())
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
contains
(
p
,
i
,
key
))
{
Page
x
=
getPageSpatial
(
p
.
getChildPage
(
i
),
key
);
if
(
x
!=
null
)
{
return
x
;
}
}
}
}
else
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
keyType
.
equals
(
p
.
getKey
(
i
),
key
))
{
return
p
;
}
}
}
return
null
;
}
protected
Page
set
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
if
(
p
==
null
)
{
throw
KEY_NOT_FOUND
;
}
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
)
{
p
=
p
.
copyOnWrite
(
writeVersion
);
setChildUpdateBox
(
p
,
i
,
c2
);
break
;
}
}
}
}
else
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
keyType
.
equals
(
p
.
getKey
(
i
),
key
))
{
p
=
p
.
copyOnWrite
(
writeVersion
);
p
.
setValue
(
i
,
value
);
break
;
}
}
}
return
p
;
}
protected
Page
removeExisting
(
Page
p
,
long
writeVersion
,
Object
key
)
{
if
(
p
==
null
)
{
throw
KEY_NOT_FOUND
;
}
if
(!
p
.
isLeaf
())
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
contains
(
p
,
i
,
key
))
{
Page
c
=
p
.
getChildPage
(
i
);
Page
c2
=
removeExisting
(
c
,
writeVersion
,
key
);
if
(
c
!=
c2
)
{
p
=
p
.
copyOnWrite
(
writeVersion
);
setChildUpdateBox
(
p
,
i
,
c2
);
break
;
}
}
}
}
else
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
keyType
.
equals
(
p
.
getKey
(
i
),
key
))
{
p
=
p
.
copyOnWrite
(
writeVersion
);
p
.
remove
(
i
);
break
;
}
}
}
return
p
;
}
/**
* Set the child and update the bounding box.
*
* @param p the parent (this page is changed)
* @param index the child index
* @param c the child page
*/
private
void
setChildUpdateBox
(
Page
p
,
int
index
,
Page
c
)
{
p
.
setKey
(
index
,
getBounds
(
c
));
p
.
setChild
(
index
,
c
);
}
private
SpatialKey
getBounds
(
Page
x
)
{
SpatialKey
bounds
=
keyType
.
copy
((
SpatialKey
)
x
.
getKey
(
0
));
for
(
int
i
=
1
;
i
<
x
.
getKeyCount
();
i
++)
{
keyType
.
increase
(
bounds
,
(
SpatialKey
)
x
.
getKey
(
i
));
}
return
bounds
;
}
protected
Page
add
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
if
(
p
==
null
)
{
Object
[]
keys
=
{
key
};
Object
[]
values
=
{
value
};
p
=
Page
.
create
(
this
,
writeVersion
,
keys
,
values
,
null
,
null
,
1
);
return
p
;
}
if
(
p
.
getKeyCount
()
>=
store
.
getMaxPageSize
())
{
// only possible if this is the root,
// otherwise we would have split earlier
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
}
else
if
(
p
.
isLeaf
())
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
keyType
.
equals
(
p
.
getKey
(
i
),
key
))
{
throw
KEY_ALREADY_EXISTS
;
}
}
p
.
insert
(
p
.
getKeyCount
(),
key
,
value
,
0
,
0
);
return
p
;
}
// p is a node
float
min
=
Float
.
MAX_VALUE
;
int
index
=
0
;
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
float
areaIncrease
=
getAreaIncrease
(
p
,
i
,
key
);
if
(
areaIncrease
<
min
)
{
index
=
i
;
min
=
areaIncrease
;
}
}
Page
c
=
p
.
getChildPage
(
index
);
if
(
c
.
getKeyCount
()
>=
store
.
getMaxPageSize
())
{
// split on the way down
c
=
c
.
copyOnWrite
(
writeVersion
);
Page
split
=
split
(
c
,
writeVersion
);
p
=
p
.
copyOnWrite
(
writeVersion
);
setChildUpdateBox
(
p
,
index
,
c
);
p
.
insert
(
index
,
getBounds
(
split
),
null
,
split
.
getPos
(),
split
.
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
setChildUpdateBox
(
p
,
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
;
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
Object
oi
=
p
.
getKey
(
i
);
for
(
int
j
=
0
;
j
<
p
.
getKeyCount
();
j
++)
{
if
(
i
==
j
)
{
continue
;
}
Object
oj
=
p
.
getKey
(
j
);
float
area
=
keyType
.
getCombinedArea
(
oi
,
oj
);
if
(
area
>
largest
)
{
largest
=
area
;
iBest
=
i
;
jBest
=
j
;
}
}
}
move
(
p
,
newP
,
iBest
);
if
(
iBest
<
jBest
)
{
jBest
--;
}
move
(
p
,
split
,
jBest
);
while
(
p
.
getKeyCount
()
>
0
)
{
float
diff
=
0
,
bestA
=
0
,
bestB
=
0
;
int
best
=
0
;
SpatialKey
ba
=
getBounds
(
newP
);
SpatialKey
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
);
if
(
d
>
diff
)
{
diff
=
d
;
bestA
=
a
;
bestB
=
b
;
best
=
i
;
}
}
if
(
bestA
<
bestB
)
{
move
(
p
,
newP
,
best
);
}
else
{
move
(
p
,
split
,
best
);
}
}
while
(
newP
.
getKeyCount
()
>
0
)
{
move
(
newP
,
p
,
0
);
}
return
split
;
}
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
);
source
.
remove
(
sourceIndex
);
}
public
void
addNodeKeys
(
ArrayList
<
SpatialKey
>
list
,
Page
p
)
{
if
(
p
!=
null
&&
!
p
.
isLeaf
())
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
list
.
add
((
SpatialKey
)
p
.
getKey
(
i
));
addNodeKeys
(
list
,
p
.
getChildPage
(
i
));
}
}
}
/**
* Go to the first element for the given key.
*
* @param p the current page
* @param parents the stack of parent page positions
* @param key the key
*/
protected
void
min
(
Page
p
,
ArrayList
<
CursorPos
>
parents
,
Object
key
)
{
while
(
p
!=
null
)
{
CursorPos
c
=
new
CursorPos
();
c
.
page
=
p
;
parents
.
add
(
c
);
if
(
p
.
isLeaf
())
{
return
;
}
p
=
p
.
getChildPage
(
0
);
}
}
/**
* Get the next key.
*
* @param parents the stack of parent page positions
* @return the next key
*/
protected
Object
nextKey
(
ArrayList
<
CursorPos
>
parents
)
{
if
(
parents
.
size
()
==
0
)
{
return
null
;
}
while
(
true
)
{
// TODO performance: avoid remove/add pairs if possible
CursorPos
p
=
parents
.
remove
(
parents
.
size
()
-
1
);
int
index
=
p
.
index
++;
if
(
index
<
p
.
page
.
getKeyCount
())
{
parents
.
add
(
p
);
return
p
.
page
.
getKey
(
index
);
}
while
(
true
)
{
if
(
parents
.
size
()
==
0
)
{
return
null
;
}
p
=
parents
.
remove
(
parents
.
size
()
-
1
);
index
=
++
p
.
index
;
if
(
index
<
p
.
page
.
getKeyCount
())
{
parents
.
add
(
p
);
Page
x
=
p
.
page
;
x
=
x
.
getChildPage
(
index
);
min
(
x
,
parents
,
null
);
break
;
}
}
}
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/SpatialKey.java
0 → 100644
浏览文件 @
ccaa8179
/*
* 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
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/SpatialType.java
0 → 100644
浏览文件 @
ccaa8179
/*
* 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
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestBtreeMapStore.java
浏览文件 @
ccaa8179
...
...
@@ -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
(
';'
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestDataUtils.java
浏览文件 @
ccaa8179
...
...
@@ -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
));
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestMapFactory.java
浏览文件 @
ccaa8179
...
...
@@ -22,9 +22,12 @@ 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
);
}
}
@Override
public
DataType
buildDataType
(
String
s
)
{
...
...
@@ -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
);
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/BtreeMap.java
浏览文件 @
ccaa8179
...
...
@@ -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
*/
pr
ivate
Object
binarySearch
(
Page
p
,
Object
key
)
{
pr
otected
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
*/
pr
ivate
Page
binarySearchPage
(
Page
p
,
Object
key
)
{
pr
otected
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)
*/
pr
ivate
Page
removeExisting
(
Page
p
,
long
writeVersion
,
Object
key
)
{
pr
otected
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
;
}
pr
ivate
void
markChanged
(
Page
oldRoot
)
{
pr
otected
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
;
}
pr
ivate
void
checkOpen
()
{
pr
otected
void
checkOpen
()
{
if
(
store
==
null
)
{
throw
new
IllegalStateException
(
"This map is closed"
);
}
}
pr
ivate
void
checkWrite
()
{
pr
otected
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
());
}
}
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/BtreeMapStore.java
浏览文件 @
ccaa8179
...
...
@@ -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
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/CursorPos.java
浏览文件 @
ccaa8179
...
...
@@ -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
;
}
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/DataType.java
浏览文件 @
ccaa8179
...
...
@@ -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.
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/DataUtils.java
浏览文件 @
ccaa8179
...
...
@@ -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
;
}
/**
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/Page.java
浏览文件 @
ccaa8179
...
...
@@ -30,9 +30,9 @@ public class Page {
private
Object
[]
keys
;
private
Object
[]
values
;
private
long
[]
children
;
private
long
[]
c
hildrenSize
;
private
long
[]
c
ounts
;
private
int
cachedCompare
;
private
long
total
Size
;
private
long
total
Count
;
private
Page
(
BtreeMap
<?,
?>
map
,
long
version
)
{
this
.
map
=
map
;
...
...
@@ -49,16 +49,16 @@ public class Page {
* @param children the children
* @return the page
*/
static
Page
create
(
BtreeMap
<?,
?>
map
,
long
version
,
Object
[]
keys
,
Object
[]
values
,
long
[]
children
,
long
[]
c
hildrenSize
,
long
total
Size
)
{
public
static
Page
create
(
BtreeMap
<?,
?>
map
,
long
version
,
Object
[]
keys
,
Object
[]
values
,
long
[]
children
,
long
[]
c
ounts
,
long
total
Count
)
{
Page
p
=
new
Page
(
map
,
version
);
p
.
pos
=
map
.
getStore
().
registerTempPage
(
p
);
p
.
keys
=
keys
;
p
.
values
=
values
;
p
.
children
=
children
;
p
.
c
hildrenSize
=
childrenSize
;
p
.
total
Size
=
totalSize
;
p
.
c
ounts
=
counts
;
p
.
total
Count
=
totalCount
;
return
p
;
}
...
...
@@ -95,23 +95,23 @@ public class Page {
return
p
;
}
Object
getKey
(
int
index
)
{
public
Object
getKey
(
int
index
)
{
return
keys
[
index
];
}
Page
getChildPage
(
int
index
)
{
public
Page
getChildPage
(
int
index
)
{
return
map
.
readPage
(
children
[
index
]);
}
Object
getValue
(
int
x
)
{
public
Object
getValue
(
int
x
)
{
return
values
[
x
];
}
int
getKeyCount
()
{
public
int
getKeyCount
()
{
return
keys
.
length
;
}
boolean
isLeaf
()
{
public
boolean
isLeaf
()
{
return
children
==
null
;
}
...
...
@@ -120,7 +120,7 @@ public class Page {
*
* @return the position
*/
long
getPos
()
{
public
long
getPos
()
{
return
pos
;
}
...
...
@@ -145,13 +145,13 @@ public class Page {
return
buff
.
toString
();
}
Page
copyOnWrite
(
long
writeVersion
)
{
public
Page
copyOnWrite
(
long
writeVersion
)
{
if
(
version
==
writeVersion
)
{
return
this
;
}
map
.
getStore
().
removePage
(
pos
);
Page
newPage
=
create
(
map
,
writeVersion
,
keys
,
values
,
children
,
c
hildrenSize
,
totalSize
);
c
ounts
,
totalCount
);
newPage
.
cachedCompare
=
cachedCompare
;
return
newPage
;
}
...
...
@@ -166,7 +166,7 @@ public class Page {
* @param key the key
* @return the value or null
*/
int
binarySearch
(
Object
key
)
{
public
int
binarySearch
(
Object
key
)
{
int
low
=
0
,
high
=
keys
.
length
-
1
;
int
x
=
cachedCompare
-
1
;
if
(
x
<
0
||
x
>
high
)
{
...
...
@@ -203,7 +203,7 @@ public class Page {
// return -(low + 1);
}
Page
split
(
int
at
)
{
public
Page
split
(
int
at
)
{
return
isLeaf
()
?
splitLeaf
(
at
)
:
splitNode
(
at
);
}
...
...
@@ -220,7 +220,7 @@ public class Page {
System
.
arraycopy
(
values
,
0
,
aValues
,
0
,
a
);
System
.
arraycopy
(
values
,
a
,
bValues
,
0
,
b
);
values
=
aValues
;
total
Size
=
keys
.
length
;
total
Count
=
keys
.
length
;
Page
newPage
=
create
(
map
,
version
,
bKeys
,
bValues
,
null
,
null
,
bKeys
.
length
);
return
newPage
;
...
...
@@ -238,61 +238,70 @@ public class Page {
System
.
arraycopy
(
children
,
0
,
aChildren
,
0
,
a
+
1
);
System
.
arraycopy
(
children
,
a
+
1
,
bChildren
,
0
,
b
);
children
=
aChildren
;
long
[]
aC
hildrenSize
=
new
long
[
a
+
1
];
long
[]
bC
hildrenSize
=
new
long
[
b
];
System
.
arraycopy
(
c
hildrenSize
,
0
,
aChildrenSize
,
0
,
a
+
1
);
System
.
arraycopy
(
c
hildrenSize
,
a
+
1
,
bChildrenSize
,
0
,
b
);
c
hildrenSize
=
aChildrenSize
;
long
[]
aC
ounts
=
new
long
[
a
+
1
];
long
[]
bC
ounts
=
new
long
[
b
];
System
.
arraycopy
(
c
ounts
,
0
,
aCounts
,
0
,
a
+
1
);
System
.
arraycopy
(
c
ounts
,
a
+
1
,
bCounts
,
0
,
b
);
c
ounts
=
aCounts
;
long
t
=
0
;
for
(
long
x
:
aC
hildrenSize
)
{
for
(
long
x
:
aC
ounts
)
{
t
+=
x
;
}
total
Size
=
t
;
total
Count
=
t
;
t
=
0
;
for
(
long
x
:
bC
hildrenSize
)
{
for
(
long
x
:
bC
ounts
)
{
t
+=
x
;
}
Page
newPage
=
create
(
map
,
version
,
bKeys
,
null
,
bChildren
,
bC
hildrenSize
,
t
);
bC
ounts
,
t
);
return
newPage
;
}
long
getTotalSize
()
{
public
long
getTotalSize
()
{
if
(
BtreeMapStore
.
ASSERT
)
{
long
check
=
0
;
if
(
isLeaf
())
{
check
=
keys
.
length
;
}
else
{
for
(
long
x
:
c
hildrenSize
)
{
for
(
long
x
:
c
ounts
)
{
check
+=
x
;
}
}
if
(
check
!=
total
Size
)
{
if
(
check
!=
total
Count
)
{
throw
new
AssertionError
(
"Expected: "
+
check
+
" got: "
+
total
Size
);
+
total
Count
);
}
}
return
total
Size
;
return
total
Count
;
}
void
setChild
(
int
index
,
long
pos
,
long
childSize
)
{
if
(
pos
!=
children
[
index
])
{
public
void
setChild
(
int
index
,
Page
c
)
{
if
(
c
.
getPos
()
!=
children
[
index
])
{
long
[]
newChildren
=
new
long
[
children
.
length
];
System
.
arraycopy
(
children
,
0
,
newChildren
,
0
,
newChildren
.
length
);
newChildren
[
index
]
=
pos
;
newChildren
[
index
]
=
c
.
getPos
()
;
children
=
newChildren
;
}
if
(
c
hildSize
!=
childrenSize
[
index
])
{
long
[]
newC
hildrenSize
=
new
long
[
childrenSize
.
length
];
System
.
arraycopy
(
c
hildrenSize
,
0
,
newChildrenSize
,
0
,
newC
hildrenSize
.
length
);
newC
hildrenSize
[
index
]
=
childSize
;
total
Size
+=
newChildrenSize
[
index
]
-
childrenSize
[
index
];
c
hildrenSize
=
newChildrenSize
;
if
(
c
.
getTotalSize
()
!=
counts
[
index
])
{
long
[]
newC
ounts
=
new
long
[
counts
.
length
];
System
.
arraycopy
(
c
ounts
,
0
,
newCounts
,
0
,
newC
ounts
.
length
);
newC
ounts
[
index
]
=
c
.
getTotalSize
()
;
total
Count
+=
newCounts
[
index
]
-
counts
[
index
];
c
ounts
=
newCounts
;
}
}
void
setValue
(
int
index
,
Object
value
)
{
public
void
setKey
(
int
index
,
Object
key
)
{
// create a copy - not required if already cloned once in this version,
// but avoid unnecessary cloning would require a "modified" flag
Object
[]
newKeys
=
new
Object
[
keys
.
length
];
System
.
arraycopy
(
keys
,
0
,
newKeys
,
0
,
newKeys
.
length
);
newKeys
[
index
]
=
key
;
keys
=
newKeys
;
}
public
void
setValue
(
int
index
,
Object
value
)
{
// create a copy - not required if already cloned once in this version,
// but avoid unnecessary cloning would require a "modified" flag
Object
[]
newValues
=
new
Object
[
values
.
length
];
...
...
@@ -318,8 +327,8 @@ public class Page {
map
.
getStore
().
removePage
(
pos
);
}
void
insert
(
int
index
,
Object
key
,
Object
value
,
long
child
,
long
c
hildSize
)
{
public
void
insert
(
int
index
,
Object
key
,
Object
value
,
long
child
,
long
c
ount
)
{
Object
[]
newKeys
=
new
Object
[
keys
.
length
+
1
];
DataUtils
.
copyWithGap
(
keys
,
newKeys
,
keys
.
length
,
index
);
newKeys
[
index
]
=
key
;
...
...
@@ -329,24 +338,22 @@ public class Page {
DataUtils
.
copyWithGap
(
values
,
newValues
,
values
.
length
,
index
);
newValues
[
index
]
=
value
;
values
=
newValues
;
total
Size
++;
total
Count
++;
}
if
(
children
!=
null
)
{
long
[]
newChildren
=
new
long
[
children
.
length
+
1
];
DataUtils
.
copyWithGap
(
children
,
newChildren
,
children
.
length
,
index
+
1
);
newChildren
[
index
+
1
]
=
child
;
DataUtils
.
copyWithGap
(
children
,
newChildren
,
children
.
length
,
index
);
newChildren
[
index
]
=
child
;
children
=
newChildren
;
long
[]
newChildrenSize
=
new
long
[
childrenSize
.
length
+
1
];
DataUtils
.
copyWithGap
(
childrenSize
,
newChildrenSize
,
childrenSize
.
length
,
index
+
1
);
newChildrenSize
[
index
+
1
]
=
childSize
;
childrenSize
=
newChildrenSize
;
totalSize
+=
childSize
;
long
[]
newCounts
=
new
long
[
counts
.
length
+
1
];
DataUtils
.
copyWithGap
(
counts
,
newCounts
,
counts
.
length
,
index
);
newCounts
[
index
]
=
count
;
counts
=
newCounts
;
totalCount
+=
count
;
}
}
void
remove
(
int
index
)
{
public
void
remove
(
int
index
)
{
Object
[]
newKeys
=
new
Object
[
keys
.
length
-
1
];
int
keyIndex
=
index
>=
keys
.
length
?
index
-
1
:
index
;
DataUtils
.
copyExcept
(
keys
,
newKeys
,
keys
.
length
,
keyIndex
);
...
...
@@ -355,18 +362,18 @@ public class Page {
Object
[]
newValues
=
new
Object
[
values
.
length
-
1
];
DataUtils
.
copyExcept
(
values
,
newValues
,
values
.
length
,
index
);
values
=
newValues
;
total
Size
--;
total
Count
--;
}
if
(
children
!=
null
)
{
long
sizeOffset
=
childrenSize
[
index
];
long
countOffset
=
counts
[
index
];
long
[]
newChildren
=
new
long
[
children
.
length
-
1
];
DataUtils
.
copyExcept
(
children
,
newChildren
,
children
.
length
,
index
);
children
=
newChildren
;
long
[]
newC
hildrenSize
=
new
long
[
childrenSize
.
length
-
1
];
DataUtils
.
copyExcept
(
c
hildrenSize
,
newChildrenSize
,
c
hildrenSize
.
length
,
index
);
c
hildrenSize
=
newChildrenSize
;
total
Size
-=
size
Offset
;
long
[]
newC
ounts
=
new
long
[
counts
.
length
-
1
];
DataUtils
.
copyExcept
(
c
ounts
,
newCounts
,
c
ounts
.
length
,
index
);
c
ounts
=
newCounts
;
total
Count
-=
count
Offset
;
}
}
...
...
@@ -413,20 +420,20 @@ public class Page {
for
(
int
i
=
0
;
i
<=
len
;
i
++)
{
children
[
i
]
=
buff
.
getLong
();
}
c
hildrenSize
=
new
long
[
len
+
1
];
c
ounts
=
new
long
[
len
+
1
];
long
total
=
0
;
for
(
int
i
=
0
;
i
<=
len
;
i
++)
{
long
s
=
DataUtils
.
readVarLong
(
buff
);
total
+=
s
;
c
hildrenSize
[
i
]
=
s
;
c
ounts
[
i
]
=
s
;
}
total
Size
=
total
;
total
Count
=
total
;
}
else
{
values
=
new
Object
[
len
];
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
values
[
i
]
=
map
.
getValueType
().
read
(
buff
);
}
total
Size
=
len
;
total
Count
=
len
;
}
}
...
...
@@ -456,7 +463,7 @@ public class Page {
buff
.
putLong
(
children
[
i
]);
}
for
(
int
i
=
0
;
i
<=
len
;
i
++)
{
DataUtils
.
writeVarLong
(
buff
,
c
hildrenSize
[
i
]);
DataUtils
.
writeVarLong
(
buff
,
c
ounts
[
i
]);
}
}
else
{
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
...
...
@@ -558,4 +565,8 @@ public class Page {
return
count
;
}
public
long
getCounts
(
int
index
)
{
return
counts
[
index
];
}
}
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/StringType.java
浏览文件 @
ccaa8179
...
...
@@ -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
;
}
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论