Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
945c201f
提交
945c201f
authored
2月 06, 2009
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
New experimental server-less multi-connection mode
上级
c142344e
显示空白字符变更
内嵌
并排
正在显示
22 个修改的文件
包含
464 行增加
和
97 行删除
+464
-97
Parser.java
h2/src/main/org/h2/command/Parser.java
+4
-0
Prepared.java
h2/src/main/org/h2/command/Prepared.java
+20
-1
TransactionCommand.java
h2/src/main/org/h2/command/dml/TransactionCommand.java
+1
-8
SysProperties.java
h2/src/main/org/h2/constant/SysProperties.java
+14
-0
ConnectionInfo.java
h2/src/main/org/h2/engine/ConnectionInfo.java
+12
-0
Database.java
h2/src/main/org/h2/engine/Database.java
+122
-9
Engine.java
h2/src/main/org/h2/engine/Engine.java
+14
-1
Session.java
h2/src/main/org/h2/engine/Session.java
+26
-3
SessionInterface.java
h2/src/main/org/h2/engine/SessionInterface.java
+14
-0
SessionRemote.java
h2/src/main/org/h2/engine/SessionRemote.java
+11
-35
SessionWithState.java
h2/src/main/org/h2/engine/SessionWithState.java
+60
-0
JdbcConnection.java
h2/src/main/org/h2/jdbc/JdbcConnection.java
+6
-3
LogSystem.java
h2/src/main/org/h2/log/LogSystem.java
+2
-0
TraceSystem.java
h2/src/main/org/h2/message/TraceSystem.java
+8
-0
help.csv
h2/src/main/org/h2/res/help.csv
+4
-4
FileLock.java
h2/src/main/org/h2/store/FileLock.java
+46
-17
PageStore.java
h2/src/main/org/h2/store/PageStore.java
+1
-0
WriterThread.java
h2/src/main/org/h2/store/WriterThread.java
+12
-0
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+4
-12
TestBase.java
h2/src/test/org/h2/test/TestBase.java
+2
-2
TestFileLock.java
h2/src/test/org/h2/test/unit/TestFileLock.java
+2
-2
TestFileLockSerialized.java
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
+79
-0
没有找到文件。
h2/src/main/org/h2/command/Parser.java
浏览文件 @
945c201f
...
...
@@ -4085,6 +4085,10 @@ public class Parser {
readIfEqualOrTo
();
read
();
return
new
NoOperation
(
session
);
}
else
if
(
readIf
(
"OPEN_NEW"
))
{
readIfEqualOrTo
();
read
();
return
new
NoOperation
(
session
);
}
else
if
(
readIf
(
"RECOVER"
))
{
readIfEqualOrTo
();
read
();
...
...
h2/src/main/org/h2/command/Prepared.java
浏览文件 @
945c201f
...
...
@@ -368,6 +368,12 @@ public abstract class Prepared {
return
sqlStatement
;
}
/**
* Get the SQL snippet of the value list.
*
* @param values the value list
* @return the SQL snippet
*/
protected
String
getSQL
(
Value
[]
values
)
{
StringBuffer
buff
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
values
.
length
;
i
++)
{
...
...
@@ -382,6 +388,12 @@ public abstract class Prepared {
return
buff
.
toString
();
}
/**
* Get the SQL snippet of the expression list.
*
* @param list the expression list
* @return the SQL snippet
*/
protected
String
getSQL
(
Expression
[]
list
)
{
StringBuffer
buff
=
new
StringBuffer
();
for
(
int
i
=
0
;
i
<
list
.
length
;
i
++)
{
...
...
@@ -396,7 +408,14 @@ public abstract class Prepared {
return
buff
.
toString
();
}
/**
* Set the SQL statement of the exception to the given row.
*
* @param ex the exception
* @param rowId the row number
* @param values the values of the row
* @return the exception
*/
protected
SQLException
setRow
(
SQLException
ex
,
int
rowId
,
String
values
)
{
if
(
ex
instanceof
JdbcSQLException
)
{
JdbcSQLException
e
=
(
JdbcSQLException
)
ex
;
...
...
h2/src/main/org/h2/command/dml/TransactionCommand.java
浏览文件 @
945c201f
...
...
@@ -9,13 +9,11 @@ package org.h2.command.dml;
import
java.sql.SQLException
;
import
org.h2.command.Prepared
;
import
org.h2.constant.SysProperties
;
import
org.h2.engine.Database
;
import
org.h2.engine.Session
;
import
org.h2.log.LogSystem
;
import
org.h2.message.Message
;
import
org.h2.result.LocalResult
;
import
org.h2.store.PageStore
;
/**
* Represents a transactional statement.
...
...
@@ -124,12 +122,7 @@ public class TransactionCommand extends Prepared {
break
;
case
CHECKPOINT:
session
.
getUser
().
checkAdmin
();
if
(
SysProperties
.
PAGE_STORE
)
{
PageStore
store
=
session
.
getDatabase
().
getPageStore
();
store
.
checkpoint
();
}
session
.
getDatabase
().
getLog
().
checkpoint
();
session
.
getDatabase
().
getTempFileDeleter
().
deleteUnused
();
session
.
getDatabase
().
checkpoint
();
break
;
case
SAVEPOINT:
session
.
addSavepoint
(
savepointName
);
...
...
h2/src/main/org/h2/constant/SysProperties.java
浏览文件 @
945c201f
...
...
@@ -446,6 +446,15 @@ public class SysProperties {
*/
public
static
final
boolean
RECOMPILE_ALWAYS
=
getBooleanSetting
(
"h2.recompileAlways"
,
false
);
/**
* System property <code>h2.reconnectCheckDelay</code> (default: 250).<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"
,
250
);
/**
* System property <code>h2.redoBufferSize</code> (default: 262144).<br />
* Size of the redo buffer (used at startup when recovering).
...
...
@@ -558,6 +567,11 @@ public class SysProperties {
*/
public
static
final
int
COLLATOR_CACHE_SIZE
=
getCollatorCacheSize
();
/**
* The current time this class was loaded (in milliseconds).
*/
public
static
final
long
TIME_START
=
System
.
currentTimeMillis
();
private
static
final
String
H2_BASE_DIR
=
"h2.baseDir"
;
private
SysProperties
()
{
...
...
h2/src/main/org/h2/engine/ConnectionInfo.java
浏览文件 @
945c201f
...
...
@@ -277,6 +277,18 @@ public class ConnectionInfo implements Cloneable {
userPasswordHash
=
sha
.
getKeyPasswordHash
(
user
,
password
);
}
/**
* Get a boolean property if it is set and return the value.
*
* @param key the property name
* @param defaultValue the default value
* @return the value
*/
public
boolean
getProperty
(
String
key
,
boolean
defaultValue
)
{
String
x
=
getProperty
(
key
,
null
);
return
x
==
null
?
defaultValue
:
Boolean
.
valueOf
(
x
).
booleanValue
();
}
/**
* Remove a boolean property if it is set and return the value.
*
...
...
h2/src/main/org/h2/engine/Database.java
浏览文件 @
945c201f
...
...
@@ -13,6 +13,7 @@ import java.util.Collections;
import
java.util.HashMap
;
import
java.util.HashSet
;
import
java.util.Iterator
;
import
java.util.Properties
;
import
java.util.Set
;
import
java.util.StringTokenizer
;
...
...
@@ -165,6 +166,10 @@ public class Database implements DataHandler {
private
TempFileDeleter
tempFileDeleter
=
TempFileDeleter
.
getInstance
();
private
PageStore
pageStore
;
private
Properties
reconnectLastLock
;
private
long
reconnectCheckNext
;
private
boolean
reconnectChangePending
;
public
Database
(
String
name
,
ConnectionInfo
ci
,
String
cipher
)
throws
SQLException
{
this
.
compareMode
=
new
CompareMode
(
null
,
null
,
0
);
this
.
persistent
=
ci
.
isPersistent
();
...
...
@@ -172,15 +177,18 @@ public class Database implements DataHandler {
this
.
databaseName
=
name
;
this
.
databaseShortName
=
parseDatabaseShortName
();
this
.
cipher
=
cipher
;
String
lockMethodName
=
ci
.
remove
Property
(
"FILE_LOCK"
,
null
);
this
.
accessModeLog
=
ci
.
remove
Property
(
"ACCESS_MODE_LOG"
,
"rw"
).
toLowerCase
();
this
.
accessModeData
=
ci
.
remove
Property
(
"ACCESS_MODE_DATA"
,
"rw"
).
toLowerCase
();
this
.
autoServerMode
=
ci
.
remove
Property
(
"AUTO_SERVER"
,
false
);
String
lockMethodName
=
ci
.
get
Property
(
"FILE_LOCK"
,
null
);
this
.
accessModeLog
=
ci
.
get
Property
(
"ACCESS_MODE_LOG"
,
"rw"
).
toLowerCase
();
this
.
accessModeData
=
ci
.
get
Property
(
"ACCESS_MODE_DATA"
,
"rw"
).
toLowerCase
();
this
.
autoServerMode
=
ci
.
get
Property
(
"AUTO_SERVER"
,
false
);
if
(
"r"
.
equals
(
accessModeData
))
{
readOnly
=
true
;
accessModeLog
=
"r"
;
}
this
.
fileLockMethod
=
FileLock
.
getFileLockMethod
(
lockMethodName
);
if
(
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
)
{
writeDelay
=
SysProperties
.
MIN_WRITE_DELAY
;
}
this
.
databaseURL
=
ci
.
getURL
();
this
.
eventListener
=
ci
.
getDatabaseEventListenerObject
();
ci
.
removeDatabaseEventListenerObject
();
...
...
@@ -199,12 +207,16 @@ public class Database implements DataHandler {
if
(
ignoreSummary
!=
null
)
{
this
.
recovery
=
true
;
}
this
.
multiVersion
=
ci
.
remove
Property
(
"MVCC"
,
false
);
boolean
closeAtVmShutdown
=
ci
.
remove
Property
(
"DB_CLOSE_ON_EXIT"
,
true
);
this
.
multiVersion
=
ci
.
get
Property
(
"MVCC"
,
false
);
boolean
closeAtVmShutdown
=
ci
.
get
Property
(
"DB_CLOSE_ON_EXIT"
,
true
);
int
traceLevelFile
=
ci
.
getIntProperty
(
SetTypes
.
TRACE_LEVEL_FILE
,
TraceSystem
.
DEFAULT_TRACE_LEVEL_FILE
);
int
traceLevelSystemOut
=
ci
.
getIntProperty
(
SetTypes
.
TRACE_LEVEL_SYSTEM_OUT
,
TraceSystem
.
DEFAULT_TRACE_LEVEL_SYSTEM_OUT
);
this
.
cacheType
=
StringUtils
.
toUpperEnglish
(
ci
.
removeProperty
(
"CACHE_TYPE"
,
CacheLRU
.
TYPE_NAME
));
openDatabase
(
traceLevelFile
,
traceLevelSystemOut
,
closeAtVmShutdown
);
}
private
void
openDatabase
(
int
traceLevelFile
,
int
traceLevelSystemOut
,
boolean
closeAtVmShutdown
)
throws
SQLException
{
try
{
open
(
traceLevelFile
,
traceLevelSystemOut
);
if
(
closeAtVmShutdown
)
{
...
...
@@ -295,6 +307,25 @@ public class Database implements DataHandler {
return
modificationDataId
;
}
private
void
reconnectModified
(
boolean
pending
)
{
if
(
readOnly
||
pending
==
reconnectChangePending
||
lock
==
null
)
{
return
;
}
try
{
if
(
pending
)
{
getTrace
().
debug
(
"wait before writing"
);
Thread
.
sleep
((
int
)
(
SysProperties
.
RECONNECT_CHECK_DELAY
*
1.1
));
}
lock
.
setProperty
(
"modificationDataId"
,
Long
.
toString
(
modificationDataId
));
lock
.
setProperty
(
"modificationMetaId"
,
Long
.
toString
(
modificationMetaId
));
lock
.
setProperty
(
"changePending"
,
pending
?
"true"
:
null
);
lock
.
save
();
reconnectChangePending
=
pending
;
}
catch
(
Exception
e
)
{
getTrace
().
error
(
"pending:"
+
pending
,
e
);
}
}
public
long
getNextModificationDataId
()
{
return
++
modificationDataId
;
}
...
...
@@ -478,12 +509,14 @@ public class Database implements DataHandler {
}
}
if
(!
readOnly
&&
fileLockMethod
!=
FileLock
.
LOCK_NO
)
{
lock
=
new
FileLock
(
traceSystem
,
Constants
.
LOCK_SLEEP
);
lock
.
lock
(
databaseName
+
Constants
.
SUFFIX_LOCK_FILE
,
fileLockMethod
==
FileLock
.
LOCK_SOCKET
);
lock
=
new
FileLock
(
traceSystem
,
databaseName
+
Constants
.
SUFFIX_LOCK_FILE
,
Constants
.
LOCK_SLEEP
);
lock
.
lock
(
fileLockMethod
);
if
(
autoServerMode
)
{
startServer
(
lock
.
getUniqueId
());
}
}
// wait until pending changes are written
isReconnectNeeded
();
if
(
SysProperties
.
PAGE_STORE
)
{
PageStore
store
=
getPageStore
();
if
(!
store
.
isNew
())
{
...
...
@@ -602,7 +635,8 @@ public class Database implements DataHandler {
"-key"
,
key
,
databaseName
});
server
.
start
();
String
address
=
NetUtils
.
getLocalAddress
()
+
":"
+
server
.
getPort
();
lock
.
addProperty
(
"server"
,
address
);
lock
.
setProperty
(
"server"
,
address
);
lock
.
save
();
}
private
void
stopServer
()
{
...
...
@@ -2138,4 +2172,83 @@ public class Database implements DataHandler {
return
null
;
}
public
boolean
isReconnectNeeded
()
{
if
(
fileLockMethod
!=
FileLock
.
LOCK_SERIALIZED
)
{
return
false
;
}
long
now
=
System
.
currentTimeMillis
();
if
(
now
<
reconnectCheckNext
)
{
return
false
;
}
reconnectCheckNext
=
now
+
SysProperties
.
RECONNECT_CHECK_DELAY
;
if
(
lock
==
null
)
{
lock
=
new
FileLock
(
traceSystem
,
databaseName
+
Constants
.
SUFFIX_LOCK_FILE
,
Constants
.
LOCK_SLEEP
);
}
Properties
prop
;
try
{
while
(
true
)
{
prop
=
lock
.
load
();
if
(
prop
.
equals
(
reconnectLastLock
))
{
return
false
;
}
if
(
prop
.
getProperty
(
"changePending"
,
null
)
==
null
)
{
break
;
}
getTrace
().
debug
(
"delay (change pending)"
);
Thread
.
sleep
(
SysProperties
.
RECONNECT_CHECK_DELAY
);
}
reconnectLastLock
=
prop
;
}
catch
(
Exception
e
)
{
getTrace
().
error
(
"readOnly:"
+
readOnly
,
e
);
// ignore
}
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.
*/
public
void
checkpointIfRequired
()
throws
SQLException
{
if
(
fileLockMethod
!=
FileLock
.
LOCK_SERIALIZED
||
readOnly
||
!
reconnectChangePending
)
{
return
;
}
long
now
=
System
.
currentTimeMillis
();
if
(
now
>
reconnectCheckNext
)
{
getTrace
().
debug
(
"checkpoint"
);
checkpoint
();
reconnectModified
(
false
);
}
}
/**
* Flush all changes and open a new log file.
*/
public
void
checkpoint
()
throws
SQLException
{
if
(
SysProperties
.
PAGE_STORE
)
{
pageStore
.
checkpoint
();
}
getLog
().
checkpoint
();
getTempFileDeleter
().
deleteUnused
();
}
/**
* This method is called before writing to the log file.
*/
public
void
beforeWriting
()
{
if
(
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
)
{
reconnectModified
(
true
);
}
}
}
h2/src/main/org/h2/engine/Engine.java
浏览文件 @
945c201f
...
...
@@ -16,6 +16,7 @@ import org.h2.constant.ErrorCode;
import
org.h2.constant.SysProperties
;
import
org.h2.message.Message
;
import
org.h2.message.Trace
;
import
org.h2.store.FileLock
;
import
org.h2.util.RandomUtils
;
import
org.h2.util.StringUtils
;
...
...
@@ -41,7 +42,7 @@ public class Engine {
private
Session
openSession
(
ConnectionInfo
ci
,
boolean
ifExists
,
String
cipher
)
throws
SQLException
{
String
name
=
ci
.
getName
();
Database
database
;
boolean
openNew
=
ci
.
remove
Property
(
"OPEN_NEW"
,
false
);
boolean
openNew
=
ci
.
get
Property
(
"OPEN_NEW"
,
false
);
if
(
openNew
||
ci
.
isUnnamedInMemory
())
{
database
=
null
;
}
else
{
...
...
@@ -105,8 +106,20 @@ public class Engine {
*/
public
Session
getSession
(
ConnectionInfo
ci
)
throws
SQLException
{
try
{
ConnectionInfo
backup
=
null
;
String
lockMethodName
=
ci
.
getProperty
(
"FILE_LOCK"
,
null
);
int
fileLockMethod
=
FileLock
.
getFileLockMethod
(
lockMethodName
);
if
(
fileLockMethod
==
FileLock
.
LOCK_SERIALIZED
)
{
try
{
backup
=
(
ConnectionInfo
)
ci
.
clone
();
}
catch
(
CloneNotSupportedException
e
)
{
}
}
Session
session
=
openSession
(
ci
);
validateUserAndPassword
(
true
);
if
(
backup
!=
null
)
{
session
.
setConnectionInfo
(
backup
);
}
return
session
;
}
catch
(
SQLException
e
)
{
if
(
e
.
getErrorCode
()
==
ErrorCode
.
WRONG_USER_OR_PASSWORD
)
{
...
...
h2/src/main/org/h2/engine/Session.java
浏览文件 @
945c201f
...
...
@@ -46,7 +46,7 @@ import org.h2.value.ValueNull;
* mode, this object resides on the server side and communicates with a
* SessionRemote object on the client side.
*/
public
class
Session
implements
SessionInterfac
e
{
public
class
Session
extends
SessionWithStat
e
{
/**
* The prefix of generated identifiers. It may not have letters, because
...
...
@@ -56,9 +56,10 @@ public class Session implements SessionInterface {
private
static
int
nextSerialId
;
private
final
int
serialId
=
nextSerialId
++;
private
Database
database
;
private
ConnectionInfo
connectionInfo
;
private
User
user
;
private
int
id
;
private
Database
database
;
private
ObjectArray
locks
=
new
ObjectArray
();
private
UndoLog
undoLog
;
private
boolean
autoCommit
=
true
;
...
...
@@ -97,6 +98,7 @@ public class Session implements SessionInterface {
private
boolean
commitOrRollbackDisabled
;
private
Table
waitForLock
;
private
int
modificationId
;
private
int
modificationIdState
;
Session
(
Database
database
,
User
user
,
int
id
)
{
this
.
database
=
database
;
...
...
@@ -625,12 +627,13 @@ public class Session implements SessionInterface {
}
}
private
void
unlockAll
()
{
private
void
unlockAll
()
throws
SQLException
{
if
(
SysProperties
.
CHECK
)
{
if
(
undoLog
.
size
()
>
0
)
{
Message
.
throwInternalError
();
}
}
database
.
afterWriting
();
if
(
locks
.
size
()
>
0
)
{
synchronized
(
database
)
{
for
(
int
i
=
0
;
i
<
locks
.
size
();
i
++)
{
...
...
@@ -641,6 +644,10 @@ public class Session implements SessionInterface {
}
}
savepoints
=
null
;
if
(
modificationIdState
!=
modificationId
)
{
sessionStateChanged
=
true
;
}
}
private
void
cleanTempTables
(
boolean
closeSession
)
throws
SQLException
{
...
...
@@ -1104,4 +1111,20 @@ public class Session implements SessionInterface {
return
modificationId
;
}
public
boolean
isReconnectNeeded
()
{
return
database
.
isReconnectNeeded
();
}
public
SessionInterface
reconnect
()
throws
SQLException
{
readSessionState
();
Session
newSession
=
Engine
.
getInstance
().
getSession
(
connectionInfo
);
newSession
.
sessionState
=
sessionState
;
newSession
.
recreateSessionState
();
return
newSession
;
}
public
void
setConnectionInfo
(
ConnectionInfo
ci
)
{
connectionInfo
=
ci
;
}
}
h2/src/main/org/h2/engine/SessionInterface.java
浏览文件 @
945c201f
...
...
@@ -72,4 +72,18 @@ public interface SessionInterface {
* Cancel the current or next command (called when closing a connection).
*/
void
cancel
();
/**
* Check if the database changed and therefore reconnecting is required.
*
* @return true if reconnecting is required
*/
boolean
isReconnectNeeded
();
/**
* Close the connection and open a new connection.
*
* @return the new connection
*/
SessionInterface
reconnect
()
throws
SQLException
;
}
h2/src/main/org/h2/engine/SessionRemote.java
浏览文件 @
945c201f
...
...
@@ -41,7 +41,7 @@ import org.h2.value.ValueString;
* The client side part of a session when using the server mode. This object
* communicates with a Session on the server side.
*/
public
class
SessionRemote
implements
SessionInterface
,
SessionFactory
,
DataHandler
{
public
class
SessionRemote
extends
SessionWithState
implements
SessionFactory
,
DataHandler
{
public
static
final
int
SESSION_PREPARE
=
0
;
public
static
final
int
SESSION_CLOSE
=
1
;
...
...
@@ -81,9 +81,6 @@ public class SessionRemote implements SessionInterface, SessionFactory, DataHand
private
boolean
autoReconnect
;
private
int
lastReconnect
;
private
SessionInterface
embedded
;
private
boolean
sessionStateChanged
;
private
ObjectArray
sessionState
;
private
boolean
sessionStateUpdating
;
private
DatabaseEventListener
eventListener
;
public
SessionRemote
()
{
...
...
@@ -259,7 +256,7 @@ public class SessionRemote implements SessionInterface, SessionFactory, DataHand
// OPEN_NEW must be removed now, otherwise
// opening a session with AUTO_SERVER fails
// if another connection is already open
backup
.
removeProperty
(
"OPEN_NEW"
,
false
);
backup
.
removeProperty
(
"OPEN_NEW"
,
null
);
connectServer
(
backup
);
return
this
;
}
...
...
@@ -451,19 +448,7 @@ public class SessionRemote implements SessionInterface, SessionFactory, DataHand
// unfortunately
connectEmbeddedOrServer
(
true
);
}
if
(
sessionState
!=
null
&&
sessionState
.
size
()
>
0
)
{
sessionStateUpdating
=
true
;
try
{
for
(
int
i
=
0
;
i
<
sessionState
.
size
();
i
++)
{
String
sql
=
(
String
)
sessionState
.
get
(
i
);
CommandInterface
ci
=
prepareCommand
(
sql
,
Integer
.
MAX_VALUE
);
ci
.
executeUpdate
();
}
}
finally
{
sessionStateUpdating
=
false
;
sessionStateChanged
=
false
;
}
}
recreateSessionState
();
if
(
eventListener
!=
null
)
{
eventListener
.
setProgress
(
DatabaseEventListener
.
STATE_RECONNECTED
,
databaseName
,
count
,
SysProperties
.
MAX_RECONNECT
);
...
...
@@ -663,25 +648,16 @@ public class SessionRemote implements SessionInterface, SessionFactory, DataHand
return
lastReconnect
;
}
/**
* Read the session state if necessary.
*/
public
void
readSessionState
()
throws
SQLException
{
if
(!
sessionStateChanged
||
sessionStateUpdating
)
{
return
;
}
sessionStateChanged
=
false
;
sessionState
=
new
ObjectArray
();
CommandInterface
ci
=
prepareCommand
(
"SELECT * FROM INFORMATION_SCHEMA.SESSION_STATE"
,
Integer
.
MAX_VALUE
);
ResultInterface
result
=
ci
.
executeQuery
(
0
,
false
);
while
(
result
.
next
())
{
Value
[]
row
=
result
.
currentRow
();
sessionState
.
add
(
row
[
1
].
getString
());
public
TempFileDeleter
getTempFileDeleter
()
{
return
TempFileDeleter
.
getInstance
();
}
public
boolean
isReconnectNeeded
()
{
return
false
;
}
public
TempFileDeleter
getTempFileDeleter
()
{
return
TempFileDeleter
.
getInstance
()
;
public
SessionInterface
reconnect
()
{
return
this
;
}
}
h2/src/main/org/h2/engine/SessionWithState.java
0 → 100644
浏览文件 @
945c201f
/*
* Copyright 2004-2009 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
engine
;
import
java.sql.SQLException
;
import
org.h2.command.CommandInterface
;
import
org.h2.result.ResultInterface
;
import
org.h2.util.ObjectArray
;
import
org.h2.value.Value
;
/**
* The base class for both remote and embedded sessions.
*/
public
abstract
class
SessionWithState
implements
SessionInterface
{
protected
ObjectArray
sessionState
;
protected
boolean
sessionStateChanged
;
private
boolean
sessionStateUpdating
;
/**
* Re-create the session state using the stored sessionState list.
*/
protected
void
recreateSessionState
()
throws
SQLException
{
if
(
sessionState
!=
null
&&
sessionState
.
size
()
>
0
)
{
sessionStateUpdating
=
true
;
try
{
for
(
int
i
=
0
;
i
<
sessionState
.
size
();
i
++)
{
String
sql
=
(
String
)
sessionState
.
get
(
i
);
CommandInterface
ci
=
prepareCommand
(
sql
,
Integer
.
MAX_VALUE
);
ci
.
executeUpdate
();
}
}
finally
{
sessionStateUpdating
=
false
;
sessionStateChanged
=
false
;
}
}
}
/**
* Read the session state if necessary.
*/
public
void
readSessionState
()
throws
SQLException
{
if
(!
sessionStateChanged
||
sessionStateUpdating
)
{
return
;
}
sessionStateChanged
=
false
;
sessionState
=
new
ObjectArray
();
CommandInterface
ci
=
prepareCommand
(
"SELECT * FROM INFORMATION_SCHEMA.SESSION_STATE"
,
Integer
.
MAX_VALUE
);
ResultInterface
result
=
ci
.
executeQuery
(
0
,
false
);
while
(
result
.
next
())
{
Value
[]
row
=
result
.
currentRow
();
sessionState
.
add
(
row
[
1
].
getString
());
}
}
}
h2/src/main/org/h2/jdbc/JdbcConnection.java
浏览文件 @
945c201f
...
...
@@ -62,9 +62,6 @@ import java.sql.SQLClientInfoException;
* </p>
*/
public
class
JdbcConnection
extends
TraceObject
implements
Connection
{
// TODO test: check if enough synchronization on jdbc objects
// TODO feature: auto-reconnect on lost connection
private
String
url
;
private
String
user
;
...
...
@@ -1266,6 +1263,12 @@ public class JdbcConnection extends TraceObject implements Connection {
if
(
session
.
isClosed
())
{
throw
Message
.
getSQLException
(
ErrorCode
.
DATABASE_CALLED_AT_SHUTDOWN
);
}
if
(
session
.
isReconnectNeeded
())
{
trace
.
debug
(
"reconnect"
);
session
=
session
.
reconnect
();
trace
=
session
.
getTrace
();
setTrace
(
trace
,
TraceObject
.
CONNECTION
,
getTraceId
());
}
}
String
getURL
()
throws
SQLException
{
...
...
h2/src/main/org/h2/log/LogSystem.java
浏览文件 @
945c201f
...
...
@@ -509,6 +509,7 @@ public class LogSystem {
return
;
}
database
.
checkWritingAllowed
();
database
.
beforeWriting
();
if
(!
file
.
isDataFile
())
{
storageId
=
-
storageId
;
}
...
...
@@ -535,6 +536,7 @@ public class LogSystem {
return
;
}
database
.
checkWritingAllowed
();
database
.
beforeWriting
();
int
storageId
=
record
.
getStorageId
();
if
(!
file
.
isDataFile
())
{
storageId
=
-
storageId
;
...
...
h2/src/main/org/h2/message/TraceSystem.java
浏览文件 @
945c201f
...
...
@@ -178,6 +178,10 @@ public class TraceSystem implements TraceWriter {
updateLevel
();
}
public
int
getLevelSystemOut
()
{
return
levelSystemOut
;
}
/**
* Set the file trace level.
*
...
...
@@ -209,6 +213,10 @@ public class TraceSystem implements TraceWriter {
updateLevel
();
}
public
int
getLevelFile
()
{
return
levelFile
;
}
private
String
format
(
String
module
,
String
s
)
{
synchronized
(
dateFormat
)
{
return
dateFormat
.
format
(
new
Date
())
+
module
+
": "
+
s
;
...
...
h2/src/main/org/h2/res/help.csv
浏览文件 @
945c201f
h2/src/main/org/h2/store/FileLock.java
浏览文件 @
945c201f
...
...
@@ -54,8 +54,14 @@ public class FileLock {
*/
public
static
final
int
LOCK_SOCKET
=
2
;
/**
* This locking method means multiple writers are allowed, and they
* synchronize themselves.
*/
public
static
final
int
LOCK_SERIALIZED
=
3
;
private
static
final
String
MAGIC
=
"FileLock"
;
private
static
final
String
FILE
=
"file"
,
SOCKET
=
"socket"
;
private
static
final
String
FILE
=
"file"
,
SOCKET
=
"socket"
,
SERIALIZED
=
"serialized"
;
private
static
final
int
RANDOM_BYTES
=
16
;
private
static
final
int
SLEEP_GAP
=
25
;
private
static
final
int
TIME_GRANULARITY
=
2000
;
...
...
@@ -101,30 +107,34 @@ public class FileLock {
* @param traceSystem the trace system to use
* @param sleep the number of milliseconds to sleep
*/
public
FileLock
(
TraceSystem
traceSystem
,
int
sleep
)
{
public
FileLock
(
TraceSystem
traceSystem
,
String
fileName
,
int
sleep
)
{
this
.
trace
=
traceSystem
.
getTrace
(
Trace
.
FILE_LOCK
);
this
.
fileName
=
fileName
;
this
.
sleep
=
sleep
;
}
/**
* Lock the file if possible. A file may only be locked once.
*
* @param fileName the name of the properties file to use
* @param allowSocket if the socket locking protocol should be used if
* possible
* @param fileLockMethod the file locking method to use
* @throws SQLException if locking was not successful
*/
public
synchronized
void
lock
(
String
fileName
,
boolean
allowSocket
)
throws
SQLException
{
public
synchronized
void
lock
(
int
fileLockMethod
)
throws
SQLException
{
this
.
fs
=
FileSystem
.
getInstance
(
fileName
);
this
.
fileName
=
fileName
;
checkServer
();
if
(
locked
)
{
Message
.
throwInternalError
(
"already locked"
);
}
if
(
allowSocket
)
{
lockSocket
();
}
else
{
switch
(
fileLockMethod
)
{
case
LOCK_FILE:
lockFile
();
break
;
case
LOCK_SOCKET:
lockSocket
();
break
;
case
LOCK_SERIALIZED:
lockSerialized
();
break
;
}
locked
=
true
;
}
...
...
@@ -155,14 +165,18 @@ public class FileLock {
}
/**
* Add a setting to the properties file.
* Add or change a setting to the properties. This call does not save the
* file.
*
* @param key the key
* @param value the value
*/
public
void
addProperty
(
String
key
,
String
value
)
throws
SQLException
{
public
void
setProperty
(
String
key
,
String
value
)
throws
SQLException
{
if
(
value
==
null
)
{
properties
.
remove
(
key
);
}
else
{
properties
.
put
(
key
,
value
);
save
();
}
}
/**
...
...
@@ -187,11 +201,10 @@ public class FileLock {
/**
* Save the lock file.
*/
void
save
()
throws
SQLException
{
public
void
save
()
throws
SQLException
{
try
{
OutputStream
out
=
fs
.
openFileOutputStream
(
fileName
,
false
);
try
{
properties
.
setProperty
(
"method"
,
String
.
valueOf
(
method
));
properties
.
store
(
out
,
MAGIC
);
}
finally
{
out
.
close
();
...
...
@@ -242,7 +255,12 @@ public class FileLock {
}
}
private
Properties
load
()
throws
SQLException
{
/**
* Load the properties file.
*
* @return the properties
*/
public
Properties
load
()
throws
SQLException
{
try
{
Properties
p2
=
SortedProperties
.
loadProperties
(
fileName
);
if
(
trace
.
isDebugEnabled
())
{
...
...
@@ -281,9 +299,17 @@ public class FileLock {
properties
.
setProperty
(
"id"
,
uniqueId
);
}
private
void
lockSerialized
()
throws
SQLException
{
method
=
SERIALIZED
;
properties
=
new
SortedProperties
();
properties
.
setProperty
(
"method"
,
String
.
valueOf
(
method
));
setUniqueId
();
}
private
void
lockFile
()
throws
SQLException
{
method
=
FILE
;
properties
=
new
SortedProperties
();
properties
.
setProperty
(
"method"
,
String
.
valueOf
(
method
));
setUniqueId
();
if
(!
fs
.
createNewFile
(
fileName
))
{
waitUntilOld
();
...
...
@@ -337,6 +363,7 @@ public class FileLock {
private
void
lockSocket
()
throws
SQLException
{
method
=
SOCKET
;
properties
=
new
SortedProperties
();
properties
.
setProperty
(
"method"
,
String
.
valueOf
(
method
));
setUniqueId
();
// if this returns 127.0.0.1,
// the computer is probably not networked
...
...
@@ -458,6 +485,8 @@ public class FileLock {
return
FileLock
.
LOCK_NO
;
}
else
if
(
method
.
equalsIgnoreCase
(
"SOCKET"
))
{
return
FileLock
.
LOCK_SOCKET
;
}
else
if
(
method
.
equalsIgnoreCase
(
"SERIALIZED"
))
{
return
FileLock
.
LOCK_SERIALIZED
;
}
else
{
throw
Message
.
getSQLException
(
ErrorCode
.
UNSUPPORTED_LOCK_METHOD_1
,
method
);
}
...
...
h2/src/main/org/h2/store/PageStore.java
浏览文件 @
945c201f
...
...
@@ -63,6 +63,7 @@ public class PageStore implements CacheWriter {
// synchronized correctly (on the index?)
// TODO two phase commit: append (not patch) commit & rollback
// TODO remove trace or use isDebugEnabled
// TODO recover tool: don't re-do uncommitted operations
/**
* The smallest possible page size.
...
...
h2/src/main/org/h2/store/WriterThread.java
浏览文件 @
945c201f
...
...
@@ -142,6 +142,17 @@ public class WriterThread extends Thread {
if
(
Constants
.
FLUSH_INDEX_DELAY
!=
0
)
{
flushIndexes
(
database
);
}
// checkpoint if required
try
{
database
.
checkpointIfRequired
();
}
catch
(
SQLException
e
)
{
TraceSystem
traceSystem
=
database
.
getTraceSystem
();
if
(
traceSystem
!=
null
)
{
traceSystem
.
getTrace
(
Trace
.
LOG
).
error
(
"reconnectCheckpoint"
,
e
);
}
}
LogSystem
log
=
database
.
getLog
();
if
(
log
==
null
)
{
break
;
...
...
@@ -154,6 +165,7 @@ public class WriterThread extends Thread {
traceSystem
.
getTrace
(
Trace
.
LOG
).
error
(
"flush"
,
e
);
}
}
// TODO log writer: could also flush the dirty cache when there is
// low activity
int
wait
=
writeDelay
;
...
...
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
945c201f
...
...
@@ -283,23 +283,15 @@ java org.h2.test.TestAll timer
/*
maybe close the database when a final static field is set to null?
select 1 from dual a where 1 in(select 1 from dual b
where 1 in(select 1 from dual c where a.x=1));
use 127.0.0.1 if other addresses don't work
isShutdown
error message on insert / merge: include SQL statement (at least table name)
PageStore.switchLogIfPossible()
drop table test;
create table test(id int);
select 1 from test where 'a'=1;
Fails: Oracle, PostgreSQL, H2
Works: MySQL, HSQLDB
use 127.0.0.1 if other addresses don't work
select for update in mvcc mode: only lock the selected records?
test case for daylight saving time enabled/move to a timezone (locking,...)
JCR: for each node type, create a table; one 'dynamic' table with parameter;
option to cache the results
<link rel="icon" type="image/png" href="/path/image.png">
...
...
h2/src/test/org/h2/test/TestBase.java
浏览文件 @
945c201f
...
...
@@ -375,8 +375,8 @@ public abstract class TestBase {
e
.
printStackTrace
();
try
{
TraceSystem
ts
=
new
TraceSystem
(
null
,
false
);
FileLock
lock
=
new
FileLock
(
ts
,
1000
);
lock
.
lock
(
"error.lock"
,
false
);
FileLock
lock
=
new
FileLock
(
ts
,
"error.lock"
,
1000
);
lock
.
lock
(
FileLock
.
LOCK_FILE
);
FileWriter
fw
=
new
FileWriter
(
"ERROR.txt"
,
true
);
PrintWriter
pw
=
new
PrintWriter
(
fw
);
e
.
printStackTrace
(
pw
);
...
...
h2/src/test/org/h2/test/unit/TestFileLock.java
浏览文件 @
945c201f
...
...
@@ -62,9 +62,9 @@ public class TestFileLock extends TestBase implements Runnable {
public
void
run
()
{
while
(!
stop
)
{
FileLock
lock
=
new
FileLock
(
new
TraceSystem
(
null
,
false
),
100
);
FileLock
lock
=
new
FileLock
(
new
TraceSystem
(
null
,
false
),
FILE
,
100
);
try
{
lock
.
lock
(
FILE
,
allowSockets
);
lock
.
lock
(
allowSockets
?
FileLock
.
LOCK_SOCKET
:
FileLock
.
LOCK_FILE
);
base
.
trace
(
lock
+
" locked"
);
locks
++;
if
(
locks
>
1
)
{
...
...
h2/src/test/org/h2/test/unit/TestFileLockSerialized.java
0 → 100644
浏览文件 @
945c201f
/*
* Copyright 2004-2009 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
test
.
unit
;
import
java.sql.Connection
;
import
java.sql.DriverManager
;
import
java.sql.ResultSet
;
import
java.sql.SQLException
;
import
java.sql.Statement
;
import
org.h2.test.TestBase
;
/**
* Test the serialized (server-less) mode.
*/
public
class
TestFileLockSerialized
extends
TestBase
{
/**
* Run just this test.
*
* @param a ignored
*/
public
static
void
main
(
String
[]
a
)
throws
Exception
{
TestBase
.
createCaller
().
init
().
test
();
}
public
void
test
()
throws
Exception
{
// TODO support long running queries
deleteDb
(
"fileLockSerialized"
);
String
url
=
"jdbc:h2:"
+
baseDir
+
"/fileLockSerialized"
;
String
writeUrl
=
url
+
";FILE_LOCK=SERIALIZED;OPEN_NEW=TRUE"
;
// ;TRACE_LEVEL_SYSTEM_OUT=3
// String readUrl = writeUrl + ";ACCESS_MODE_LOG=R;ACCESS_MODE_DATA=R";
trace
(
"create database"
);
Class
.
forName
(
"org.h2.Driver"
);
Connection
conn
=
DriverManager
.
getConnection
(
writeUrl
,
"sa"
,
"sa"
);
Statement
stat
=
conn
.
createStatement
();
stat
.
execute
(
"create table test(id int primary key)"
);
Connection
conn3
=
DriverManager
.
getConnection
(
writeUrl
,
"sa"
,
"sa"
);
Statement
stat3
=
conn3
.
createStatement
();
Connection
conn2
=
DriverManager
.
getConnection
(
writeUrl
,
"sa"
,
"sa"
);
Statement
stat2
=
conn2
.
createStatement
();
printResult
(
stat2
,
"select * from test"
);
stat2
.
execute
(
"create local temporary table temp(name varchar)"
);
printResult
(
stat2
,
"select * from temp"
);
trace
(
"insert row 1"
);
stat
.
execute
(
"insert into test values(1)"
);
trace
(
"insert row 2"
);
stat3
.
execute
(
"insert into test values(2)"
);
printResult
(
stat2
,
"select * from test"
);
printResult
(
stat2
,
"select * from temp"
);
conn
.
close
();
conn2
.
close
();
conn3
.
close
();
}
private
void
printResult
(
Statement
stat
,
String
sql
)
throws
SQLException
{
trace
(
"query: "
+
sql
);
ResultSet
rs
=
stat
.
executeQuery
(
sql
);
int
rowCount
=
0
;
while
(
rs
.
next
())
{
trace
(
" "
+
rs
.
getString
(
1
));
rowCount
++;
}
trace
(
" "
+
rowCount
+
" row(s)"
);
}
}
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论