Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
d1e64d7e
提交
d1e64d7e
authored
15 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Automatically converted to the new page store format
上级
eec75255
显示空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
160 行增加
和
15 行删除
+160
-15
Recover.java
h2/src/main/org/h2/tools/Recover.java
+132
-15
TestPageStore.java
h2/src/test/org/h2/test/unit/TestPageStore.java
+28
-0
没有找到文件。
h2/src/main/org/h2/tools/Recover.java
浏览文件 @
d1e64d7e
...
...
@@ -17,13 +17,18 @@ import java.io.InputStreamReader;
import
java.io.OutputStream
;
import
java.io.PrintWriter
;
import
java.io.Reader
;
import
java.sql.Connection
;
import
java.sql.SQLException
;
import
java.util.ArrayList
;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Properties
;
import
java.util.UUID
;
import
java.util.zip.CRC32
;
import
org.h2.Driver
;
import
org.h2.command.Parser
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.engine.DbObject
;
import
org.h2.engine.MetaRecord
;
...
...
@@ -69,6 +74,8 @@ import org.h2.value.ValueLong;
*/
public
class
Recover
extends
Tool
implements
DataHandler
{
private
static
final
String
SUFFIX_UNCOMMITTED
=
".uncommitted.txt"
;
private
String
databaseName
;
private
int
block
;
private
int
blockCount
;
...
...
@@ -480,20 +487,21 @@ public class Recover extends Tool implements DataHandler {
lobFilesInDirectories
=
FileUtils
.
exists
(
databaseName
+
Constants
.
SUFFIX_LOBS_DIRECTORY
);
}
private
void
dumpLog
(
String
fileName
,
boolean
s
essionState
)
{
private
void
dumpLog
(
String
fileName
,
boolean
onlySetS
essionState
)
{
PrintWriter
writer
=
null
;
FileStore
store
=
null
;
boolean
containsUncommitted
=
false
;
try
{
if
(
s
essionState
)
{
if
(
onlySetS
essionState
)
{
sessionCommit
=
New
.
hashMap
();
}
setDatabaseName
(
fileName
.
substring
(
fileName
.
length
()
-
Constants
.
SUFFIX_LOG_FILE
.
length
()));
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
=
getWriter
(
fileName
,
".txt"
);
}
store
=
FileStore
.
open
(
null
,
fileName
,
"r"
);
long
length
=
store
.
length
();
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
.
println
(
"// length: "
+
length
);
}
int
offset
=
FileStore
.
HEADER_LENGTH
;
...
...
@@ -506,7 +514,7 @@ public class Recover extends Tool implements DataHandler {
s
.
reset
();
if
(
length
<
FileStore
.
HEADER_LENGTH
+
len
)
{
// this is an empty file
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
.
println
(
"// empty file"
);
}
return
;
...
...
@@ -517,7 +525,7 @@ public class Recover extends Tool implements DataHandler {
int
firstUncommittedPos
=
s
.
readInt
();
int
firstUnwrittenPos
=
s
.
readInt
();
int
max
=
(
int
)
(
length
/
blockSize
);
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
.
println
(
"// id: "
+
id
);
writer
.
println
(
"// firstUncommittedPos: "
+
firstUncommittedPos
);
writer
.
println
(
"// firstUnwrittenPos: "
+
firstUnwrittenPos
);
...
...
@@ -549,7 +557,7 @@ public class Recover extends Tool implements DataHandler {
// Math.abs(Integer.MIN_VALUE) == Integer.MIN_VALUE
blocks
=
MathUtils
.
convertLongToInt
(
Math
.
abs
(
s
.
readInt
()));
if
(
blocks
==
0
)
{
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
.
println
(
"// ["
+
pos
+
"] blocks: "
+
blocks
+
" (end)"
);
}
break
;
...
...
@@ -557,12 +565,14 @@ public class Recover extends Tool implements DataHandler {
char
type
=
(
char
)
s
.
readByte
();
int
sessionId
=
s
.
readInt
();
if
(
type
==
'P'
)
{
containsUncommitted
=
true
;
String
transaction
=
s
.
readString
();
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
.
println
(
"// prepared session: "
+
sessionId
+
" tx: "
+
transaction
);
}
}
else
if
(
type
==
'C'
)
{
if
(!
sessionState
)
{
containsUncommitted
=
true
;
if
(!
onlySetSessionState
)
{
writer
.
println
(
"// commit session: "
+
sessionId
);
}
else
{
sessionCommit
.
put
(
sessionId
,
pos
);
...
...
@@ -582,14 +592,15 @@ public class Recover extends Tool implements DataHandler {
if
(
sumLength
>
0
)
{
s
.
read
(
summary
,
0
,
sumLength
);
}
if
(!
s
essionState
)
{
if
(!
onlySetS
essionState
)
{
writer
.
println
(
"// summary session: "
+
sessionId
+
" fileType: "
+
fileType
+
" sumLength: "
+
sumLength
);
dumpSummary
(
writer
,
summary
);
}
break
;
}
case
'T'
:
if
(!
sessionState
)
{
containsUncommitted
=
true
;
if
(!
onlySetSessionState
)
{
writer
.
println
(
"// truncate session: "
+
sessionId
+
" storage: "
+
storageId
+
" pos: "
+
recId
+
" blockCount: "
+
blockCount
);
if
(
sessionCommit
.
get
(
sessionId
)
>=
pos
)
{
setStorage
(
storageId
);
...
...
@@ -598,7 +609,8 @@ public class Recover extends Tool implements DataHandler {
}
break
;
case
'I'
:
if
(!
sessionState
)
{
containsUncommitted
=
true
;
if
(!
onlySetSessionState
)
{
writer
.
println
(
"// insert session: "
+
sessionId
+
" storage: "
+
storageId
+
" pos: "
+
recId
+
" blockCount: "
+
blockCount
);
if
(
storageId
>=
0
)
{
if
(
sessionCommit
.
get
(
sessionId
)
>=
pos
)
{
...
...
@@ -609,7 +621,8 @@ public class Recover extends Tool implements DataHandler {
}
break
;
case
'D'
:
if
(!
sessionState
)
{
containsUncommitted
=
true
;
if
(!
onlySetSessionState
)
{
writer
.
println
(
"// delete session: "
+
sessionId
+
" storage: "
+
storageId
+
" pos: "
+
recId
+
" blockCount: "
+
blockCount
);
if
(
storageId
>=
0
)
{
if
(
sessionCommit
.
get
(
sessionId
)
>=
pos
)
{
...
...
@@ -620,16 +633,26 @@ public class Recover extends Tool implements DataHandler {
}
break
;
default
:
if
(!
sessionState
)
{
containsUncommitted
=
true
;
if
(!
onlySetSessionState
)
{
writer
.
println
(
"// type?: "
+
type
+
" session: "
+
sessionId
+
" storage: "
+
storageId
+
" pos: "
+
recId
+
" blockCount: "
+
blockCount
);
}
break
;
}
}
}
if
(!
sessionState
)
{
if
(!
onlySetSessionState
)
{
writer
.
close
();
if
(
containsUncommitted
)
{
String
db
=
fileName
.
substring
(
0
,
fileName
.
length
()
-
Constants
.
SUFFIX_LOG_FILE
.
length
());
int
idx
=
db
.
lastIndexOf
(
'.'
);
if
(
idx
>=
0
)
{
db
=
db
.
substring
(
0
,
idx
);
writer
=
getWriter
(
db
+
".db"
,
SUFFIX_UNCOMMITTED
);
writer
.
close
();
}
}
}
}
catch
(
Throwable
e
)
{
writeError
(
writer
,
e
);
}
finally
{
...
...
@@ -1802,4 +1825,98 @@ public class Recover extends Tool implements DataHandler {
return
null
;
}
/**
* Delete all files that were created by the recover tool.
*
* @param dir the directory
* @param db the database name
*/
public
static
void
deleteRecoverFiles
(
String
dir
,
String
db
)
throws
SQLException
{
ArrayList
<
String
>
files
=
getRecoverFiles
(
dir
,
db
);
for
(
String
s
:
files
)
{
FileUtils
.
delete
(
s
);
}
}
private
static
ArrayList
<
String
>
getRecoverFiles
(
String
dir
,
String
db
)
throws
SQLException
{
if
(
dir
==
null
||
dir
.
equals
(
""
))
{
dir
=
"."
;
}
dir
=
FileUtils
.
normalize
(
dir
);
ArrayList
<
String
>
files
=
New
.
arrayList
();
String
start
=
FileUtils
.
normalize
(
dir
+
"/"
+
db
);
String
[]
list
=
FileUtils
.
listFiles
(
dir
);
for
(
int
i
=
0
;
list
!=
null
&&
i
<
list
.
length
;
i
++)
{
String
f
=
list
[
i
];
boolean
ok
=
false
;
if
(
f
.
endsWith
(
".data.sql"
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
SUFFIX_UNCOMMITTED
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
".index.txt"
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
".log.txt"
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
Constants
.
SUFFIX_LOBS_DIRECTORY
))
{
if
(
start
==
null
||
FileUtils
.
fileStartsWith
(
f
,
start
+
"."
))
{
files
.
addAll
(
getRecoverFiles
(
f
,
null
));
}
}
else
if
(
f
.
endsWith
(
".lob.comp.txt"
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
".lob.db.txt"
))
{
ok
=
true
;
}
else
if
(
f
.
endsWith
(
".h2.sql"
))
{
ok
=
true
;
}
if
(
ok
)
{
if
(
db
==
null
||
FileUtils
.
fileStartsWith
(
f
,
start
+
"."
))
{
String
fileName
=
f
;
files
.
add
(
fileName
);
}
}
}
return
files
;
}
/**
* Try to convert a database to the page store format.
*
* @param dir the directory
* @param db the database name
* @throws SQLException if conversion fails
*/
public
static
void
convert
(
String
dir
,
String
db
)
throws
SQLException
{
Recover
.
execute
(
dir
,
db
);
if
(
FileUtils
.
exists
(
dir
+
"/"
+
db
+
SUFFIX_UNCOMMITTED
))
{
Recover
.
deleteRecoverFiles
(
dir
,
db
);
throw
Message
.
getSQLException
(
ErrorCode
.
DATA_CONVERSION_ERROR_1
,
"- database cannot be converted to the page store format "
+
"because it was not closed normally. "
+
"Open and close the database with an older version "
+
"of H2 before converting."
);
}
FileUtils
.
delete
(
dir
+
"/"
+
db
+
".backup.zip"
);
Backup
.
execute
(
dir
+
"/"
+
db
+
".backup.zip"
,
dir
,
db
,
true
);
DeleteDbFiles
.
execute
(
dir
,
db
,
true
);
String
randomUser
=
UUID
.
randomUUID
().
toString
().
toUpperCase
();
Properties
prop
=
new
Properties
();
prop
.
setProperty
(
"user"
,
randomUser
);
prop
.
setProperty
(
"password"
,
""
);
Connection
conn
=
Driver
.
load
().
connect
(
"jdbc:h2:file:"
+
dir
+
"/"
+
db
,
prop
);
InputStream
in
=
null
;
try
{
in
=
FileUtils
.
openFileInputStream
(
dir
+
"/"
+
db
+
".data.sql"
);
in
=
new
BufferedInputStream
(
in
,
Constants
.
IO_BUFFER_SIZE
);
Reader
reader
=
new
InputStreamReader
(
in
);
RunScript
.
execute
(
conn
,
reader
);
conn
.
createStatement
().
execute
(
"DROP USER \""
+
randomUser
+
"\""
);
conn
.
close
();
}
catch
(
IOException
e
)
{
throw
Message
.
convertIOException
(
e
,
dir
+
"/"
+
db
);
}
finally
{
IOUtils
.
closeSilently
(
in
);
}
Recover
.
deleteRecoverFiles
(
dir
,
db
);
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestPageStore.java
浏览文件 @
d1e64d7e
...
...
@@ -36,6 +36,7 @@ public class TestPageStore extends TestBase implements DatabaseEventListener {
}
public
void
test
()
throws
Exception
{
testAutoConvert
();
testLargeDatabaseFastOpen
();
testUniqueIndexReopen
();
testExistingOld
();
...
...
@@ -50,6 +51,33 @@ public class TestPageStore extends TestBase implements DatabaseEventListener {
testFuzzOperations
();
}
private
void
testAutoConvert
()
throws
SQLException
{
if
(
config
.
memory
)
{
return
;
}
deleteDb
(
"pageStore"
);
Connection
conn
;
conn
=
getConnection
(
"pageStore;PAGE_STORE=FALSE"
);
conn
.
createStatement
().
execute
(
"create table test(id int, data clob)"
);
conn
.
createStatement
().
execute
(
"insert into test select x, space(10000) from system_range(1, 2)"
);
conn
.
createStatement
().
execute
(
"shutdown immediately"
);
try
{
conn
.
close
();
}
catch
(
SQLException
e
)
{
// ignore
}
try
{
getConnection
(
"pageStore;PAGE_STORE=TRUE"
);
fail
();
}
catch
(
SQLException
e
)
{
assertKnownException
(
e
);
}
conn
=
getConnection
(
"pageStore"
);
conn
.
close
();
conn
=
getConnection
(
"pageStore;PAGE_STORE=TRUE"
);
conn
.
close
();
}
private
void
testLargeDatabaseFastOpen
()
throws
SQLException
{
if
(
config
.
memory
)
{
return
;
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论