Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
bc7a26f6
提交
bc7a26f6
authored
11月 07, 2012
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
A persistent multi-version map: add store version and settings.
上级
670d256c
显示空白字符变更
内嵌
并排
正在显示
3 个修改的文件
包含
157 行增加
和
42 行删除
+157
-42
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+44
-15
MVMap.java
h2/src/tools/org/h2/dev/store/btree/MVMap.java
+77
-11
MVStore.java
h2/src/tools/org/h2/dev/store/btree/MVStore.java
+36
-16
没有找到文件。
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
bc7a26f6
...
...
@@ -31,6 +31,7 @@ public class TestMVStore extends TestBase {
}
public
void
test
()
throws
InterruptedException
{
testSetting
();
testIterateOldVersion
();
testObjects
();
testExample
();
...
...
@@ -54,6 +55,33 @@ public class TestMVStore extends TestBase {
testSimple
();
}
private
void
testSetting
()
{
String
fileName
=
getBaseDir
()
+
"/testSetting.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
=
MVStore
.
open
(
fileName
);
assertEquals
(
0
,
s
.
getCurrentVersion
());
assertEquals
(
0
,
s
.
getStoreVersion
());
s
.
setStoreVersion
(
1
);
assertEquals
(
null
,
s
.
getSetting
(
"hello"
));
s
.
setSetting
(
"test"
,
"Hello"
);
assertEquals
(
"Hello"
,
s
.
getSetting
(
"test"
));
s
.
close
();
s
=
MVStore
.
open
(
fileName
);
assertEquals
(
0
,
s
.
getCurrentVersion
());
assertEquals
(
0
,
s
.
getStoreVersion
());
s
.
setStoreVersion
(
1
);
assertEquals
(
null
,
s
.
getSetting
(
"hello"
));
s
.
setSetting
(
"test"
,
"Hello"
);
assertEquals
(
"Hello"
,
s
.
getSetting
(
"test"
));
s
.
store
();
s
.
close
();
s
=
MVStore
.
open
(
fileName
);
assertEquals
(
1
,
s
.
getCurrentVersion
());
assertEquals
(
1
,
s
.
getStoreVersion
());
assertEquals
(
"Hello"
,
s
.
getSetting
(
"test"
));
s
.
close
();
}
private
void
testIterateOldVersion
()
{
MVStore
s
;
Map
<
Integer
,
Integer
>
map
;
...
...
@@ -184,7 +212,8 @@ public class TestMVStore extends TestBase {
for
(
int
i
=
20
;
i
<
40
;
i
++)
{
assertEquals
(
"Hi"
,
m
.
put
(
i
,
"Hello"
));
}
long
old
=
s
.
incrementVersion
();
long
old
=
s
.
getCurrentVersion
();
s
.
incrementVersion
();
for
(
int
i
=
10
;
i
<
15
;
i
++)
{
m
.
put
(
i
,
"Hallo"
);
}
...
...
@@ -313,7 +342,7 @@ public class TestMVStore extends TestBase {
assertEquals
(-
1
,
s
.
getRetainChunk
());
s
.
setRetainChunk
(
0
);
assertEquals
(
0
,
s
.
getRetainChunk
());
assertEquals
(
1
,
s
.
getCurrentVersion
());
assertEquals
(
0
,
s
.
getCurrentVersion
());
assertFalse
(
s
.
hasUnsavedChanges
());
MVMap
<
String
,
String
>
m
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
assertTrue
(
s
.
hasUnsavedChanges
());
...
...
@@ -324,12 +353,12 @@ public class TestMVStore extends TestBase {
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
long
v2
=
s
.
store
();
assertEquals
(
2
,
v2
);
assertEquals
(
3
,
s
.
getCurrentVersion
());
assertEquals
(
2
,
s
.
getCurrentVersion
());
assertFalse
(
s
.
hasUnsavedChanges
());
s
.
close
();
s
=
openStore
(
fileName
);
assertEquals
(
3
,
s
.
getCurrentVersion
());
assertEquals
(
2
,
s
.
getCurrentVersion
());
s
.
setRetainChunk
(
0
);
meta
=
s
.
getMetaMap
();
m
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
...
...
@@ -346,12 +375,12 @@ public class TestMVStore extends TestBase {
assertNull
(
meta
.
get
(
"map.data1"
));
assertNull
(
m0
.
get
(
"1"
));
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
s
.
store
(
);
assertEquals
(
2
,
s
.
store
()
);
s
.
close
();
s
=
openStore
(
fileName
);
s
.
setRetainChunk
(
0
);
assertEquals
(
3
,
s
.
getCurrentVersion
());
assertEquals
(
2
,
s
.
getCurrentVersion
());
meta
=
s
.
getMetaMap
();
assertTrue
(
meta
.
get
(
"map.data"
)
!=
null
);
assertTrue
(
meta
.
get
(
"map.data0"
)
!=
null
);
...
...
@@ -363,10 +392,10 @@ public class TestMVStore extends TestBase {
assertFalse
(
m0
.
isReadOnly
());
m
.
put
(
"1"
,
"Hallo"
);
s
.
incrementVersion
();
assertEquals
(
4
,
s
.
getCurrentVersion
());
assertEquals
(
3
,
s
.
getCurrentVersion
());
long
v4
=
s
.
store
();
assertEquals
(
4
,
v4
);
assertEquals
(
5
,
s
.
getCurrentVersion
());
assertEquals
(
4
,
s
.
getCurrentVersion
());
s
.
close
();
s
=
openStore
(
fileName
);
...
...
@@ -395,12 +424,12 @@ public class TestMVStore extends TestBase {
String
fileName
=
getBaseDir
()
+
"/testRollback.h3"
;
FileUtils
.
delete
(
fileName
);
MVStore
s
=
openStore
(
fileName
);
assertEquals
(
1
,
s
.
getCurrentVersion
());
assertEquals
(
0
,
s
.
getCurrentVersion
());
s
.
setMaxPageSize
(
5
);
MVMap
<
String
,
String
>
m
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
s
.
rollbackTo
(
0
);
assertTrue
(
m
.
isClosed
());
assertEquals
(
1
,
s
.
getCurrentVersion
());
assertEquals
(
0
,
s
.
getCurrentVersion
());
m
=
s
.
openMap
(
"data"
,
String
.
class
,
String
.
class
);
MVMap
<
String
,
String
>
m0
=
s
.
openMap
(
"data0"
,
String
.
class
,
String
.
class
);
...
...
@@ -411,7 +440,7 @@ public class TestMVStore extends TestBase {
}
long
v1
=
s
.
incrementVersion
();
assertEquals
(
1
,
v1
);
assertEquals
(
2
,
s
.
getCurrentVersion
());
assertEquals
(
1
,
s
.
getCurrentVersion
());
MVMap
<
String
,
String
>
m1
=
s
.
openMap
(
"data1"
,
String
.
class
,
String
.
class
);
assertEquals
(
"Test"
,
m2
.
get
(
"1"
));
m
.
put
(
"1"
,
"Hallo"
);
...
...
@@ -421,7 +450,7 @@ public class TestMVStore extends TestBase {
assertEquals
(
"Hallo"
,
m
.
get
(
"1"
));
assertEquals
(
"Hallo"
,
m1
.
get
(
"1"
));
s
.
rollbackTo
(
v1
);
assertEquals
(
2
,
s
.
getCurrentVersion
());
assertEquals
(
1
,
s
.
getCurrentVersion
());
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
assertEquals
(
"Test"
,
m2
.
get
(
""
+
i
));
}
...
...
@@ -443,11 +472,11 @@ public class TestMVStore extends TestBase {
data
.
put
(
"1"
,
"Hello"
);
data
.
put
(
"2"
,
"World"
);
s
.
store
();
assertEquals
(
"1/
1
///"
,
m
.
get
(
"map.data"
));
assertEquals
(
"1/
0
///"
,
m
.
get
(
"map.data"
));
assertTrue
(
m
.
containsKey
(
"chunk.1"
));
assertEquals
(
"Hello"
,
data
.
put
(
"1"
,
"Hallo"
));
s
.
store
();
assertEquals
(
"1/
1
///"
,
m
.
get
(
"map.data"
));
assertEquals
(
"1/
0
///"
,
m
.
get
(
"map.data"
));
assertTrue
(
m
.
get
(
"root.1"
).
length
()
>
0
);
assertTrue
(
m
.
containsKey
(
"chunk.1"
));
assertTrue
(
m
.
containsKey
(
"chunk.2"
));
...
...
@@ -577,7 +606,7 @@ public class TestMVStore extends TestBase {
m
.
put
(
j
+
i
,
"Hello "
+
j
);
}
s
.
store
();
//
s.compact(80);
s
.
compact
(
80
);
s
.
close
();
long
len
=
FileUtils
.
size
(
fileName
);
// System.out.println(" len:" + len);
...
...
h2/src/tools/org/h2/dev/store/btree/MVMap.java
浏览文件 @
bc7a26f6
...
...
@@ -13,6 +13,7 @@ import java.util.HashMap;
import
java.util.Iterator
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentMap
;
/**
* A stored map.
...
...
@@ -20,7 +21,8 @@ import java.util.Set;
* @param <K> the key class
* @param <V> the value class
*/
public
class
MVMap
<
K
,
V
>
extends
AbstractMap
<
K
,
V
>
{
public
class
MVMap
<
K
,
V
>
extends
AbstractMap
<
K
,
V
>
implements
ConcurrentMap
<
K
,
V
>
{
/**
* The store.
...
...
@@ -50,7 +52,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
this
.
keyType
=
keyType
;
this
.
valueType
=
valueType
;
this
.
createVersion
=
createVersion
;
this
.
root
=
Page
.
createEmpty
(
this
,
createVersion
);
this
.
root
=
Page
.
createEmpty
(
this
,
createVersion
-
1
);
}
/**
...
...
@@ -212,11 +214,13 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
* Remove all entries, and close the map.
*/
public
void
removeMap
()
{
if
(!
store
.
isMetaMap
(
this
))
{
checkWrite
();
root
.
removeAllRecursive
();
store
.
removeMap
(
name
);
close
();
}
}
/**
* Close the map, making it read only and release the memory.
...
...
@@ -248,6 +252,69 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
return
result
;
}
/**
* Add a key-value pair if it does not yet exist.
*
* @param key the key (may not be null)
* @return the old value if the key existed, or null otherwise
*/
public
synchronized
V
putIfAbsent
(
K
key
,
V
value
)
{
V
old
=
get
(
key
);
if
(
old
==
null
)
{
put
(
key
,
value
);
}
return
old
;
}
/**
* Remove a key-value pair if the value matches the stored one.
*
* @param key the key (may not be null)
* @param value the expected value
* @return true if the item was removed
*/
public
synchronized
boolean
remove
(
Object
key
,
Object
value
)
{
V
old
=
get
(
key
);
if
(
old
.
equals
(
value
))
{
remove
(
key
);
return
true
;
}
return
false
;
}
/**
* Replace a value for an existing key, if the value matches.
*
* @param key the key (may not be null)
* @param oldValue the expected value
* @param newValue the new value
* @return true if the value was replaced
*/
public
synchronized
boolean
replace
(
K
key
,
V
oldValue
,
V
newValue
)
{
V
old
=
get
(
key
);
if
(
old
.
equals
(
oldValue
))
{
put
(
key
,
newValue
);
return
true
;
}
return
false
;
}
/**
* Replace a value for an existing key.
*
* @param key the key (may not be null)
* @param value the new value
* @return true if the value was replaced
*/
public
synchronized
V
replace
(
K
key
,
V
value
)
{
V
old
=
get
(
key
);
if
(
old
!=
null
)
{
put
(
key
,
value
);
return
old
;
}
return
null
;
}
/**
* Remove a key-value pair.
*
...
...
@@ -370,7 +437,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
* @param rootPos the position, 0 for empty
*/
void
setRootPos
(
long
rootPos
)
{
root
=
rootPos
==
0
?
Page
.
createEmpty
(
this
,
0
)
:
readPage
(
rootPos
);
root
=
rootPos
==
0
?
Page
.
createEmpty
(
this
,
-
1
)
:
readPage
(
rootPos
);
}
/**
...
...
@@ -382,7 +449,6 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
public
Iterator
<
K
>
keyIterator
(
K
from
)
{
checkOpen
();
return
new
Cursor
<
K
,
V
>(
this
,
root
,
from
);
// return new Cursor<K, V>(this, root, from);
}
/**
...
...
@@ -463,9 +529,9 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
void
rollbackTo
(
long
version
)
{
checkWrite
();
removeUnusedOldVersions
();
if
(
version
<
createVersion
)
{
if
(
version
<
=
createVersion
)
{
removeMap
();
}
else
if
(
root
.
getVersion
()
!
=
version
)
{
}
else
if
(
root
.
getVersion
()
>
=
version
)
{
// iterating in descending order -
// this is not terribly efficient if there are many versions
ArrayList
<
Page
>
list
=
oldRoots
;
...
...
@@ -474,7 +540,7 @@ public class MVMap<K, V> extends AbstractMap<K, V> {
Page
p
=
list
.
get
(
i
);
root
=
p
;
list
.
remove
(
i
);
if
(
p
.
getVersion
()
<
=
version
)
{
if
(
p
.
getVersion
()
<
version
)
{
break
;
}
}
...
...
h2/src/tools/org/h2/dev/store/btree/MVStore.java
浏览文件 @
bc7a26f6
...
...
@@ -35,8 +35,6 @@ header:
H:3,blockSize=4096,...
TODO:
- support database version / app version
- atomic test-and-set (when supporting concurrent writes)
- possibly split chunk data into immutable and mutable
- support stores that span multiple files (chunks stored in other files)
- triggers
...
...
@@ -46,7 +44,7 @@ TODO:
- compression: maybe hash table reset speeds up compression
- use file level locking to ensure there is only one writer
- pluggable cache (specially for in-memory file systems)
- store the factory class in the file header
-
maybe
store the factory class in the file header
- support custom fields in the header
- auto-server: store port in the header
- recovery: keep a list of old chunks
...
...
@@ -64,6 +62,7 @@ TODO:
- test and possibly improve compact operation (for large dbs)
- support background writes (concurrent modification & store)
- limited support for writing to old versions (branches)
- support concurrent operations (including file I/O)
*/
...
...
@@ -121,7 +120,7 @@ public class MVStore {
private
Compressor
compressor
;
private
long
currentVersion
=
1
;
private
long
currentVersion
;
private
int
readCount
;
private
int
writeCount
;
...
...
@@ -317,6 +316,10 @@ public class MVStore {
mapsChanged
.
remove
(
map
.
getId
());
}
boolean
isMetaMap
(
MVMap
<?,
?>
map
)
{
return
map
==
meta
;
}
private
String
getDataType
(
Class
<?>
clazz
)
{
if
(
clazz
==
String
.
class
)
{
return
""
;
...
...
@@ -483,10 +486,10 @@ public class MVStore {
/**
* Increment the current version.
*
* @return the
old
version
* @return the
new
version
*/
public
long
incrementVersion
()
{
return
currentVersion
++
;
return
++
currentVersion
;
}
/**
...
...
@@ -494,7 +497,7 @@ public class MVStore {
* there are no unsaved changes, otherwise it stores the data and increments
* the current version.
*
* @return the
version before the commit
* @return the
new version (incremented if there were changes)
*/
public
long
store
()
{
if
(!
hasUnsavedChanges
())
{
...
...
@@ -514,7 +517,7 @@ public class MVStore {
c
.
maxLengthLive
=
Long
.
MAX_VALUE
;
c
.
start
=
Long
.
MAX_VALUE
;
c
.
length
=
Integer
.
MAX_VALUE
;
c
.
version
=
currentVersion
;
c
.
version
=
currentVersion
+
1
;
chunks
.
put
(
c
.
id
,
c
);
meta
.
put
(
"chunk."
+
c
.
id
,
c
.
toString
());
applyFreedChunks
();
...
...
@@ -1007,11 +1010,28 @@ public class MVStore {
return
true
;
}
public
int
getStoreVersion
()
{
String
x
=
getSetting
(
"storeVersion"
);
return
x
==
null
?
0
:
Integer
.
parseInt
(
x
);
}
public
void
setStoreVersion
(
int
version
)
{
setSetting
(
"storeVersion"
,
Integer
.
toString
(
version
));
}
public
String
getSetting
(
String
key
)
{
return
meta
.
get
(
"setting."
+
key
);
}
public
void
setSetting
(
String
key
,
String
value
)
{
meta
.
put
(
"setting."
+
key
,
value
);
}
/**
* Revert to the
given version. All later changes (stored or not) are
*
forgotten. All maps that were created later are closed. A rollback to
*
a version before the last stored version is immediately persisted.
*
Before this method returns, the current version is incremen
ted.
* Revert to the
beginning of the given version. All later changes (stored
*
or not) are forgotten. All maps that were created later are closed. A
*
rollback to a version before the last stored version is immediately
*
persis
ted.
*
* @param version the version to revert to
*/
...
...
@@ -1050,7 +1070,7 @@ public class MVStore {
}
}
for
(
MVMap
<?,
?>
m
:
maps
.
values
())
{
if
(
m
.
getCreateVersion
()
>
version
)
{
if
(
m
.
getCreateVersion
()
>
=
version
)
{
m
.
close
();
removeMap
(
m
.
getName
());
}
else
{
...
...
@@ -1061,7 +1081,7 @@ public class MVStore {
}
}
}
this
.
currentVersion
=
version
+
1
;
this
.
currentVersion
=
version
;
}
private
void
revertTemp
()
{
...
...
@@ -1073,8 +1093,8 @@ public class MVStore {
}
/**
* Get the current version of the
store
. When a new store is created, the
* version is
1
. For each commit, it is incremented by one.
* Get the current version of the
data
. When a new store is created, the
* version is
0
. For each commit, it is incremented by one.
*
* @return the version
*/
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论