Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
xxadev
vscode
提交
eaf3e0fd
V
vscode
项目概览
xxadev
/
vscode
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
V
vscode
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
eaf3e0fd
编写于
1月 08, 2019
作者:
B
Benjamin Pasero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
storage - recover from backup upon exit when we detected a corrupt DB during runtime
上级
64585dd5
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
39 addition
and
23 deletion
+39
-23
src/vs/base/node/storage.ts
src/vs/base/node/storage.ts
+33
-21
src/vs/base/test/node/storage/storage.test.ts
src/vs/base/test/node/storage/storage.test.ts
+6
-2
未找到文件。
src/vs/base/node/storage.ts
浏览文件 @
eaf3e0fd
...
...
@@ -6,7 +6,7 @@
import
{
Database
,
Statement
}
from
'
vscode-sqlite3
'
;
import
{
Disposable
,
IDisposable
}
from
'
vs/base/common/lifecycle
'
;
import
{
Emitter
,
Event
}
from
'
vs/base/common/event
'
;
import
{
ThrottledDelayer
,
timeout
}
from
'
vs/base/common/async
'
;
import
{
ThrottledDelayer
,
timeout
,
always
}
from
'
vs/base/common/async
'
;
import
{
isUndefinedOrNull
}
from
'
vs/base/common/types
'
;
import
{
mapToString
,
setToString
}
from
'
vs/base/common/map
'
;
import
{
basename
}
from
'
path
'
;
...
...
@@ -411,26 +411,38 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
return
this
.
whenOpened
.
then
(
result
=>
{
return
new
Promise
((
resolve
,
reject
)
=>
{
result
.
db
.
close
(
error
=>
{
if
(
error
)
{
this
.
handleSQLiteError
(
error
,
`[storage
${
this
.
name
}
] close():
${
error
}
`
);
result
.
db
.
close
(
closeError
=>
{
if
(
closeError
)
{
this
.
handleSQLiteError
(
closeError
,
`[storage
${
this
.
name
}
] close():
${
closeError
}
`
);
}
return
reject
(
error
);
if
(
result
.
path
===
SQLiteStorageDatabase
.
IN_MEMORY_PATH
)
{
return
resolve
();
// return early for in-memory DBs
}
if
(
this
.
isCorrupt
)
{
// If the DB is corrupt, make sure to rename the file so that we can start
// from a fresh DB or a previous backup on the next startup and not be stuck
// with a corrupt DB for ever.
this
.
logger
.
error
(
`[storage
${
this
.
name
}
] close(): removing corrupt DB and trying to restore backup`
);
return
always
(
rename
(
result
.
path
,
this
.
toCorruptPath
(
result
.
path
))
.
then
(()
=>
rename
(
this
.
toBackupPath
(
result
.
path
),
result
.
path
)),
()
=>
closeError
?
reject
(
closeError
)
:
resolve
());
}
if
(
closeError
)
{
return
reject
(
closeError
);
}
// If the DB closed successfully and we are not running in-memory
// and the DB did not get corrupted during runtime, make a backup
// of the DB so that we can use it as fallback in case the actual
// DB becomes corrupt.
if
(
result
.
path
!==
SQLiteStorageDatabase
.
IN_MEMORY_PATH
&&
!
this
.
isCorrupt
)
{
return
this
.
backup
(
result
).
then
(
resolve
,
error
=>
{
this
.
logger
.
error
(
`[storage
${
this
.
name
}
] backup():
${
error
}
`
);
return
this
.
backup
(
result
).
then
(
resolve
,
error
=>
{
this
.
logger
.
error
(
`[storage
${
this
.
name
}
] backup():
${
error
}
`
);
return
resolve
();
// ignore failing backup
});
}
return
resolve
();
return
resolve
();
// ignore failing backup
});
});
});
});
...
...
@@ -512,6 +524,14 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
.
then
(()
=>
this
.
doOpen
(
path
));
}
private
handleSQLiteError
(
error
:
Error
&
{
code
?:
string
},
msg
:
string
):
void
{
if
(
error
.
code
===
'
SQLITE_CORRUPT
'
||
error
.
code
===
'
SQLITE_NOTADB
'
)
{
this
.
isCorrupt
=
true
;
}
this
.
logger
.
error
(
msg
);
}
private
toCorruptPath
(
path
:
string
):
string
{
const
randomSuffix
=
Math
.
random
().
toString
(
36
).
replace
(
/
[^
a-z
]
+/g
,
''
).
substr
(
0
,
4
);
...
...
@@ -652,14 +672,6 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
stmt
.
removeListener
(
'
error
'
,
statementErrorListener
);
});
}
private
handleSQLiteError
(
error
:
Error
&
{
code
?:
string
},
msg
:
string
):
void
{
if
(
error
.
code
===
'
SQLITE_CORRUPT
'
||
error
.
code
===
'
SQLITE_NOTADB
'
)
{
this
.
isCorrupt
=
true
;
}
this
.
logger
.
error
(
msg
);
}
}
class
SQLiteStorageDatabaseLogger
{
...
...
src/vs/base/test/node/storage/storage.test.ts
浏览文件 @
eaf3e0fd
...
...
@@ -8,7 +8,7 @@ import { generateUuid } from 'vs/base/common/uuid';
import
{
join
}
from
'
path
'
;
import
{
tmpdir
}
from
'
os
'
;
import
{
equal
,
ok
}
from
'
assert
'
;
import
{
mkdirp
,
del
,
writeFile
}
from
'
vs/base/node/pfs
'
;
import
{
mkdirp
,
del
,
writeFile
,
exists
}
from
'
vs/base/node/pfs
'
;
import
{
timeout
}
from
'
vs/base/common/async
'
;
import
{
Event
,
Emitter
}
from
'
vs/base/common/event
'
;
import
{
isWindows
}
from
'
vs/base/common/platform
'
;
...
...
@@ -427,7 +427,7 @@ suite('SQLite Storage Library', () => {
await
del
(
storageDir
,
tmpdir
());
});
test
(
'
basics (
corrupt DB does not backup
)
'
,
async
()
=>
{
test
(
'
basics (
DB that becomes corrupt during runtime restores backup on close()
)
'
,
async
()
=>
{
if
(
isWindows
)
{
await
Promise
.
resolve
();
// Windows will fail to write to open DB due to locking
...
...
@@ -449,6 +449,8 @@ suite('SQLite Storage Library', () => {
await
storage
.
updateItems
({
insert
:
items
});
await
storage
.
close
();
equal
(
await
exists
(
`
${
storagePath
}
.backup`
),
true
);
storage
=
new
SQLiteStorageDatabase
(
storagePath
);
await
storage
.
getItems
();
...
...
@@ -462,6 +464,8 @@ suite('SQLite Storage Library', () => {
await
storage
.
close
();
equal
(
await
exists
(
`
${
storagePath
}
.backup`
),
false
);
storage
=
new
SQLiteStorageDatabase
(
storagePath
);
const
storedItems
=
await
storage
.
getItems
();
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录