Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
c662be41
提交
c662be41
authored
1月 18, 2013
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
MVStore: auto-save (every few MBs and every 1-2 seconds)
上级
5c75744e
全部展开
隐藏空白字符变更
内嵌
并排
正在显示
6 个修改的文件
包含
449 行增加
和
220 行删除
+449
-220
MVMap.java
h2/src/main/org/h2/mvstore/MVMap.java
+100
-54
MVMapConcurrent.java
h2/src/main/org/h2/mvstore/MVMapConcurrent.java
+34
-23
MVStore.java
h2/src/main/org/h2/mvstore/MVStore.java
+274
-111
Page.java
h2/src/main/org/h2/mvstore/Page.java
+3
-3
MVRTreeMap.java
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
+32
-28
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+6
-1
没有找到文件。
h2/src/main/org/h2/mvstore/MVMap.java
浏览文件 @
c662be41
...
...
@@ -48,6 +48,9 @@ public class MVMap<K, V> extends AbstractMap<K, V>
private
boolean
closed
;
private
boolean
readOnly
;
private
volatile
boolean
writing
;
private
volatile
int
writeCount
;
protected
MVMap
(
DataType
keyType
,
DataType
valueType
)
{
this
.
keyType
=
keyType
;
this
.
valueType
=
valueType
;
...
...
@@ -91,13 +94,17 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/
@SuppressWarnings
(
"unchecked"
)
public
V
put
(
K
key
,
V
value
)
{
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
p
=
splitRootIfNeeded
(
p
,
writeVersion
);
Object
result
=
put
(
p
,
writeVersion
,
key
,
value
);
newRoot
(
p
);
return
(
V
)
result
;
beforeWrite
();
try
{
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
p
=
splitRootIfNeeded
(
p
,
writeVersion
);
Object
result
=
put
(
p
,
writeVersion
,
key
,
value
);
newRoot
(
p
);
return
(
V
)
result
;
}
finally
{
afterWrite
();
}
}
/**
...
...
@@ -488,9 +495,13 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* Remove all entries.
*/
public
void
clear
()
{
checkWrite
();
root
.
removeAllRecursive
();
newRoot
(
Page
.
createEmpty
(
this
,
store
.
getCurrentVersion
()));
beforeWrite
();
try
{
root
.
removeAllRecursive
();
newRoot
(
Page
.
createEmpty
(
this
,
store
.
getCurrentVersion
()));
}
finally
{
afterWrite
();
}
}
/**
...
...
@@ -498,11 +509,16 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/
public
void
removeMap
()
{
checkOpen
();
if
(
this
!=
store
.
getMetaMap
())
{
checkWrite
();
if
(
this
==
store
.
getMetaMap
())
{
return
;
}
beforeWrite
();
try
{
root
.
removeAllRecursive
();
store
.
removeMap
(
id
);
close
();
}
finally
{
afterWrite
();
}
}
...
...
@@ -527,13 +543,17 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @return the old value if the key existed, or null otherwise
*/
public
V
remove
(
Object
key
)
{
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
@SuppressWarnings
(
"unchecked"
)
V
result
=
(
V
)
remove
(
p
,
writeVersion
,
key
);
newRoot
(
p
);
return
result
;
beforeWrite
();
try
{
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
@SuppressWarnings
(
"unchecked"
)
V
result
=
(
V
)
remove
(
p
,
writeVersion
,
key
);
newRoot
(
p
);
return
result
;
}
finally
{
afterWrite
();
}
}
/**
...
...
@@ -616,7 +636,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
result
=
p
.
getValue
(
index
);
p
.
remove
(
index
);
if
(
p
.
getKeyCount
()
==
0
)
{
removePage
(
p
);
removePage
(
p
.
getPos
()
);
}
}
return
result
;
...
...
@@ -638,7 +658,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
if
(
p
.
getKeyCount
()
==
0
)
{
p
.
setChild
(
index
,
c
);
p
.
setCounts
(
index
,
c
);
removePage
(
p
);
removePage
(
p
.
getPos
()
);
}
else
{
p
.
remove
(
index
);
}
...
...
@@ -673,15 +693,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
}
/**
* Check whether this map has any unsaved changes.
*
* @return true if there are unsaved changes.
*/
public
boolean
hasUnsavedChanges
()
{
return
!
oldRoots
.
isEmpty
();
}
/**
* Compare two keys.
*
...
...
@@ -819,30 +830,34 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @param version the version
*/
void
rollbackTo
(
long
version
)
{
checkWrite
();
removeUnusedOldVersions
();
if
(
version
<=
createVersion
)
{
// the map is removed later
}
else
if
(
root
.
getVersion
()
>=
version
)
{
// iterating in descending order -
// this is not terribly efficient if there are many versions
ArrayList
<
Page
>
list
=
oldRoots
;
while
(
list
.
size
()
>
0
)
{
int
i
=
list
.
size
()
-
1
;
Page
p
=
list
.
get
(
i
);
root
=
p
;
list
.
remove
(
i
);
if
(
p
.
getVersion
()
<
version
)
{
break
;
beforeWrite
();
try
{
removeUnusedOldVersions
();
if
(
version
<=
createVersion
)
{
// the map is removed later
}
else
if
(
root
.
getVersion
()
>=
version
)
{
// iterating in descending order -
// this is not terribly efficient if there are many versions
ArrayList
<
Page
>
list
=
oldRoots
;
while
(
list
.
size
()
>
0
)
{
int
i
=
list
.
size
()
-
1
;
Page
p
=
list
.
get
(
i
);
root
=
p
;
list
.
remove
(
i
);
if
(
p
.
getVersion
()
<
version
)
{
break
;
}
}
}
}
finally
{
afterWrite
();
}
}
/**
* Forget all old versions.
*/
void
removeAllOldVersions
()
{
private
void
removeAllOldVersions
()
{
// create a new instance
// because another thread might iterate over it
oldRoots
=
new
ArrayList
<
Page
>();
...
...
@@ -887,16 +902,44 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
/**
* Check whether writing is allowed.
* This method is called before writing to the map. The default
* implementation checks whether writing is allowed.
*
* @throws
IllegalState
Exception if the map is read-only
* @throws
UnsupportedOperation
Exception if the map is read-only
*/
protected
void
check
Write
()
{
protected
void
before
Write
()
{
if
(
readOnly
)
{
checkOpen
();
throw
DataUtils
.
newUnsupportedOperationException
(
"This map is read-only"
);
}
writing
=
true
;
store
.
beforeWrite
();
}
/**
* This method is called after writing to the map.
*/
protected
void
afterWrite
()
{
writeCount
++;
writing
=
false
;
}
void
waitUntilWritten
(
long
version
)
{
if
(
root
.
getVersion
()
<
version
)
{
// a write will create a new version
return
;
}
// wait until writing is done,
// but only for the current write operation
// a bit like a spin lock
int
w
=
writeCount
;
while
(
writing
)
{
if
(
writeCount
>
w
)
{
return
;
}
Thread
.
yield
();
}
}
public
int
hashCode
()
{
...
...
@@ -926,8 +969,8 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*
* @param p the page
*/
protected
void
removePage
(
Page
p
)
{
store
.
removePage
(
p
.
getPos
()
);
protected
void
removePage
(
long
pos
)
{
store
.
removePage
(
this
,
pos
);
}
/**
...
...
@@ -1051,15 +1094,18 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @param newMapName the name name
*/
public
void
renameMap
(
String
newMapName
)
{
checkWrite
();
store
.
renameMap
(
this
,
newMapName
);
beforeWrite
();
try
{
store
.
renameMap
(
this
,
newMapName
);
}
finally
{
afterWrite
();
}
}
public
String
toString
()
{
return
asString
(
null
);
}
/**
* A builder for maps.
*
...
...
h2/src/main/org/h2/mvstore/MVMapConcurrent.java
浏览文件 @
c662be41
...
...
@@ -34,35 +34,46 @@ public class MVMapConcurrent<K, V> extends MVMap<K, V> {
@SuppressWarnings
(
"unchecked"
)
public
V
put
(
K
key
,
V
value
)
{
checkWrite
();
V
result
=
get
(
key
);
if
(
value
.
equals
(
result
))
{
return
result
;
}
long
writeVersion
=
store
.
getCurrentVersion
();
synchronized
(
this
)
{
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
p
=
splitRootIfNeeded
(
p
,
writeVersion
);
result
=
(
V
)
put
(
p
,
writeVersion
,
key
,
value
);
newRoot
(
p
);
beforeWrite
();
try
{
// even if the result is the same, we still update the value
// (otherwise compact doesn't work)
get
(
key
);
long
writeVersion
=
store
.
getCurrentVersion
();
synchronized
(
this
)
{
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
p
=
splitRootIfNeeded
(
p
,
writeVersion
);
V
result
=
(
V
)
put
(
p
,
writeVersion
,
key
,
value
);
newRoot
(
p
);
return
result
;
}
}
finally
{
afterWrite
();
}
return
result
;
}
void
waitUntilWritten
(
long
version
)
{
// no need to wait
}
@SuppressWarnings
(
"unchecked"
)
public
V
remove
(
Object
key
)
{
checkWrite
();
V
result
=
get
(
key
);
if
(
result
==
null
)
{
return
null
;
}
long
writeVersion
=
store
.
getCurrentVersion
();
synchronized
(
this
)
{
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
result
=
(
V
)
remove
(
p
,
writeVersion
,
key
);
newRoot
(
p
);
beforeWrite
();
try
{
V
result
=
get
(
key
);
if
(
result
==
null
)
{
return
null
;
}
long
writeVersion
=
store
.
getCurrentVersion
();
synchronized
(
this
)
{
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
result
=
(
V
)
remove
(
p
,
writeVersion
,
key
);
newRoot
(
p
);
}
return
result
;
}
finally
{
afterWrite
();
}
return
result
;
}
/**
...
...
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
c662be41
差异被折叠。
点击展开。
h2/src/main/org/h2/mvstore/Page.java
浏览文件 @
c662be41
...
...
@@ -267,7 +267,7 @@ public class Page {
* @return a page with the given version
*/
public
Page
copy
(
long
version
)
{
map
.
getStore
().
removePage
(
pos
);
map
.
removePage
(
pos
);
Page
newPage
=
create
(
map
,
version
,
keyCount
,
keys
,
values
,
children
,
childrenPages
,
counts
,
totalCount
,
...
...
@@ -541,14 +541,14 @@ public class Page {
long
c
=
children
[
i
];
int
type
=
DataUtils
.
getPageType
(
c
);
if
(
type
==
DataUtils
.
PAGE_TYPE_LEAF
)
{
map
.
getStore
().
removePage
(
c
);
map
.
removePage
(
c
);
}
else
{
map
.
readPage
(
c
).
removeAllRecursive
();
}
}
}
}
map
.
getStore
().
removePage
(
pos
);
map
.
removePage
(
pos
);
}
/**
...
...
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
浏览文件 @
c662be41
...
...
@@ -150,7 +150,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
result
=
p
.
getValue
(
i
);
p
.
remove
(
i
);
if
(
p
.
getKeyCount
()
==
0
)
{
removePage
(
p
);
removePage
(
p
.
getPos
()
);
}
break
;
}
...
...
@@ -170,7 +170,7 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
// this child was deleted
p
.
remove
(
i
);
if
(
p
.
getKeyCount
()
==
0
)
{
removePage
(
p
);
removePage
(
p
.
getPos
()
);
}
break
;
}
...
...
@@ -211,34 +211,38 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
}
private
Object
putOrAdd
(
SpatialKey
key
,
V
value
,
boolean
alwaysAdd
)
{
checkWrite
();
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
Object
result
;
if
(
alwaysAdd
||
get
(
key
)
==
null
)
{
if
(
p
.
getMemory
()
>
store
.
getPageSize
()
&&
p
.
getKeyCount
()
>
1
)
{
// only possible if this is the root, else we would have split earlier
// (this requires maxPageSize is fixed)
long
totalCount
=
p
.
getTotalCount
();
Page
split
=
split
(
p
,
writeVersion
);
Object
k1
=
getBounds
(
p
);
Object
k2
=
getBounds
(
split
);
Object
[]
keys
=
{
k1
,
k2
};
long
[]
children
=
{
p
.
getPos
(),
split
.
getPos
(),
0
};
Page
[]
childrenPages
=
{
p
,
split
,
null
};
long
[]
counts
=
{
p
.
getTotalCount
(),
split
.
getTotalCount
(),
0
};
p
=
Page
.
create
(
this
,
writeVersion
,
2
,
keys
,
null
,
children
,
childrenPages
,
counts
,
totalCount
,
0
,
0
);
// now p is a node; continues
beforeWrite
();
try
{
long
writeVersion
=
store
.
getCurrentVersion
();
Page
p
=
copyOnWrite
(
root
,
writeVersion
);
Object
result
;
if
(
alwaysAdd
||
get
(
key
)
==
null
)
{
if
(
p
.
getMemory
()
>
store
.
getPageSize
()
&&
p
.
getKeyCount
()
>
1
)
{
// only possible if this is the root, else we would have split earlier
// (this requires maxPageSize is fixed)
long
totalCount
=
p
.
getTotalCount
();
Page
split
=
split
(
p
,
writeVersion
);
Object
k1
=
getBounds
(
p
);
Object
k2
=
getBounds
(
split
);
Object
[]
keys
=
{
k1
,
k2
};
long
[]
children
=
{
p
.
getPos
(),
split
.
getPos
(),
0
};
Page
[]
childrenPages
=
{
p
,
split
,
null
};
long
[]
counts
=
{
p
.
getTotalCount
(),
split
.
getTotalCount
(),
0
};
p
=
Page
.
create
(
this
,
writeVersion
,
2
,
keys
,
null
,
children
,
childrenPages
,
counts
,
totalCount
,
0
,
0
);
// now p is a node; continues
}
add
(
p
,
writeVersion
,
key
,
value
);
result
=
null
;
}
else
{
result
=
set
(
p
,
writeVersion
,
key
,
value
);
}
add
(
p
,
writeVersion
,
key
,
value
);
re
sult
=
null
;
}
else
{
result
=
set
(
p
,
writeVersion
,
key
,
value
);
newRoot
(
p
);
re
turn
result
;
}
finally
{
afterWrite
(
);
}
newRoot
(
p
);
return
result
;
}
/**
...
...
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
c662be41
...
...
@@ -206,7 +206,7 @@ public class TestMVStore extends TestBase {
s
.
store
();
s
.
close
();
int
[]
expectedReadsForCacheSize
=
{
34
12
,
2590
,
1924
,
1440
,
1102
,
956
,
918
34
07
,
2590
,
1924
,
1440
,
1106
,
956
,
918
};
for
(
int
cacheSize
=
0
;
cacheSize
<=
6
;
cacheSize
+=
4
)
{
s
=
new
MVStore
.
Builder
().
...
...
@@ -723,17 +723,22 @@ public class TestMVStore extends TestBase {
m
.
put
(
"1"
,
"Hello"
);
assertEquals
(
1
,
s
.
incrementVersion
());
s
.
rollbackTo
(
1
);
assertEquals
(
1
,
s
.
getCurrentVersion
());
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
long
v2
=
s
.
store
();
assertEquals
(
2
,
v2
);
assertEquals
(
2
,
s
.
getCurrentVersion
());
assertFalse
(
s
.
hasUnsavedChanges
());
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
s
.
close
();
s
=
openStore
(
fileName
);
assertEquals
(
2
,
s
.
getCurrentVersion
());
meta
=
s
.
getMetaMap
();
m
=
s
.
openMap
(
"data"
);
assertFalse
(
s
.
hasUnsavedChanges
());
assertEquals
(
"Hello"
,
m
.
get
(
"1"
));
m0
=
s
.
openMap
(
"data0"
);
MVMap
<
String
,
String
>
m1
=
s
.
openMap
(
"data1"
);
m
.
put
(
"1"
,
"Hallo"
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论