Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
27252c09
提交
27252c09
authored
15 年前
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
More bugs in the server-less multi-connection mode have been fixed.
上级
1d4b9c7a
隐藏空白字符变更
内嵌
并排
正在显示
13 个修改的文件
包含
323 行增加
和
122 行删除
+323
-122
SysProperties.java
h2/src/main/org/h2/constant/SysProperties.java
+2
-2
Database.java
h2/src/main/org/h2/engine/Database.java
+115
-35
Session.java
h2/src/main/org/h2/engine/Session.java
+14
-3
SessionInterface.java
h2/src/main/org/h2/engine/SessionInterface.java
+2
-1
SessionRemote.java
h2/src/main/org/h2/engine/SessionRemote.java
+1
-1
JdbcConnection.java
h2/src/main/org/h2/jdbc/JdbcConnection.java
+35
-9
JdbcPreparedStatement.java
h2/src/main/org/h2/jdbc/JdbcPreparedStatement.java
+29
-19
JdbcStatement.java
h2/src/main/org/h2/jdbc/JdbcStatement.java
+33
-8
JdbcXAConnection.java
h2/src/main/org/h2/jdbcx/JdbcXAConnection.java
+2
-2
LogSystem.java
h2/src/main/org/h2/log/LogSystem.java
+17
-7
FileLock.java
h2/src/main/org/h2/store/FileLock.java
+19
-4
WriterThread.java
h2/src/main/org/h2/store/WriterThread.java
+3
-31
TestFileLockSerialized.java
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
+51
-0
没有找到文件。
h2/src/main/org/h2/constant/SysProperties.java
浏览文件 @
27252c09
...
...
@@ -463,13 +463,13 @@ public class SysProperties {
public
static
final
boolean
RECOMPILE_ALWAYS
=
getBooleanSetting
(
"h2.recompileAlways"
,
false
);
/**
* System property <code>h2.reconnectCheckDelay</code> (default:
25
0).<br />
* System property <code>h2.reconnectCheckDelay</code> (default:
10
0).<br />
* Check the .lock.db file every this many milliseconds to detect that the
* database was changed. The process writing to the database must first
* notify a change in the .lock.db file, then wait twice this many
* milliseconds before updating the database.
*/
public
static
final
int
RECONNECT_CHECK_DELAY
=
getIntSetting
(
"h2.reconnectCheckDelay"
,
25
0
);
public
static
final
int
RECONNECT_CHECK_DELAY
=
getIntSetting
(
"h2.reconnectCheckDelay"
,
10
0
);
/**
* System property <code>h2.redoBufferSize</code> (default: 262144).<br />
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/Database.java
浏览文件 @
27252c09
...
...
@@ -22,6 +22,7 @@ import org.h2.command.dml.SetTypes;
import
org.h2.constant.ErrorCode
;
import
org.h2.constant.SysProperties
;
import
org.h2.constraint.Constraint
;
import
org.h2.index.BtreeIndex
;
import
org.h2.index.Cursor
;
import
org.h2.index.Index
;
import
org.h2.index.IndexType
;
...
...
@@ -310,32 +311,61 @@ public class Database implements DataHandler {
return
modificationDataId
;
}
private
void
reconnectModified
(
boolean
pending
)
{
if
(
readOnly
||
lock
==
null
)
{
return
;
/**
* Set or reset the pending change flag in the .lock.db file.
*
* @param pending the new value of the flag
* @return true if the call was successful,
* false if another connection was faster
*/
synchronized
boolean
reconnectModified
(
boolean
pending
)
{
if
(
readOnly
||
lock
==
null
||
fileLockMethod
!=
FileLock
.
LOCK_SERIALIZED
)
{
return
true
;
}
try
{
if
(
pending
==
reconnectChangePending
)
{
long
now
=
System
.
currentTimeMillis
();
if
(
now
>
reconnectCheckNext
)
{
lock
.
save
();
if
(
pending
)
{
String
pos
=
log
==
null
?
null
:
log
.
getWritePos
();
lock
.
setProperty
(
"logPos"
,
pos
);
lock
.
save
();
}
reconnectCheckNext
=
now
+
SysProperties
.
RECONNECT_CHECK_DELAY
;
}
return
;
return
true
;
}
Properties
old
=
lock
.
load
();
if
(
pending
)
{
getTrace
().
debug
(
"wait before writing"
);
Thread
.
sleep
((
int
)
(
SysProperties
.
RECONNECT_CHECK_DELAY
*
1.1
));
Properties
now
=
lock
.
load
();
if
(!
now
.
equals
(
old
))
{
// somebody else was faster
return
false
;
}
}
lock
.
setProperty
(
"modificationDataId"
,
Long
.
toString
(
modificationDataId
)
);
lock
.
setProperty
(
"
modificationMetaId"
,
Long
.
toString
(
modificationMetaId
)
);
String
pos
=
log
==
null
?
null
:
log
.
getWritePos
(
);
lock
.
setProperty
(
"
logPos"
,
pos
);
lock
.
setProperty
(
"changePending"
,
pending
?
"true"
:
null
);
lock
.
save
();
reconnectLastLock
=
lock
.
load
();
old
=
lock
.
save
();
if
(
pending
)
{
getTrace
().
debug
(
"wait before writing again"
);
Thread
.
sleep
((
int
)
(
SysProperties
.
RECONNECT_CHECK_DELAY
*
1.1
));
Properties
now
=
lock
.
load
();
if
(!
now
.
equals
(
old
))
{
// somebody else was faster
return
false
;
}
}
reconnectLastLock
=
old
;
reconnectChangePending
=
pending
;
reconnectCheckNext
=
System
.
currentTimeMillis
()
+
SysProperties
.
RECONNECT_CHECK_DELAY
;
return
true
;
}
catch
(
Exception
e
)
{
getTrace
().
error
(
"pending:"
+
pending
,
e
);
return
false
;
}
}
...
...
@@ -533,7 +563,9 @@ public class Database implements DataHandler {
}
// wait until pending changes are written
isReconnectNeeded
();
beforeWriting
();
while
(!
beforeWriting
())
{
// until we can write (file are not open - no need to re-connect)
}
if
(
SysProperties
.
PAGE_STORE
)
{
starting
=
true
;
getPageStore
();
...
...
@@ -635,7 +667,6 @@ public class Database implements DataHandler {
}
systemSession
.
commit
(
true
);
traceSystem
.
getTrace
(
Trace
.
DATABASE
).
info
(
"opened "
+
databaseName
);
afterWriting
();
}
public
Schema
getMainSchema
()
{
...
...
@@ -1055,9 +1086,11 @@ public class Database implements DataHandler {
if
(
closing
)
{
return
;
}
if
(
isReconnectNeeded
()
)
{
// another connection
wrote - don't write anything
if
(
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
&&
!
reconnectChangePending
)
{
// another connection
may have written something - don't write
try
{
// make sure the log doesn't try to write
log
.
setReadOnly
(
true
);
closeOpenFilesAndUnlock
(
false
);
}
catch
(
SQLException
e
)
{
// ignore
...
...
@@ -1194,6 +1227,7 @@ public class Database implements DataHandler {
pageStore
.
checkpoint
();
}
}
reconnectModified
(
false
);
closeFiles
();
if
(
persistent
&&
lock
==
null
&&
fileLockMethod
!=
FileLock
.
LOCK_NO
)
{
// everything already closed (maybe in checkPowerOff)
...
...
@@ -1736,6 +1770,11 @@ public class Database implements DataHandler {
if
(
noDiskSpace
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
NO_DISK_SPACE_AVAILABLE
);
}
if
(
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
)
{
if
(!
reconnectChangePending
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
DATABASE_IS_READ_ONLY
);
}
}
}
public
boolean
getReadOnly
()
{
...
...
@@ -2183,10 +2222,21 @@ public class Database implements DataHandler {
return
null
;
}
/**
* Check if the contents of the database was changed and therefore it is
* required to re-connect. This method waits until pending changes are
* completed. If a pending change takes too long (more than 2 seconds), the
* pending change is broken.
*
* @return true if reconnecting is required
*/
public
boolean
isReconnectNeeded
()
{
if
(
fileLockMethod
!=
FileLock
.
LOCK_SERIALIZED
)
{
return
false
;
}
if
(
reconnectChangePending
)
{
return
false
;
}
long
now
=
System
.
currentTimeMillis
();
if
(
now
<
reconnectCheckNext
)
{
return
false
;
...
...
@@ -2195,25 +2245,27 @@ public class Database implements DataHandler {
if
(
lock
==
null
)
{
lock
=
new
FileLock
(
traceSystem
,
databaseName
+
Constants
.
SUFFIX_LOCK_FILE
,
Constants
.
LOCK_SLEEP
);
}
Properties
prop
;
try
{
Properties
prop
=
lock
.
load
(),
first
=
prop
;
while
(
true
)
{
prop
=
lock
.
load
();
if
(
prop
.
equals
(
reconnectLastLock
))
{
return
false
;
}
if
(
prop
.
getProperty
(
"changePending"
,
null
)
==
null
)
{
break
;
}
if
(
System
.
currentTimeMillis
()
>
now
+
SysProperties
.
RECONNECT_CHECK_DELAY
*
4
)
{
// the writing process didn't update the file -
// it may have terminated
lock
.
setProperty
(
"changePending"
,
null
);
lock
.
save
();
break
;
if
(
System
.
currentTimeMillis
()
>
now
+
SysProperties
.
RECONNECT_CHECK_DELAY
*
10
)
{
if
(
first
.
equals
(
prop
))
{
// the writing process didn't update the file -
// it may have terminated
lock
.
setProperty
(
"changePending"
,
null
);
lock
.
save
();
break
;
}
}
getTrace
().
debug
(
"delay (change pending)"
);
Thread
.
sleep
(
SysProperties
.
RECONNECT_CHECK_DELAY
);
prop
=
lock
.
load
();
}
reconnectLastLock
=
prop
;
}
catch
(
Exception
e
)
{
...
...
@@ -2223,32 +2275,56 @@ public class Database implements DataHandler {
return
true
;
}
/**
* This method is called after writing to the database.
*/
public
void
afterWriting
()
throws
SQLException
{
if
(
fileLockMethod
!=
FileLock
.
LOCK_SERIALIZED
||
readOnly
)
{
return
;
}
reconnectCheckNext
=
System
.
currentTimeMillis
()
+
1
;
}
/**
* Flush all changes when using the serialized mode, and if there are
* pending changes.
* pending changes, and some time has passed. This switches to a new
* transaction log and resets the change pending flag in
* the .lock.db file.
*/
public
void
checkpointIfRequired
()
throws
SQLException
{
if
(
fileLockMethod
!=
FileLock
.
LOCK_SERIALIZED
||
readOnly
||
!
reconnectChangePending
)
{
return
;
}
long
now
=
System
.
currentTimeMillis
();
if
(
now
>
reconnectCheckNext
)
{
if
(
now
>
reconnectCheckNext
+
SysProperties
.
RECONNECT_CHECK_DELAY
)
{
getTrace
().
debug
(
"checkpoint"
);
flushIndexes
(
0
);
checkpoint
();
reconnectModified
(
false
);
}
}
/**
* Flush the indexes that were last changed prior to some time.
*
* @param maxLastChange indexes that were changed
* afterwards are not flushed; 0 to flush all indexes
*/
public
synchronized
void
flushIndexes
(
long
maxLastChange
)
{
ObjectArray
array
=
getAllSchemaObjects
(
DbObject
.
INDEX
);
for
(
int
i
=
0
;
i
<
array
.
size
();
i
++)
{
DbObject
obj
=
(
DbObject
)
array
.
get
(
i
);
if
(
obj
instanceof
BtreeIndex
)
{
BtreeIndex
idx
=
(
BtreeIndex
)
obj
;
if
(
idx
.
getLastChange
()
==
0
)
{
continue
;
}
Table
tab
=
idx
.
getTable
();
if
(
tab
.
isLockedExclusively
())
{
continue
;
}
if
(
maxLastChange
!=
0
&&
idx
.
getLastChange
()
>
maxLastChange
)
{
continue
;
}
try
{
idx
.
flush
(
systemSession
);
}
catch
(
SQLException
e
)
{
getTrace
().
error
(
"flush index "
+
idx
.
getName
(),
e
);
}
}
}
}
/**
* Flush all changes and open a new log file.
*/
...
...
@@ -2262,11 +2338,15 @@ public class Database implements DataHandler {
/**
* This method is called before writing to the log file.
*
* @return true if the call was successful,
* false if another connection was faster
*/
public
void
beforeWriting
()
{
public
boolean
beforeWriting
()
{
if
(
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
)
{
reconnectModified
(
true
);
re
turn
re
connectModified
(
true
);
}
return
true
;
}
/**
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/Session.java
浏览文件 @
27252c09
...
...
@@ -634,7 +634,6 @@ public class Session extends SessionWithState {
Message
.
throwInternalError
();
}
}
database
.
afterWriting
();
if
(
locks
.
size
()
>
0
)
{
synchronized
(
database
)
{
for
(
int
i
=
0
;
i
<
locks
.
size
();
i
++)
{
...
...
@@ -1112,8 +1111,20 @@ public class Session extends SessionWithState {
return
modificationId
;
}
public
boolean
isReconnectNeeded
()
{
return
database
.
isReconnectNeeded
();
public
boolean
isReconnectNeeded
(
boolean
write
)
{
while
(
true
)
{
boolean
reconnect
=
database
.
isReconnectNeeded
();
if
(
reconnect
)
{
return
true
;
}
if
(
write
)
{
if
(
database
.
beforeWriting
())
{
return
false
;
}
}
else
{
return
false
;
}
}
}
public
SessionInterface
reconnect
()
throws
SQLException
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/SessionInterface.java
浏览文件 @
27252c09
...
...
@@ -76,9 +76,10 @@ public interface SessionInterface {
/**
* Check if the database changed and therefore reconnecting is required.
*
* @param write if the next operation may be writing
* @return true if reconnecting is required
*/
boolean
isReconnectNeeded
();
boolean
isReconnectNeeded
(
boolean
write
);
/**
* Close the connection and open a new connection.
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/engine/SessionRemote.java
浏览文件 @
27252c09
...
...
@@ -652,7 +652,7 @@ public class SessionRemote extends SessionWithState implements SessionFactory, D
return
TempFileDeleter
.
getInstance
();
}
public
boolean
isReconnectNeeded
()
{
public
boolean
isReconnectNeeded
(
boolean
write
)
{
return
false
;
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/jdbc/JdbcConnection.java
浏览文件 @
27252c09
...
...
@@ -400,7 +400,7 @@ public class JdbcConnection extends TraceObject implements Connection {
public
synchronized
void
commit
()
throws
SQLException
{
try
{
debugCodeCall
(
"commit"
);
checkClosed
();
checkClosed
ForWrite
();
commit
=
prepareCommand
(
"COMMIT"
,
commit
);
commit
.
executeUpdate
();
}
catch
(
Exception
e
)
{
...
...
@@ -418,7 +418,7 @@ public class JdbcConnection extends TraceObject implements Connection {
public
synchronized
void
rollback
()
throws
SQLException
{
try
{
debugCodeCall
(
"rollback"
);
checkClosed
();
checkClosed
ForWrite
();
rollbackInternal
();
}
catch
(
Exception
e
)
{
throw
logAndConvert
(
e
);
...
...
@@ -641,6 +641,8 @@ public class JdbcConnection extends TraceObject implements Connection {
*/
public
void
setQueryTimeout
(
int
seconds
)
throws
SQLException
{
try
{
debugCodeCall
(
"setQueryTimeout"
,
seconds
);
checkClosed
();
setQueryTimeout
=
prepareCommand
(
"SET QUERY_TIMEOUT ?"
,
setQueryTimeout
);
((
ParameterInterface
)
setQueryTimeout
.
getParameters
().
get
(
0
)).
setValue
(
ValueInt
.
get
(
seconds
*
1000
),
false
);
setQueryTimeout
.
executeUpdate
();
...
...
@@ -654,6 +656,8 @@ public class JdbcConnection extends TraceObject implements Connection {
*/
public
int
getQueryTimeout
()
throws
SQLException
{
try
{
debugCodeCall
(
"getQueryTimeout"
);
checkClosed
();
getQueryTimeout
=
prepareCommand
(
"SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=?"
,
getQueryTimeout
);
((
ParameterInterface
)
getQueryTimeout
.
getParameters
().
get
(
0
)).
setValue
(
ValueString
.
get
(
"QUERY_TIMEOUT"
),
false
);
ResultInterface
result
=
getQueryTimeout
.
executeQuery
(
0
,
false
);
...
...
@@ -668,7 +672,6 @@ public class JdbcConnection extends TraceObject implements Connection {
}
catch
(
Exception
e
)
{
throw
logAndConvert
(
e
);
}
}
/**
...
...
@@ -903,7 +906,7 @@ public class JdbcConnection extends TraceObject implements Connection {
try
{
JdbcSavepoint
sp
=
convertSavepoint
(
savepoint
);
debugCode
(
"rollback("
+
sp
.
getTraceObjectName
()
+
");"
);
checkClosed
();
checkClosed
ForWrite
();
sp
.
rollback
();
}
catch
(
Exception
e
)
{
throw
logAndConvert
(
e
);
...
...
@@ -1249,20 +1252,43 @@ public class JdbcConnection extends TraceObject implements Connection {
}
/**
* INTERNAL
* Check if this connection is closed.
* The next operation is a read request.
*
* @return true if the session was re-connected
* @throws SQLException if the connection or session is closed
*/
protected
boolean
checkClosed
()
throws
SQLException
{
return
checkClosed
(
false
);
}
/**
* Check if this connection is closed.
* The next operation may be a write request.
*
* @return true if the session was re-connected
* @throws SQLException if the connection or session is closed
*/
private
boolean
checkClosedForWrite
()
throws
SQLException
{
return
checkClosed
(
true
);
}
/**
* INTERNAL
* Check if this connection is closed.
*
* @param write if the next operation is possibly writing
* @return true if the session was re-connected
* @throws SQLException if the connection or session is closed
*/
protected
boolean
checkClosed
(
boolean
write
)
throws
SQLException
{
if
(
session
==
null
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
OBJECT_CLOSED
);
}
if
(
session
.
isClosed
())
{
throw
Message
.
getSQLException
(
ErrorCode
.
DATABASE_CALLED_AT_SHUTDOWN
);
}
if
(
session
.
isReconnectNeeded
())
{
if
(
session
.
isReconnectNeeded
(
write
))
{
trace
.
debug
(
"reconnect"
);
session
=
session
.
reconnect
();
setTrace
(
session
.
getTrace
());
...
...
@@ -1340,7 +1366,7 @@ public class JdbcConnection extends TraceObject implements Connection {
try
{
int
id
=
getNextId
(
TraceObject
.
CLOB
);
debugCodeAssign
(
"Clob"
,
TraceObject
.
CLOB
,
id
,
"createClob()"
);
checkClosed
();
checkClosed
ForWrite
();
ValueLob
v
=
ValueLob
.
createSmallLob
(
Value
.
CLOB
,
new
byte
[
0
]);
return
new
JdbcClob
(
this
,
v
,
id
);
}
catch
(
Exception
e
)
{
...
...
@@ -1357,7 +1383,7 @@ public class JdbcConnection extends TraceObject implements Connection {
try
{
int
id
=
getNextId
(
TraceObject
.
BLOB
);
debugCodeAssign
(
"Blob"
,
TraceObject
.
BLOB
,
id
,
"createClob()"
);
checkClosed
();
checkClosed
ForWrite
();
ValueLob
v
=
ValueLob
.
createSmallLob
(
Value
.
BLOB
,
new
byte
[
0
]);
return
new
JdbcBlob
(
this
,
v
,
id
);
}
catch
(
Exception
e
)
{
...
...
@@ -1375,7 +1401,7 @@ public class JdbcConnection extends TraceObject implements Connection {
try {
int id = getNextId(TraceObject.CLOB);
debugCodeAssign("NClob", TraceObject.CLOB, id, "createNClob()");
checkClosed();
checkClosed
ForWrite
();
ValueLob v = ValueLob.createSmallLob(Value.CLOB, new byte[0]);
return new JdbcClob(this, v, id);
} catch (Exception e) {
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/jdbc/JdbcPreparedStatement.java
浏览文件 @
27252c09
...
...
@@ -124,7 +124,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
public
int
executeUpdate
()
throws
SQLException
{
try
{
debugCodeCall
(
"executeUpdate"
);
checkClosed
();
checkClosed
ForWrite
();
return
executeUpdateInternal
();
}
catch
(
Exception
e
)
{
throw
logAndConvert
(
e
);
...
...
@@ -159,7 +159,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCodeCall
(
"execute"
);
}
checkClosed
();
checkClosed
ForWrite
();
closeOldResultSet
();
boolean
returnsResultSet
;
synchronized
(
conn
.
getSession
())
{
...
...
@@ -703,7 +703,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setBlob("
+
parameterIndex
+
", x);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
;
if
(
x
==
null
)
{
v
=
ValueNull
.
INSTANCE
;
...
...
@@ -728,7 +728,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setBlob("
+
parameterIndex
+
", x);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createBlob
(
x
,
-
1
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -748,7 +748,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setClob("
+
parameterIndex
+
", x);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
;
if
(
x
==
null
)
{
v
=
ValueNull
.
INSTANCE
;
...
...
@@ -773,7 +773,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setClob("
+
parameterIndex
+
", x);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
;
if
(
x
==
null
)
{
v
=
ValueNull
.
INSTANCE
;
...
...
@@ -832,7 +832,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setBinaryStream("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createBlob
(
x
,
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -888,7 +888,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setAsciiStream("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createClob
(
IOUtils
.
getAsciiReader
(
x
),
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -943,7 +943,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setCharacterStream("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createClob
(
x
,
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -1031,7 +1031,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
public
int
[]
executeBatch
()
throws
SQLException
{
try
{
debugCodeCall
(
"executeBatch"
);
checkClosed
();
checkClosed
ForWrite
();
if
(
batchParameters
==
null
)
{
// TODO batch: check what other database do if no parameters are set
batchParameters
=
new
ObjectArray
();
...
...
@@ -1081,7 +1081,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
public
void
addBatch
()
throws
SQLException
{
try
{
debugCodeCall
(
"addBatch"
);
checkClosed
();
checkClosed
ForWrite
();
ObjectArray
parameters
=
command
.
getParameters
();
Value
[]
set
=
new
Value
[
parameters
.
size
()];
for
(
int
i
=
0
;
i
<
parameters
.
size
();
i
++)
{
...
...
@@ -1271,7 +1271,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setNCharacterStream("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createClob
(
x
,
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -1303,7 +1303,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if (isDebugEnabled()) {
debugCode("setNClob("+parameterIndex+", x);");
}
checkClosed();
checkClosed
ForWrite
();
Value v;
if (x == null) {
v = ValueNull.INSTANCE;
...
...
@@ -1329,7 +1329,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setNClob("
+
parameterIndex
+
", x);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createClob
(
x
,
-
1
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -1349,7 +1349,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setClob("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createClob
(
x
,
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -1369,7 +1369,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setBlob("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createBlob
(
x
,
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -1389,7 +1389,7 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
if
(
isDebugEnabled
())
{
debugCode
(
"setNClob("
+
parameterIndex
+
", x, "
+
length
+
"L);"
);
}
checkClosed
();
checkClosed
ForWrite
();
Value
v
=
conn
.
createClob
(
x
,
length
);
setParameter
(
parameterIndex
,
v
);
}
catch
(
Exception
e
)
{
...
...
@@ -1413,10 +1413,20 @@ public class JdbcPreparedStatement extends JdbcStatement implements PreparedStat
return
getTraceObjectName
()
+
": "
+
command
;
}
boolean
checkClosed
(
)
throws
SQLException
{
if
(
super
.
checkClosed
())
{
protected
boolean
checkClosed
(
boolean
write
)
throws
SQLException
{
if
(
super
.
checkClosed
(
write
))
{
// if the session was re-connected, re-prepare the statement
ObjectArray
oldParams
=
command
.
getParameters
();
command
=
conn
.
prepareCommand
(
sql
,
fetchSize
);
ObjectArray
newParams
=
command
.
getParameters
();
for
(
int
i
=
0
;
i
<
oldParams
.
size
();
i
++)
{
ParameterInterface
old
=
(
ParameterInterface
)
oldParams
.
get
(
i
);
Value
value
=
old
.
getParamValue
();
if
(
value
!=
null
)
{
ParameterInterface
n
=
(
ParameterInterface
)
newParams
.
get
(
i
);
n
.
setValue
(
value
,
false
);
}
}
return
true
;
}
return
false
;
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/jdbc/JdbcStatement.java
浏览文件 @
27252c09
...
...
@@ -105,7 +105,7 @@ public class JdbcStatement extends TraceObject implements Statement {
public
int
executeUpdate
(
String
sql
)
throws
SQLException
{
try
{
debugCodeCall
(
"executeUpdate"
,
sql
);
checkClosed
();
checkClosed
ForWrite
();
closeOldResultSet
();
if
(
escapeProcessing
)
{
sql
=
conn
.
translateSQL
(
sql
);
...
...
@@ -144,7 +144,7 @@ public class JdbcStatement extends TraceObject implements Statement {
if
(
isDebugEnabled
())
{
debugCodeCall
(
"execute"
,
sql
);
}
checkClosed
();
checkClosed
ForWrite
();
closeOldResultSet
();
if
(
escapeProcessing
)
{
sql
=
conn
.
translateSQL
(
sql
);
...
...
@@ -610,7 +610,7 @@ public class JdbcStatement extends TraceObject implements Statement {
public
int
[]
executeBatch
()
throws
SQLException
{
try
{
debugCodeCall
(
"executeBatch"
);
checkClosed
();
checkClosed
ForWrite
();
if
(
batchCommands
==
null
)
{
// TODO batch: check what other database do if no commands are set
batchCommands
=
new
ObjectArray
();
...
...
@@ -843,22 +843,47 @@ public class JdbcStatement extends TraceObject implements Statement {
// =============================================================
/**
* Check if this connection is closed.
* The next operation is a read request.
*
* @return true if the session was re-connected
* @throws SQLException if the connection or session is closed
*/
boolean
checkClosed
()
throws
SQLException
{
return
checkClosed
(
false
);
}
/**
* Check if this connection is closed.
* The next operation may be a write request.
*
* @return true if the session was re-connected
* @throws SQLException if the connection or session is closed
*/
boolean
checkClosedForWrite
()
throws
SQLException
{
return
checkClosed
(
true
);
}
/**
* Check if the statement is closed.
*
* @param write if the next operation is possibly writing
* @return true if a reconnect was required
* @throws SQLException if it is closed
*/
boolean
checkClosed
(
)
throws
SQLException
{
protected
boolean
checkClosed
(
boolean
write
)
throws
SQLException
{
if
(
conn
==
null
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
OBJECT_CLOSED
);
}
if
(
conn
.
checkClosed
())
{
if
(!
conn
.
checkClosed
(
write
))
{
return
false
;
}
do
{
session
=
conn
.
getSession
();
setTrace
(
session
.
getTrace
());
return
true
;
}
return
false
;
}
while
(
conn
.
checkClosed
(
write
));
return
true
;
}
/**
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/jdbcx/JdbcXAConnection.java
浏览文件 @
27252c09
...
...
@@ -494,11 +494,11 @@ implements XAConnection, XAResource
return
isClosed
||
super
.
isClosed
();
}
protected
synchronized
boolean
checkClosed
()
throws
SQLException
{
protected
synchronized
boolean
checkClosed
(
boolean
write
)
throws
SQLException
{
if
(
isClosed
)
{
throw
Message
.
getSQLException
(
ErrorCode
.
OBJECT_CLOSED
);
}
return
super
.
checkClosed
();
return
super
.
checkClosed
(
write
);
}
}
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/log/LogSystem.java
浏览文件 @
27252c09
...
...
@@ -240,14 +240,16 @@ public class LogSystem {
/**
* Roll back any uncommitted transactions if required, and apply committed
* changed to the data files.
*
* @return if recovery was needed
*/
public
void
recover
()
throws
SQLException
{
public
boolean
recover
()
throws
SQLException
{
if
(
database
==
null
)
{
return
;
return
false
;
}
synchronized
(
database
)
{
if
(
closed
)
{
return
;
return
false
;
}
undo
=
new
ObjectArray
();
for
(
int
i
=
0
;
i
<
activeLogs
.
size
();
i
++)
{
...
...
@@ -282,7 +284,7 @@ public class LogSystem {
if
(!
readOnly
&&
fileChanged
&&
!
containsInDoubtTransactions
())
{
checkpoint
();
}
return
;
return
fileChanged
;
}
}
...
...
@@ -514,7 +516,6 @@ public class LogSystem {
return
;
}
database
.
checkWritingAllowed
();
database
.
beforeWriting
();
if
(!
file
.
isDataFile
())
{
storageId
=
-
storageId
;
}
...
...
@@ -541,7 +542,6 @@ public class LogSystem {
return
;
}
database
.
checkWritingAllowed
();
database
.
beforeWriting
();
int
storageId
=
record
.
getStorageId
();
if
(!
file
.
isDataFile
())
{
storageId
=
-
storageId
;
...
...
@@ -569,6 +569,7 @@ public class LogSystem {
if
(
closed
||
disabled
)
{
return
;
}
database
.
checkWritingAllowed
();
flushAndCloseUnused
();
currentLog
=
new
LogFile
(
this
,
currentLog
.
getId
()
+
1
,
fileNamePrefix
);
activeLogs
.
add
(
currentLog
);
...
...
@@ -668,7 +669,7 @@ public class LogSystem {
*
* @param readOnly the new value
*/
void
setReadOnly
(
boolean
readOnly
)
{
public
void
setReadOnly
(
boolean
readOnly
)
{
this
.
readOnly
=
readOnly
;
}
...
...
@@ -706,4 +707,13 @@ public class LogSystem {
return
accessMode
;
}
/**
* Get the write position.
*
* @return the write position
*/
public
String
getWritePos
()
{
return
currentLog
.
getId
()
+
"/"
+
currentLog
.
getPos
();
}
}
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/FileLock.java
浏览文件 @
27252c09
...
...
@@ -200,8 +200,10 @@ public class FileLock {
/**
* Save the lock file.
*
* @return the saved properties
*/
public
void
save
()
throws
SQLException
{
public
Properties
save
()
throws
SQLException
{
try
{
OutputStream
out
=
fs
.
openFileOutputStream
(
fileName
,
false
);
try
{
...
...
@@ -213,6 +215,7 @@ public class FileLock {
if
(
trace
.
isDebugEnabled
())
{
trace
.
debug
(
"save "
+
properties
);
}
return
properties
;
}
catch
(
IOException
e
)
{
throw
getExceptionFatal
(
"Could not save properties "
+
fileName
,
e
);
}
...
...
@@ -301,9 +304,21 @@ public class FileLock {
private
void
lockSerialized
()
throws
SQLException
{
method
=
SERIALIZED
;
properties
=
new
SortedProperties
();
properties
.
setProperty
(
"method"
,
String
.
valueOf
(
method
));
setUniqueId
();
if
(
fs
.
createNewFile
(
fileName
))
{
properties
=
new
SortedProperties
();
properties
.
setProperty
(
"method"
,
String
.
valueOf
(
method
));
setUniqueId
();
save
();
}
else
{
while
(
true
)
{
try
{
properties
=
load
();
}
catch
(
SQLException
e
)
{
// ignore
}
return
;
}
}
}
private
void
lockFile
()
throws
SQLException
{
...
...
This diff is collapsed.
Click to expand it.
h2/src/main/org/h2/store/WriterThread.java
浏览文件 @
27252c09
...
...
@@ -8,18 +8,13 @@ package org.h2.store;
import
java.lang.ref.WeakReference
;
import
java.sql.SQLException
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Constants
;
import
org.h2.engine.Database
;
import
org.h2.engine.DbObject
;
import
org.h2.index.BtreeIndex
;
import
org.h2.log.LogSystem
;
import
org.h2.message.Trace
;
import
org.h2.message.TraceSystem
;
import
org.h2.table.Table
;
import
org.h2.util.FileUtils
;
import
org.h2.util.ObjectArray
;
/**
* The writer thread is responsible to flush the transaction log file from time
...
...
@@ -91,35 +86,12 @@ public class WriterThread implements Runnable {
return
log
;
}
private
void
flushIndexes
(
Database
database
)
{
private
void
flushIndexes
IfRequired
(
Database
database
)
{
long
time
=
System
.
currentTimeMillis
();
if
(
lastIndexFlush
+
Constants
.
FLUSH_INDEX_DELAY
>
time
)
{
return
;
}
synchronized
(
database
)
{
ObjectArray
array
=
database
.
getAllSchemaObjects
(
DbObject
.
INDEX
);
for
(
int
i
=
0
;
i
<
array
.
size
();
i
++)
{
DbObject
obj
=
(
DbObject
)
array
.
get
(
i
);
if
(
obj
instanceof
BtreeIndex
)
{
BtreeIndex
idx
=
(
BtreeIndex
)
obj
;
if
(
idx
.
getLastChange
()
==
0
)
{
continue
;
}
Table
tab
=
idx
.
getTable
();
if
(
tab
.
isLockedExclusively
())
{
continue
;
}
if
(
idx
.
getLastChange
()
+
Constants
.
FLUSH_INDEX_DELAY
>
time
)
{
continue
;
}
try
{
idx
.
flush
(
database
.
getSystemSession
());
}
catch
(
SQLException
e
)
{
database
.
getTrace
(
Trace
.
DATABASE
).
error
(
"flush index "
+
idx
.
getName
(),
e
);
}
}
}
}
database
.
flushIndexes
(
time
-
Constants
.
FLUSH_INDEX_DELAY
);
lastIndexFlush
=
time
;
}
...
...
@@ -141,7 +113,7 @@ public class WriterThread implements Runnable {
break
;
}
if
(
Constants
.
FLUSH_INDEX_DELAY
!=
0
)
{
flushIndexes
(
database
);
flushIndexes
IfRequired
(
database
);
}
// checkpoint if required
...
...
This diff is collapsed.
Click to expand it.
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
浏览文件 @
27252c09
...
...
@@ -34,6 +34,8 @@ public class TestFileLockSerialized extends TestBase {
public
void
test
()
throws
Exception
{
Class
.
forName
(
"org.h2.Driver"
);
testThreeMostlyReaders
(
true
);
testThreeMostlyReaders
(
false
);
testTwoReaders
();
testTwoWriters
();
testPendingWrite
();
...
...
@@ -41,6 +43,55 @@ public class TestFileLockSerialized extends TestBase {
testConcurrentReadWrite
();
}
private
void
testThreeMostlyReaders
(
final
boolean
write
)
throws
Exception
{
deleteDb
(
"fileLockSerialized"
);
String
url
=
"jdbc:h2:"
+
baseDir
+
"/fileLockSerialized;FILE_LOCK=SERIALIZED;OPEN_NEW=TRUE"
;
int
len
=
3
;
final
Exception
[]
ex
=
new
Exception
[
1
];
final
Connection
[]
conn
=
new
Connection
[
len
];
final
boolean
[]
stop
=
new
boolean
[
1
];
Thread
[]
threads
=
new
Thread
[
len
];
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
final
Connection
c
=
DriverManager
.
getConnection
(
url
);
conn
[
i
]
=
c
;
if
(
i
==
0
)
{
conn
[
i
].
createStatement
().
execute
(
"create table test(id int) as select 1"
);
}
Thread
t
=
new
Thread
(
new
Runnable
()
{
public
void
run
()
{
try
{
PreparedStatement
p
=
c
.
prepareStatement
(
"select * from test where id = ?"
);
while
(!
stop
[
0
])
{
if
(
write
)
{
if
(
Math
.
random
()
>
0.9
)
{
c
.
createStatement
().
execute
(
"update test set id = id"
);
}
}
p
.
setInt
(
1
,
1
);
Thread
.
sleep
(
10
);
p
.
executeQuery
();
p
.
clearParameters
();
}
c
.
close
();
}
catch
(
Exception
e
)
{
ex
[
0
]
=
e
;
}
}
});
t
.
start
();
threads
[
i
]
=
t
;
}
Thread
.
sleep
(
1000
);
stop
[
0
]
=
true
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
threads
[
i
].
join
();
}
if
(
ex
[
0
]
!=
null
)
{
throw
ex
[
0
];
}
DriverManager
.
getConnection
(
url
).
close
();
}
private
void
testTwoReaders
()
throws
Exception
{
deleteDb
(
"fileLockSerialized"
);
String
url
=
"jdbc:h2:"
+
baseDir
+
"/fileLockSerialized;FILE_LOCK=SERIALIZED;OPEN_NEW=TRUE"
;
...
...
This diff is collapsed.
Click to expand it.
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论