Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
cd49d27d
提交
cd49d27d
authored
9月 02, 2012
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
A persistent multi-version map (work in progress) - implement complete java.util.Map interface
上级
7ef5bbc4
显示空白字符变更
内嵌
并排
正在显示
5 个修改的文件
包含
87 行增加
和
71 行删除
+87
-71
MVRTreeMap.java
h2/src/test/org/h2/test/store/MVRTreeMap.java
+25
-26
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+17
-11
MVMap.java
h2/src/tools/org/h2/dev/store/btree/MVMap.java
+33
-22
MVStore.java
h2/src/tools/org/h2/dev/store/btree/MVStore.java
+9
-11
Page.java
h2/src/tools/org/h2/dev/store/btree/Page.java
+3
-1
没有找到文件。
h2/src/test/org/h2/test/store/MVRTreeMap.java
浏览文件 @
cd49d27d
...
...
@@ -150,23 +150,26 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
return
bounds
;
}
public
void
put
(
K
key
,
V
value
)
{
putOrAdd
(
key
,
value
,
false
);
@SuppressWarnings
(
"unchecked"
)
public
V
put
(
K
key
,
V
value
)
{
return
(
V
)
putOrAdd
(
key
,
value
,
false
);
}
public
void
add
(
K
key
,
V
value
)
{
putOrAdd
(
key
,
value
,
true
);
}
public
void
putOrAdd
(
K
key
,
V
value
,
boolean
alwaysAdd
)
{
public
Object
putOrAdd
(
K
key
,
V
value
,
boolean
alwaysAdd
)
{
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
root
;
Object
result
;
if
(
p
==
null
)
{
Object
[]
keys
=
{
key
};
Object
[]
values
=
{
value
};
p
=
Page
.
create
(
this
,
writeVersion
,
1
,
keys
,
values
,
null
,
null
,
null
,
1
,
0
);
result
=
null
;
}
else
if
(
alwaysAdd
||
get
(
key
)
==
null
)
{
if
(
p
.
getKeyCount
()
>
store
.
getMaxPageSize
())
{
// only possible if this is the root, else we would have split earlier
...
...
@@ -183,43 +186,41 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
totalCount
,
0
);
// now p is a node; continues
}
p
=
add
(
p
,
writeVersion
,
key
,
value
);
add
(
p
,
writeVersion
,
key
,
value
);
result
=
null
;
}
else
{
p
=
set
(
p
,
writeVersion
,
key
,
value
);
result
=
set
(
p
,
writeVersion
,
key
,
value
);
}
setRoot
(
p
);
return
result
;
}
protected
Page
set
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
protected
Object
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
);
Page
c2
=
set
(
c
,
writeVersion
,
key
,
value
);
if
(
c
!=
c2
)
{
p
=
p
.
copyOnWrite
(
writeVersion
);
p
.
setChild
(
i
,
c2
);
break
;
Page
c
=
p
.
getChildPage
(
i
).
copyOnWrite
(
writeVersion
);
Object
result
=
set
(
c
,
writeVersion
,
key
,
value
);
if
(
result
!=
null
)
{
p
.
setChild
(
i
,
c
);
return
result
;
}
}
}
}
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
.
setValue
(
i
,
value
);
}
}
}
return
p
;
return
null
;
}
protected
Page
add
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
protected
void
add
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
if
(
p
.
isLeaf
())
{
p
=
p
.
copyOnWrite
(
writeVersion
);
p
.
insertLeaf
(
p
.
getKeyCount
(),
key
,
value
);
return
p
;
return
;
}
// p is a node
int
index
=
-
1
;
...
...
@@ -241,25 +242,23 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
}
}
}
Page
c
=
p
.
getChildPage
(
index
);
Page
c
=
p
.
getChildPage
(
index
)
.
copyOnWrite
(
writeVersion
)
;
if
(
c
.
getKeyCount
()
>=
store
.
getMaxPageSize
())
{
// split on the way down
c
=
c
.
copyOnWrite
(
writeVersion
);
Page
split
=
split
(
c
,
writeVersion
);
p
=
p
.
copyOnWrite
(
writeVersion
);
p
.
setKey
(
index
,
getBounds
(
c
));
p
.
setChild
(
index
,
c
);
p
.
insertNode
(
index
,
getBounds
(
split
),
split
);
// now we are not sure where to add
return
add
(
p
,
writeVersion
,
key
,
value
);
add
(
p
,
writeVersion
,
key
,
value
);
return
;
}
Page
c2
=
add
(
c
,
writeVersion
,
key
,
value
);
p
=
p
.
copyOnWrite
(
writeVersion
);
add
(
c
,
writeVersion
,
key
,
value
);
Object
bounds
=
p
.
getKey
(
index
);
keyType
.
increaseBounds
(
bounds
,
key
);
p
.
setKey
(
index
,
bounds
);
p
.
setChild
(
index
,
c2
);
return
p
;
p
.
setChild
(
index
,
c
);
}
private
Page
split
(
Page
p
,
long
writeVersion
)
{
...
...
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
cd49d27d
...
...
@@ -56,12 +56,12 @@ public class TestMVStore extends TestBase {
s
.
setMaxPageSize
(
6
);
MVMap
<
Integer
,
String
>
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
String
.
class
);
for
(
int
i
=
0
;
i
<
60
;
i
++)
{
m
.
put
(
i
,
"H
ello
"
);
m
.
put
(
i
,
"H
i
"
);
}
s
.
commit
();
s
.
store
();
for
(
int
i
=
20
;
i
<
40
;
i
++)
{
m
.
put
(
i
,
"Hello"
);
assertEquals
(
"Hi"
,
m
.
put
(
i
,
"Hello"
)
);
}
s
.
commit
();
for
(
int
i
=
10
;
i
<
15
;
i
++)
{
...
...
@@ -318,7 +318,7 @@ public class TestMVStore extends TestBase {
s
.
store
();
assertEquals
(
"1/1///"
,
m
.
get
(
"map.data"
));
assertTrue
(
m
.
containsKey
(
"chunk.1"
));
data
.
put
(
"1"
,
"Hallo"
);
assertEquals
(
"Hello"
,
data
.
put
(
"1"
,
"Hallo"
)
);
s
.
store
();
assertEquals
(
"1/1///"
,
m
.
get
(
"map.data"
));
assertTrue
(
m
.
get
(
"root.1"
).
length
()
>
0
);
...
...
@@ -341,7 +341,7 @@ public class TestMVStore extends TestBase {
MVMap
<
Integer
,
String
>
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
String
.
class
);
// t = System.currentTimeMillis();
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
m
.
put
(
i
,
"Hello World"
);
assertNull
(
m
.
put
(
i
,
"Hello World"
)
);
}
// System.out.println("put: " + (System.currentTimeMillis() - t));
// t = System.currentTimeMillis();
...
...
@@ -404,7 +404,7 @@ public class TestMVStore extends TestBase {
// p.startCollecting();
// long t = System.currentTimeMillis();
for
(
int
i
=
0
;
i
<
count
;
i
++)
{
m
.
put
(
i
,
"hello "
+
i
);
assertNull
(
m
.
put
(
i
,
"hello "
+
i
)
);
assertEquals
(
"hello "
+
i
,
m
.
get
(
i
));
}
// System.out.println("put: " + (System.currentTimeMillis() - t));
...
...
@@ -515,6 +515,7 @@ public class TestMVStore extends TestBase {
Random
r
=
new
Random
(
1
);
int
operationCount
=
1000
;
int
maxValue
=
30
;
Integer
expected
,
got
;
for
(
int
i
=
0
;
i
<
operationCount
;
i
++)
{
int
k
=
r
.
nextInt
(
maxValue
);
int
v
=
r
.
nextInt
();
...
...
@@ -522,14 +523,19 @@ public class TestMVStore extends TestBase {
switch
(
r
.
nextInt
(
3
))
{
case
0
:
log
(
i
+
": put "
+
k
+
" = "
+
v
);
m
.
put
(
k
,
v
);
map
.
put
(
k
,
v
);
expected
=
map
.
put
(
k
,
v
);
got
=
m
.
put
(
k
,
v
);
if
(
expected
==
null
)
{
assertNull
(
got
);
}
else
{
assertEquals
(
expected
,
got
);
}
compareAll
=
true
;
break
;
case
1
:
log
(
i
+
": remove "
+
k
);
Integer
expected
=
map
.
remove
(
k
);
Integer
got
=
m
.
remove
(
k
);
expected
=
map
.
remove
(
k
);
got
=
m
.
remove
(
k
);
if
(
expected
==
null
)
{
assertNull
(
got
);
}
else
{
...
...
@@ -553,8 +559,8 @@ public class TestMVStore extends TestBase {
Iterator
<
Integer
>
itExpected
=
map
.
keySet
().
iterator
();
while
(
itExpected
.
hasNext
())
{
assertTrue
(
it
.
hasNext
());
Integer
expected
=
itExpected
.
next
();
Integer
got
=
it
.
next
();
expected
=
itExpected
.
next
();
got
=
it
.
next
();
assertEquals
(
expected
,
got
);
}
assertFalse
(
it
.
hasNext
());
...
...
h2/src/tools/org/h2/dev/store/btree/MVMap.java
浏览文件 @
cd49d27d
...
...
@@ -6,8 +6,11 @@
*/
package
org
.
h2
.
dev
.
store
.
btree
;
import
java.util.AbstractMap
;
import
java.util.AbstractSet
;
import
java.util.HashMap
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.TreeMap
;
...
...
@@ -17,7 +20,7 @@ import java.util.TreeMap;
* @param <K> the key class
* @param <V> the value class
*/
public
class
MVMap
<
K
,
V
>
{
public
class
MVMap
<
K
,
V
>
extends
AbstractMap
<
K
,
V
>
{
protected
final
MVStore
store
;
protected
Page
root
;
...
...
@@ -51,16 +54,20 @@ public class MVMap<K, V> {
*
* @param key the key
* @param value the value
* @return the old value if the key existed, or null otherwise
*/
public
void
put
(
K
key
,
V
value
)
{
@SuppressWarnings
(
"unchecked"
)
public
V
put
(
K
key
,
V
value
)
{
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
root
;
Object
result
;
if
(
p
==
null
)
{
Object
[]
keys
=
{
key
};
Object
[]
values
=
{
value
};
p
=
Page
.
create
(
this
,
writeVersion
,
1
,
keys
,
values
,
null
,
null
,
null
,
1
,
0
);
result
=
null
;
}
else
{
p
=
p
.
copyOnWrite
(
writeVersion
);
if
(
p
.
getKeyCount
()
>
store
.
getMaxPageSize
())
{
...
...
@@ -76,9 +83,10 @@ public class MVMap<K, V> {
keys
,
null
,
children
,
childrenPages
,
counts
,
totalCount
,
0
);
// now p is a node; insert continues
}
put
(
p
,
writeVersion
,
key
,
value
);
result
=
put
(
p
,
writeVersion
,
key
,
value
);
}
setRoot
(
p
);
return
(
V
)
result
;
}
/**
...
...
@@ -90,16 +98,15 @@ public class MVMap<K, V> {
* @param key the key
* @param value the value (may not be null)
*/
protected
void
put
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
protected
Object
put
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
if
(
p
.
isLeaf
())
{
int
index
=
p
.
binarySearch
(
key
);
if
(
index
<
0
)
{
index
=
-
index
-
1
;
p
.
insertLeaf
(
index
,
key
,
value
);
}
else
{
p
.
setValue
(
index
,
value
);
return
null
;
}
return
;
return
p
.
setValue
(
index
,
value
)
;
}
// p is a node
int
index
=
p
.
binarySearch
(
key
);
...
...
@@ -108,8 +115,7 @@ public class MVMap<K, V> {
}
else
{
index
++;
}
Page
cOld
=
p
.
getChildPage
(
index
);
Page
c
=
cOld
.
copyOnWrite
(
writeVersion
);
Page
c
=
p
.
getChildPage
(
index
).
copyOnWrite
(
writeVersion
);
if
(
c
.
getKeyCount
()
>=
store
.
getMaxPageSize
())
{
// split on the way down
int
at
=
c
.
getKeyCount
()
/
2
;
...
...
@@ -118,14 +124,11 @@ public class MVMap<K, V> {
p
.
setChild
(
index
,
split
);
p
.
insertNode
(
index
,
k
,
c
);
// now we are not sure where to add
put
(
p
,
writeVersion
,
key
,
value
);
return
;
return
put
(
p
,
writeVersion
,
key
,
value
);
}
long
oldSize
=
c
.
getTotalCount
();
put
(
c
,
writeVersion
,
key
,
value
);
if
(
cOld
!=
c
||
oldSize
!=
c
.
getTotalCount
())
{
Object
result
=
put
(
c
,
writeVersion
,
key
,
value
);
p
.
setChild
(
index
,
c
);
}
return
result
;
}
/**
...
...
@@ -312,9 +315,9 @@ public class MVMap<K, V> {
* Remove a key-value pair, if the key exists.
*
* @param key the key
* @return the old value if the key existed
* @return the old value if the key existed
, or null otherwise
*/
public
V
remove
(
K
key
)
{
public
V
remove
(
Object
key
)
{
checkWrite
();
Page
p
=
root
;
if
(
p
==
null
)
{
...
...
@@ -468,6 +471,14 @@ public class MVMap<K, V> {
return
c
;
}
public
Set
<
Map
.
Entry
<
K
,
V
>>
entrySet
()
{
HashMap
<
K
,
V
>
map
=
new
HashMap
<
K
,
V
>();
for
(
K
k
:
keySet
())
{
map
.
put
(
k
,
get
(
k
));
}
return
map
.
entrySet
();
}
public
Set
<
K
>
keySet
()
{
checkOpen
();
final
Page
root
=
this
.
root
;
...
...
@@ -582,6 +593,10 @@ public class MVMap<K, V> {
return
id
;
}
public
boolean
equals
(
Object
o
)
{
return
this
==
o
;
}
public
int
size
()
{
long
size
=
getSize
();
return
size
>
Integer
.
MAX_VALUE
?
Integer
.
MAX_VALUE
:
(
int
)
size
;
...
...
@@ -591,10 +606,6 @@ public class MVMap<K, V> {
return
root
==
null
?
0
:
root
.
getTotalCount
();
}
public
boolean
equals
(
Object
o
)
{
return
this
==
o
;
}
long
getCreateVersion
()
{
return
createVersion
;
}
...
...
h2/src/tools/org/h2/dev/store/btree/MVStore.java
浏览文件 @
cd49d27d
...
...
@@ -38,27 +38,25 @@ header:
blockSize=4096
TODO:
- rename commit to incrementVersion
- implement complete java.util.Map interface
- test with very small chunks, possibly speed up very small transactions
- check what happens on concurrent reads and 1 write; multiple writes
- support all objects (using serialization)
- concurrent iterator (when to call commit; read on first hasNext())
- compact: use total max length instead of page count (liveCount)
- support background writes (store old version)
- avoid using java.util.Properties (it allocates quite a lot of memory)
- support large binaries
- support database version / schema version
- limited support for writing to old versions (branches)
- atomic test-and-set (when supporting concurrent writes)
- support background writes (store old version)
- file header could be a regular chunk, end of file the second
- possibly split chunk data into immutable and mutable
- test with very small chunks, possibly speed up very small transactions
- compact: use total max length instead of page count (liveCount)
- check what happens on concurrent reads and 1 write; multiple writes
- concurrent iterator (when to call commit)
- support large binaries
- support stores that span multiple files (chunks stored in other files)
- triggers
- support database version / schema version
- implement more counted b-tree (skip, get positions)
- merge pages if small
- r-tree: add missing features (NN search for example)
- compression: maybe hash table reset speeds up compression
- avoid using java.util.Properties (it allocates quite a lot of memory)
- support all objects (using serialization)
*/
...
...
h2/src/tools/org/h2/dev/store/btree/Page.java
浏览文件 @
cd49d27d
...
...
@@ -346,12 +346,14 @@ public class Page {
keys
[
index
]
=
key
;
}
public
void
setValue
(
int
index
,
Object
value
)
{
public
Object
setValue
(
int
index
,
Object
value
)
{
Object
old
=
values
[
index
];
if
((
sharedFlags
&
SHARED_VALUES
)
!=
0
)
{
values
=
Arrays
.
copyOf
(
values
,
values
.
length
);
sharedFlags
&=
~
SHARED_VALUES
;
}
values
[
index
]
=
value
;
return
old
;
}
/**
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论