Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
3b75267b
提交
3b75267b
authored
4月 23, 2014
作者:
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
...
@@ -19,6 +19,9 @@ Change Log
<h2>
Next Version (unreleased)
</h2>
<h2>
Next Version (unreleased)
</h2>
<ul><li>
Improve error message when the user specifies an unsupported combination of database settings.
<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: support for volatile maps (that don't store changes).
</li><li>
MVStore mode: in-memory databases now also use the MVStore.
</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,
</li><li>
In server mode, appending ";autocommit=false" to the database URL was working,
...
...
h2/src/main/org/h2/mvstore/Chunk.java
浏览文件 @
3b75267b
...
@@ -126,6 +126,9 @@ public class Chunk {
...
@@ -126,6 +126,9 @@ public class Chunk {
}
}
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
// there could be various reasons
// there could be various reasons
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupt reading chunk at position {0}"
,
start
,
e
);
}
}
throw
DataUtils
.
newIllegalStateException
(
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
DataUtils
.
ERROR_FILE_CORRUPT
,
...
...
h2/src/main/org/h2/mvstore/DataUtils.java
浏览文件 @
3b75267b
...
@@ -871,7 +871,7 @@ public class DataUtils {
...
@@ -871,7 +871,7 @@ public class DataUtils {
* @return the parsed value
* @return the parsed value
* @throws IllegalStateException if parsing fails
* @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
)
{
String
key
,
long
defaultValue
)
{
Object
v
=
map
.
get
(
key
);
Object
v
=
map
.
get
(
key
);
if
(
v
==
null
)
{
if
(
v
==
null
)
{
...
...
h2/src/main/org/h2/mvstore/MVMap.java
浏览文件 @
3b75267b
...
@@ -459,13 +459,31 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -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
* @param
p the page
* @return the
value
, or null if not found
* @return the
key
, or null if not found
*/
*/
protected
Page
getPage
(
K
key
)
{
protected
K
getLiveKey
(
Page
p
)
{
return
binarySearchPage
(
root
,
key
);
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
;
}
}
/**
/**
...
@@ -917,7 +935,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -917,7 +935,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public
boolean
isReadOnly
()
{
public
boolean
isReadOnly
()
{
return
readOnly
;
return
readOnly
;
}
}
/**
/**
* Set the volatile flag of the map.
* Set the volatile flag of the map.
*
*
...
@@ -926,12 +944,12 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -926,12 +944,12 @@ public class MVMap<K, V> extends AbstractMap<K, V>
public
void
setVolatile
(
boolean
isVolatile
)
{
public
void
setVolatile
(
boolean
isVolatile
)
{
this
.
isVolatile
=
isVolatile
;
this
.
isVolatile
=
isVolatile
;
}
}
/**
/**
* Whether this is volatile map, meaning that changes
* Whether this is volatile map, meaning that changes
* are not persisted. By default (even if the store is not persisted),
* are not persisted. By default (even if the store is not persisted),
* maps are not volatile.
* maps are not volatile.
*
*
* @return whether this map is volatile
* @return whether this map is volatile
*/
*/
public
boolean
isVolatile
()
{
public
boolean
isVolatile
()
{
...
@@ -1166,7 +1184,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
...
@@ -1166,7 +1184,7 @@ public class MVMap<K, V> extends AbstractMap<K, V>
}
}
return
buff
.
toString
();
return
buff
.
toString
();
}
}
void
setWriteVersion
(
long
writeVersion
)
{
void
setWriteVersion
(
long
writeVersion
)
{
this
.
writeVersion
=
writeVersion
;
this
.
writeVersion
=
writeVersion
;
}
}
...
...
h2/src/main/org/h2/mvstore/MVStore.java
浏览文件 @
3b75267b
...
@@ -108,8 +108,8 @@ MVStore:
...
@@ -108,8 +108,8 @@ MVStore:
- test chunk id rollover
- test chunk id rollover
- feature to auto-compact from time to time and on close
- feature to auto-compact from time to time and on close
- compact very small chunks
- compact very small chunks
- Page: to save memory, combine keys & values into one array
- Page: to save memory, combine keys & values into one array
(also children & counts). Maybe remove some other
(also children & counts). Maybe remove some other
fields (childrenCount for example)
fields (childrenCount for example)
*/
*/
...
@@ -798,6 +798,18 @@ public class MVStore {
...
@@ -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.
* Get the chunk for the given position.
*
*
...
@@ -805,6 +817,17 @@ public class MVStore {
...
@@ -805,6 +817,17 @@ public class MVStore {
* @return the chunk
* @return the chunk
*/
*/
private
Chunk
getChunk
(
long
pos
)
{
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
);
int
chunkId
=
DataUtils
.
getPageChunkId
(
pos
);
Chunk
c
=
chunks
.
get
(
chunkId
);
Chunk
c
=
chunks
.
get
(
chunkId
);
if
(
c
==
null
)
{
if
(
c
==
null
)
{
...
@@ -815,9 +838,7 @@ public class MVStore {
...
@@ -815,9 +838,7 @@ public class MVStore {
}
}
String
s
=
meta
.
get
(
Chunk
.
getMetaKey
(
chunkId
));
String
s
=
meta
.
get
(
Chunk
.
getMetaKey
(
chunkId
));
if
(
s
==
null
)
{
if
(
s
==
null
)
{
throw
DataUtils
.
newIllegalStateException
(
return
null
;
DataUtils
.
ERROR_FILE_CORRUPT
,
"Chunk {0} not found"
,
chunkId
);
}
}
c
=
Chunk
.
fromString
(
s
);
c
=
Chunk
.
fromString
(
s
);
if
(
c
.
block
==
Long
.
MAX_VALUE
)
{
if
(
c
.
block
==
Long
.
MAX_VALUE
)
{
...
@@ -1450,7 +1471,8 @@ public class MVStore {
...
@@ -1450,7 +1471,8 @@ public class MVStore {
* before calling this method.
* before calling this method.
*
*
* @param targetFillRate the minimum percentage of live entries
* @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
* @return if a chunk was re-written
*/
*/
public
synchronized
boolean
compact
(
int
targetFillRate
,
int
minSaving
)
{
public
synchronized
boolean
compact
(
int
targetFillRate
,
int
minSaving
)
{
...
@@ -1497,22 +1519,28 @@ public class MVStore {
...
@@ -1497,22 +1519,28 @@ public class MVStore {
Collections
.
sort
(
old
,
new
Comparator
<
Chunk
>()
{
Collections
.
sort
(
old
,
new
Comparator
<
Chunk
>()
{
@Override
@Override
public
int
compare
(
Chunk
o1
,
Chunk
o2
)
{
public
int
compare
(
Chunk
o1
,
Chunk
o2
)
{
return
new
Integer
(
o1
.
collectPriority
)
int
comp
=
new
Integer
(
o1
.
collectPriority
).
.
compareTo
(
o2
.
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
// find out up to were in the old list we need to move
long
saved
=
0
;
long
saved
=
0
;
long
totalSize
=
0
;
Chunk
move
=
null
;
Chunk
move
=
null
;
for
(
Chunk
c
:
old
)
{
for
(
Chunk
c
:
old
)
{
long
save
=
c
.
maxLen
-
c
.
maxLenLive
;
long
size
=
c
.
maxLen
-
c
.
maxLenLive
;
totalSize
+=
c
.
maxLenLive
;
if
(
move
!=
null
)
{
if
(
move
!=
null
)
{
if
(
saved
>
minSaving
)
{
if
(
saved
>
minSaving
&&
totalSize
>
minSaving
)
{
break
;
break
;
}
}
}
}
saved
+=
s
av
e
;
saved
+=
s
iz
e
;
move
=
c
;
move
=
c
;
}
}
if
(
saved
<
minSaving
)
{
if
(
saved
<
minSaving
)
{
...
@@ -1532,20 +1560,32 @@ public class MVStore {
...
@@ -1532,20 +1560,32 @@ public class MVStore {
// iterate over all the pages in the old pages
// iterate over all the pages in the old pages
for
(
Chunk
c
:
old
)
{
for
(
Chunk
c
:
old
)
{
copyLive
(
c
,
old
);
copyLive
(
c
);
}
}
commitAndSave
();
commitAndSave
();
return
true
;
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
;
long
start
=
chunk
.
block
*
BLOCK_SIZE
;
int
length
=
chunk
.
len
*
BLOCK_SIZE
;
int
length
=
chunk
.
len
*
BLOCK_SIZE
;
ByteBuffer
buff
=
fileStore
.
readFully
(
start
,
length
);
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
;
int
pagesRemaining
=
chunk
.
pageCount
;
markMetaChanged
();
markMetaChanged
();
boolean
mapNotOpen
=
false
;
int
changeCount
=
0
;
while
(
pagesRemaining
--
>
0
)
{
while
(
pagesRemaining
--
>
0
)
{
int
offset
=
buff
.
position
();
int
offset
=
buff
.
position
();
int
pageLength
=
buff
.
getInt
();
int
pageLength
=
buff
.
getInt
();
...
@@ -1559,32 +1599,51 @@ public class MVStore {
...
@@ -1559,32 +1599,51 @@ public class MVStore {
@SuppressWarnings
(
"unchecked"
)
@SuppressWarnings
(
"unchecked"
)
MVMap
<
Object
,
Object
>
map
=
(
MVMap
<
Object
,
Object
>)
getMap
(
mapId
);
MVMap
<
Object
,
Object
>
map
=
(
MVMap
<
Object
,
Object
>)
getMap
(
mapId
);
if
(
map
==
null
)
{
if
(
map
==
null
)
{
// pages of maps that are not open or that have been removed
boolean
mapExists
=
meta
.
containsKey
(
"root."
+
Integer
.
toHexString
(
mapId
));
// later on are not moved (for maps that are not open, the live
if
(
mapExists
)
{
// counter is not decremented, so the chunk is not removed)
// 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
);
buff
.
position
(
offset
+
pageLength
);
continue
;
continue
;
}
}
buff
.
position
(
offset
);
buff
.
position
(
offset
);
Page
page
=
new
Page
(
map
,
0
);
Page
page
=
new
Page
(
map
,
0
);
page
.
read
(
buff
,
chunk
.
id
,
buff
.
position
(),
length
);
page
.
read
(
buff
,
chunk
.
id
,
buff
.
position
(),
length
);
for
(
int
i
=
0
;
i
<
page
.
getKeyCount
();
i
++)
{
int
type
=
page
.
isLeaf
()
?
0
:
1
;
Object
k
=
page
.
getKey
(
i
);
long
pos
=
DataUtils
.
getPagePos
(
chunk
.
id
,
offset
,
pageLength
,
type
);
Page
p
=
map
.
getPage
(
k
);
page
.
setPos
(
pos
);
if
(
p
==
null
)
{
Object
k
=
map
.
getLiveKey
(
page
);
// was removed later - ignore
if
(
k
!=
null
)
{
// or the chunk no longer exists
Object
value
=
map
.
remove
(
k
);
}
else
if
(
p
.
getPos
()
==
0
)
{
if
(
value
!=
null
)
{
// temporarily changed - ok
map
.
put
(
k
,
value
);
// TODO move old data if there is an uncommitted change?
changeCount
++;
}
else
{
}
Chunk
c
=
getChunk
(
p
.
getPos
());
}
if
(
old
.
contains
(
c
))
{
}
Object
value
=
map
.
remove
(
k
);
if
(!
mapNotOpen
&&
changeCount
==
0
)
{
map
.
put
(
k
,
value
);
// 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
);
}
}
}
}
}
...
...
h2/src/main/org/h2/mvstore/MVStoreTool.java
浏览文件 @
3b75267b
...
@@ -11,9 +11,14 @@ import java.io.PrintWriter;
...
@@ -11,9 +11,14 @@ import java.io.PrintWriter;
import
java.io.Writer
;
import
java.io.Writer
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
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.mvstore.type.StringDataType
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FilePath
;
import
org.h2.store.fs.FileUtils
;
/**
/**
* Utility methods used in combination with the MVStore.
* Utility methods used in combination with the MVStore.
...
@@ -24,8 +29,10 @@ public class MVStoreTool {
...
@@ -24,8 +29,10 @@ public class MVStoreTool {
* Runs this tool.
* Runs this tool.
* Options are case sensitive. Supported options are:
* Options are case sensitive. Supported options are:
* <table>
* <table>
* <tr><td>[-dump <
dir
>]</td>
* <tr><td>[-dump <
fileName
>]</td>
* <td>Dump the contends of the file</td></tr>
* <td>Dump the contends of the file</td></tr>
* <tr><td>[-info <fileName>]</td>
* <td>Get summary information about a file</td></tr>
* </table>
* </table>
*
*
* @param args the command line arguments
* @param args the command line arguments
...
@@ -35,6 +42,9 @@ public class MVStoreTool {
...
@@ -35,6 +42,9 @@ public class MVStoreTool {
if
(
"-dump"
.
equals
(
args
[
i
]))
{
if
(
"-dump"
.
equals
(
args
[
i
]))
{
String
fileName
=
args
[++
i
];
String
fileName
=
args
[++
i
];
dump
(
fileName
,
new
PrintWriter
(
System
.
out
));
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 {
...
@@ -48,6 +58,15 @@ public class MVStoreTool {
dump
(
fileName
,
new
PrintWriter
(
System
.
out
));
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
* Read the contents of the file and display them in a human-readable
* format.
* format.
...
@@ -85,7 +104,13 @@ public class MVStoreTool {
...
@@ -85,7 +104,13 @@ public class MVStoreTool {
continue
;
continue
;
}
}
block
.
position
(
0
);
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
;
int
length
=
c
.
len
*
MVStore
.
BLOCK_SIZE
;
pw
.
printf
(
"%n%0"
+
len
+
"x chunkHeader %s%n"
,
pw
.
printf
(
"%n%0"
+
len
+
"x chunkHeader %s%n"
,
pos
,
c
.
toString
());
pos
,
c
.
toString
());
...
@@ -152,7 +177,7 @@ public class MVStoreTool {
...
@@ -152,7 +177,7 @@ public class MVStoreTool {
pw
.
printf
(
" %d children >= %s @ chunk %x +%0"
+
pw
.
printf
(
" %d children >= %s @ chunk %x +%0"
+
len
+
"x%n"
,
len
+
"x%n"
,
counts
[
entries
],
counts
[
entries
],
keys
[
entries
],
keys
.
length
>=
entries
?
null
:
keys
[
entries
],
DataUtils
.
getPageChunkId
(
cp
),
DataUtils
.
getPageChunkId
(
cp
),
DataUtils
.
getPageOffset
(
cp
));
DataUtils
.
getPageOffset
(
cp
));
}
else
if
(!
compressed
)
{
}
else
if
(!
compressed
)
{
...
@@ -204,4 +229,67 @@ public class MVStoreTool {
...
@@ -204,4 +229,67 @@ public class MVStoreTool {
pw
.
flush
();
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
);
}
}
}
h2/src/main/org/h2/mvstore/Page.java
浏览文件 @
3b75267b
...
@@ -222,6 +222,24 @@ public class Page {
...
@@ -222,6 +222,24 @@ public class Page {
return
p
!=
null
?
p
:
map
.
readPage
(
children
[
index
]);
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.
* Get the value at the given index.
*
*
...
@@ -264,6 +282,10 @@ public class Page {
...
@@ -264,6 +282,10 @@ public class Page {
StringBuilder
buff
=
new
StringBuilder
();
StringBuilder
buff
=
new
StringBuilder
();
buff
.
append
(
"id: "
).
append
(
System
.
identityHashCode
(
this
)).
append
(
'\n'
);
buff
.
append
(
"id: "
).
append
(
System
.
identityHashCode
(
this
)).
append
(
'\n'
);
buff
.
append
(
"pos: "
).
append
(
Long
.
toHexString
(
pos
)).
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
++)
{
for
(
int
i
=
0
;
i
<=
keyCount
;
i
++)
{
if
(
i
>
0
)
{
if
(
i
>
0
)
{
buff
.
append
(
" "
);
buff
.
append
(
" "
);
...
@@ -734,16 +756,16 @@ public class Page {
...
@@ -734,16 +756,16 @@ public class Page {
if
(
pageLength
>
maxLength
)
{
if
(
pageLength
>
maxLength
)
{
throw
DataUtils
.
newIllegalStateException
(
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupted
, expected page length =< {0}, got {1
}"
,
"File corrupted
in chunk {0}, expected page length =< {1}, got {2
}"
,
maxLength
,
pageLength
);
chunkId
,
maxLength
,
pageLength
);
}
}
short
check
=
buff
.
getShort
();
short
check
=
buff
.
getShort
();
int
mapId
=
DataUtils
.
readVarInt
(
buff
);
int
mapId
=
DataUtils
.
readVarInt
(
buff
);
if
(
mapId
!=
map
.
getId
())
{
if
(
mapId
!=
map
.
getId
())
{
throw
DataUtils
.
newIllegalStateException
(
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupted
, expected map id {0}, got {1
}"
,
"File corrupted
in chunk {0}, expected map id {1}, got {2
}"
,
map
.
getId
(),
mapId
);
chunkId
,
map
.
getId
(),
mapId
);
}
}
int
checkTest
=
DataUtils
.
getCheckValue
(
chunkId
)
int
checkTest
=
DataUtils
.
getCheckValue
(
chunkId
)
^
DataUtils
.
getCheckValue
(
offset
)
^
DataUtils
.
getCheckValue
(
offset
)
...
@@ -751,8 +773,8 @@ public class Page {
...
@@ -751,8 +773,8 @@ public class Page {
if
(
check
!=
(
short
)
checkTest
)
{
if
(
check
!=
(
short
)
checkTest
)
{
throw
DataUtils
.
newIllegalStateException
(
throw
DataUtils
.
newIllegalStateException
(
DataUtils
.
ERROR_FILE_CORRUPT
,
DataUtils
.
ERROR_FILE_CORRUPT
,
"File corrupted
, expected check value {0}, got {1
}"
,
"File corrupted
in chunk {0}, expected check value {1}, got {2
}"
,
checkTest
,
check
);
ch
unkId
,
ch
eckTest
,
check
);
}
}
int
len
=
DataUtils
.
readVarInt
(
buff
);
int
len
=
DataUtils
.
readVarInt
(
buff
);
keys
=
new
Object
[
len
];
keys
=
new
Object
[
len
];
...
@@ -1007,4 +1029,8 @@ public class Page {
...
@@ -1007,4 +1029,8 @@ public class Page {
map
.
removePage
(
pos
,
memory
);
map
.
removePage
(
pos
,
memory
);
}
}
public
void
setPos
(
long
pos
)
{
this
.
pos
=
pos
;
}
}
}
h2/src/main/org/h2/mvstore/db/MVTableEngine.java
浏览文件 @
3b75267b
...
@@ -191,7 +191,7 @@ public class MVTableEngine implements TableEngine {
...
@@ -191,7 +191,7 @@ public class MVTableEngine implements TableEngine {
if
(
s
==
null
||
s
.
isReadOnly
())
{
if
(
s
==
null
||
s
.
isReadOnly
())
{
return
;
return
;
}
}
if
(!
store
.
compact
(
50
,
1024
*
1024
))
{
if
(!
store
.
compact
(
50
,
4
*
1024
*
1024
))
{
store
.
commit
();
store
.
commit
();
}
}
}
}
...
@@ -297,7 +297,7 @@ public class MVTableEngine implements TableEngine {
...
@@ -297,7 +297,7 @@ public class MVTableEngine implements TableEngine {
public
void
compactFile
(
long
maxCompactTime
)
{
public
void
compactFile
(
long
maxCompactTime
)
{
store
.
setRetentionTime
(
0
);
store
.
setRetentionTime
(
0
);
long
start
=
System
.
currentTimeMillis
();
long
start
=
System
.
currentTimeMillis
();
while
(
store
.
compact
(
99
,
16
*
1024
))
{
while
(
store
.
compact
(
99
,
4
*
1024
*
1024
))
{
store
.
sync
();
store
.
sync
();
long
time
=
System
.
currentTimeMillis
()
-
start
;
long
time
=
System
.
currentTimeMillis
()
-
start
;
if
(
time
>
maxCompactTime
)
{
if
(
time
>
maxCompactTime
)
{
...
@@ -320,7 +320,7 @@ public class MVTableEngine implements TableEngine {
...
@@ -320,7 +320,7 @@ public class MVTableEngine implements TableEngine {
if
(!
store
.
getFileStore
().
isReadOnly
())
{
if
(!
store
.
getFileStore
().
isReadOnly
())
{
transactionStore
.
close
();
transactionStore
.
close
();
long
start
=
System
.
currentTimeMillis
();
long
start
=
System
.
currentTimeMillis
();
while
(
store
.
compact
(
90
,
32
*
1024
))
{
while
(
store
.
compact
(
90
,
4
*
1024
*
1024
))
{
long
time
=
System
.
currentTimeMillis
()
-
start
;
long
time
=
System
.
currentTimeMillis
()
-
start
;
if
(
time
>
maxCompactTime
)
{
if
(
time
>
maxCompactTime
)
{
break
;
break
;
...
...
h2/src/main/org/h2/mvstore/db/TransactionStore.java
浏览文件 @
3b75267b
...
@@ -24,7 +24,7 @@ import org.h2.mvstore.type.ObjectDataType;
...
@@ -24,7 +24,7 @@ import org.h2.mvstore.type.ObjectDataType;
import
org.h2.util.New
;
import
org.h2.util.New
;
/**
/**
* A store that supports concurrent transactions.
* A store that supports concurrent
MVCC read-committed
transactions.
*/
*/
public
class
TransactionStore
{
public
class
TransactionStore
{
...
...
h2/src/main/org/h2/mvstore/rtree/MVRTreeMap.java
浏览文件 @
3b75267b
...
@@ -122,8 +122,25 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
...
@@ -122,8 +122,25 @@ public class MVRTreeMap<V> extends MVMap<SpatialKey, V> {
}
}
@Override
@Override
protected
Page
getPage
(
SpatialKey
key
)
{
protected
SpatialKey
getLiveKey
(
Page
p
)
{
return
getPage
(
root
,
key
);
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
)
{
private
Page
getPage
(
Page
p
,
Object
key
)
{
...
...
h2/src/main/org/h2/tools/Recover.java
浏览文件 @
3b75267b
...
@@ -585,6 +585,8 @@ public class Recover extends Tool implements DataHandler {
...
@@ -585,6 +585,8 @@ public class Recover extends Tool implements DataHandler {
Constants
.
SUFFIX_MV_FILE
.
length
()));
Constants
.
SUFFIX_MV_FILE
.
length
()));
MVStore
mv
=
new
MVStore
.
Builder
().
fileName
(
fileName
).
readOnly
().
open
();
MVStore
mv
=
new
MVStore
.
Builder
().
fileName
(
fileName
).
readOnly
().
open
();
dumpLobMaps
(
writer
,
mv
);
dumpLobMaps
(
writer
,
mv
);
writer
.
println
(
"-- Meta"
);
dumpMeta
(
writer
,
mv
);
writer
.
println
(
"-- Tables"
);
writer
.
println
(
"-- Tables"
);
TransactionStore
store
=
new
TransactionStore
(
mv
);
TransactionStore
store
=
new
TransactionStore
(
mv
);
try
{
try
{
...
@@ -654,6 +656,13 @@ public class Recover extends Tool implements DataHandler {
...
@@ -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
)
{
private
void
dumpLobMaps
(
PrintWriter
writer
,
MVStore
mv
)
{
lobMaps
=
mv
.
hasMap
(
"lobData"
);
lobMaps
=
mv
.
hasMap
(
"lobData"
);
if
(!
lobMaps
)
{
if
(!
lobMaps
)
{
...
...
h2/src/test/org/h2/test/store/TestMVStore.java
浏览文件 @
3b75267b
...
@@ -110,7 +110,7 @@ public class TestMVStore extends TestBase {
...
@@ -110,7 +110,7 @@ public class TestMVStore extends TestBase {
// longer running tests
// longer running tests
testLargerThan2G
();
testLargerThan2G
();
}
}
private
void
testVolatileMap
()
{
private
void
testVolatileMap
()
{
String
fileName
=
getBaseDir
()
+
"/testVolatile.h3"
;
String
fileName
=
getBaseDir
()
+
"/testVolatile.h3"
;
MVStore
store
=
new
MVStore
.
Builder
().
MVStore
store
=
new
MVStore
.
Builder
().
...
@@ -1673,7 +1673,7 @@ public class TestMVStore extends TestBase {
...
@@ -1673,7 +1673,7 @@ public class TestMVStore extends TestBase {
m
=
s
.
openMap
(
"data"
);
m
=
s
.
openMap
(
"data"
);
assertTrue
(
s
.
compact
(
80
,
16
*
1024
));
assertTrue
(
s
.
compact
(
80
,
16
*
1024
));
assert
Tru
e
(
s
.
compact
(
80
,
1024
));
assert
Fals
e
(
s
.
compact
(
80
,
1024
));
int
chunkCount3
=
0
;
int
chunkCount3
=
0
;
for
(
String
k
:
meta
.
keySet
())
{
for
(
String
k
:
meta
.
keySet
())
{
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论