Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
422f2826
Unverified
提交
422f2826
authored
12月 27, 2018
作者:
Andrei Tokar
提交者:
GitHub
12月 27, 2018
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #1627 from h2database/append-single
Use lock to protect append buffer
上级
c3afed94
770812c7
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
389 行增加
和
263 行删除
+389
-263
MVMap.java
h2/src/main/org/h2/mvstore/MVMap.java
+297
-229
MVStore.java
h2/src/main/org/h2/mvstore/MVStore.java
+1
-1
Page.java
h2/src/main/org/h2/mvstore/Page.java
+30
-0
MVRTreeMap.java
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
+1
-1
Transaction.java
h2/src/main/org/h2/mvstore/tx/Transaction.java
+40
-18
TransactionMap.java
h2/src/main/org/h2/mvstore/tx/TransactionMap.java
+19
-13
TransactionStore.java
h2/src/main/org/h2/mvstore/tx/TransactionStore.java
+1
-1
没有找到文件。
h2/src/main/org/h2/mvstore/MVMap.java
浏览文件 @
422f2826
...
@@ -48,9 +48,11 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -48,9 +48,11 @@ public class MVMap<K, V> extends AbstractMap<K, V>
private
final
DataType
valueType
;
private
final
DataType
valueType
;
private
final
int
keysPerPage
;
private
final
int
keysPerPage
;
private
final
boolean
singleWriter
;
private
final
boolean
singleWriter
;
private
final
K
keysBuffer
[]
;
private
final
K
[]
keysBuffer
;
private
final
V
valuesBuffer
[]
;
private
final
V
[]
valuesBuffer
;
private
final
Object
lock
=
new
Object
();
private
volatile
boolean
notificationRequested
;
/**
/**
* Whether the map is closed. Volatile so we don't accidentally write to a
* Whether the map is closed. Volatile so we don't accidentally write to a
...
@@ -619,16 +621,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -619,16 +621,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return
0
;
return
0
;
}
}
assert
p
.
getKeyCount
()
>
0
;
assert
p
.
getKeyCount
()
>
0
;
@SuppressWarnings
(
"unchecked"
)
return
rewritePage
(
p
)
?
0
:
1
;
K
key
=
(
K
)
p
.
getKey
(
0
);
V
value
=
get
(
key
);
if
(
value
!=
null
)
{
if
(
isClosed
())
{
return
0
;
}
replace
(
key
,
value
,
value
);
}
return
1
;
}
}
int
writtenPageCount
=
0
;
int
writtenPageCount
=
0
;
for
(
int
i
=
0
;
i
<
getChildPageCount
(
p
);
i
++)
{
for
(
int
i
=
0
;
i
<
getChildPageCount
(
p
);
i
++)
{
...
@@ -658,14 +651,8 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -658,14 +651,8 @@ public class MVMap<K, V> extends AbstractMap<K, V>
while
(!
p2
.
isLeaf
())
{
while
(!
p2
.
isLeaf
())
{
p2
=
p2
.
getChildPage
(
0
);
p2
=
p2
.
getChildPage
(
0
);
}
}
@SuppressWarnings
(
"unchecked"
)
if
(
rewritePage
(
p2
))
{
K
key
=
(
K
)
p2
.
getKey
(
0
);
return
0
;
V
value
=
get
(
key
);
if
(
value
!=
null
)
{
if
(
isClosed
())
{
return
0
;
}
replace
(
key
,
value
,
value
);
}
}
writtenPageCount
++;
writtenPageCount
++;
}
}
...
@@ -673,6 +660,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -673,6 +660,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
return
writtenPageCount
;
return
writtenPageCount
;
}
}
private
boolean
rewritePage
(
Page
p
)
{
@SuppressWarnings
(
"unchecked"
)
K
key
=
(
K
)
p
.
getKey
(
0
);
V
value
=
get
(
key
);
if
(
value
!=
null
)
{
if
(
isClosed
())
{
return
true
;
}
replace
(
key
,
value
,
value
);
}
return
false
;
}
/**
/**
* Get a cursor to iterate over a number of keys and values.
* Get a cursor to iterate over a number of keys and values.
*
*
...
@@ -779,17 +779,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -779,17 +779,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @return the root page
* @return the root page
*/
*/
public
final
Page
getRootPage
()
{
public
final
Page
getRootPage
()
{
return
g
etRoot
().
root
;
return
flushAndG
etRoot
().
root
;
}
}
public
final
RootReference
getRoot
()
{
public
RootReference
getRoot
()
{
RootReference
rootReference
=
getRootInternal
();
return
root
.
get
();
return
singleWriter
&&
rootReference
.
getAppendCounter
()
>
0
?
flushAppendBuffer
(
rootReference
)
:
rootReference
;
}
}
private
RootReference
getRootInternal
()
{
public
RootReference
flushAndGetRoot
()
{
return
root
.
get
();
RootReference
rootReference
=
getRoot
();
if
(
singleWriter
&&
rootReference
.
getAppendCounter
()
>
0
)
{
return
flushAppendBuffer
(
rootReference
,
false
);
}
return
rootReference
;
}
}
final
void
setRoot
(
Page
rootPage
)
{
final
void
setRoot
(
Page
rootPage
)
{
...
@@ -814,13 +816,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -814,13 +816,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/
*/
private
RootReference
setNewRoot
(
RootReference
oldRoot
,
Page
newRootPage
,
private
RootReference
setNewRoot
(
RootReference
oldRoot
,
Page
newRootPage
,
int
attemptUpdateCounter
,
boolean
obeyLock
)
{
int
attemptUpdateCounter
,
boolean
obeyLock
)
{
RootReference
currentRoot
=
g
etRoot
();
RootReference
currentRoot
=
flushAndG
etRoot
();
assert
newRootPage
!=
null
||
currentRoot
!=
null
;
assert
newRootPage
!=
null
||
currentRoot
!=
null
;
if
(
currentRoot
!=
oldRoot
&&
oldRoot
!=
null
)
{
if
(
currentRoot
!=
oldRoot
&&
oldRoot
!=
null
)
{
return
null
;
return
null
;
}
}
RootReference
previous
=
currentRoot
;
RootReference
previous
=
currentRoot
;
int
appendCounter
=
0
;
long
updateCounter
=
1
;
long
updateCounter
=
1
;
long
newVersion
=
INITIAL_VERSION
;
long
newVersion
=
INITIAL_VERSION
;
if
(
currentRoot
!=
null
)
{
if
(
currentRoot
!=
null
)
{
...
@@ -834,12 +837,13 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -834,12 +837,13 @@ public class MVMap<K, V> extends AbstractMap<K, V>
newVersion
=
currentRoot
.
version
;
newVersion
=
currentRoot
.
version
;
previous
=
currentRoot
.
previous
;
previous
=
currentRoot
.
previous
;
appendCounter
=
currentRoot
.
getAppendCounter
();
updateCounter
+=
currentRoot
.
updateCounter
;
updateCounter
+=
currentRoot
.
updateCounter
;
attemptUpdateCounter
+=
currentRoot
.
updateAttemptCounter
;
attemptUpdateCounter
+=
currentRoot
.
updateAttemptCounter
;
}
}
RootReference
updatedRootReference
=
new
RootReference
(
newRootPage
,
newVersion
,
previous
,
update
Counter
,
RootReference
updatedRootReference
=
new
RootReference
(
newRootPage
,
newVersion
,
previous
,
append
Counter
,
attemptUpdateCounter
,
false
);
updateCounter
,
attemptUpdateCounter
);
boolean
success
=
root
.
compareAndSet
(
currentRoot
,
updatedRootReference
);
boolean
success
=
root
.
compareAndSet
(
currentRoot
,
updatedRootReference
);
return
success
?
updatedRootReference
:
null
;
return
success
?
updatedRootReference
:
null
;
}
}
...
@@ -858,7 +862,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -858,7 +862,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
void
rollbackRoot
(
long
version
)
void
rollbackRoot
(
long
version
)
{
{
RootReference
rootReference
=
g
etRoot
();
RootReference
rootReference
=
flushAndG
etRoot
();
RootReference
previous
;
RootReference
previous
;
while
(
rootReference
.
version
>=
version
&&
(
previous
=
rootReference
.
previous
)
!=
null
)
{
while
(
rootReference
.
version
>=
version
&&
(
previous
=
rootReference
.
previous
)
!=
null
)
{
if
(
root
.
compareAndSet
(
rootReference
,
previous
))
{
if
(
root
.
compareAndSet
(
rootReference
,
previous
))
{
...
@@ -1070,7 +1074,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1070,7 +1074,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
final
boolean
hasChangesSince
(
long
version
)
{
final
boolean
hasChangesSince
(
long
version
)
{
RootReference
rootReference
=
getRoot
();
RootReference
rootReference
=
getRoot
();
Page
root
=
rootReference
.
root
;
Page
root
=
rootReference
.
root
;
return
!
root
.
isSaved
()
&&
root
.
getTotalCount
()
>
0
||
return
!
root
.
isSaved
()
&&
root
Reference
.
getTotalCount
()
>
0
||
getVersion
(
rootReference
)
>
version
;
getVersion
(
rootReference
)
>
version
;
}
}
...
@@ -1123,7 +1127,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1123,7 +1127,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
final
RootReference
setWriteVersion
(
long
writeVersion
)
{
final
RootReference
setWriteVersion
(
long
writeVersion
)
{
int
attempt
=
0
;
int
attempt
=
0
;
while
(
true
)
{
while
(
true
)
{
RootReference
rootReference
=
g
etRoot
();
RootReference
rootReference
=
flushAndG
etRoot
();
if
(
rootReference
.
version
>=
writeVersion
)
{
if
(
rootReference
.
version
>=
writeVersion
)
{
return
rootReference
;
return
rootReference
;
}
else
if
(
isClosed
())
{
}
else
if
(
isClosed
())
{
...
@@ -1198,83 +1202,138 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1198,83 +1202,138 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* If map was used in append mode, this method will ensure that append buffer
* If map was used in append mode, this method will ensure that append buffer
* is flushed - emptied with all entries inserted into map as a new leaf.
* is flushed - emptied with all entries inserted into map as a new leaf.
* @param rootReference current RootReference
* @param rootReference current RootReference
* @param lockedForUpdate whether rootReference is pre-locked already and
* should stay locked upon return
* @return potentially updated RootReference
* @return potentially updated RootReference
*/
*/
private
RootReference
flushAppendBuffer
(
RootReference
rootReference
)
{
private
RootReference
flushAppendBuffer
(
RootReference
rootReference
,
boolean
lockedForUpdate
)
{
int
attempt
=
0
;
IntValueHolder
unsavedMemoryHolder
=
new
IntValueHolder
();
int
keyCount
;
RootReference
lockedRootReference
=
lockedForUpdate
?
rootReference
:
null
;
while
((
keyCount
=
rootReference
.
getAppendCounter
())
>
0
)
{
try
{
Page
page
=
Page
.
createLeaf
(
this
,
int
attempt
=
0
;
Arrays
.
copyOf
(
keysBuffer
,
keyCount
),
int
keyCount
;
Arrays
.
copyOf
(
valuesBuffer
,
keyCount
),
while
((
keyCount
=
rootReference
.
getAppendCounter
())
>
0
)
{
0
);
if
(
lockedRootReference
==
null
)
{
CursorPos
pos
=
rootReference
.
root
.
getAppendCursorPos
(
null
);
lockedRootReference
=
tryLock
(
rootReference
,
++
attempt
);
assert
page
.
map
==
this
;
rootReference
=
lockedRootReference
==
null
?
getRoot
()
:
lockedRootReference
;
assert
pos
!=
null
;
continue
;
assert
page
.
getKeyCount
()
>
0
;
Object
key
=
page
.
getKey
(
0
);
assert
pos
.
index
<
0
:
pos
.
index
;
int
index
=
-
pos
.
index
-
1
;
assert
index
==
pos
.
page
.
getKeyCount
()
:
index
+
" != "
+
pos
.
page
.
getKeyCount
();
Page
p
=
pos
.
page
;
pos
=
pos
.
parent
;
CursorPos
tip
=
pos
;
int
unsavedMemory
=
page
.
getMemory
();
while
(
true
)
{
if
(
pos
==
null
)
{
if
(
p
.
getKeyCount
()
==
0
)
{
p
=
page
;
}
else
{
Object
keys
[]
=
new
Object
[]
{
key
};
Page
.
PageReference
children
[]
=
new
Page
.
PageReference
[]
{
new
Page
.
PageReference
(
p
),
new
Page
.
PageReference
(
page
)};
p
=
Page
.
createNode
(
this
,
keys
,
children
,
p
.
getTotalCount
()
+
page
.
getTotalCount
(),
0
);
}
break
;
}
}
Page
c
=
p
;
p
=
pos
.
page
;
Page
rootPage
=
rootReference
.
root
;
index
=
pos
.
index
;
CursorPos
pos
=
rootPage
.
getAppendCursorPos
(
null
);
assert
pos
!=
null
;
assert
pos
.
index
<
0
:
pos
.
index
;
int
index
=
-
pos
.
index
-
1
;
assert
index
==
pos
.
page
.
getKeyCount
()
:
index
+
" != "
+
pos
.
page
.
getKeyCount
();
Page
p
=
pos
.
page
;
CursorPos
tip
=
pos
;
pos
=
pos
.
parent
;
pos
=
pos
.
parent
;
p
=
p
.
copy
();
p
.
setChild
(
index
,
page
);
int
remainingBuffer
=
0
;
p
.
insertNode
(
index
,
key
,
c
);
Page
page
=
null
;
if
((
keyCount
=
p
.
getKeyCount
())
<=
store
.
getKeysPerPage
()
&&
int
available
=
store
.
getKeysPerPage
()
-
p
.
getKeyCount
();
(
p
.
getMemory
()
<
store
.
getMaxPageSize
()
||
keyCount
<=
(
p
.
isLeaf
()
?
1
:
2
)))
{
if
(
available
>
0
)
{
break
;
p
=
p
.
copy
();
if
(
keyCount
<=
available
)
{
p
.
expand
(
keyCount
,
keysBuffer
,
valuesBuffer
);
}
else
{
p
.
expand
(
available
,
keysBuffer
,
valuesBuffer
);
keyCount
-=
available
;
if
(
lockedForUpdate
)
{
System
.
arraycopy
(
keysBuffer
,
available
,
keysBuffer
,
0
,
keyCount
);
System
.
arraycopy
(
valuesBuffer
,
available
,
valuesBuffer
,
0
,
keyCount
);
remainingBuffer
=
keyCount
;
}
else
{
Object
[]
keys
=
new
Object
[
keyCount
];
Object
[]
values
=
new
Object
[
keyCount
];
System
.
arraycopy
(
keysBuffer
,
available
,
keys
,
0
,
keyCount
);
System
.
arraycopy
(
valuesBuffer
,
available
,
values
,
0
,
keyCount
);
page
=
Page
.
createLeaf
(
this
,
keys
,
values
,
0
);
}
}
}
else
{
page
=
Page
.
createLeaf
(
this
,
Arrays
.
copyOf
(
keysBuffer
,
keyCount
),
Arrays
.
copyOf
(
valuesBuffer
,
keyCount
),
0
);
}
}
int
at
=
keyCount
-
2
;
key
=
p
.
getKey
(
at
);
unsavedMemoryHolder
.
value
=
0
;
page
=
p
.
split
(
at
);
if
(
page
!=
null
)
{
unsavedMemory
+=
p
.
getMemory
()
+
page
.
getMemory
();
assert
page
.
map
==
this
;
}
assert
page
.
getKeyCount
()
>
0
;
unsavedMemory
+=
p
.
getMemory
();
Object
key
=
page
.
getKey
(
0
);
while
(
pos
!=
null
)
{
unsavedMemoryHolder
.
value
+=
page
.
getMemory
();
Page
c
=
p
;
while
(
true
)
{
p
=
pos
.
page
;
if
(
pos
==
null
)
{
p
=
p
.
copy
();
if
(
p
.
getKeyCount
()
==
0
)
{
p
.
setChild
(
pos
.
index
,
c
);
p
=
page
;
unsavedMemory
+=
p
.
getMemory
();
}
else
{
pos
=
pos
.
parent
;
Object
[]
keys
=
new
Object
[]{
key
};
}
Page
.
PageReference
[]
children
=
new
Page
.
PageReference
[]{
RootReference
updatedRootReference
=
new
RootReference
(
rootReference
,
p
,
++
attempt
);
new
Page
.
PageReference
(
p
),
if
(
root
.
compareAndSet
(
rootReference
,
updatedRootReference
))
{
new
Page
.
PageReference
(
page
)};
while
(
tip
!=
null
)
{
p
=
Page
.
createNode
(
this
,
keys
,
children
,
p
.
getTotalCount
()
+
page
.
getTotalCount
(),
0
);
tip
.
page
.
removePage
();
}
tip
=
tip
.
parent
;
break
;
}
Page
c
=
p
;
p
=
pos
.
page
;
index
=
pos
.
index
;
pos
=
pos
.
parent
;
p
=
p
.
copy
();
p
.
setChild
(
index
,
page
);
p
.
insertNode
(
index
,
key
,
c
);
if
((
keyCount
=
p
.
getKeyCount
())
<=
store
.
getKeysPerPage
()
&&
(
p
.
getMemory
()
<
store
.
getMaxPageSize
()
||
keyCount
<=
(
p
.
isLeaf
()
?
1
:
2
)))
{
break
;
}
int
at
=
keyCount
-
2
;
key
=
p
.
getKey
(
at
);
page
=
p
.
split
(
at
);
unsavedMemoryHolder
.
value
+=
p
.
getMemory
()
+
page
.
getMemory
();
}
}
}
if
(
store
.
getFileStore
()
!=
null
)
{
p
=
replacePage
(
pos
,
p
,
unsavedMemoryHolder
);
store
.
registerUnsavedPage
(
unsavedMemory
);
RootReference
updatedRootReference
=
new
RootReference
(
rootReference
,
p
,
remainingBuffer
,
lockedForUpdate
);
if
(
root
.
compareAndSet
(
rootReference
,
updatedRootReference
))
{
lockedRootReference
=
null
;
while
(
tip
!=
null
)
{
tip
.
page
.
removePage
();
tip
=
tip
.
parent
;
}
if
(
store
.
getFileStore
()
!=
null
)
{
store
.
registerUnsavedPage
(
unsavedMemoryHolder
.
value
);
}
assert
lockedForUpdate
||
updatedRootReference
.
getAppendCounter
()
==
0
;
return
updatedRootReference
;
}
}
assert
updatedRootReference
.
getAppendCounter
()
==
0
;
rootReference
=
getRoot
();
return
updatedRootReference
;
}
}
finally
{
if
(
lockedRootReference
!=
null
&&
!
lockedForUpdate
)
{
assert
rootReference
.
root
==
lockedRootReference
.
root
;
rootReference
=
unlockRoot
(
lockedRootReference
.
root
,
lockedRootReference
.
appendCounter
);
}
}
rootReference
=
getRootInternal
();
}
}
return
rootReference
;
return
rootReference
;
}
}
private
static
Page
replacePage
(
CursorPos
path
,
Page
replacement
,
IntValueHolder
unsavedMemoryHolder
)
{
int
unsavedMemory
=
replacement
.
getMemory
();
while
(
path
!=
null
)
{
Page
child
=
replacement
;
replacement
=
path
.
page
.
copy
();
replacement
.
setChild
(
path
.
index
,
child
);
unsavedMemory
+=
replacement
.
getMemory
();
path
=
path
.
parent
;
}
unsavedMemoryHolder
.
value
+=
unsavedMemory
;
return
replacement
;
}
/**
/**
* Appends entry to this map. this method is NOT thread safe and can not be used
* Appends entry to this map. this method is NOT thread safe and can not be used
* neither concurrently, nor in combination with any method that updates this map.
* neither concurrently, nor in combination with any method that updates this map.
...
@@ -1284,22 +1343,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1284,22 +1343,19 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* @param value to be appended
* @param value to be appended
*/
*/
public
void
append
(
K
key
,
V
value
)
{
public
void
append
(
K
key
,
V
value
)
{
int
attempt
=
0
;
RootReference
rootReference
=
lockRoot
(
getRoot
(),
1
);
boolean
success
=
false
;
int
appendCounter
=
rootReference
.
getAppendCounter
();
while
(!
success
)
{
try
{
RootReference
rootReference
=
getRootInternal
();
int
appendCounter
=
rootReference
.
getAppendCounter
();
if
(
appendCounter
>=
keysPerPage
)
{
if
(
appendCounter
>=
keysPerPage
)
{
beforeWrite
();
rootReference
=
flushAppendBuffer
(
rootReference
,
true
);
rootReference
=
flushAppendBuffer
(
rootReference
);
appendCounter
=
rootReference
.
getAppendCounter
();
appendCounter
=
rootReference
.
getAppendCounter
();
assert
appendCounter
<
keysPerPage
;
assert
appendCounter
<
keysPerPage
;
}
}
keysBuffer
[
appendCounter
]
=
key
;
keysBuffer
[
appendCounter
]
=
key
;
valuesBuffer
[
appendCounter
]
=
value
;
valuesBuffer
[
appendCounter
]
=
value
;
++
appendCounter
;
RootReference
updatedRootReference
=
new
RootReference
(
rootReference
,
appendCounter
+
1
,
++
attempt
);
}
finally
{
success
=
root
.
compareAndSet
(
rootReference
,
updatedRootReference
);
unlockRoot
(
rootReference
.
root
,
appendCounter
);
}
}
}
}
...
@@ -1309,24 +1365,25 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1309,24 +1365,25 @@ public class MVMap<K, V> extends AbstractMap<K, V>
* Non-updating method may be used concurrently, but latest removal may not be visible.
* Non-updating method may be used concurrently, but latest removal may not be visible.
*/
*/
public
void
trimLast
()
{
public
void
trimLast
()
{
int
attempt
=
0
;
RootReference
rootReference
=
getRoot
();
boolean
success
;
int
appendCounter
=
rootReference
.
getAppendCounter
();
do
{
boolean
useRegularRemove
=
appendCounter
==
0
;
RootReference
rootReference
=
getRootInternal
();
if
(!
useRegularRemove
)
{
int
appendCounter
=
rootReference
.
getAppendCounter
();
rootReference
=
lockRoot
(
rootReference
,
1
);
if
(
appendCounter
>
0
)
{
appendCounter
=
rootReference
.
getAppendCounter
();
RootReference
updatedRootReference
=
new
RootReference
(
rootReference
,
appendCounter
-
1
,
++
attempt
);
useRegularRemove
=
appendCounter
==
0
;
success
=
root
.
compareAndSet
(
rootReference
,
updatedRootReference
);
if
(!
useRegularRemove
)
{
}
else
{
--
appendCounter
;
assert
rootReference
.
root
.
getKeyCount
()
>
0
;
Page
lastLeaf
=
rootReference
.
root
.
getAppendCursorPos
(
null
).
page
;
assert
lastLeaf
.
isLeaf
();
assert
lastLeaf
.
getKeyCount
()
>
0
;
Object
key
=
lastLeaf
.
getKey
(
lastLeaf
.
getKeyCount
()
-
1
);
success
=
remove
(
key
)
!=
null
;
assert
success
;
}
}
}
while
(!
success
);
unlockRoot
(
rootReference
.
root
,
appendCounter
);
}
if
(
useRegularRemove
)
{
Page
lastLeaf
=
rootReference
.
root
.
getAppendCursorPos
(
null
).
page
;
assert
lastLeaf
.
isLeaf
();
assert
lastLeaf
.
getKeyCount
()
>
0
;
Object
key
=
lastLeaf
.
getKey
(
lastLeaf
.
getKeyCount
()
-
1
);
remove
(
key
);
}
}
}
@Override
@Override
...
@@ -1365,38 +1422,36 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1365,38 +1422,36 @@ public class MVMap<K, V> extends AbstractMap<K, V>
*/
*/
public
final
byte
appendCounter
;
public
final
byte
appendCounter
;
RootReference
(
Page
root
,
long
version
,
RootReference
previous
,
RootReference
(
Page
root
,
long
version
,
RootReference
previous
,
int
appendCounter
,
long
updateCounter
,
long
updateAttemptCounter
)
{
long
updateCounter
,
long
updateAttemptCounter
,
boolean
lockedForUpdate
)
{
this
.
root
=
root
;
this
.
root
=
root
;
this
.
version
=
version
;
this
.
version
=
version
;
this
.
previous
=
previous
;
this
.
previous
=
previous
;
this
.
updateCounter
=
updateCounter
;
this
.
updateCounter
=
updateCounter
;
this
.
updateAttemptCounter
=
updateAttemptCounter
;
this
.
updateAttemptCounter
=
updateAttemptCounter
;
this
.
lockedForUpdate
=
lockedForUpdat
e
;
this
.
lockedForUpdate
=
fals
e
;
this
.
appendCounter
=
0
;
this
.
appendCounter
=
(
byte
)
appendCounter
;
}
}
// This one is used for locking
// This one is used for locking
RootReference
(
RootReference
r
)
{
RootReference
(
RootReference
r
,
int
attempt
)
{
this
.
root
=
r
.
root
;
this
.
root
=
r
.
root
;
this
.
version
=
r
.
version
;
this
.
version
=
r
.
version
;
this
.
previous
=
r
.
previous
;
this
.
previous
=
r
.
previous
;
this
.
updateCounter
=
r
.
updateCounter
;
this
.
updateCounter
=
r
.
updateCounter
+
1
;
this
.
updateAttemptCounter
=
r
.
updateAttemptCounter
;
this
.
updateAttemptCounter
=
r
.
updateAttemptCounter
+
attempt
;
this
.
lockedForUpdate
=
true
;
this
.
lockedForUpdate
=
true
;
this
.
appendCounter
=
0
;
this
.
appendCounter
=
r
.
appendCounter
;
}
}
// This one is used for unlocking
// This one is used for unlocking
RootReference
(
RootReference
r
,
Page
root
,
int
a
ttempt
)
{
RootReference
(
RootReference
r
,
Page
root
,
int
a
ppendCounter
,
boolean
lockedForUpdate
)
{
this
.
root
=
root
;
this
.
root
=
root
;
this
.
version
=
r
.
version
;
this
.
version
=
r
.
version
;
this
.
previous
=
r
.
previous
;
this
.
previous
=
r
.
previous
;
this
.
updateCounter
=
r
.
updateCounter
+
1
;
this
.
updateCounter
=
r
.
updateCounter
;
this
.
updateAttemptCounter
=
r
.
updateAttemptCounter
+
attempt
;
this
.
updateAttemptCounter
=
r
.
updateAttemptCounter
;
this
.
lockedForUpdate
=
fals
e
;
this
.
lockedForUpdate
=
lockedForUpdat
e
;
this
.
appendCounter
=
0
;
this
.
appendCounter
=
(
byte
)
appendCounter
;
}
}
// This one is used for version change
// This one is used for version change
...
@@ -1426,21 +1481,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1426,21 +1481,14 @@ public class MVMap<K, V> extends AbstractMap<K, V>
this
.
appendCounter
=
0
;
this
.
appendCounter
=
0
;
}
}
// This one is used for append buffer maintenance
RootReference
(
RootReference
r
,
int
appendCounter
,
int
attempt
)
{
this
.
root
=
r
.
root
;
this
.
version
=
r
.
version
;
this
.
previous
=
r
.
previous
;
this
.
updateCounter
=
r
.
updateCounter
+
1
;
this
.
updateAttemptCounter
=
r
.
updateAttemptCounter
+
attempt
;
this
.
lockedForUpdate
=
r
.
lockedForUpdate
;
this
.
appendCounter
=
(
byte
)
appendCounter
;
}
public
int
getAppendCounter
()
{
public
int
getAppendCounter
()
{
return
appendCounter
&
0xff
;
return
appendCounter
&
0xff
;
}
}
public
long
getTotalCount
()
{
return
root
.
getTotalCount
()
+
getAppendCounter
();
}
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
return
"RootReference("
+
System
.
identityHashCode
(
root
)+
","
+
version
+
","
+
lockedForUpdate
+
")"
;
return
"RootReference("
+
System
.
identityHashCode
(
root
)+
","
+
version
+
","
+
lockedForUpdate
+
")"
;
...
@@ -1707,36 +1755,32 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1707,36 +1755,32 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public
void
reset
()
{}
public
void
reset
()
{}
}
}
@SuppressWarnings
(
"unchecked"
)
public
V
operate
(
K
key
,
V
value
,
DecisionMaker
<?
super
V
>
decisionMaker
)
{
public
V
operate
(
K
key
,
V
value
,
DecisionMaker
<?
super
V
>
decisionMaker
)
{
beforeWrite
();
beforeWrite
();
IntValueHolder
unsavedMemoryHolder
=
new
IntValueHolder
();
int
attempt
=
0
;
int
attempt
=
0
;
RootReference
oldRootReference
=
null
;
while
(
true
)
{
while
(
true
)
{
RootReference
rootReference
=
getRoot
();
RootReference
rootReference
=
flushAndGetRoot
();
int
contention
=
0
;
RootReference
lockedRootReference
=
null
;
if
(
oldRootReference
!=
null
)
{
if
((++
attempt
>
3
||
rootReference
.
lockedForUpdate
))
{
long
updateAttemptCounter
=
rootReference
.
updateAttemptCounter
-
lockedRootReference
=
lockRoot
(
rootReference
,
attempt
);
oldRootReference
.
updateAttemptCounter
;
rootReference
=
lockedRootReference
;
assert
updateAttemptCounter
>=
0
:
updateAttemptCounter
;
long
updateCounter
=
rootReference
.
updateCounter
-
oldRootReference
.
updateCounter
;
assert
updateCounter
>=
0
:
updateCounter
;
assert
updateAttemptCounter
>=
updateCounter
:
updateAttemptCounter
+
" >= "
+
updateCounter
;
contention
=
(
int
)((
updateAttemptCounter
+
1
)
/
(
updateCounter
+
1
));
}
}
oldRootReference
=
rootReference
;
Page
rootPage
=
rootReference
.
root
;
++
attempt
;
int
appendCounter
=
rootReference
.
getAppendCounter
();
CursorPos
pos
=
traverseDown
(
rootReference
.
root
,
key
);
CursorPos
tip
;
Page
p
=
pos
.
page
;
V
result
;
int
index
=
pos
.
index
;
unsavedMemoryHolder
.
value
=
0
;
CursorPos
tip
=
pos
;
pos
=
pos
.
parent
;
@SuppressWarnings
(
"unchecked"
)
V
result
=
index
<
0
?
null
:
(
V
)
p
.
getValue
(
index
);
Decision
decision
=
decisionMaker
.
decide
(
result
,
value
);
int
unsavedMemory
=
0
;
boolean
needUnlock
=
false
;
try
{
try
{
CursorPos
pos
=
traverseDown
(
rootPage
,
key
);
Page
p
=
pos
.
page
;
int
index
=
pos
.
index
;
tip
=
pos
;
pos
=
pos
.
parent
;
result
=
index
<
0
?
null
:
(
V
)
p
.
getValue
(
index
);
Decision
decision
=
decisionMaker
.
decide
(
result
,
value
);
switch
(
decision
)
{
switch
(
decision
)
{
case
REPEAT:
case
REPEAT:
decisionMaker
.
reset
();
decisionMaker
.
reset
();
...
@@ -1755,10 +1799,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1755,10 +1799,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
}
return
null
;
return
null
;
}
}
if
(
attempt
>
2
&&
!(
needUnlock
=
lockRoot
(
decisionMaker
,
rootReference
,
attempt
,
contention
)))
{
continue
;
}
if
(
p
.
getTotalCount
()
==
1
&&
pos
!=
null
)
{
if
(
p
.
getTotalCount
()
==
1
&&
pos
!=
null
)
{
p
=
pos
.
page
;
p
=
pos
.
page
;
index
=
pos
.
index
;
index
=
pos
.
index
;
...
@@ -1775,10 +1816,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1775,10 +1816,6 @@ public class MVMap<K, V> extends AbstractMap<K, V>
break
;
break
;
}
}
case
PUT:
{
case
PUT:
{
if
(
attempt
>
2
&&
!(
needUnlock
=
lockRoot
(
decisionMaker
,
rootReference
,
attempt
,
contention
)))
{
continue
;
}
value
=
decisionMaker
.
selectValue
(
result
,
value
);
value
=
decisionMaker
.
selectValue
(
result
,
value
);
p
=
p
.
copy
();
p
=
p
.
copy
();
if
(
index
<
0
)
{
if
(
index
<
0
)
{
...
@@ -1791,11 +1828,10 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1791,11 +1828,10 @@ public class MVMap<K, V> extends AbstractMap<K, V>
int
at
=
keyCount
>>
1
;
int
at
=
keyCount
>>
1
;
Object
k
=
p
.
getKey
(
at
);
Object
k
=
p
.
getKey
(
at
);
Page
split
=
p
.
split
(
at
);
Page
split
=
p
.
split
(
at
);
unsavedMemory
+=
p
.
getMemory
();
unsavedMemoryHolder
.
value
+=
p
.
getMemory
()
+
split
.
getMemory
();
unsavedMemory
+=
split
.
getMemory
();
if
(
pos
==
null
)
{
if
(
pos
==
null
)
{
Object
keys
[]
=
{
k
};
Object
[]
keys
=
{
k
};
Page
.
PageReference
children
[]
=
{
Page
.
PageReference
[]
children
=
{
new
Page
.
PageReference
(
p
),
new
Page
.
PageReference
(
p
),
new
Page
.
PageReference
(
split
)
new
Page
.
PageReference
(
split
)
};
};
...
@@ -1816,70 +1852,97 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1816,70 +1852,97 @@ public class MVMap<K, V> extends AbstractMap<K, V>
break
;
break
;
}
}
}
}
unsavedMemory
+=
p
.
getMemory
();
p
=
replacePage
(
pos
,
p
,
unsavedMemoryHolder
);
while
(
pos
!=
null
)
{
rootPage
=
p
;
Page
c
=
p
;
if
(
lockedRootReference
==
null
&&
!
updateRoot
(
rootReference
,
p
,
attempt
))
{
p
=
pos
.
page
;
p
=
p
.
copy
();
p
.
setChild
(
pos
.
index
,
c
);
unsavedMemory
+=
p
.
getMemory
();
pos
=
pos
.
parent
;
}
if
(
needUnlock
)
{
unlockRoot
(
p
,
attempt
);
needUnlock
=
false
;
}
else
if
(!
updateRoot
(
rootReference
,
p
,
attempt
))
{
decisionMaker
.
reset
();
decisionMaker
.
reset
();
continue
;
continue
;
}
}
while
(
tip
!=
null
)
{
tip
.
page
.
removePage
();
tip
=
tip
.
parent
;
}
if
(
store
.
getFileStore
()
!=
null
)
{
store
.
registerUnsavedPage
(
unsavedMemory
);
}
return
result
;
}
finally
{
}
finally
{
if
(
needUnlock
)
{
if
(
lockedRootReference
!=
null
)
{
unlockRoot
(
root
Reference
.
root
,
attempt
);
unlockRoot
(
root
Page
,
appendCounter
);
}
}
}
}
while
(
tip
!=
null
)
{
tip
.
page
.
removePage
();
tip
=
tip
.
parent
;
}
if
(
store
.
getFileStore
()
!=
null
)
{
store
.
registerUnsavedPage
(
unsavedMemoryHolder
.
value
);
}
return
result
;
}
}
}
}
private
boolean
lockRoot
(
DecisionMaker
<?
super
V
>
decisionMaker
,
RootReference
rootReference
,
private
RootReference
lockRoot
(
RootReference
rootReference
,
int
attempt
)
{
int
attempt
,
int
contention
)
{
while
(
true
)
{
boolean
success
=
lockRoot
(
rootReference
);
RootReference
lockedRootReference
=
tryLock
(
rootReference
,
attempt
++);
if
(!
success
)
{
if
(
lockedRootReference
!=
null
)
{
decisionMaker
.
reset
();
return
lockedRootReference
;
if
(
attempt
>
4
)
{
}
if
(
attempt
<=
24
)
{
rootReference
=
getRoot
();
Thread
.
yield
();
}
}
else
{
}
private
RootReference
tryLock
(
RootReference
rootReference
,
int
attempt
)
{
if
(!
rootReference
.
lockedForUpdate
)
{
RootReference
lockedRootReference
=
new
RootReference
(
rootReference
,
attempt
);
if
(
root
.
compareAndSet
(
rootReference
,
lockedRootReference
))
{
return
lockedRootReference
;
}
}
RootReference
oldRootReference
=
rootReference
.
previous
;
int
contention
=
1
;
if
(
oldRootReference
!=
null
)
{
long
updateAttemptCounter
=
rootReference
.
updateAttemptCounter
-
oldRootReference
.
updateAttemptCounter
;
assert
updateAttemptCounter
>=
0
:
updateAttemptCounter
;
long
updateCounter
=
rootReference
.
updateCounter
-
oldRootReference
.
updateCounter
;
assert
updateCounter
>=
0
:
updateCounter
;
assert
updateAttemptCounter
>=
updateCounter
:
updateAttemptCounter
+
" >= "
+
updateCounter
;
contention
+=
(
int
)((
updateAttemptCounter
+
1
)
/
(
updateCounter
+
1
));
}
if
(
attempt
>
4
)
{
if
(
attempt
<=
12
)
{
Thread
.
yield
();
}
else
if
(
attempt
<=
24
)
{
try
{
Thread
.
sleep
(
0
,
10
*
contention
+
5
);
}
catch
(
InterruptedException
ex
)
{
throw
new
RuntimeException
(
ex
);
}
}
else
{
synchronized
(
lock
)
{
notificationRequested
=
true
;
try
{
try
{
Thread
.
sleep
(
0
,
100
/
contention
+
50
);
lock
.
wait
(
100
);
}
catch
(
InterruptedException
ex
)
{
}
catch
(
InterruptedException
ignore
)
{
throw
new
RuntimeException
(
ex
);
}
}
}
}
}
}
}
}
return
success
;
return
null
;
}
private
boolean
lockRoot
(
RootReference
rootReference
)
{
return
!
rootReference
.
lockedForUpdate
&&
root
.
compareAndSet
(
rootReference
,
new
RootReference
(
rootReference
));
}
}
private
void
unlockRoot
(
Page
newRoot
,
int
attempt
)
{
private
RootReference
unlockRoot
(
Page
newRoot
,
int
appendCounter
)
{
RootReference
updatedRootReference
;
boolean
success
;
boolean
success
;
do
{
do
{
RootReference
rootReference
=
getRoot
();
RootReference
rootReference
=
getRoot
();
RootReference
updatedRootReference
=
new
RootReference
(
rootReference
,
newRoot
,
attempt
);
assert
rootReference
.
lockedForUpdate
;
updatedRootReference
=
new
RootReference
(
rootReference
,
newRoot
,
appendCounter
,
false
);
success
=
root
.
compareAndSet
(
rootReference
,
updatedRootReference
);
success
=
root
.
compareAndSet
(
rootReference
,
updatedRootReference
);
}
while
(!
success
);
}
while
(!
success
);
if
(
notificationRequested
)
{
synchronized
(
lock
)
{
notificationRequested
=
false
;
lock
.
notifyAll
();;
}
}
return
updatedRootReference
;
}
}
private
static
CursorPos
traverseDown
(
Page
p
,
Object
key
)
{
private
static
CursorPos
traverseDown
(
Page
p
,
Object
key
)
{
...
@@ -1929,4 +1992,9 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1929,4 +1992,9 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
}
}
}
private
static
final
class
IntValueHolder
{
int
value
;
IntValueHolder
()
{}
}
}
}
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
422f2826
...
@@ -1401,7 +1401,7 @@ public class MVStore implements AutoCloseable {
...
@@ -1401,7 +1401,7 @@ public class MVStore implements AutoCloseable {
try
{
try
{
ChunkIdsCollector
collector
=
new
ChunkIdsCollector
(
meta
.
getId
());
ChunkIdsCollector
collector
=
new
ChunkIdsCollector
(
meta
.
getId
());
long
oldestVersionToKeep
=
getOldestVersionToKeep
();
long
oldestVersionToKeep
=
getOldestVersionToKeep
();
MVMap
.
RootReference
rootReference
=
meta
.
g
etRoot
();
MVMap
.
RootReference
rootReference
=
meta
.
flushAndG
etRoot
();
if
(
fast
)
{
if
(
fast
)
{
MVMap
.
RootReference
previous
;
MVMap
.
RootReference
previous
;
while
(
rootReference
.
version
>=
oldestVersionToKeep
&&
(
previous
=
rootReference
.
previous
)
!=
null
)
{
while
(
rootReference
.
version
>=
oldestVersionToKeep
&&
(
previous
=
rootReference
.
previous
)
!=
null
)
{
...
...
h2/src/main/org/h2/mvstore/Page.java
浏览文件 @
422f2826
...
@@ -493,6 +493,16 @@ public abstract class Page implements Cloneable
...
@@ -493,6 +493,16 @@ public abstract class Page implements Cloneable
return
bKeys
;
return
bKeys
;
}
}
abstract
void
expand
(
int
extraKeyCount
,
Object
[]
extraKeys
,
Object
[]
extraValues
);
final
void
expandKeys
(
int
extraKeyCount
,
Object
[]
extraKeys
)
{
int
keyCount
=
getKeyCount
();
Object
[]
newKeys
=
createKeyStorage
(
keyCount
+
extraKeyCount
);
System
.
arraycopy
(
keys
,
0
,
newKeys
,
0
,
keyCount
);
System
.
arraycopy
(
extraKeys
,
0
,
newKeys
,
keyCount
,
extraKeyCount
);
keys
=
newKeys
;
}
/**
/**
* Get the total number of key-value pairs, including child pages.
* Get the total number of key-value pairs, including child pages.
*
*
...
@@ -1012,6 +1022,11 @@ public abstract class Page implements Cloneable
...
@@ -1012,6 +1022,11 @@ public abstract class Page implements Cloneable
return
newPage
;
return
newPage
;
}
}
@Override
public
void
expand
(
int
keyCount
,
Object
[]
extraKys
,
Object
[]
extraValues
)
{
throw
new
UnsupportedOperationException
();
}
@Override
@Override
public
long
getTotalCount
()
{
public
long
getTotalCount
()
{
assert
!
isComplete
()
||
totalCount
==
calculateTotalCount
()
:
assert
!
isComplete
()
||
totalCount
==
calculateTotalCount
()
:
...
@@ -1324,6 +1339,21 @@ public abstract class Page implements Cloneable
...
@@ -1324,6 +1339,21 @@ public abstract class Page implements Cloneable
return
newPage
;
return
newPage
;
}
}
@Override
public
void
expand
(
int
extraKeyCount
,
Object
[]
extraKeys
,
Object
[]
extraValues
)
{
int
keyCount
=
getKeyCount
();
expandKeys
(
extraKeyCount
,
extraKeys
);
if
(
values
!=
null
)
{
Object
[]
newValues
=
createValueStorage
(
keyCount
+
extraKeyCount
);
System
.
arraycopy
(
values
,
0
,
newValues
,
0
,
keyCount
);
System
.
arraycopy
(
extraValues
,
0
,
newValues
,
keyCount
,
extraKeyCount
);
values
=
newValues
;
}
if
(
isPersistent
())
{
recalculateMemory
();
}
}
@Override
@Override
public
long
getTotalCount
()
{
public
long
getTotalCount
()
{
return
getKeyCount
();
return
getKeyCount
();
...
...
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
浏览文件 @
422f2826
...
@@ -134,7 +134,7 @@ public final class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
...
@@ -134,7 +134,7 @@ public final class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
int
attempt
=
0
;
int
attempt
=
0
;
while
(
true
)
{
while
(
true
)
{
++
attempt
;
++
attempt
;
RootReference
rootReference
=
g
etRoot
();
RootReference
rootReference
=
flushAndG
etRoot
();
Page
p
=
rootReference
.
root
.
copy
(
true
);
Page
p
=
rootReference
.
root
.
copy
(
true
);
V
result
=
operate
(
p
,
key
,
value
,
decisionMaker
);
V
result
=
operate
(
p
,
key
,
value
,
decisionMaker
);
if
(!
p
.
isLeaf
()
&&
p
.
getTotalCount
()
==
0
)
{
if
(!
p
.
isLeaf
()
&&
p
.
getTotalCount
()
==
0
)
{
...
...
h2/src/main/org/h2/mvstore/tx/Transaction.java
浏览文件 @
422f2826
...
@@ -61,7 +61,7 @@ public class Transaction {
...
@@ -61,7 +61,7 @@ public class Transaction {
*/
*/
private
static
final
int
STATUS_ROLLED_BACK
=
5
;
private
static
final
int
STATUS_ROLLED_BACK
=
5
;
private
static
final
String
STATUS_NAMES
[]
=
{
private
static
final
String
[]
STATUS_NAMES
=
{
"CLOSED"
,
"OPEN"
,
"PREPARED"
,
"COMMITTED"
,
"ROLLING_BACK"
,
"ROLLED_BACK"
"CLOSED"
,
"OPEN"
,
"PREPARED"
,
"COMMITTED"
,
"ROLLING_BACK"
,
"ROLLED_BACK"
};
};
static
final
int
LOG_ID_BITS
=
40
;
static
final
int
LOG_ID_BITS
=
40
;
...
@@ -91,7 +91,7 @@ public class Transaction {
...
@@ -91,7 +91,7 @@ public class Transaction {
/**
/**
* This is really a transaction identity, because it's not re-used.
* This is really a transaction identity, because it's not re-used.
*/
*/
public
final
long
sequenceNum
;
final
long
sequenceNum
;
/*
/*
* Transaction state is an atomic composite field:
* Transaction state is an atomic composite field:
...
@@ -138,12 +138,17 @@ public class Transaction {
...
@@ -138,12 +138,17 @@ public class Transaction {
/**
/**
* Map on which this transaction is blocked.
* Map on which this transaction is blocked.
*/
*/
MVMap
<?,
VersionedValue
>
blockingMap
;
private
MVMap
<?,
VersionedValue
>
blockingMap
;
/**
/**
* Key in blockingMap on which this transaction is blocked.
* Key in blockingMap on which this transaction is blocked.
*/
*/
Object
blockingKey
;
private
Object
blockingKey
;
/**
* Whether other transaction(s) are waiting for this to close.
*/
private
volatile
boolean
notificationRequested
;
Transaction
(
TransactionStore
store
,
int
transactionId
,
long
sequenceNum
,
int
status
,
Transaction
(
TransactionStore
store
,
int
transactionId
,
long
sequenceNum
,
int
status
,
...
@@ -237,7 +242,8 @@ public class Transaction {
...
@@ -237,7 +242,8 @@ public class Transaction {
}
}
public
int
getBlockerId
()
{
public
int
getBlockerId
()
{
return
blockingTransaction
==
null
?
0
:
blockingTransaction
.
ownerId
;
Transaction
blocker
=
this
.
blockingTransaction
;
return
blocker
==
null
?
0
:
blocker
.
ownerId
;
}
}
/**
/**
...
@@ -390,19 +396,25 @@ public class Transaction {
...
@@ -390,19 +396,25 @@ public class Transaction {
public
void
rollbackToSavepoint
(
long
savepointId
)
{
public
void
rollbackToSavepoint
(
long
savepointId
)
{
long
lastState
=
setStatus
(
STATUS_ROLLING_BACK
);
long
lastState
=
setStatus
(
STATUS_ROLLING_BACK
);
long
logId
=
getLogId
(
lastState
);
long
logId
=
getLogId
(
lastState
);
boolean
success
;
try
{
try
{
store
.
rollbackTo
(
this
,
logId
,
savepointId
);
store
.
rollbackTo
(
this
,
logId
,
savepointId
);
}
finally
{
}
finally
{
notifyAllWaitingTransactions
();
if
(
notificationRequested
)
{
notifyAllWaitingTransactions
();
}
long
expectedState
=
composeState
(
STATUS_ROLLING_BACK
,
logId
,
hasRollback
(
lastState
));
long
expectedState
=
composeState
(
STATUS_ROLLING_BACK
,
logId
,
hasRollback
(
lastState
));
long
newState
=
composeState
(
STATUS_OPEN
,
savepointId
,
true
);
long
newState
=
composeState
(
STATUS_OPEN
,
savepointId
,
true
);
if
(!
statusAndLogId
.
compareAndSet
(
expectedState
,
newState
))
{
do
{
throw
DataUtils
.
newIllegalStateException
(
success
=
statusAndLogId
.
compareAndSet
(
expectedState
,
newState
);
DataUtils
.
ERROR_TRANSACTION_ILLEGAL_STATE
,
}
while
(!
success
&&
statusAndLogId
.
get
()
==
expectedState
);
"Transaction {0} concurrently modified "
+
}
"while rollback to savepoint was in progress"
,
// this is moved outside of finally block to avert masking original exception, if any
transactionId
);
if
(!
success
)
{
}
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_TRANSACTION_ILLEGAL_STATE
,
"Transaction {0} concurrently modified while rollback to savepoint was in progress"
,
transactionId
);
}
}
}
}
...
@@ -474,7 +486,7 @@ public class Transaction {
...
@@ -474,7 +486,7 @@ public class Transaction {
void
closeIt
()
{
void
closeIt
()
{
long
lastState
=
setStatus
(
STATUS_CLOSED
);
long
lastState
=
setStatus
(
STATUS_CLOSED
);
store
.
store
.
deregisterVersionUsage
(
txCounter
);
store
.
store
.
deregisterVersionUsage
(
txCounter
);
if
(
hasChanges
(
lastState
)
||
hasRollback
(
lastState
)
)
{
if
(
(
hasChanges
(
lastState
)
||
hasRollback
(
lastState
))
&&
notificationRequested
)
{
notifyAllWaitingTransactions
();
notifyAllWaitingTransactions
();
}
}
}
}
...
@@ -483,7 +495,10 @@ public class Transaction {
...
@@ -483,7 +495,10 @@ public class Transaction {
notifyAll
();
notifyAll
();
}
}
public
boolean
waitFor
(
Transaction
toWaitFor
)
{
public
boolean
waitFor
(
Transaction
toWaitFor
,
MVMap
<?,
VersionedValue
>
map
,
Object
key
)
{
blockingTransaction
=
toWaitFor
;
blockingMap
=
map
;
blockingKey
=
key
;
if
(
isDeadlocked
(
toWaitFor
))
{
if
(
isDeadlocked
(
toWaitFor
))
{
StringBuilder
details
=
new
StringBuilder
(
StringBuilder
details
=
new
StringBuilder
(
String
.
format
(
"Transaction %d has been chosen as a deadlock victim. Details:%n"
,
transactionId
));
String
.
format
(
"Transaction %d has been chosen as a deadlock victim. Details:%n"
,
transactionId
));
...
@@ -504,7 +519,6 @@ public class Transaction {
...
@@ -504,7 +519,6 @@ public class Transaction {
}
}
}
}
blockingTransaction
=
toWaitFor
;
try
{
try
{
return
toWaitFor
.
waitForThisToEnd
(
timeoutMillis
);
return
toWaitFor
.
waitForThisToEnd
(
timeoutMillis
);
}
finally
{
}
finally
{
...
@@ -527,6 +541,7 @@ public class Transaction {
...
@@ -527,6 +541,7 @@ public class Transaction {
private
synchronized
boolean
waitForThisToEnd
(
int
millis
)
{
private
synchronized
boolean
waitForThisToEnd
(
int
millis
)
{
long
until
=
System
.
currentTimeMillis
()
+
millis
;
long
until
=
System
.
currentTimeMillis
()
+
millis
;
notificationRequested
=
true
;
long
state
;
long
state
;
int
status
;
int
status
;
while
((
status
=
getStatus
(
state
=
statusAndLogId
.
get
()))
!=
STATUS_CLOSED
while
((
status
=
getStatus
(
state
=
statusAndLogId
.
get
()))
!=
STATUS_CLOSED
...
@@ -557,8 +572,15 @@ public class Transaction {
...
@@ -557,8 +572,15 @@ public class Transaction {
@Override
@Override
public
String
toString
()
{
public
String
toString
()
{
long
state
=
statusAndLogId
.
get
();
return
transactionId
+
"("
+
sequenceNum
+
") "
+
stateToString
();
return
transactionId
+
"("
+
sequenceNum
+
") "
+
STATUS_NAMES
[
getStatus
(
state
)]
+
" "
+
getLogId
(
state
);
}
private
String
stateToString
()
{
return
stateToString
(
statusAndLogId
.
get
());
}
private
static
String
stateToString
(
long
state
)
{
return
STATUS_NAMES
[
getStatus
(
state
)]
+
(
hasRollback
(
state
)
?
"<"
:
""
)
+
" "
+
getLogId
(
state
);
}
}
...
...
h2/src/main/org/h2/mvstore/tx/TransactionMap.java
浏览文件 @
422f2826
...
@@ -46,7 +46,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -46,7 +46,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
/**
/**
* The transaction which is used for this map.
* The transaction which is used for this map.
*/
*/
final
Transaction
transaction
;
private
final
Transaction
transaction
;
TransactionMap
(
Transaction
transaction
,
MVMap
<
K
,
VersionedValue
>
map
)
{
TransactionMap
(
Transaction
transaction
,
MVMap
<
K
,
VersionedValue
>
map
)
{
this
.
transaction
=
transaction
;
this
.
transaction
=
transaction
;
...
@@ -105,16 +105,16 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -105,16 +105,16 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
long
undoLogSize
;
long
undoLogSize
;
do
{
do
{
committingTransactions
=
store
.
committingTransactions
.
get
();
committingTransactions
=
store
.
committingTransactions
.
get
();
mapRootReference
=
map
.
g
etRoot
();
mapRootReference
=
map
.
flushAndG
etRoot
();
BitSet
opentransactions
=
store
.
openTransactions
.
get
();
BitSet
opentransactions
=
store
.
openTransactions
.
get
();
undoLogRootReferences
=
new
MVMap
.
RootReference
[
opentransactions
.
length
()];
undoLogRootReferences
=
new
MVMap
.
RootReference
[
opentransactions
.
length
()];
undoLogSize
=
0
;
undoLogSize
=
0
;
for
(
int
i
=
opentransactions
.
nextSetBit
(
0
);
i
>=
0
;
i
=
opentransactions
.
nextSetBit
(
i
+
1
))
{
for
(
int
i
=
opentransactions
.
nextSetBit
(
0
);
i
>=
0
;
i
=
opentransactions
.
nextSetBit
(
i
+
1
))
{
MVMap
<
Long
,
Object
[]>
undoLog
=
store
.
undoLogs
[
i
];
MVMap
<
Long
,
Object
[]>
undoLog
=
store
.
undoLogs
[
i
];
if
(
undoLog
!=
null
)
{
if
(
undoLog
!=
null
)
{
MVMap
.
RootReference
rootReference
=
undoLog
.
g
etRoot
();
MVMap
.
RootReference
rootReference
=
undoLog
.
flushAndG
etRoot
();
undoLogRootReferences
[
i
]
=
rootReference
;
undoLogRootReferences
[
i
]
=
rootReference
;
undoLogSize
+=
rootReference
.
root
.
getTotalCount
()
+
rootReference
.
getAppendCounter
();
undoLogSize
+=
rootReference
.
getTotalCount
();
}
}
}
}
}
while
(
committingTransactions
!=
store
.
committingTransactions
.
get
()
||
}
while
(
committingTransactions
!=
store
.
committingTransactions
.
get
()
||
...
@@ -125,7 +125,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -125,7 +125,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
// should be considered as committed.
// should be considered as committed.
// Subsequent processing uses this snapshot info only.
// Subsequent processing uses this snapshot info only.
Page
mapRootPage
=
mapRootReference
.
root
;
Page
mapRootPage
=
mapRootReference
.
root
;
long
size
=
mapRoot
Pag
e
.
getTotalCount
();
long
size
=
mapRoot
Referenc
e
.
getTotalCount
();
// if we are looking at the map without any uncommitted values
// if we are looking at the map without any uncommitted values
if
(
undoLogSize
==
0
)
{
if
(
undoLogSize
==
0
)
{
return
size
;
return
size
;
...
@@ -241,6 +241,16 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -241,6 +241,16 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
return
set
(
key
,
decisionMaker
);
return
set
(
key
,
decisionMaker
);
}
}
/**
* Appends entry to uderlying map. This method may be used concurrently,
* but latest appended values are not guaranteed to be visible.
* @param key should be higher in map's order than any existing key
* @param value to be appended
*/
public
void
append
(
K
key
,
V
value
)
{
map
.
append
(
key
,
VersionedValueUncommitted
.
getInstance
(
transaction
.
log
(
map
.
getId
(),
key
,
null
),
value
,
null
));
}
/**
/**
* Lock row for the given key.
* Lock row for the given key.
* <p>
* <p>
...
@@ -298,16 +308,12 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -298,16 +308,12 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
assert
decision
!=
MVMap
.
Decision
.
REPEAT
;
assert
decision
!=
MVMap
.
Decision
.
REPEAT
;
blockingTransaction
=
decisionMaker
.
getBlockingTransaction
();
blockingTransaction
=
decisionMaker
.
getBlockingTransaction
();
if
(
decision
!=
MVMap
.
Decision
.
ABORT
||
blockingTransaction
==
null
)
{
if
(
decision
!=
MVMap
.
Decision
.
ABORT
||
blockingTransaction
==
null
)
{
transaction
.
blockingMap
=
null
;
transaction
.
blockingKey
=
null
;
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
V
res
=
result
==
null
?
null
:
(
V
)
result
.
getCurrentValue
();
V
res
=
result
==
null
?
null
:
(
V
)
result
.
getCurrentValue
();
return
res
;
return
res
;
}
}
decisionMaker
.
reset
();
decisionMaker
.
reset
();
transaction
.
blockingMap
=
map
;
}
while
(
blockingTransaction
.
sequenceNum
>
sequenceNumWhenStarted
||
transaction
.
waitFor
(
blockingTransaction
,
map
,
key
));
transaction
.
blockingKey
=
key
;
}
while
(
blockingTransaction
.
sequenceNum
>
sequenceNumWhenStarted
||
transaction
.
waitFor
(
blockingTransaction
));
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_TRANSACTION_LOCKED
,
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_TRANSACTION_LOCKED
,
"Map entry <{0}> with key <{1}> and value {2} is locked by tx {3} and can not be updated by tx {4}"
"Map entry <{0}> with key <{1}> and value {2} is locked by tx {3} and can not be updated by tx {4}"
...
@@ -669,8 +675,8 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -669,8 +675,8 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
private
final
boolean
includeAllUncommitted
;
private
final
boolean
includeAllUncommitted
;
private
X
current
;
private
X
current
;
protected
TMIterator
(
TransactionMap
<
K
,?>
transactionMap
,
K
from
,
K
to
,
boolean
includeAllUncommitted
)
{
TMIterator
(
TransactionMap
<
K
,?>
transactionMap
,
K
from
,
K
to
,
boolean
includeAllUncommitted
)
{
Transaction
transaction
=
transactionMap
.
transaction
;
Transaction
transaction
=
transactionMap
.
getTransaction
()
;
this
.
transactionId
=
transaction
.
transactionId
;
this
.
transactionId
=
transaction
.
transactionId
;
TransactionStore
store
=
transaction
.
store
;
TransactionStore
store
=
transaction
.
store
;
MVMap
<
K
,
VersionedValue
>
map
=
transactionMap
.
map
;
MVMap
<
K
,
VersionedValue
>
map
=
transactionMap
.
map
;
...
@@ -683,7 +689,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
...
@@ -683,7 +689,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
MVMap
.
RootReference
mapRootReference
;
MVMap
.
RootReference
mapRootReference
;
do
{
do
{
committingTransactions
=
store
.
committingTransactions
.
get
();
committingTransactions
=
store
.
committingTransactions
.
get
();
mapRootReference
=
map
.
g
etRoot
();
mapRootReference
=
map
.
flushAndG
etRoot
();
}
while
(
committingTransactions
!=
store
.
committingTransactions
.
get
());
}
while
(
committingTransactions
!=
store
.
committingTransactions
.
get
());
// Now we have a snapshot, where mapRootReference points to state of the map
// Now we have a snapshot, where mapRootReference points to state of the map
// and committingTransactions mask tells us which of seemingly uncommitted changes
// and committingTransactions mask tells us which of seemingly uncommitted changes
...
...
h2/src/main/org/h2/mvstore/tx/TransactionStore.java
浏览文件 @
422f2826
...
@@ -390,7 +390,7 @@ public class TransactionStore {
...
@@ -390,7 +390,7 @@ public class TransactionStore {
*/
*/
long
addUndoLogRecord
(
int
transactionId
,
long
logId
,
Object
[]
undoLogRecord
)
{
long
addUndoLogRecord
(
int
transactionId
,
long
logId
,
Object
[]
undoLogRecord
)
{
MVMap
<
Long
,
Object
[]>
undoLog
=
undoLogs
[
transactionId
];
MVMap
<
Long
,
Object
[]>
undoLog
=
undoLogs
[
transactionId
];
L
ong
undoKey
=
getOperationId
(
transactionId
,
logId
);
l
ong
undoKey
=
getOperationId
(
transactionId
,
logId
);
if
(
logId
==
0
&&
!
undoLog
.
isEmpty
())
{
if
(
logId
==
0
&&
!
undoLog
.
isEmpty
())
{
throw
DataUtils
.
newIllegalStateException
(
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_TOO_MANY_OPEN_TRANSACTIONS
,
DataUtils
.
ERROR_TOO_MANY_OPEN_TRANSACTIONS
,
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论