Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
d7721db1
提交
d7721db1
authored
14 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
New experimental database file locking mechanism "FS" to use native file locking.
上级
d6517168
master
noel-pr1
plus33-master
pr/267
stumc-Issue#576
version-1.4.198
version-1.4.197
version-1.4.196
version-1.4.195
version-1.4.194
version-1.4.193
version-1.4.192
version-1.4.191
version-1.4.190
version-1.4.188
version-1.4.187
version-1.4.186
version-1.4.185
version-1.4.184
version-1.4.183
version-1.4.182
version-1.4.181
version-1.4.178
version-1.4.177
version-1.3
version-1.2
version-1.1
version-1.0
无相关合并请求
隐藏空白字符变更
内嵌
并排
正在显示
20 个修改的文件
包含
250 行增加
和
14 行删除
+250
-14
Database.java
h2/src/main/org/h2/engine/Database.java
+11
-6
FileLock.java
h2/src/main/org/h2/store/FileLock.java
+9
-0
FileStore.java
h2/src/main/org/h2/store/FileStore.java
+17
-0
PageStore.java
h2/src/main/org/h2/store/PageStore.java
+18
-1
FileObject.java
h2/src/main/org/h2/store/fs/FileObject.java
+12
-0
FileObjectDisk.java
h2/src/main/org/h2/store/fs/FileObjectDisk.java
+25
-0
FileObjectDiskChannel.java
h2/src/main/org/h2/store/fs/FileObjectDiskChannel.java
+25
-0
FileObjectDiskMapped.java
h2/src/main/org/h2/store/fs/FileObjectDiskMapped.java
+25
-0
FileObjectMemory.java
h2/src/main/org/h2/store/fs/FileObjectMemory.java
+8
-0
FileObjectMemoryData.java
h2/src/main/org/h2/store/fs/FileObjectMemoryData.java
+21
-0
FileObjectSplit.java
h2/src/main/org/h2/store/fs/FileObjectSplit.java
+8
-0
FileObjectZip.java
h2/src/main/org/h2/store/fs/FileObjectZip.java
+8
-0
TestPowerOffFs.java
h2/src/test/org/h2/test/synth/TestPowerOffFs.java
+1
-3
TestPowerOffFs2.java
h2/src/test/org/h2/test/synth/TestPowerOffFs2.java
+1
-3
FileObjectDatabase.java
h2/src/test/org/h2/test/unit/FileObjectDatabase.java
+8
-0
TestFileLock.java
h2/src/test/org/h2/test/unit/TestFileLock.java
+18
-0
TestPageStore.java
h2/src/test/org/h2/test/unit/TestPageStore.java
+14
-0
DebugFileObject.java
h2/src/test/org/h2/test/utils/DebugFileObject.java
+11
-0
DebugFileSystem.java
h2/src/test/org/h2/test/utils/DebugFileSystem.java
+2
-1
RecordingFileObject.java
h2/src/test/org/h2/test/utils/RecordingFileObject.java
+8
-0
没有找到文件。
h2/src/main/org/h2/engine/Database.java
浏览文件 @
d7721db1
...
...
@@ -507,7 +507,7 @@ public class Database implements DataHandler {
traceSystem
.
getTrace
(
Trace
.
DATABASE
)
.
info
(
"opening "
+
databaseName
+
" (build "
+
Constants
.
BUILD_ID
+
")"
);
if
(
autoServerMode
)
{
if
(
readOnly
||
fileLockMethod
==
FileLock
.
LOCK_NO
||
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
)
{
if
(
readOnly
||
fileLockMethod
==
FileLock
.
LOCK_NO
||
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
||
fileLockMethod
==
FileLock
.
LOCK_FS
)
{
throw
DbException
.
getUnsupportedException
(
"autoServerMode && (readOnly || fileLockMethod == NO"
+
" || fileLockMethod == SERIALIZED)"
);
}
...
...
@@ -519,10 +519,12 @@ public class Database implements DataHandler {
}
}
if
(!
readOnly
&&
fileLockMethod
!=
FileLock
.
LOCK_NO
)
{
lock
=
new
FileLock
(
traceSystem
,
lockFileName
,
Constants
.
LOCK_SLEEP
);
lock
.
lock
(
fileLockMethod
);
if
(
autoServerMode
)
{
startServer
(
lock
.
getUniqueId
());
if
(
fileLockMethod
!=
FileLock
.
LOCK_FS
)
{
lock
=
new
FileLock
(
traceSystem
,
lockFileName
,
Constants
.
LOCK_SLEEP
);
lock
.
lock
(
fileLockMethod
);
if
(
autoServerMode
)
{
startServer
(
lock
.
getUniqueId
());
}
}
}
while
(
isReconnectNeeded
()
&&
!
beforeWriting
())
{
...
...
@@ -1142,7 +1144,7 @@ public class Database implements DataHandler {
}
reconnectModified
(
false
);
closeFiles
();
if
(
persistent
&&
lock
==
null
&&
fileLockMethod
!=
FileLock
.
LOCK_NO
)
{
if
(
persistent
&&
lock
==
null
&&
fileLockMethod
!=
FileLock
.
LOCK_NO
&&
fileLockMethod
!=
FileLock
.
LOCK_FS
)
{
// everything already closed (maybe in checkPowerOff)
// don't delete temp files in this case because
// the database could be open now (even from within another process)
...
...
@@ -2056,6 +2058,9 @@ public class Database implements DataHandler {
if
(
pageSize
!=
SysProperties
.
PAGE_SIZE
)
{
pageStore
.
setPageSize
(
pageSize
);
}
if
(!
readOnly
&&
fileLockMethod
==
FileLock
.
LOCK_FS
)
{
pageStore
.
setLockFile
(
true
);
}
pageStore
.
open
();
}
return
pageStore
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/FileLock.java
浏览文件 @
d7721db1
...
...
@@ -57,6 +57,11 @@ public class FileLock implements Runnable {
*/
public
static
final
int
LOCK_SERIALIZED
=
3
;
/**
* Use the file system to lock the file; don't use a separate lock file.
*/
public
static
final
int
LOCK_FS
=
4
;
private
static
final
String
MAGIC
=
"FileLock"
;
private
static
final
String
FILE
=
"file"
,
SOCKET
=
"socket"
,
SERIALIZED
=
"serialized"
;
private
static
final
int
RANDOM_BYTES
=
16
;
...
...
@@ -134,6 +139,8 @@ public class FileLock implements Runnable {
case
LOCK_SERIALIZED:
lockSerialized
();
break
;
case
LOCK_FS:
break
;
}
locked
=
true
;
}
...
...
@@ -462,6 +469,8 @@ public class FileLock implements Runnable {
return
FileLock
.
LOCK_SOCKET
;
}
else
if
(
method
.
equalsIgnoreCase
(
"SERIALIZED"
))
{
return
FileLock
.
LOCK_SERIALIZED
;
}
else
if
(
method
.
equalsIgnoreCase
(
"FS"
))
{
return
FileLock
.
LOCK_FS
;
}
else
{
throw
DbException
.
get
(
ErrorCode
.
UNSUPPORTED_LOCK_METHOD_1
,
method
);
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/FileStore.java
浏览文件 @
d7721db1
...
...
@@ -509,4 +509,21 @@ public class FileStore {
return
textMode
;
}
/**
* Try to lock the file.
*
* @return true if successful
*/
public
boolean
tryLock
()
{
return
file
.
tryLock
();
}
/**
* Release the file lock.
*/
public
void
releaseLock
()
{
file
.
releaseLock
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/PageStore.java
浏览文件 @
d7721db1
...
...
@@ -184,6 +184,7 @@ public class PageStore implements CacheWriter {
private
long
logSizeBase
;
private
HashMap
<
String
,
Integer
>
statistics
;
private
int
logMode
=
LOG_MODE_SYNC
;
private
boolean
lockFile
;
/**
* Create a new page store object.
...
...
@@ -281,6 +282,7 @@ public class PageStore implements CacheWriter {
setPageSize
(
pageSize
);
freeListPagesPerList
=
PageFreeList
.
getPagesAddressed
(
pageSize
);
file
=
database
.
openFile
(
fileName
,
accessMode
,
false
);
lockFile
();
recoveryRunning
=
true
;
writeStaticHeader
();
writeVariableHeader
();
...
...
@@ -294,8 +296,17 @@ public class PageStore implements CacheWriter {
increaseFileSize
();
}
private
void
lockFile
()
{
if
(
lockFile
)
{
if
(!
file
.
tryLock
())
{
throw
DbException
.
get
(
ErrorCode
.
DATABASE_ALREADY_OPEN_1
,
fileName
);
}
}
}
private
void
openExisting
()
{
file
=
database
.
openFile
(
fileName
,
accessMode
,
true
);
lockFile
();
readStaticHeader
();
freeListPagesPerList
=
PageFreeList
.
getPagesAddressed
(
pageSize
);
fileLength
=
file
.
length
();
...
...
@@ -304,6 +315,7 @@ public class PageStore implements CacheWriter {
if
(
database
.
isReadOnly
())
{
throw
DbException
.
get
(
ErrorCode
.
FILE_CORRUPTED_1
,
fileName
+
" pageCount: "
+
pageCount
);
}
file
.
releaseLock
();
file
.
close
();
IOUtils
.
delete
(
fileName
);
openNew
();
...
...
@@ -800,6 +812,7 @@ public class PageStore implements CacheWriter {
}
if
(
file
!=
null
)
{
try
{
file
.
releaseLock
();
file
.
close
();
}
finally
{
file
=
null
;
...
...
@@ -1304,7 +1317,7 @@ public class PageStore implements CacheWriter {
void
redoDelete
(
int
logPos
,
int
tableId
,
long
key
)
{
Index
index
=
metaObjects
.
get
(
tableId
);
PageDataIndex
scan
=
(
PageDataIndex
)
index
;
Row
row
=
scan
.
getRow
(
key
);
Row
row
=
scan
.
getRow
WithKey
(
key
);
redo
(
logPos
,
tableId
,
row
,
false
);
}
...
...
@@ -1729,4 +1742,8 @@ public class PageStore implements CacheWriter {
return
logMode
;
}
public
void
setLockFile
(
boolean
lockFile
)
{
this
.
lockFile
=
lockFile
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObject.java
浏览文件 @
d7721db1
...
...
@@ -75,4 +75,16 @@ public interface FileObject {
*/
String
getName
();
/**
* Try to lock the file exclusively.
*
* @return true if locking was successful
*/
boolean
tryLock
();
/**
* Release the file lock.
*/
void
releaseLock
();
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectDisk.java
浏览文件 @
d7721db1
...
...
@@ -9,6 +9,7 @@ package org.h2.store.fs;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.io.RandomAccessFile
;
import
java.nio.channels.FileLock
;
import
org.h2.constant.SysProperties
;
import
org.h2.util.IOUtils
;
...
...
@@ -18,6 +19,7 @@ import org.h2.util.IOUtils;
public
class
FileObjectDisk
extends
RandomAccessFile
implements
FileObject
{
private
final
String
name
;
private
FileLock
lock
;
FileObjectDisk
(
String
fileName
,
String
mode
)
throws
FileNotFoundException
{
super
(
fileName
,
mode
);
...
...
@@ -47,4 +49,27 @@ public class FileObjectDisk extends RandomAccessFile implements FileObject {
return
name
;
}
public
synchronized
boolean
tryLock
()
{
if
(
lock
==
null
)
{
try
{
lock
=
getChannel
().
tryLock
();
}
catch
(
Exception
e
)
{
// could not lock (OverlappingFileLockException)
}
return
lock
!=
null
;
}
return
false
;
}
public
synchronized
void
releaseLock
()
{
if
(
lock
!=
null
)
{
try
{
lock
.
release
();
}
catch
(
IOException
e
)
{
// ignore
}
lock
=
null
;
}
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectDiskChannel.java
浏览文件 @
d7721db1
...
...
@@ -11,6 +11,7 @@ import java.io.IOException;
import
java.io.RandomAccessFile
;
import
java.nio.ByteBuffer
;
import
java.nio.channels.FileChannel
;
import
java.nio.channels.FileLock
;
/**
* File which uses NIO FileChannel.
...
...
@@ -19,6 +20,7 @@ public class FileObjectDiskChannel implements FileObject {
private
final
String
name
;
private
FileChannel
channel
;
private
FileLock
lock
;
FileObjectDiskChannel
(
String
fileName
,
String
mode
)
throws
FileNotFoundException
{
this
.
name
=
fileName
;
...
...
@@ -86,4 +88,27 @@ public class FileObjectDiskChannel implements FileObject {
channel
.
write
(
buf
);
}
public
synchronized
boolean
tryLock
()
{
if
(
lock
==
null
)
{
try
{
lock
=
channel
.
tryLock
();
}
catch
(
IOException
e
)
{
// could not lock
}
return
lock
!=
null
;
}
return
false
;
}
public
synchronized
void
releaseLock
()
{
if
(
lock
!=
null
)
{
try
{
lock
.
release
();
}
catch
(
IOException
e
)
{
// ignore
}
lock
=
null
;
}
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectDiskMapped.java
浏览文件 @
d7721db1
...
...
@@ -13,6 +13,7 @@ import java.lang.ref.WeakReference;
import
java.lang.reflect.Method
;
import
java.nio.BufferUnderflowException
;
import
java.nio.MappedByteBuffer
;
import
java.nio.channels.FileLock
;
import
java.nio.channels.FileChannel.MapMode
;
import
org.h2.constant.SysProperties
;
import
org.h2.util.IOUtils
;
...
...
@@ -28,6 +29,7 @@ public class FileObjectDiskMapped implements FileObject {
private
final
MapMode
mode
;
private
RandomAccessFile
file
;
private
MappedByteBuffer
mapped
;
private
FileLock
lock
;
/**
* The position within the file. Can't use the position of the mapped buffer
...
...
@@ -180,4 +182,27 @@ public class FileObjectDiskMapped implements FileObject {
pos
+=
len
;
}
public
synchronized
boolean
tryLock
()
{
if
(
lock
==
null
)
{
try
{
lock
=
file
.
getChannel
().
tryLock
();
}
catch
(
IOException
e
)
{
// could not lock
}
return
lock
!=
null
;
}
return
false
;
}
public
synchronized
void
releaseLock
()
{
if
(
lock
!=
null
)
{
try
{
lock
.
release
();
}
catch
(
IOException
e
)
{
// ignore
}
lock
=
null
;
}
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectMemory.java
浏览文件 @
d7721db1
...
...
@@ -69,4 +69,12 @@ public class FileObjectMemory implements FileObject {
return
data
.
getLastModified
();
}
public
boolean
tryLock
()
{
return
data
.
tryLock
();
}
public
void
releaseLock
()
{
data
.
releaseLock
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectMemoryData.java
浏览文件 @
d7721db1
...
...
@@ -37,6 +37,7 @@ class FileObjectMemoryData {
private
byte
[][]
data
;
private
long
lastModified
;
private
boolean
isReadOnly
;
private
volatile
boolean
locked
;
static
{
byte
[]
n
=
new
byte
[
BLOCK_SIZE
];
...
...
@@ -295,4 +296,24 @@ class FileObjectMemoryData {
return
true
;
}
/**
* Lock the file.
*
* @return if successful
*/
synchronized
boolean
tryLock
()
{
if
(
locked
)
{
return
false
;
}
locked
=
true
;
return
true
;
}
/**
* Unlock the file.
*/
public
synchronized
void
releaseLock
()
{
locked
=
false
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectSplit.java
浏览文件 @
d7721db1
...
...
@@ -152,4 +152,12 @@ public class FileObjectSplit implements FileObject {
return
name
;
}
public
boolean
tryLock
()
{
return
list
[
0
].
tryLock
();
}
public
void
releaseLock
()
{
list
[
0
].
releaseLock
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/fs/FileObjectZip.java
浏览文件 @
d7721db1
...
...
@@ -107,4 +107,12 @@ public class FileObjectZip implements FileObject {
return
file
.
getName
();
}
public
boolean
tryLock
()
{
return
false
;
}
public
void
releaseLock
()
{
// ignore
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/synth/TestPowerOffFs.java
浏览文件 @
d7721db1
...
...
@@ -11,7 +11,6 @@ import java.sql.DriverManager;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.constant.ErrorCode
;
import
org.h2.store.fs.FileSystem
;
import
org.h2.test.TestBase
;
import
org.h2.test.utils.DebugFileSystem
;
...
...
@@ -32,8 +31,7 @@ public class TestPowerOffFs extends TestBase {
}
public
void
test
()
throws
Exception
{
DebugFileSystem
.
register
();
fs
=
(
DebugFileSystem
)
FileSystem
.
getInstance
(
"debug:/"
);
fs
=
DebugFileSystem
.
register
();
test
(
Integer
.
MAX_VALUE
);
System
.
out
.
println
(
Integer
.
MAX_VALUE
-
fs
.
getPowerOffCount
());
System
.
out
.
println
(
"done"
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/synth/TestPowerOffFs2.java
浏览文件 @
d7721db1
...
...
@@ -14,7 +14,6 @@ import java.sql.Statement;
import
java.util.ArrayList
;
import
java.util.Random
;
import
org.h2.constant.ErrorCode
;
import
org.h2.store.fs.FileSystem
;
import
org.h2.test.TestBase
;
import
org.h2.test.utils.DebugFileSystem
;
import
org.h2.util.New
;
...
...
@@ -44,9 +43,8 @@ public class TestPowerOffFs2 extends TestBase {
}
public
void
test
()
throws
Exception
{
DebugFileSystem
.
register
();
fs
=
DebugFileSystem
.
register
();
url
=
"jdbc:h2:debug:memFS:powerOffFs;FILE_LOCK=NO;TRACE_LEVEL_FILE=0;WRITE_DELAY=0;CACHE_SIZE=32"
;
fs
=
(
DebugFileSystem
)
FileSystem
.
getInstance
(
"debug:/"
);
for
(
int
i
=
0
;;
i
++)
{
test
(
i
);
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/FileObjectDatabase.java
浏览文件 @
d7721db1
...
...
@@ -90,4 +90,12 @@ public class FileObjectDatabase implements FileObject {
return
fileName
;
}
public
void
releaseLock
()
{
// ignore
}
public
boolean
tryLock
()
{
return
false
;
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestFileLock.java
浏览文件 @
d7721db1
...
...
@@ -7,6 +7,10 @@
package
org
.
h2
.
test
.
unit
;
import
java.io.File
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.SQLException
;
import
org.h2.constant.ErrorCode
;
import
org.h2.engine.Constants
;
import
org.h2.message.TraceSystem
;
import
org.h2.store.FileLock
;
...
...
@@ -50,12 +54,26 @@ public class TestFileLock extends TestBase implements Runnable {
if
(!
getFile
().
startsWith
(
TestBase
.
BASE_TEST_DIR
))
{
return
;
}
testFsFileLock
();
testFutureModificationDate
();
testSimple
();
test
(
false
);
test
(
true
);
}
private
void
testFsFileLock
()
throws
Exception
{
deleteDb
(
"fileLock"
);
String
url
=
"jdbc:h2:"
+
getBaseDir
()
+
"/fileLock;FILE_LOCK=FS;OPEN_NEW=TRUE"
;
Connection
conn
=
DriverManager
.
getConnection
(
url
);
try
{
DriverManager
.
getConnection
(
url
);
fail
();
}
catch
(
SQLException
e
)
{
assertEquals
(
ErrorCode
.
DATABASE_ALREADY_OPEN_1
,
e
.
getErrorCode
());
}
conn
.
close
();
}
private
void
testFutureModificationDate
()
throws
Exception
{
File
f
=
new
File
(
getFile
());
f
.
delete
();
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestPageStore.java
浏览文件 @
d7721db1
...
...
@@ -38,6 +38,7 @@ public class TestPageStore extends TestBase implements DatabaseEventListener {
}
public
void
test
()
throws
Exception
{
testInsertReverse
();
testInsertDelete
();
testCheckpoint
();
testDropRecreate
();
...
...
@@ -64,6 +65,19 @@ public class TestPageStore extends TestBase implements DatabaseEventListener {
deleteDb
(
"pageStore"
);
}
private
void
testInsertReverse
()
throws
SQLException
{
deleteDb
(
"pageStore"
);
Connection
conn
;
conn
=
getConnection
(
"pageStore"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(id int primary key, data varchar)"
);
stat
.
execute
(
"insert into test select -x, space(100) from system_range(1, 1000)"
);
stat
.
execute
(
"drop table test"
);
stat
.
execute
(
"create table test(id int primary key, data varchar)"
);
stat
.
execute
(
"insert into test select -x, space(2048) from system_range(1, 1000)"
);
conn
.
close
();
}
private
void
testInsertDelete
()
{
Row
[]
x
=
new
Row
[
0
];
Row
r
=
new
Row
(
null
,
0
);
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/utils/DebugFileObject.java
浏览文件 @
d7721db1
...
...
@@ -87,4 +87,15 @@ public class DebugFileObject implements FileObject {
throw
e
;
}
}
public
boolean
tryLock
()
{
debug
(
"tryLock"
);
return
file
.
tryLock
();
}
public
void
releaseLock
()
{
debug
(
"releaseLock"
);
file
.
releaseLock
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/utils/DebugFileSystem.java
浏览文件 @
d7721db1
...
...
@@ -33,8 +33,9 @@ public class DebugFileSystem extends FileSystem {
/**
* Register the file system.
*/
public
static
void
register
()
{
public
static
DebugFileSystem
register
()
{
FileSystem
.
register
(
INSTANCE
);
return
INSTANCE
;
}
/**
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/utils/RecordingFileObject.java
浏览文件 @
d7721db1
...
...
@@ -67,4 +67,12 @@ public class RecordingFileObject implements FileObject {
fs
.
log
(
Recorder
.
WRITE
,
name
,
buff
,
file
.
getFilePointer
());
}
public
boolean
tryLock
()
{
return
file
.
tryLock
();
}
public
void
releaseLock
()
{
file
.
releaseLock
();
}
}
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论