Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
2ceb5ec6
提交
2ceb5ec6
authored
12 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
A persistent multi-version map (work in progress)
上级
a94da0f4
全部展开
显示空白字符变更
内嵌
并排
正在显示
18 个修改的文件
包含
866 行增加
和
262 行删除
+866
-262
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+4
-2
MVRTreeMap.java
h2/src/test/org/h2/test/store/MVRTreeMap.java
+30
-19
SequenceMap.java
h2/src/test/org/h2/test/store/SequenceMap.java
+9
-1
SpatialKey.java
h2/src/test/org/h2/test/store/SpatialKey.java
+30
-2
SpatialType.java
h2/src/test/org/h2/test/store/SpatialType.java
+46
-7
TestConcurrent.java
h2/src/test/org/h2/test/store/TestConcurrent.java
+134
-0
TestDataUtils.java
h2/src/test/org/h2/test/store/TestDataUtils.java
+20
-0
TestMVRTree.java
h2/src/test/org/h2/test/store/TestMVRTree.java
+14
-9
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+94
-10
FilePathCache.java
h2/src/tools/org/h2/dev/store/FilePathCache.java
+4
-0
CacheLIRS.java
h2/src/tools/org/h2/dev/store/btree/CacheLIRS.java
+4
-1
Chunk.java
h2/src/tools/org/h2/dev/store/btree/Chunk.java
+21
-28
Cursor.java
h2/src/tools/org/h2/dev/store/btree/Cursor.java
+33
-0
DataUtils.java
h2/src/tools/org/h2/dev/store/btree/DataUtils.java
+76
-1
MVMap.java
h2/src/tools/org/h2/dev/store/btree/MVMap.java
+127
-84
MVStore.java
h2/src/tools/org/h2/dev/store/btree/MVStore.java
+88
-45
MapFactory.java
h2/src/tools/org/h2/dev/store/btree/MapFactory.java
+3
-3
Page.java
h2/src/tools/org/h2/dev/store/btree/Page.java
+129
-50
没有找到文件。
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
2ceb5ec6
...
...
@@ -104,6 +104,7 @@ import org.h2.test.server.TestNestedLoop;
import
org.h2.test.server.TestWeb
;
import
org.h2.test.server.TestInit
;
import
org.h2.test.store.TestCacheLIRS
;
import
org.h2.test.store.TestConcurrent
;
import
org.h2.test.store.TestDataUtils
;
import
org.h2.test.store.TestMVStore
;
import
org.h2.test.store.TestMVRTree
;
...
...
@@ -664,11 +665,12 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
}
private
void
testUnit
()
{
// store
new
TestMVStore
().
runTest
(
this
);
// mv store
new
TestCacheLIRS
().
runTest
(
this
);
new
TestConcurrent
().
runTest
(
this
);
new
TestDataUtils
().
runTest
(
this
);
new
TestMVRTree
().
runTest
(
this
);
new
TestMVStore
().
runTest
(
this
);
// unit
new
TestAutoReconnect
().
runTest
(
this
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/MVRTreeMap.java
浏览文件 @
2ceb5ec6
...
...
@@ -35,9 +35,6 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
@SuppressWarnings
(
"unchecked"
)
public
V
get
(
Object
key
)
{
checkOpen
();
if
(
root
==
null
)
{
return
null
;
}
return
(
V
)
get
(
root
,
key
);
}
...
...
@@ -73,13 +70,10 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
}
protected
Page
getPage
(
K
key
)
{
if
(
root
==
null
)
{
return
null
;
}
return
getPage
(
root
,
key
);
}
pr
otected
Page
getPage
(
Page
p
,
Object
key
)
{
pr
ivate
Page
getPage
(
Page
p
,
Object
key
)
{
if
(!
p
.
isLeaf
())
{
for
(
int
i
=
0
;
i
<
p
.
getKeyCount
();
i
++)
{
if
(
contains
(
p
,
i
,
key
))
{
...
...
@@ -155,26 +149,26 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
return
(
V
)
putOrAdd
(
key
,
value
,
false
);
}
/**
* Add a given key-value pair. The key should not exist (if it exists, the
* result is undefined).
*
* @param key the key
* @param value the value
*/
public
void
add
(
K
key
,
V
value
)
{
putOrAdd
(
key
,
value
,
true
);
}
p
ublic
Object
putOrAdd
(
K
key
,
V
value
,
boolean
alwaysAdd
)
{
p
rivate
Object
putOrAdd
(
K
key
,
V
value
,
boolean
alwaysAdd
)
{
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
root
;
Page
p
=
root
.
copyOnWrite
(
writeVersion
)
;
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
(
alwaysAdd
||
get
(
key
)
==
null
)
{
if
(
p
.
getKeyCount
()
>
store
.
getMaxPageSize
())
{
// only possible if this is the root, else we would have split earlier
// (this requires maxPageSize is fixed)
p
=
p
.
copyOnWrite
(
writeVersion
);
long
totalCount
=
p
.
getTotalCount
();
Page
split
=
split
(
p
,
writeVersion
);
Object
[]
keys
=
{
getBounds
(
p
),
getBounds
(
split
)
};
...
...
@@ -195,7 +189,16 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
return
result
;
}
protected
Object
set
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
/**
* Update the value for the given key. The key must exist.
*
* @param p the page
* @param writeVersion the write version
* @param key the key
* @param value the value
* @return the old value
*/
private
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
))
{
...
...
@@ -217,7 +220,7 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
return
null
;
}
pr
otected
void
add
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
pr
ivate
void
add
(
Page
p
,
long
writeVersion
,
Object
key
,
Object
value
)
{
if
(
p
.
isLeaf
())
{
p
.
insertLeaf
(
p
.
getKeyCount
(),
key
,
value
);
return
;
...
...
@@ -379,6 +382,13 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
source
.
remove
(
sourceIndex
);
}
/**
* Add all node keys (including internal bounds) to the given list.
* This is mainly used to visualize the internal splits.
*
* @param list the list
* @param p the root page
*/
@SuppressWarnings
(
"unchecked"
)
public
void
addNodeKeys
(
ArrayList
<
K
>
list
,
Page
p
)
{
if
(
p
!=
null
&&
!
p
.
isLeaf
())
{
...
...
@@ -395,6 +405,7 @@ public class MVRTreeMap<K, V> extends MVMap<K, V> {
* @param p the current page
* @param cursor the cursor
* @param key the key
* @return the cursor position
*/
protected
CursorPos
min
(
Page
p
,
Cursor
<
K
,
V
>
cursor
,
Object
key
)
{
if
(
p
==
null
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/SequenceMap.java
浏览文件 @
2ceb5ec6
...
...
@@ -21,7 +21,15 @@ import org.h2.dev.store.btree.DataType;
*/
public
class
SequenceMap
<
K
,
V
>
extends
MVMap
<
K
,
V
>
{
int
min
=
1
,
max
=
10
;
/**
* The minimum value.
*/
int
min
=
1
;
/**
* The maximum value.
*/
int
max
=
10
;
SequenceMap
(
MVStore
store
,
int
id
,
String
name
,
DataType
keyType
,
DataType
valueType
,
long
createVersion
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/SpatialKey.java
浏览文件 @
2ceb5ec6
...
...
@@ -14,8 +14,8 @@ import java.util.Arrays;
*/
public
class
SpatialKey
{
p
ublic
long
id
;
private
float
[]
minMax
;
p
rivate
final
long
id
;
private
f
inal
f
loat
[]
minMax
;
/**
* Create a new key.
...
...
@@ -28,22 +28,50 @@ public class SpatialKey {
this
.
minMax
=
minMax
;
}
/**
* Get the minimum value for the given dimension.
*
* @param dim the dimension
* @return the value
*/
public
float
min
(
int
dim
)
{
return
minMax
[
dim
+
dim
];
}
/**
* Set the minimum value for the given dimension.
*
* @param dim the dimension
* @param x the value
*/
public
void
setMin
(
int
dim
,
float
x
)
{
minMax
[
dim
+
dim
]
=
x
;
}
/**
* Get the maximum value for the given dimension.
*
* @param dim the dimension
* @return the value
*/
public
float
max
(
int
dim
)
{
return
minMax
[
dim
+
dim
+
1
];
}
/**
* Set the maximum value for the given dimension.
*
* @param dim the dimension
* @param x the value
*/
public
void
setMax
(
int
dim
,
float
x
)
{
minMax
[
dim
+
dim
+
1
]
=
x
;
}
public
long
getId
()
{
return
id
;
}
public
String
toString
()
{
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
id
).
append
(
": ("
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/SpatialType.java
浏览文件 @
2ceb5ec6
...
...
@@ -27,20 +27,33 @@ public class SpatialType implements DataType {
this
.
dimensions
=
dimensions
;
}
/**
* Read a value from a string.
*
* @param s the string
* @return the value
*/
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
;
long
la
=
((
SpatialKey
)
a
).
getId
()
;
long
lb
=
((
SpatialKey
)
b
).
getId
()
;
return
la
<
lb
?
-
1
:
la
>
lb
?
1
:
0
;
}
/**
* Check whether two spatial values are equal.
*
* @param a the first value
* @param b the second value
* @return true if they are equal
*/
public
boolean
equals
(
Object
a
,
Object
b
)
{
long
la
=
((
SpatialKey
)
a
).
id
;
long
lb
=
((
SpatialKey
)
b
).
id
;
long
la
=
((
SpatialKey
)
a
).
getId
()
;
long
lb
=
((
SpatialKey
)
b
).
getId
()
;
return
la
==
lb
;
}
...
...
@@ -70,7 +83,7 @@ public class SpatialType implements DataType {
buff
.
putFloat
(
k
.
max
(
i
));
}
}
DataUtils
.
writeVarLong
(
buff
,
k
.
id
);
DataUtils
.
writeVarLong
(
buff
,
k
.
getId
()
);
}
@Override
...
...
@@ -97,6 +110,13 @@ public class SpatialType implements DataType {
return
"s"
+
dimensions
;
}
/**
* Check whether the two objects overlap.
*
* @param objA the first object
* @param objB the second object
* @return true if they overlap
*/
public
boolean
isOverlap
(
Object
objA
,
Object
objB
)
{
SpatialKey
a
=
(
SpatialKey
)
objA
;
SpatialKey
b
=
(
SpatialKey
)
objB
;
...
...
@@ -108,6 +128,12 @@ public class SpatialType implements DataType {
return
true
;
}
/**
* Increase the bounds in the given spatial object.
*
* @param bounds the bounds (may be modified)
* @param add the value
*/
public
void
increaseBounds
(
Object
bounds
,
Object
add
)
{
SpatialKey
b
=
(
SpatialKey
)
bounds
;
SpatialKey
a
=
(
SpatialKey
)
add
;
...
...
@@ -144,7 +170,14 @@ public class SpatialType implements DataType {
return
areaNew
-
areaOld
;
}
public
float
getCombinedArea
(
Object
objA
,
Object
objB
)
{
/**
* Get the combined area of both objects.
*
* @param objA the first object
* @param objB the second object
* @return the area
*/
float
getCombinedArea
(
Object
objA
,
Object
objB
)
{
SpatialKey
a
=
(
SpatialKey
)
objA
;
SpatialKey
b
=
(
SpatialKey
)
objB
;
float
area
=
1
;
...
...
@@ -193,7 +226,13 @@ public class SpatialType implements DataType {
return
true
;
}
public
Object
createBoundingBox
(
Object
objA
)
{
/**
* Create a bounding box starting with the given object.
*
* @param objA the object
* @return the bounding box
*/
Object
createBoundingBox
(
Object
objA
)
{
float
[]
minMax
=
new
float
[
dimensions
*
2
];
SpatialKey
a
=
(
SpatialKey
)
objA
;
for
(
int
i
=
0
;
i
<
dimensions
;
i
++)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestConcurrent.java
0 → 100644
浏览文件 @
2ceb5ec6
/*
* 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.util.Map
;
import
java.util.Random
;
import
org.h2.dev.store.btree.MVMap
;
import
org.h2.dev.store.btree.MVStore
;
import
org.h2.test.TestBase
;
import
org.h2.util.Task
;
/**
* Tests concurrently accessing a tree map store.
*/
public
class
TestConcurrent
extends
TestMVStore
{
/**
* Run just this test.
*
* @param a ignored
*/
public
static
void
main
(
String
...
a
)
throws
Exception
{
TestBase
.
createCaller
().
init
().
test
();
}
public
void
test
()
throws
InterruptedException
{
testConcurrentWrite
();
testConcurrentRead
();
}
/**
* Test what happens on concurrent write. Concurrent write may corrupt the
* map, so that keys and values may become null.
*/
private
void
testConcurrentWrite
()
throws
InterruptedException
{
final
MVStore
s
=
openStore
(
null
);
final
MVMap
<
Integer
,
Integer
>
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
Integer
.
class
);
final
int
size
=
20
;
final
Random
rand
=
new
Random
(
1
);
Task
task
=
new
Task
()
{
public
void
call
()
throws
Exception
{
while
(!
stop
)
{
try
{
if
(
rand
.
nextBoolean
())
{
m
.
put
(
rand
.
nextInt
(
size
),
1
);
}
else
{
m
.
remove
(
rand
.
nextInt
(
size
));
}
m
.
get
(
rand
.
nextInt
(
size
));
}
catch
(
NullPointerException
e
)
{
// ignore
}
}
}
};
task
.
execute
();
Thread
.
sleep
(
1
);
for
(
int
j
=
0
;
j
<
10
;
j
++)
{
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
try
{
if
(
rand
.
nextBoolean
())
{
m
.
put
(
rand
.
nextInt
(
size
),
2
);
}
else
{
m
.
remove
(
rand
.
nextInt
(
size
));
}
m
.
get
(
rand
.
nextInt
(
size
));
}
catch
(
NullPointerException
e
)
{
// ignore
}
}
s
.
incrementVersion
();
Thread
.
sleep
(
1
);
}
task
.
get
();
// verify the structure is still somewhat usable
for
(
int
x
:
m
.
keySet
())
{
try
{
m
.
get
(
x
);
}
catch
(
NullPointerException
e
)
{
// ignore
}
}
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
try
{
m
.
get
(
i
);
}
catch
(
NullPointerException
e
)
{
// ignore
}
}
s
.
close
();
}
private
void
testConcurrentRead
()
throws
InterruptedException
{
final
MVStore
s
=
openStore
(
null
);
final
MVMap
<
Integer
,
Integer
>
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
Integer
.
class
);
final
int
size
=
3
;
int
x
=
(
int
)
s
.
getCurrentVersion
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
m
.
put
(
i
,
x
);
}
s
.
incrementVersion
();
Task
task
=
new
Task
()
{
public
void
call
()
throws
Exception
{
while
(!
stop
)
{
long
v
=
s
.
getCurrentVersion
()
-
1
;
Map
<
Integer
,
Integer
>
old
=
m
.
openVersion
(
v
);
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Integer
x
=
old
.
get
(
i
);
if
(
x
==
null
||
(
int
)
v
!=
x
)
{
Map
<
Integer
,
Integer
>
old2
=
m
.
openVersion
(
v
);
throw
new
AssertionError
(
x
+
"<>"
+
v
+
" at "
+
i
+
" "
+
old2
);
}
}
}
}
};
task
.
execute
();
Thread
.
sleep
(
1
);
for
(
int
j
=
0
;
j
<
100
;
j
++)
{
x
=
(
int
)
s
.
getCurrentVersion
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
m
.
put
(
i
,
x
);
}
s
.
incrementVersion
();
Thread
.
sleep
(
1
);
}
task
.
get
();
s
.
close
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestDataUtils.java
浏览文件 @
2ceb5ec6
...
...
@@ -6,6 +6,7 @@
package
org
.
h2
.
test
.
store
;
import
java.nio.ByteBuffer
;
import
java.util.HashMap
;
import
org.h2.dev.store.btree.DataUtils
;
import
org.h2.test.TestBase
;
...
...
@@ -24,12 +25,31 @@ public class TestDataUtils extends TestBase {
}
public
void
test
()
throws
Exception
{
testMap
();
testVarIntVarLong
();
testCheckValue
();
testPagePos
();
testEncodeLength
();
}
private
void
testMap
()
{
StringBuilder
buff
=
new
StringBuilder
();
DataUtils
.
appendMap
(
buff
,
""
,
""
);
DataUtils
.
appendMap
(
buff
,
"a"
,
"1"
);
DataUtils
.
appendMap
(
buff
,
"b"
,
","
);
DataUtils
.
appendMap
(
buff
,
"c"
,
"1,2"
);
DataUtils
.
appendMap
(
buff
,
"d"
,
"\"test\""
);
assertEquals
(
":,a:1,b:\",\",c:\"1,2\",d:\"\\\"test\\\"\""
,
buff
.
toString
());
HashMap
<
String
,
String
>
m
=
DataUtils
.
parseMap
(
buff
.
toString
());
assertEquals
(
5
,
m
.
size
());
assertEquals
(
""
,
m
.
get
(
""
));
assertEquals
(
"1"
,
m
.
get
(
"a"
));
assertEquals
(
","
,
m
.
get
(
"b"
));
assertEquals
(
"1,2"
,
m
.
get
(
"c"
));
assertEquals
(
"\"test\""
,
m
.
get
(
"d"
));
}
private
void
testVarIntVarLong
()
{
ByteBuffer
buff
=
ByteBuffer
.
allocate
(
100
);
for
(
long
x
=
0
;
x
<
1000
;
x
++)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestMVRTree.java
浏览文件 @
2ceb5ec6
/*
* 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.awt.AlphaComposite
;
...
...
@@ -34,14 +39,14 @@ public class TestMVRTree extends TestMVStore {
}
public
void
test
()
{
test
Rtree
Many
();
test
Rt
ree
();
testRandom
Rtree
();
testMany
();
test
T
ree
();
testRandom
();
testCustomMapType
();
}
private
void
test
Rtree
Many
()
{
String
fileName
=
getBaseDir
()
+
"/test
Rtree
.h3"
;
private
void
testMany
()
{
String
fileName
=
getBaseDir
()
+
"/test
Many
.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
;
s
=
openStore
(
fileName
);
...
...
@@ -103,8 +108,8 @@ public class TestMVRTree extends TestMVStore {
// System.out.println("remove: " + (System.currentTimeMillis() - t));
}
private
void
test
Rt
ree
()
{
String
fileName
=
getBaseDir
()
+
"/test
Rt
ree.h3"
;
private
void
test
T
ree
()
{
String
fileName
=
getBaseDir
()
+
"/test
T
ree.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
;
s
=
openStore
(
fileName
);
...
...
@@ -195,8 +200,8 @@ public class TestMVRTree extends TestMVStore {
return
rect
;
}
private
void
testRandom
Rtree
()
{
String
fileName
=
getBaseDir
()
+
"/testR
treeR
andom.h3"
;
private
void
testRandom
()
{
String
fileName
=
getBaseDir
()
+
"/testRandom.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
MVRTreeMap
<
SpatialKey
,
String
>
m
=
s
.
openMap
(
"data"
,
"r"
,
"s2"
,
""
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
2ceb5ec6
...
...
@@ -7,6 +7,7 @@ package org.h2.test.store;
import
java.util.ArrayList
;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Random
;
import
java.util.TreeMap
;
import
org.h2.dev.store.btree.MVMap
;
...
...
@@ -30,8 +31,10 @@ public class TestMVStore extends TestBase {
TestBase
.
createCaller
().
init
().
test
();
}
public
void
test
()
{
public
void
test
()
throws
InterruptedException
{
testExample
();
testIterateOverChanges
();
testOpenStoreCloseLoop
();
testVersion
();
testTruncateFile
();
testFastDelete
();
...
...
@@ -49,31 +52,105 @@ public class TestMVStore extends TestBase {
testSimple
();
}
private
void
testExample
()
{
String
fileName
=
getBaseDir
()
+
"/testOpenClose.h3"
;
FileUtils
.
delete
(
fileName
);
// open the store (in-memory if fileName is null)
MVStore
s
=
MVStore
.
open
(
fileName
);
// create/get the map "data"
// the String.class, String.class will be optional later
MVMap
<
String
,
String
>
map
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
// add some data
map
.
put
(
"1"
,
"Hello"
);
map
.
put
(
"2"
,
"World"
);
// get the current version, for later use
long
oldVersion
=
s
.
getCurrentVersion
();
// from now on, the old version is read-only
s
.
incrementVersion
();
// more changes, in the new version
// changes can be rolled back if required
// changes always go into 'head' (the newest version)
map
.
put
(
"1"
,
"Hi"
);
map
.
remove
(
"2"
);
// access the old data (before incrementVersion)
MVMap
<
String
,
String
>
oldMap
=
map
.
openVersion
(
oldVersion
);
// store the newest data to disk
s
.
store
();
// print the old version (can be done
// concurrently with further modifications)
// this will print Hello World
// System.out.println(oldMap.get("1"));
// System.out.println(oldMap.get("2"));
oldMap
.
close
();
// print the newest version ("Hi")
// System.out.println(map.get("1"));
// close the store - this doesn't write to disk
s
.
close
();
}
private
void
testOpenStoreCloseLoop
()
{
String
fileName
=
getBaseDir
()
+
"/testOpenClose.h3"
;
FileUtils
.
delete
(
fileName
);
for
(
int
k
=
0
;
k
<
1
;
k
++)
{
// long t = System.currentTimeMillis();
for
(
int
j
=
0
;
j
<
3
;
j
++)
{
MVStore
s
=
openStore
(
fileName
);
Map
<
String
,
Integer
>
m
=
s
.
openMap
(
"data"
,
String
.
class
,
Integer
.
class
);
for
(
int
i
=
0
;
i
<
3
;
i
++)
{
Integer
x
=
m
.
get
(
"value"
);
m
.
put
(
"value"
,
x
==
null
?
0
:
x
+
1
);
s
.
store
();
}
s
.
close
();
}
// System.out.println("open/close: " + (System.currentTimeMillis() - t));
// System.out.println("size: " + FileUtils.size(fileName));
}
}
private
void
testIterateOverChanges
()
{
String
fileName
=
getBaseDir
()
+
"/test
Version
.h3"
;
String
fileName
=
getBaseDir
()
+
"/test
Iterate
.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
s
.
setMaxPageSize
(
6
);
MVMap
<
Integer
,
String
>
m
=
s
.
openMap
(
"data"
,
Integer
.
class
,
String
.
class
);
for
(
int
i
=
0
;
i
<
6
0
;
i
++)
{
for
(
int
i
=
0
;
i
<
10
0
;
i
++)
{
m
.
put
(
i
,
"Hi"
);
}
s
.
commit
();
s
.
incrementVersion
();
s
.
store
();
for
(
int
i
=
20
;
i
<
40
;
i
++)
{
assertEquals
(
"Hi"
,
m
.
put
(
i
,
"Hello"
));
}
s
.
commit
();
s
.
incrementVersion
();
for
(
int
i
=
10
;
i
<
15
;
i
++)
{
m
.
put
(
i
,
"Hallo"
);
}
m
.
put
(
50
,
"Hallo"
);
for
(
int
i
=
90
;
i
<
100
;
i
++)
{
assertEquals
(
"Hi"
,
m
.
remove
(
i
));
}
assertEquals
(
null
,
m
.
put
(
100
,
"Hallo"
));
Iterator
<
Integer
>
it
=
m
.
changeIterator
(
s
.
getCurrentVersion
());
ArrayList
<
Integer
>
list
=
New
.
arrayList
();
while
(
it
.
hasNext
())
{
list
.
add
(
it
.
next
());
}
assertEquals
(
"[9, 10, 11, 12, 13, 14, 48, 49, 50]"
,
list
.
toString
());
assertEquals
(
"[9, 10, 11, 12, 13, 14, 48, 49, 50
, 87, 88, 89, 100
]"
,
list
.
toString
());
}
private
void
testVersion
()
{
...
...
@@ -85,13 +162,14 @@ public class TestMVStore extends TestBase {
s
=
openStore
(
fileName
);
m
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
long
first
=
s
.
getCurrentVersion
();
s
.
incrementVersion
();
m
.
put
(
"1"
,
"Hello"
);
m
.
put
(
"2"
,
"World"
);
for
(
int
i
=
10
;
i
<
20
;
i
++)
{
m
.
put
(
""
+
i
,
"data"
);
}
s
.
commit
();
long
old
=
s
.
getCurrentVersion
();
s
.
incrementVersion
();
m
.
put
(
"1"
,
"Hallo"
);
m
.
put
(
"2"
,
"Welt"
);
MVMap
<
String
,
String
>
mFirst
;
...
...
@@ -192,7 +270,7 @@ public class TestMVStore extends TestBase {
assertTrue
(
s
.
hasUnsavedChanges
());
MVMap
<
String
,
String
>
m0
=
s
.
openMap
(
"data0"
,
String
.
class
,
String
.
class
);
m
.
put
(
"1"
,
"Hello"
);
assertEquals
(
1
,
s
.
commit
());
assertEquals
(
1
,
s
.
incrementVersion
());
s
.
rollbackTo
(
1
);
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
long
v2
=
s
.
store
();
...
...
@@ -235,7 +313,7 @@ public class TestMVStore extends TestBase {
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
assertFalse
(
m0
.
isReadOnly
());
m
.
put
(
"1"
,
"Hallo"
);
s
.
commit
();
s
.
incrementVersion
();
assertEquals
(
4
,
s
.
getCurrentVersion
());
long
v4
=
s
.
store
();
assertEquals
(
4
,
v4
);
...
...
@@ -282,7 +360,7 @@ public class TestMVStore extends TestBase {
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
m2
.
put
(
""
+
i
,
"Test"
);
}
long
v1
=
s
.
commit
();
long
v1
=
s
.
incrementVersion
();
assertEquals
(
1
,
v1
);
assertEquals
(
2
,
s
.
getCurrentVersion
());
MVMap
<
String
,
String
>
m1
=
s
.
openMap
(
"data1"
,
String
.
class
,
String
.
class
);
...
...
@@ -667,6 +745,12 @@ public class TestMVStore extends TestBase {
s
.
close
();
}
/**
* Open a store for the given file name, using a small page size.
*
* @param fileName the file name (null for in-memory)
* @return the store
*/
protected
static
MVStore
openStore
(
String
fileName
)
{
MVStore
store
=
MVStore
.
open
(
fileName
,
new
TestMapFactory
());
store
.
setMaxPageSize
(
10
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/FilePathCache.java
浏览文件 @
2ceb5ec6
...
...
@@ -47,6 +47,10 @@ public class FilePathCache extends FilePathWrapper {
this
.
size
=
base
.
size
();
}
protected
void
implCloseChannel
()
throws
IOException
{
base
.
close
();
}
public
FileChannel
position
(
long
newPosition
)
throws
IOException
{
this
.
pos
=
newPosition
;
return
this
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/CacheLIRS.java
浏览文件 @
2ceb5ec6
...
...
@@ -15,7 +15,7 @@ import java.util.Map;
import
java.util.Set
;
/**
* A scan resist
e
nt cache. It is meant to cache objects that are relatively
* A scan resist
a
nt cache. It is meant to cache objects that are relatively
* costly to acquire, for example file content.
* <p>
* This implementation is not multi-threading save. Null keys or null values are
...
...
@@ -237,6 +237,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
*
* @param key the key (may not be null)
* @param value the value (may not be null)
* @return the old value, or null if there is no resident entry
*/
public
V
put
(
K
key
,
V
value
)
{
return
put
(
key
,
value
,
averageMemory
);
...
...
@@ -250,6 +251,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
* @param key the key (may not be null)
* @param value the value (may not be null)
* @param memory the memory used for the given entry
* @return the old value, or null if there is no resident entry
*/
public
V
put
(
K
key
,
V
value
,
int
memory
)
{
if
(
value
==
null
)
{
...
...
@@ -484,6 +486,7 @@ public class CacheLIRS<K, V> extends AbstractMap<K, V> implements Map<K, V> {
/**
* Check whether there is a resident entry for the given key.
*
* @param key the key (may not be null)
* @return true if there is a resident entry
*/
public
boolean
containsKey
(
Object
key
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/Chunk.java
浏览文件 @
2ceb5ec6
...
...
@@ -6,9 +6,7 @@
*/
package
org
.
h2
.
dev
.
store
.
btree
;
import
java.io.ByteArrayInputStream
;
import
java.io.IOException
;
import
java.util.Properties
;
import
java.util.HashMap
;
/**
* A chunk of data, containing one or multiple pages.
...
...
@@ -23,7 +21,7 @@ import java.util.Properties;
* 8 bytes: metaRootPos
* [ Page ] *
*/
class
Chunk
{
public
class
Chunk
{
/**
* The chunk id.
...
...
@@ -65,7 +63,7 @@ class Chunk {
*/
long
version
;
Chunk
(
int
id
)
{
public
Chunk
(
int
id
)
{
this
.
id
=
id
;
}
...
...
@@ -75,22 +73,17 @@ class Chunk {
* @param s the string
* @return the block
*/
static
Chunk
fromString
(
String
s
)
{
Properties
prop
=
new
Properties
();
try
{
prop
.
load
(
new
ByteArrayInputStream
(
s
.
getBytes
(
"UTF-8"
)));
int
id
=
Integer
.
parseInt
(
prop
.
get
(
"id"
).
toString
());
public
static
Chunk
fromString
(
String
s
)
{
HashMap
<
String
,
String
>
map
=
DataUtils
.
parseMap
(
s
);
int
id
=
Integer
.
parseInt
(
map
.
get
(
"id"
));
Chunk
c
=
new
Chunk
(
id
);
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
.
metaRootPos
=
Long
.
parseLong
(
prop
.
get
(
"metaRoot"
).
toString
(
));
c
.
version
=
Long
.
parseLong
(
prop
.
get
(
"version"
).
toString
(
));
c
.
start
=
Long
.
parseLong
(
map
.
get
(
"start"
));
c
.
length
=
Long
.
parseLong
(
map
.
get
(
"length"
));
c
.
entryCount
=
Integer
.
parseInt
(
map
.
get
(
"entryCount"
));
c
.
liveCount
=
Integer
.
parseInt
(
map
.
get
(
"liveCount"
));
c
.
metaRootPos
=
Long
.
parseLong
(
map
.
get
(
"metaRoot"
));
c
.
version
=
Long
.
parseLong
(
map
.
get
(
"version"
));
return
c
;
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
public
int
getFillRate
()
{
...
...
@@ -107,13 +100,13 @@ class Chunk {
public
String
toString
()
{
return
"id:"
+
id
+
"\n
"
+
"start:"
+
start
+
"\n
"
+
"length:"
+
length
+
"\n
"
+
"entryCount:"
+
entryCount
+
"\n
"
+
"liveCount:"
+
liveCount
+
"\n
"
+
"metaRoot:"
+
metaRootPos
+
"\n
"
+
"version:"
+
version
+
"\n"
;
"id:"
+
id
+
",
"
+
"start:"
+
start
+
",
"
+
"length:"
+
length
+
",
"
+
"entryCount:"
+
entryCount
+
",
"
+
"liveCount:"
+
liveCount
+
",
"
+
"metaRoot:"
+
metaRootPos
+
",
"
+
"version:"
+
version
;
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/Cursor.java
浏览文件 @
2ceb5ec6
...
...
@@ -26,6 +26,12 @@ public class Cursor<K, V> implements Iterator<K> {
this
.
map
=
map
;
}
/**
* Fetch the first key.
*
* @param root the root page
* @param from the key, or null
*/
void
start
(
Page
root
,
K
from
)
{
currentPos
=
min
(
root
,
from
);
if
(
currentPos
!=
null
)
{
...
...
@@ -41,6 +47,9 @@ public class Cursor<K, V> implements Iterator<K> {
return
c
==
null
?
null
:
c
;
}
/**
* Fetch the next key.
*/
@SuppressWarnings
(
"unchecked"
)
protected
void
fetchNext
()
{
current
=
(
K
)
map
.
nextKey
(
currentPos
,
this
);
...
...
@@ -54,19 +63,43 @@ public class Cursor<K, V> implements Iterator<K> {
throw
new
UnsupportedOperationException
();
}
/**
* Add a cursor position to the stack.
*
* @param p the cursor position
*/
public
void
push
(
CursorPos
p
)
{
parents
.
add
(
p
);
}
/**
* Remove the latest cursor position from the stack and return it.
*
* @return the cursor position, or null if none
*/
public
CursorPos
pop
()
{
int
size
=
parents
.
size
();
return
size
==
0
?
null
:
parents
.
remove
(
size
-
1
);
}
/**
* Visit the first key that is greater or equal the given key.
*
* @param p the page
* @param from the key, or null
* @return the cursor position
*/
public
CursorPos
min
(
Page
p
,
K
from
)
{
return
map
.
min
(
p
,
this
,
from
);
}
/**
* Visit the first key within this child page.
*
* @param p the page
* @param childIndex the child index
* @return the cursor position
*/
public
CursorPos
visitChild
(
Page
p
,
int
childIndex
)
{
p
=
p
.
getChildPage
(
childIndex
);
currentPos
=
min
(
p
,
null
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/DataUtils.java
浏览文件 @
2ceb5ec6
...
...
@@ -9,6 +9,8 @@ package org.h2.dev.store.btree;
import
java.io.IOException
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.util.HashMap
;
import
org.h2.util.New
;
/**
* Utility methods
...
...
@@ -195,7 +197,14 @@ public class DataUtils {
}
}
static
void
readFully
(
FileChannel
file
,
ByteBuffer
buff
)
throws
IOException
{
/**
* Read from a file channel until the target buffer is full, or end-of-file
* has been reached.
*
* @param file the file channel
* @param buff the target buffer
*/
public
static
void
readFully
(
FileChannel
file
,
ByteBuffer
buff
)
throws
IOException
{
do
{
int
len
=
file
.
read
(
buff
);
if
(
len
<
0
)
{
...
...
@@ -302,4 +311,70 @@ public class DataUtils {
return
(
short
)
((
x
>>
16
)
^
x
);
}
/**
* Append a key-value pair to the string buffer. Keys may not contain a
* colon. Values that contain a comma or a double quote are enclosed in
* double quotes, with special characters escaped using a backslash.
*
* @param buff the target buffer
* @param key the key
* @param value the value
*/
public
static
void
appendMap
(
StringBuilder
buff
,
String
key
,
Object
value
)
{
if
(
buff
.
length
()
>
0
)
{
buff
.
append
(
','
);
}
buff
.
append
(
key
).
append
(
':'
);
String
v
=
value
.
toString
();
if
(
v
.
indexOf
(
','
)
<
0
&&
v
.
indexOf
(
'\"'
)
<
0
)
{
buff
.
append
(
value
);
}
else
{
buff
.
append
(
'\"'
);
for
(
int
i
=
0
,
size
=
v
.
length
();
i
<
size
;
i
++)
{
char
c
=
v
.
charAt
(
i
);
if
(
c
==
'\"'
)
{
buff
.
append
(
'\\'
);
}
buff
.
append
(
c
);
}
buff
.
append
(
'\"'
);
}
}
/**
* Parse a key-value pair list.
*
* @param s the list
* @return the map
*/
public
static
HashMap
<
String
,
String
>
parseMap
(
String
s
)
{
HashMap
<
String
,
String
>
map
=
New
.
hashMap
();
for
(
int
i
=
0
,
size
=
s
.
length
();
i
<
size
;)
{
int
startKey
=
i
;
i
=
s
.
indexOf
(
':'
,
i
);
String
key
=
s
.
substring
(
startKey
,
i
++);
StringBuilder
buff
=
new
StringBuilder
();
while
(
i
<
size
)
{
char
c
=
s
.
charAt
(
i
++);
if
(
c
==
','
)
{
break
;
}
else
if
(
c
==
'\"'
)
{
while
(
i
<
size
)
{
c
=
s
.
charAt
(
i
++);
if
(
c
==
'\\'
)
{
i
++;
}
else
if
(
c
==
'\"'
)
{
break
;
}
buff
.
append
(
c
);
}
}
else
{
buff
.
append
(
c
);
}
}
map
.
put
(
key
,
buff
.
toString
());
}
return
map
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/MVMap.java
浏览文件 @
2ceb5ec6
差异被折叠。
点击展开。
h2/src/tools/org/h2/dev/store/btree/MVStore.java
浏览文件 @
2ceb5ec6
差异被折叠。
点击展开。
h2/src/tools/org/h2/dev/store/btree/MapFactory.java
浏览文件 @
2ceb5ec6
This diff is collapsed.
Click to expand it.
h2/src/tools/org/h2/dev/store/btree/Page.java
浏览文件 @
2ceb5ec6
...
...
@@ -15,18 +15,26 @@ import org.h2.compress.Compressor;
/**
* A page (a node or a leaf).
* <p>
* For b-tree nodes, the key at a given index is larger than the largest key of
the
* child at the same index.
* For b-tree nodes, the key at a given index is larger than the largest key of
*
the
child at the same index.
* <p>
* File format: page length (including length): int check value: short map id:
* varInt number of keys: varInt type: byte (0: leaf, 1: node; +2: compressed)
* compressed: bytes saved (varInt) keys leaf: values (one for each key) node:
* children (1 more than keys)
* File format:
* page length (including length): int
* check value: short
* map id: varInt
* number of keys: varInt
* type: byte (0: leaf, 1: node; +2: compressed)
* compressed: bytes saved (varInt)
* keys
* leaf: values (one for each key)
* node: children (1 more than keys)
*/
public
class
Page
{
private
static
final
int
SHARED_KEYS
=
1
,
SHARED_VALUES
=
2
,
SHARED_CHILDREN
=
4
,
SHARED_COUNTS
=
8
;
private
static
final
Object
[]
EMPTY_OBJECT_ARRAY
=
new
Object
[
0
];
private
final
MVMap
<?,
?>
map
;
private
final
long
version
;
private
long
pos
;
...
...
@@ -54,14 +62,32 @@ public class Page {
this
.
version
=
version
;
}
/**
* Create a new, empty page.
*
* @param map the map
* @param version the version
* @return the new page
*/
public
static
Page
createEmpty
(
MVMap
<?,
?>
map
,
long
version
)
{
return
create
(
map
,
version
,
0
,
EMPTY_OBJECT_ARRAY
,
EMPTY_OBJECT_ARRAY
,
null
,
null
,
null
,
0
,
0
);
}
/**
* Create a new page. The arrays are not cloned.
*
* @param map the map
* @param version the version
* @param keyCount the number of keys
* @param keys the keys
* @param values the values
* @param children the children
* @param childrenPages the children pages
* @param counts the children counts
* @param totalCount the total number of keys
* @param sharedFlags which arrays are shared
* @return the page
*/
public
static
Page
create
(
MVMap
<?,
?>
map
,
long
version
,
...
...
@@ -84,9 +110,10 @@ public class Page {
/**
* Read a page.
*
* @param file the file
* @param map the map
* @param filePos the position in the file
* @param pos the page position
* @param buff the source buffer
* @return the page
*/
static
Page
read
(
FileChannel
file
,
MVMap
<?,
?>
map
,
...
...
@@ -114,27 +141,61 @@ public class Page {
return
p
;
}
/**
* Get the key at the given index.
*
* @param index the index
* @return the key
*/
public
Object
getKey
(
int
index
)
{
return
keys
[
index
];
}
/**
* Get the child page at the given index.
*
* @param index the index
* @return the child page
*/
public
Page
getChildPage
(
int
index
)
{
Page
p
=
childrenPages
[
index
];
return
p
!=
null
?
p
:
map
.
readPage
(
children
[
index
]);
}
/**
* Get the position of the child page at the given index.
*
* @param index the index
* @return the position
*/
long
getChildPagePos
(
int
index
)
{
return
children
[
index
];
}
public
Object
getValue
(
int
x
)
{
return
values
[
x
];
/**
* Get the value at the given index.
*
* @param index the index
* @return the value
*/
public
Object
getValue
(
int
index
)
{
return
values
[
index
];
}
/**
* Get the number of keys in this page.
*
* @return the number of keys
*/
public
int
getKeyCount
()
{
return
keyCount
;
}
/**
* Check whether this is a leaf page.
*
* @return true if it is a leaf
*/
public
boolean
isLeaf
()
{
return
children
==
null
;
}
...
...
@@ -169,6 +230,13 @@ public class Page {
return
buff
.
toString
();
}
/**
* Create a copy of this page, if the write version is higher than the
* current version.
*
* @param writeVersion the write version
* @return a page with the given write version
*/
public
Page
copyOnWrite
(
long
writeVersion
)
{
if
(
version
==
writeVersion
)
{
return
this
;
...
...
@@ -198,8 +266,9 @@ public class Page {
if
(
x
<
0
||
x
>
high
)
{
x
=
(
low
+
high
)
>>>
1
;
}
Object
[]
k
=
keys
;
while
(
low
<=
high
)
{
int
compare
=
map
.
compare
(
key
,
k
eys
[
x
]);
int
compare
=
map
.
compare
(
key
,
k
[
x
]);
if
(
compare
>
0
)
{
low
=
x
+
1
;
}
else
if
(
compare
<
0
)
{
...
...
@@ -229,7 +298,13 @@ public class Page {
// return -(low + 1);
}
public
Page
split
(
int
at
)
{
/**
* Split the page. This modifies the current page.
*
* @param at the split index
* @return the page with the entries after the split index
*/
Page
split
(
int
at
)
{
return
isLeaf
()
?
splitLeaf
(
at
)
:
splitNode
(
at
);
}
...
...
@@ -299,6 +374,11 @@ public class Page {
return
newPage
;
}
/**
* Get the total number of key-value pairs, including child pages.
*
* @return the number of key-value pairs
*/
public
long
getTotalCount
()
{
if
(
MVStore
.
ASSERT
)
{
long
check
=
0
;
...
...
@@ -317,6 +397,12 @@ public class Page {
return
totalCount
;
}
/**
* Replace the child page.
*
* @param index the index
* @param c the new child page
*/
public
void
setChild
(
int
index
,
Page
c
)
{
if
(
c
!=
childrenPages
[
index
]
||
c
.
getPos
()
!=
children
[
index
])
{
if
((
sharedFlags
&
SHARED_CHILDREN
)
!=
0
)
{
...
...
@@ -338,6 +424,12 @@ public class Page {
}
}
/**
* Replace the key.
*
* @param index the index
* @param key the new key
*/
public
void
setKey
(
int
index
,
Object
key
)
{
if
((
sharedFlags
&
SHARED_KEYS
)
!=
0
)
{
keys
=
Arrays
.
copyOf
(
keys
,
keys
.
length
);
...
...
@@ -346,6 +438,13 @@ public class Page {
keys
[
index
]
=
key
;
}
/**
* Replace the value.
*
* @param index the index
* @param value the new value
* @return the old value
*/
public
Object
setValue
(
int
index
,
Object
value
)
{
Object
old
=
values
[
index
];
if
((
sharedFlags
&
SHARED_VALUES
)
!=
0
)
{
...
...
@@ -379,6 +478,13 @@ public class Page {
map
.
getStore
().
removePage
(
pos
);
}
/**
* Insert a key-value pair into this leaf.
*
* @param index the index
* @param key the key
* @param value the value
*/
public
void
insertLeaf
(
int
index
,
Object
key
,
Object
value
)
{
if
(((
sharedFlags
&
SHARED_KEYS
)
==
0
)
&&
keys
.
length
>
keyCount
+
1
)
{
if
(
index
<
keyCount
)
{
...
...
@@ -401,6 +507,13 @@ public class Page {
totalCount
++;
}
/**
* Insert a child into this node.
*
* @param index the index
* @param key the key
* @param childPage the child page
*/
public
void
insertNode
(
int
index
,
Object
key
,
Page
childPage
)
{
Object
[]
newKeys
=
new
Object
[
keyCount
+
1
];
...
...
@@ -428,6 +541,11 @@ public class Page {
totalCount
+=
childPage
.
getTotalCount
();
}
/**
* Remove the key and value (or child) at the given index.
*
* @param index the index
*/
public
void
remove
(
int
index
)
{
int
keyIndex
=
index
>=
keyCount
?
index
-
1
:
index
;
if
((
sharedFlags
&
SHARED_KEYS
)
==
0
&&
keys
.
length
>
keyCount
-
4
)
{
...
...
@@ -478,41 +596,6 @@ public class Page {
}
}
// public void remove(int index) {
// Object[] newKeys = new Object[keyCount - 1];
// int keyIndex = index >= keyCount ? index - 1 : index;
// DataUtils.copyExcept(keys, newKeys, keyCount, keyIndex);
// keys = newKeys;
// sharedFlags &= ~SHARED_KEYS;
// if (values != null) {
// Object[] newValues = new Object[keyCount - 1];
// DataUtils.copyExcept(values, newValues, keyCount, index);
// values = newValues;
// sharedFlags &= ~SHARED_VALUES;
// totalCount--;
// }
// keyCount--;
// if (children != null) {
// long countOffset = counts[index];
//
// long[] newChildren = new long[children.length - 1];
// DataUtils.copyExcept(children, newChildren, children.length, index);
// children = newChildren;
//
// Page[] newChildrenPages = new Page[childrenPages.length - 1];
// DataUtils.copyExcept(childrenPages, newChildrenPages, childrenPages.length, index);
// childrenPages = newChildrenPages;
//
// long[] newCounts = new long[counts.length - 1];
// DataUtils.copyExcept(counts, newCounts,
// counts.length, index);
// counts = newCounts;
//
// sharedFlags &= ~(SHARED_CHILDREN | SHARED_COUNTS);
// totalCount -= countOffset;
// }
// }
private
void
read
(
ByteBuffer
buff
,
int
chunkId
,
int
offset
,
int
maxLength
)
{
int
start
=
buff
.
position
();
int
pageLength
=
buff
.
getInt
();
...
...
@@ -701,10 +784,6 @@ public class Page {
return
count
;
}
public
long
getCounts
(
int
index
)
{
return
counts
[
index
];
}
long
getVersion
()
{
return
version
;
}
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论