Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
3b75267b
提交
3b75267b
authored
10 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
MVStore: some database file could not be compacted.
上级
8829bf60
显示空白字符变更
内嵌
并排
正在显示
12 个修改的文件
包含
282 行增加
和
59 行删除
+282
-59
changelog.html
h2/src/docsrc/html/changelog.html
+3
-0
Chunk.java
h2/src/main/org/h2/mvstore/Chunk.java
+3
-0
DataUtils.java
h2/src/main/org/h2/mvstore/DataUtils.java
+1
-1
MVMap.java
h2/src/main/org/h2/mvstore/MVMap.java
+27
-9
MVStore.java
h2/src/main/org/h2/mvstore/MVStore.java
+91
-32
MVStoreTool.java
h2/src/main/org/h2/mvstore/MVStoreTool.java
+91
-3
Page.java
h2/src/main/org/h2/mvstore/Page.java
+32
-6
MVTableEngine.java
h2/src/main/org/h2/mvstore/db/MVTableEngine.java
+3
-3
TransactionStore.java
h2/src/main/org/h2/mvstore/db/TransactionStore.java
+1
-1
MVRTreeMap.java
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
+19
-2
Recover.java
h2/src/main/org/h2/tools/Recover.java
+9
-0
TestMVStore.java
h2/src/test/org/h2/test/store/TestMVStore.java
+2
-2
没有找到文件。
h2/src/docsrc/html/changelog.html
浏览文件 @
3b75267b
...
...
@@ -19,6 +19,9 @@ Change Log
<h2>
Next Version (unreleased)
</h2>
<ul><li>
Improve error message when the user specifies an unsupported combination of database settings.
</li><li>
MVStore: some database file could not be compacted due to a bug in
the bookkeeping of the fill rate. Also, database file were compacted quite slowly.
This has been improved; but more changes in this area are expected.
</li><li>
MVStore: support for volatile maps (that don't store changes).
</li><li>
MVStore mode: in-memory databases now also use the MVStore.
</li><li>
In server mode, appending ";autocommit=false" to the database URL was working,
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/Chunk.java
浏览文件 @
3b75267b
...
...
@@ -126,6 +126,9 @@ public class Chunk {
}
}
catch
(
Exception
e
)
{
// there could be various reasons
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupt reading chunk at position {0}"
,
start
,
e
);
}
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/DataUtils.java
浏览文件 @
3b75267b
...
...
@@ -871,7 +871,7 @@ public class DataUtils {
* @return the parsed value
* @throws IllegalStateException if parsing fails
*/
public
static
long
readHexLong
(
Hash
Map
<
String
,
?
extends
Object
>
map
,
public
static
long
readHexLong
(
Map
<
String
,
?
extends
Object
>
map
,
String
key
,
long
defaultValue
)
{
Object
v
=
map
.
get
(
key
);
if
(
v
==
null
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/MVMap.java
浏览文件 @
3b75267b
...
...
@@ -459,13 +459,31 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
/**
* Get
the page for the given valu
e.
* Get
a key that is referenced in the given page or a child pag
e.
*
* @param
key the key
* @return the
value
, or null if not found
* @param
p the page
* @return the
key
, or null if not found
*/
protected
Page
getPage
(
K
key
)
{
return
binarySearchPage
(
root
,
key
);
protected
K
getLiveKey
(
Page
p
)
{
while
(!
p
.
isLeaf
())
{
p
=
p
.
getLiveChildPage
(
0
);
if
(
p
==
null
)
{
return
null
;
}
}
@SuppressWarnings
(
"unchecked"
)
K
key
=
(
K
)
p
.
getKey
(
0
);
Page
p2
=
binarySearchPage
(
root
,
key
);
if
(
p2
==
null
)
{
return
null
;
}
if
(
p2
.
getPos
()
==
0
)
{
return
p2
==
p
?
key
:
null
;
}
if
(
p2
.
getPos
()
==
p
.
getPos
())
{
return
key
;
}
return
null
;
}
/**
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
3b75267b
...
...
@@ -798,6 +798,18 @@ public class MVStore {
}
}
/**
* Whether the chunk at the given position is live.
*
* @param pos the position of the page
* @return true if it is live
*/
boolean
isChunkLive
(
long
pos
)
{
int
chunkId
=
DataUtils
.
getPageChunkId
(
pos
);
String
s
=
meta
.
get
(
Chunk
.
getMetaKey
(
chunkId
));
return
s
!=
null
;
}
/**
* Get the chunk for the given position.
*
...
...
@@ -805,6 +817,17 @@ public class MVStore {
* @return the chunk
*/
private
Chunk
getChunk
(
long
pos
)
{
Chunk
c
=
getChunkIfFound
(
pos
);
if
(
c
==
null
)
{
int
chunkId
=
DataUtils
.
getPageChunkId
(
pos
);
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"Chunk {0} not found"
,
chunkId
);
}
return
c
;
}
private
Chunk
getChunkIfFound
(
long
pos
)
{
int
chunkId
=
DataUtils
.
getPageChunkId
(
pos
);
Chunk
c
=
chunks
.
get
(
chunkId
);
if
(
c
==
null
)
{
...
...
@@ -815,9 +838,7 @@ public class MVStore {
}
String
s
=
meta
.
get
(
Chunk
.
getMetaKey
(
chunkId
));
if
(
s
==
null
)
{
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"Chunk {0} not found"
,
chunkId
);
return
null
;
}
c
=
Chunk
.
fromString
(
s
);
if
(
c
.
block
==
Long
.
MAX_VALUE
)
{
...
...
@@ -1450,7 +1471,8 @@ public class MVStore {
* before calling this method.
*
* @param targetFillRate the minimum percentage of live entries
* @param minSaving the minimum amount of saved space
* @param minSaving the amount of saved space,
* which is also the size of the new chunk
* @return if a chunk was re-written
*/
public
synchronized
boolean
compact
(
int
targetFillRate
,
int
minSaving
)
{
...
...
@@ -1497,22 +1519,28 @@ public class MVStore {
Collections
.
sort
(
old
,
new
Comparator
<
Chunk
>()
{
@Override
public
int
compare
(
Chunk
o1
,
Chunk
o2
)
{
return
new
Integer
(
o1
.
collectPriority
)
.
compareTo
(
o2
.
collectPriority
);
int
comp
=
new
Integer
(
o1
.
collectPriority
).
compareTo
(
o2
.
collectPriority
);
if
(
comp
==
0
)
{
comp
=
new
Long
(
o1
.
maxLenLive
).
compareTo
(
o2
.
maxLenLive
);
}
return
comp
;
}
});
// find out up to were in the old list we need to move
long
saved
=
0
;
long
totalSize
=
0
;
Chunk
move
=
null
;
for
(
Chunk
c
:
old
)
{
long
save
=
c
.
maxLen
-
c
.
maxLenLive
;
long
size
=
c
.
maxLen
-
c
.
maxLenLive
;
totalSize
+=
c
.
maxLenLive
;
if
(
move
!=
null
)
{
if
(
saved
>
minSaving
)
{
if
(
saved
>
minSaving
&&
totalSize
>
minSaving
)
{
break
;
}
}
saved
+=
s
av
e
;
saved
+=
s
iz
e
;
move
=
c
;
}
if
(
saved
<
minSaving
)
{
...
...
@@ -1532,20 +1560,32 @@ public class MVStore {
// iterate over all the pages in the old pages
for
(
Chunk
c
:
old
)
{
copyLive
(
c
,
old
);
copyLive
(
c
);
}
commitAndSave
();
return
true
;
}
private
void
copyLive
(
Chunk
chunk
,
ArrayList
<
Chunk
>
old
)
{
private
void
copyLive
(
Chunk
chunk
)
{
if
(
chunk
.
pageCountLive
==
0
)
{
// remove this chunk in the next save operation
registerFreePage
(
currentVersion
,
chunk
.
id
,
0
,
0
);
return
;
}
long
start
=
chunk
.
block
*
BLOCK_SIZE
;
int
length
=
chunk
.
len
*
BLOCK_SIZE
;
ByteBuffer
buff
=
fileStore
.
readFully
(
start
,
length
);
Chunk
.
readChunkHeader
(
buff
,
start
);
Chunk
c
=
Chunk
.
readChunkHeader
(
buff
,
start
);
if
(
c
.
id
!=
chunk
.
id
)
{
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"Expected chunk {0}, got {1}"
,
chunk
.
id
,
c
.
id
);
}
int
pagesRemaining
=
chunk
.
pageCount
;
markMetaChanged
();
boolean
mapNotOpen
=
false
;
int
changeCount
=
0
;
while
(
pagesRemaining
--
>
0
)
{
int
offset
=
buff
.
position
();
int
pageLength
=
buff
.
getInt
();
...
...
@@ -1559,31 +1599,50 @@ public class MVStore {
@SuppressWarnings
(
"unchecked"
)
MVMap
<
Object
,
Object
>
map
=
(
MVMap
<
Object
,
Object
>)
getMap
(
mapId
);
if
(
map
==
null
)
{
// pages of maps that are not open or that have been removed
// later on are not moved (for maps that are not open, the live
// counter is not decremented, so the chunk is not removed)
boolean
mapExists
=
meta
.
containsKey
(
"root."
+
Integer
.
toHexString
(
mapId
));
if
(
mapExists
)
{
// pages of maps that were removed: the live count was
// already decremented, but maps that are not open, the
// chunk is not removed
mapNotOpen
=
true
;
}
buff
.
position
(
offset
+
pageLength
);
continue
;
}
buff
.
position
(
offset
);
Page
page
=
new
Page
(
map
,
0
);
page
.
read
(
buff
,
chunk
.
id
,
buff
.
position
(),
length
);
for
(
int
i
=
0
;
i
<
page
.
getKeyCount
();
i
++)
{
Object
k
=
page
.
getKey
(
i
);
Page
p
=
map
.
getPage
(
k
);
if
(
p
==
null
)
{
// was removed later - ignore
// or the chunk no longer exists
}
else
if
(
p
.
getPos
()
==
0
)
{
// temporarily changed - ok
// TODO move old data if there is an uncommitted change?
}
else
{
Chunk
c
=
getChunk
(
p
.
getPos
());
if
(
old
.
contains
(
c
))
{
int
type
=
page
.
isLeaf
()
?
0
:
1
;
long
pos
=
DataUtils
.
getPagePos
(
chunk
.
id
,
offset
,
pageLength
,
type
);
page
.
setPos
(
pos
);
Object
k
=
map
.
getLiveKey
(
page
);
if
(
k
!=
null
)
{
Object
value
=
map
.
remove
(
k
);
if
(
value
!=
null
)
{
map
.
put
(
k
,
value
);
changeCount
++;
}
}
}
if
(!
mapNotOpen
&&
changeCount
==
0
)
{
// if all maps are open, but no changes were made,
// then live bookkeeping is wrong, and we anyway
// remove the chunk
// (but we first need to check that there are no
// pending changes)
for
(
HashMap
<
Integer
,
Chunk
>
e
:
freedPageSpace
.
values
())
{
for
(
int
x
:
e
.
keySet
())
{
if
(
x
==
chunk
.
id
)
{
changeCount
++;
break
;
}
}
}
if
(
changeCount
==
0
)
{
// bookkeeping is broken for this chunk:
// fix it
registerFreePage
(
currentVersion
,
chunk
.
id
,
chunk
.
maxLenLive
,
chunk
.
pageCountLive
);
}
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/MVStoreTool.java
浏览文件 @
3b75267b
...
...
@@ -11,9 +11,14 @@ import java.io.PrintWriter;
import
java.io.Writer
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.sql.Timestamp
;
import
java.util.Map
;
import
java.util.Map.Entry
;
import
java.util.TreeMap
;
import
org.h2.mvstore.type.StringDataType
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FileUtils
;
/**
* Utility methods used in combination with the MVStore.
...
...
@@ -24,8 +29,10 @@ public class MVStoreTool {
* Runs this tool.
* Options are case sensitive. Supported options are:
* <table>
* <tr><td>[-dump <
dir
>]</td>
* <tr><td>[-dump <
fileName
>]</td>
* <td>Dump the contends of the file</td></tr>
* <tr><td>[-info <fileName>]</td>
* <td>Get summary information about a file</td></tr>
* </table>
*
* @param args the command line arguments
...
...
@@ -35,6 +42,9 @@ public class MVStoreTool {
if
(
"-dump"
.
equals
(
args
[
i
]))
{
String
fileName
=
args
[++
i
];
dump
(
fileName
,
new
PrintWriter
(
System
.
out
));
}
else
if
(
"-info"
.
equals
(
args
[
i
]))
{
String
fileName
=
args
[++
i
];
info
(
fileName
,
new
PrintWriter
(
System
.
out
));
}
}
}
...
...
@@ -48,6 +58,15 @@ public class MVStoreTool {
dump
(
fileName
,
new
PrintWriter
(
System
.
out
));
}
/**
* Read the summary information of the file and write them to system out.
*
* @param fileName the name of the file
*/
public
static
void
info
(
String
fileName
)
{
info
(
fileName
,
new
PrintWriter
(
System
.
out
));
}
/**
* Read the contents of the file and display them in a human-readable
* format.
...
...
@@ -85,7 +104,13 @@ public class MVStoreTool {
continue
;
}
block
.
position
(
0
);
Chunk
c
=
Chunk
.
readChunkHeader
(
block
,
pos
);
Chunk
c
=
null
;
try
{
c
=
Chunk
.
readChunkHeader
(
block
,
pos
);
}
catch
(
IllegalStateException
e
)
{
pos
+=
blockSize
;
continue
;
}
int
length
=
c
.
len
*
MVStore
.
BLOCK_SIZE
;
pw
.
printf
(
"%n%0"
+
len
+
"x chunkHeader %s%n"
,
pos
,
c
.
toString
());
...
...
@@ -152,7 +177,7 @@ public class MVStoreTool {
pw
.
printf
(
" %d children >= %s @ chunk %x +%0"
+
len
+
"x%n"
,
counts
[
entries
],
keys
[
entries
],
keys
.
length
>=
entries
?
null
:
keys
[
entries
],
DataUtils
.
getPageChunkId
(
cp
),
DataUtils
.
getPageOffset
(
cp
));
}
else
if
(!
compressed
)
{
...
...
@@ -204,4 +229,67 @@ public class MVStoreTool {
pw
.
flush
();
}
/**
* Read the summary information of the file and write them to system out.
*
* @param fileName the name of the file
* @param writer the print writer
*/
public
static
void
info
(
String
fileName
,
Writer
writer
)
{
PrintWriter
pw
=
new
PrintWriter
(
writer
,
true
);
if
(!
FilePath
.
get
(
fileName
).
exists
())
{
pw
.
println
(
"File not found: "
+
fileName
);
return
;
}
long
fileLength
=
FileUtils
.
size
(
fileName
);
MVStore
store
=
new
MVStore
.
Builder
().
fileName
(
fileName
).
readOnly
().
open
();
try
{
MVMap
<
String
,
String
>
meta
=
store
.
getMetaMap
();
Map
<
String
,
Object
>
header
=
store
.
getStoreHeader
();
long
fileCreated
=
DataUtils
.
readHexLong
(
header
,
"created"
,
0L
);
TreeMap
<
Integer
,
Chunk
>
chunks
=
new
TreeMap
<
Integer
,
Chunk
>();
long
chunkLength
=
0
;
long
maxLength
=
0
;
long
maxLengthLive
=
0
;
for
(
Entry
<
String
,
String
>
e
:
meta
.
entrySet
())
{
String
k
=
e
.
getKey
();
if
(
k
.
startsWith
(
"chunk."
))
{
Chunk
c
=
Chunk
.
fromString
(
e
.
getValue
());
chunks
.
put
(
c
.
id
,
c
);
chunkLength
+=
c
.
len
*
MVStore
.
BLOCK_SIZE
;
maxLength
+=
c
.
maxLen
;
maxLengthLive
+=
c
.
maxLenLive
;
}
}
pw
.
printf
(
"Created: %s\n"
,
formatTimestamp
(
fileCreated
));
pw
.
printf
(
"File length: %d\n"
,
fileLength
);
pw
.
printf
(
"Chunk length: %d\n"
,
chunkLength
);
pw
.
printf
(
"Chunk count: %d\n"
,
chunks
.
size
());
pw
.
printf
(
"Used space: %d%%\n"
,
100
*
chunkLength
/
fileLength
);
pw
.
printf
(
"Chunk fill rate: %d%%\n"
,
100
*
maxLengthLive
/
maxLength
);
for
(
Entry
<
Integer
,
Chunk
>
e
:
chunks
.
entrySet
())
{
Chunk
c
=
e
.
getValue
();
long
created
=
fileCreated
+
c
.
time
;
pw
.
printf
(
" Chunk %d: %s, %d%% used, %d blocks\n"
,
c
.
id
,
formatTimestamp
(
created
),
100
*
c
.
maxLenLive
/
c
.
maxLen
,
c
.
len
);
}
}
catch
(
Exception
e
)
{
pw
.
println
(
"ERROR: "
+
e
);
e
.
printStackTrace
(
pw
);
}
finally
{
store
.
close
();
}
pw
.
flush
();
}
private
static
String
formatTimestamp
(
long
t
)
{
String
x
=
new
Timestamp
(
t
).
toString
();
return
x
.
substring
(
0
,
19
);
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/Page.java
浏览文件 @
3b75267b
...
...
@@ -222,6 +222,24 @@ public class Page {
return
p
!=
null
?
p
:
map
.
readPage
(
children
[
index
]);
}
/**
* Get the child page at the given index, if it is live.
*
* @param index the child index
* @return the page, or null if the chunk is not live
*/
public
Page
getLiveChildPage
(
int
index
)
{
Page
p
=
childrenPages
[
index
];
if
(
p
!=
null
)
{
return
p
;
}
long
pos
=
children
[
index
];
if
(!
map
.
store
.
isChunkLive
(
pos
))
{
return
null
;
}
return
getChildPage
(
index
);
}
/**
* Get the value at the given index.
*
...
...
@@ -264,6 +282,10 @@ public class Page {
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
"id: "
).
append
(
System
.
identityHashCode
(
this
)).
append
(
'\n'
);
buff
.
append
(
"pos: "
).
append
(
Long
.
toHexString
(
pos
)).
append
(
"\n"
);
if
(
pos
!=
0
)
{
int
chunkId
=
DataUtils
.
getPageChunkId
(
pos
);
buff
.
append
(
"chunk: "
).
append
(
Long
.
toHexString
(
chunkId
)).
append
(
"\n"
);
}
for
(
int
i
=
0
;
i
<=
keyCount
;
i
++)
{
if
(
i
>
0
)
{
buff
.
append
(
" "
);
...
...
@@ -734,16 +756,16 @@ public class Page {
if
(
pageLength
>
maxLength
)
{
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupted
, expected page length =< {0}, got {1
}"
,
maxLength
,
pageLength
);
"File corrupted
in chunk {0}, expected page length =< {1}, got {2
}"
,
chunkId
,
maxLength
,
pageLength
);
}
short
check
=
buff
.
getShort
();
int
mapId
=
DataUtils
.
readVarInt
(
buff
);
if
(
mapId
!=
map
.
getId
())
{
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupted
, expected map id {0}, got {1
}"
,
map
.
getId
(),
mapId
);
"File corrupted
in chunk {0}, expected map id {1}, got {2
}"
,
chunkId
,
map
.
getId
(),
mapId
);
}
int
checkTest
=
DataUtils
.
getCheckValue
(
chunkId
)
^
DataUtils
.
getCheckValue
(
offset
)
...
...
@@ -751,8 +773,8 @@ public class Page {
if
(
check
!=
(
short
)
checkTest
)
{
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupted
, expected check value {0}, got {1
}"
,
checkTest
,
check
);
"File corrupted
in chunk {0}, expected check value {1}, got {2
}"
,
ch
unkId
,
ch
eckTest
,
check
);
}
int
len
=
DataUtils
.
readVarInt
(
buff
);
keys
=
new
Object
[
len
];
...
...
@@ -1007,4 +1029,8 @@ public class Page {
map
.
removePage
(
pos
,
memory
);
}
public
void
setPos
(
long
pos
)
{
this
.
pos
=
pos
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/db/MVTableEngine.java
浏览文件 @
3b75267b
...
...
@@ -191,7 +191,7 @@ public class MVTableEngine implements TableEngine {
if
(
s
==
null
||
s
.
isReadOnly
())
{
return
;
}
if
(!
store
.
compact
(
50
,
1024
*
1024
))
{
if
(!
store
.
compact
(
50
,
4
*
1024
*
1024
))
{
store
.
commit
();
}
}
...
...
@@ -297,7 +297,7 @@ public class MVTableEngine implements TableEngine {
public
void
compactFile
(
long
maxCompactTime
)
{
store
.
setRetentionTime
(
0
);
long
start
=
System
.
currentTimeMillis
();
while
(
store
.
compact
(
99
,
16
*
1024
))
{
while
(
store
.
compact
(
99
,
4
*
1024
*
1024
))
{
store
.
sync
();
long
time
=
System
.
currentTimeMillis
()
-
start
;
if
(
time
>
maxCompactTime
)
{
...
...
@@ -320,7 +320,7 @@ public class MVTableEngine implements TableEngine {
if
(!
store
.
getFileStore
().
isReadOnly
())
{
transactionStore
.
close
();
long
start
=
System
.
currentTimeMillis
();
while
(
store
.
compact
(
90
,
32
*
1024
))
{
while
(
store
.
compact
(
90
,
4
*
1024
*
1024
))
{
long
time
=
System
.
currentTimeMillis
()
-
start
;
if
(
time
>
maxCompactTime
)
{
break
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/db/TransactionStore.java
浏览文件 @
3b75267b
...
...
@@ -24,7 +24,7 @@ import org.h2.mvstore.type.ObjectDataType;
import
org.h2.util.New
;
/**
* A store that supports concurrent transactions.
* A store that supports concurrent
MVCC read-committed
transactions.
*/
public
class
TransactionStore
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
浏览文件 @
3b75267b
...
...
@@ -122,8 +122,25 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
}
@Override
protected
Page
getPage
(
SpatialKey
key
)
{
return
getPage
(
root
,
key
);
protected
SpatialKey
getLiveKey
(
Page
p
)
{
while
(!
p
.
isLeaf
())
{
p
=
p
.
getLiveChildPage
(
0
);
if
(
p
==
null
)
{
return
null
;
}
}
SpatialKey
key
=
(
SpatialKey
)
p
.
getKey
(
0
);
Page
p2
=
getPage
(
root
,
key
);
if
(
p2
==
null
)
{
return
null
;
}
if
(
p2
.
getPos
()
==
0
)
{
return
p2
==
p
?
key
:
null
;
}
if
(
p2
.
getPos
()
==
p
.
getPos
())
{
return
key
;
}
return
null
;
}
private
Page
getPage
(
Page
p
,
Object
key
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/tools/Recover.java
浏览文件 @
3b75267b
...
...
@@ -585,6 +585,8 @@ public class Recover extends Tool implements DataHandler {
Constants
.
SUFFIX_MV_FILE
.
length
()));
MVStore
mv
=
new
MVStore
.
Builder
().
fileName
(
fileName
).
readOnly
().
open
();
dumpLobMaps
(
writer
,
mv
);
writer
.
println
(
"-- Meta"
);
dumpMeta
(
writer
,
mv
);
writer
.
println
(
"-- Tables"
);
TransactionStore
store
=
new
TransactionStore
(
mv
);
try
{
...
...
@@ -654,6 +656,13 @@ public class Recover extends Tool implements DataHandler {
}
}
private
static
void
dumpMeta
(
PrintWriter
writer
,
MVStore
mv
)
{
MVMap
<
String
,
String
>
meta
=
mv
.
getMetaMap
();
for
(
Entry
<
String
,
String
>
e
:
meta
.
entrySet
())
{
writer
.
println
(
"-- "
+
e
.
getKey
()
+
" = "
+
e
.
getValue
());
}
}
private
void
dumpLobMaps
(
PrintWriter
writer
,
MVStore
mv
)
{
lobMaps
=
mv
.
hasMap
(
"lobData"
);
if
(!
lobMaps
)
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
3b75267b
...
...
@@ -1673,7 +1673,7 @@ public class TestMVStore extends TestBase {
m
=
s
.
openMap
(
"data"
);
assertTrue
(
s
.
compact
(
80
,
16
*
1024
));
assert
Tru
e
(
s
.
compact
(
80
,
1024
));
assert
Fals
e
(
s
.
compact
(
80
,
1024
));
int
chunkCount3
=
0
;
for
(
String
k
:
meta
.
keySet
())
{
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论