Skip to content
项目
群组
代码片段
帮助
正在加载...
帮助
为 GitLab 提交贡献
登录/注册
切换导航
H
h2database
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
计划
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
Administrator
h2database
Commits
5773980e
提交
5773980e
authored
2月 13, 2008
作者:
Thomas Mueller
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
--no commit message
--no commit message
上级
b790d91a
显示空白字符变更
内嵌
并排
正在显示
15 个修改的文件
包含
240 行增加
和
229 行删除
+240
-229
features.html
h2/src/docsrc/html/features.html
+2
-0
ErrorCode.java
h2/src/main/org/h2/constant/ErrorCode.java
+70
-2
Database.java
h2/src/main/org/h2/engine/Database.java
+10
-10
Function.java
h2/src/main/org/h2/expression/Function.java
+1
-0
LogFile.java
h2/src/main/org/h2/log/LogFile.java
+4
-0
LogSystem.java
h2/src/main/org/h2/log/LogSystem.java
+1
-1
help.csv
h2/src/main/org/h2/res/help.csv
+1
-0
DiskFile.java
h2/src/main/org/h2/store/DiskFile.java
+9
-0
FileStore.java
h2/src/main/org/h2/store/FileStore.java
+4
-4
WriterThread.java
h2/src/main/org/h2/store/WriterThread.java
+19
-1
DelayedFileDeleter.java
h2/src/main/org/h2/util/DelayedFileDeleter.java
+0
-180
TempFileDeleter.java
h2/src/main/org/h2/util/TempFileDeleter.java
+74
-0
TestAll.java
h2/src/test/org/h2/test/TestAll.java
+17
-20
TestReadOnly.java
h2/src/test/org/h2/test/db/TestReadOnly.java
+16
-11
test.in.txt
h2/src/test/org/h2/test/test.in.txt
+12
-0
没有找到文件。
h2/src/docsrc/html/features.html
浏览文件 @
5773980e
...
@@ -599,6 +599,8 @@ SQL grammar documentation.
...
@@ -599,6 +599,8 @@ SQL grammar documentation.
<p>
<p>
Usually, the database opens log, data and index files with the access mode 'rw', meaning
Usually, the database opens log, data and index files with the access mode 'rw', meaning
read-write (except for read only databases, where the mode 'r' is used).
read-write (except for read only databases, where the mode 'r' is used).
To open a database in read-only mode if the files are not read-only, use
ACCESS_MODE_DATA=r.
Also supported are 'rws' and 'rwd'.
Also supported are 'rws' and 'rwd'.
The access mode used for log files is set via ACCESS_MODE_LOG; for
The access mode used for log files is set via ACCESS_MODE_LOG; for
data and index files use ACCESS_MODE_DATA.
data and index files use ACCESS_MODE_DATA.
...
...
h2/src/main/org/h2/constant/ErrorCode.java
浏览文件 @
5773980e
...
@@ -1118,13 +1118,68 @@ public class ErrorCode {
...
@@ -1118,13 +1118,68 @@ public class ErrorCode {
*/
*/
public
static
final
int
FUNCTION_ALIAS_ALREADY_EXISTS_1
=
90076
;
public
static
final
int
FUNCTION_ALIAS_ALREADY_EXISTS_1
=
90076
;
private
int
todo44
;
/**
* The error with code <code>90077</code> is thrown when
* trying to drop a system function or a function alias that does not exist.
* Example:
* <pre>
* DROP ALIAS SQRT;
* </pre>
*/
public
static
final
int
FUNCTION_ALIAS_NOT_FOUND_1
=
90077
;
public
static
final
int
FUNCTION_ALIAS_NOT_FOUND_1
=
90077
;
/**
* The error with code <code>90078</code> is thrown when
* trying to create a schema if an object with this name already exists.
* Example:
* <pre>
* CREATE SCHEMA TEST_SCHEMA;
* CREATE SCHEMA TEST_SCHEMA;
* </pre>
*/
public
static
final
int
SCHEMA_ALREADY_EXISTS_1
=
90078
;
public
static
final
int
SCHEMA_ALREADY_EXISTS_1
=
90078
;
/**
* The error with code <code>90079</code> is thrown when
* trying to drop a schema that does not exist.
* Example:
* <pre>
* DROP SCHEMA UNKNOWN;
* </pre>
*/
public
static
final
int
SCHEMA_NOT_FOUND_1
=
90079
;
public
static
final
int
SCHEMA_NOT_FOUND_1
=
90079
;
/**
* The error with code <code>90080</code> is thrown when
* trying to rename a object to a different schema, or when trying to
* create a related object in another schema.
* Example:
* <pre>
* CREATE SCHEMA TEST_SCHEMA;
* CREATE TABLE TEST(ID INT);
* CREATE INDEX TEST_ID ON TEST(ID);
* ALTER INDEX TEST_ID RENAME TO TEST_SCHEMA.IDX_TEST_ID;
* </pre>
*/
public
static
final
int
SCHEMA_NAME_MUST_MATCH
=
90080
;
public
static
final
int
SCHEMA_NAME_MUST_MATCH
=
90080
;
/**
* The error with code <code>90081</code> is thrown when
* trying to alter a column to not allow NULL, if there
* is already data in the table where this column is NULL.
* Example:
* <pre>
* CREATE TABLE TEST(ID INT);
* INSERT INTO TEST VALUES(NULL);
* ALTER TABLE TEST ALTER COLUMN ID VARCHAR NOT NULL;
* </pre>
*/
public
static
final
int
COLUMN_CONTAINS_NULL_VALUES_1
=
90081
;
public
static
final
int
COLUMN_CONTAINS_NULL_VALUES_1
=
90081
;
/**
* The error with code <code>90082</code> is thrown when
* trying to drop a system generated sequence.
*/
public
static
final
int
SEQUENCE_BELONGS_TO_A_TABLE_1
=
90082
;
public
static
final
int
SEQUENCE_BELONGS_TO_A_TABLE_1
=
90082
;
/**
/**
...
@@ -1137,6 +1192,16 @@ public class ErrorCode {
...
@@ -1137,6 +1192,16 @@ public class ErrorCode {
* </pre>
* </pre>
*/
*/
public
static
final
int
COLUMN_MAY_BE_REFERENCED_1
=
90083
;
public
static
final
int
COLUMN_MAY_BE_REFERENCED_1
=
90083
;
/**
* The error with code <code>90084</code> is thrown when
* trying to drop the last column of a table.
* Example:
* <pre>
* CREATE TABLE TEST(ID INT);
* ALTER TABLE TEST DROP COLUMN ID;
* </pre>
*/
public
static
final
int
CANNOT_DROP_LAST_COLUMN
=
90084
;
public
static
final
int
CANNOT_DROP_LAST_COLUMN
=
90084
;
/**
/**
...
@@ -1153,6 +1218,9 @@ public class ErrorCode {
...
@@ -1153,6 +1218,9 @@ public class ErrorCode {
* </pre>
* </pre>
*/
*/
public
static
final
int
INDEX_BELONGS_TO_CONSTRAINT_1
=
90085
;
public
static
final
int
INDEX_BELONGS_TO_CONSTRAINT_1
=
90085
;
private
int
todo37
;
public
static
final
int
CLASS_NOT_FOUND_1
=
90086
;
public
static
final
int
CLASS_NOT_FOUND_1
=
90086
;
public
static
final
int
METHOD_NOT_FOUND_1
=
90087
;
public
static
final
int
METHOD_NOT_FOUND_1
=
90087
;
public
static
final
int
UNKNOWN_MODE_1
=
90088
;
public
static
final
int
UNKNOWN_MODE_1
=
90088
;
...
...
h2/src/main/org/h2/engine/Database.java
浏览文件 @
5773980e
...
@@ -51,7 +51,6 @@ import org.h2.util.BitField;
...
@@ -51,7 +51,6 @@ import org.h2.util.BitField;
import
org.h2.util.ByteUtils
;
import
org.h2.util.ByteUtils
;
import
org.h2.util.CacheLRU
;
import
org.h2.util.CacheLRU
;
import
org.h2.util.ClassUtils
;
import
org.h2.util.ClassUtils
;
import
org.h2.util.DelayedFileDeleter
;
import
org.h2.util.FileUtils
;
import
org.h2.util.FileUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.IOUtils
;
import
org.h2.util.IntHashMap
;
import
org.h2.util.IntHashMap
;
...
@@ -160,13 +159,10 @@ public class Database implements DataHandler {
...
@@ -160,13 +159,10 @@ public class Database implements DataHandler {
String
lockMethodName
=
ci
.
removeProperty
(
"FILE_LOCK"
,
null
);
String
lockMethodName
=
ci
.
removeProperty
(
"FILE_LOCK"
,
null
);
this
.
accessModeLog
=
ci
.
removeProperty
(
"ACCESS_MODE_LOG"
,
"rw"
).
toLowerCase
();
this
.
accessModeLog
=
ci
.
removeProperty
(
"ACCESS_MODE_LOG"
,
"rw"
).
toLowerCase
();
this
.
accessModeData
=
ci
.
removeProperty
(
"ACCESS_MODE_DATA"
,
"rw"
).
toLowerCase
();
this
.
accessModeData
=
ci
.
removeProperty
(
"ACCESS_MODE_DATA"
,
"rw"
).
toLowerCase
();
int
testing
;
if
(
"r"
.
equals
(
accessModeData
))
{
if
(
"r"
.
equals
(
accessModeData
))
{
readOnly
=
true
;
readOnly
=
true
;
accessModeLog
=
"r"
;
accessModeLog
=
"r"
;
}
}
this
.
fileLockMethod
=
FileLock
.
getFileLockMethod
(
lockMethodName
);
this
.
fileLockMethod
=
FileLock
.
getFileLockMethod
(
lockMethodName
);
this
.
textStorage
=
ci
.
getTextStorage
();
this
.
textStorage
=
ci
.
getTextStorage
();
this
.
databaseURL
=
ci
.
getURL
();
this
.
databaseURL
=
ci
.
getURL
();
...
@@ -431,12 +427,8 @@ public class Database implements DataHandler {
...
@@ -431,12 +427,8 @@ public class Database implements DataHandler {
if
(
persistent
)
{
if
(
persistent
)
{
String
dataFileName
=
databaseName
+
Constants
.
SUFFIX_DATA_FILE
;
String
dataFileName
=
databaseName
+
Constants
.
SUFFIX_DATA_FILE
;
if
(
FileUtils
.
exists
(
dataFileName
))
{
if
(
FileUtils
.
exists
(
dataFileName
))
{
int
testingReadOnly
;
// if it is already read-only because ACCESS_MODE_DATA=r
// if it is already read-only because ACCESS_MODE_DATA=r
readOnly
=
readOnly
|
FileUtils
.
isReadOnly
(
dataFileName
);
readOnly
=
readOnly
|
FileUtils
.
isReadOnly
(
dataFileName
);
// readOnly = FileUtils.isReadOnly(dataFileName);
textStorage
=
isTextStorage
(
dataFileName
,
textStorage
);
textStorage
=
isTextStorage
(
dataFileName
,
textStorage
);
}
}
}
}
...
@@ -933,7 +925,11 @@ public class Database implements DataHandler {
...
@@ -933,7 +925,11 @@ public class Database implements DataHandler {
private
void
stopWriter
()
{
private
void
stopWriter
()
{
if
(
writer
!=
null
)
{
if
(
writer
!=
null
)
{
try
{
writer
.
stopThread
();
writer
.
stopThread
();
}
catch
(
SQLException
e
)
{
traceSystem
.
getTrace
(
Trace
.
DATABASE
).
error
(
"close"
,
e
);
}
writer
=
null
;
writer
=
null
;
}
}
}
}
...
@@ -1366,7 +1362,11 @@ public class Database implements DataHandler {
...
@@ -1366,7 +1362,11 @@ public class Database implements DataHandler {
}
}
public
void
deleteLogFileLater
(
String
fileName
)
throws
SQLException
{
public
void
deleteLogFileLater
(
String
fileName
)
throws
SQLException
{
DelayedFileDeleter
.
getInstance
().
deleteLater
(
fileName
);
if
(
writer
!=
null
)
{
writer
.
deleteLogFileLater
(
fileName
);
}
else
{
FileUtils
.
delete
(
fileName
);
}
}
}
public
Class
loadUserClass
(
String
className
)
throws
SQLException
{
public
Class
loadUserClass
(
String
className
)
throws
SQLException
{
...
...
h2/src/main/org/h2/expression/Function.java
浏览文件 @
5773980e
...
@@ -1447,6 +1447,7 @@ public class Function extends Expression implements FunctionCall {
...
@@ -1447,6 +1447,7 @@ public class Function extends Expression implements FunctionCall {
case
LTRIM:
case
LTRIM:
case
RTRIM:
case
RTRIM:
case
TRIM:
case
TRIM:
min
=
1
;
max
=
2
;
max
=
2
;
break
;
break
;
case
REPLACE:
case
REPLACE:
...
...
h2/src/main/org/h2/log/LogFile.java
浏览文件 @
5773980e
...
@@ -103,6 +103,10 @@ public class LogFile {
...
@@ -103,6 +103,10 @@ public class LogFile {
}
}
}
}
int
id
=
Integer
.
parseInt
(
s
);
int
id
=
Integer
.
parseInt
(
s
);
if
(!
FileUtils
.
exists
(
fileName
))
{
// the file could have been deleted by now (by the DelayedFileDeleter)
return
null
;
}
return
new
LogFile
(
log
,
id
,
fileNamePrefix
);
return
new
LogFile
(
log
,
id
,
fileNamePrefix
);
}
}
...
...
h2/src/main/org/h2/log/LogSystem.java
浏览文件 @
5773980e
...
@@ -266,7 +266,7 @@ if(SysProperties.getIntSetting(SysProperties.H2_LOG_DELETE_DELAY, 0) > 0) {
...
@@ -266,7 +266,7 @@ if(SysProperties.getIntSetting(SysProperties.H2_LOG_DELETE_DELAY, 0) > 0) {
for
(
int
i
=
0
;
i
<
activeLogs
.
size
();
i
++)
{
for
(
int
i
=
0
;
i
<
activeLogs
.
size
();
i
++)
{
LogFile
current
=
(
LogFile
)
activeLogs
.
get
(
i
);
LogFile
current
=
(
LogFile
)
activeLogs
.
get
(
i
);
if
(
last
!=
null
&&
last
.
getId
()
+
1
!=
current
.
getId
())
{
if
(
last
!=
null
&&
last
.
getId
()
+
1
!=
current
.
getId
())
{
throw
Message
.
getInternalError
(
"Mi
i
ssing log file: "
+
last
.
getId
()
+
", "
+
current
.
getId
());
throw
Message
.
getInternalError
(
"Missing log file: "
+
last
.
getId
()
+
", "
+
current
.
getId
());
}
}
last
=
current
;
last
=
current
;
}
}
...
...
h2/src/main/org/h2/res/help.csv
浏览文件 @
5773980e
...
@@ -795,6 +795,7 @@ SET [DATABASE] COLLATION
...
@@ -795,6 +795,7 @@ SET [DATABASE] COLLATION
","
","
Sets the collation used for comparing strings.
Sets the collation used for comparing strings.
This command can only be executed if there are no tables defined.
This command can only be executed if there are no tables defined.
See java.test.Collator for details about STRENGTH.
This setting is persistent.
This setting is persistent.
Admin rights are required to execute this command.
Admin rights are required to execute this command.
","
","
...
...
h2/src/main/org/h2/store/DiskFile.java
浏览文件 @
5773980e
...
@@ -41,6 +41,15 @@ import org.h2.util.ObjectArray;
...
@@ -41,6 +41,15 @@ import org.h2.util.ObjectArray;
* The disk file is responsible for caching; each object contains a {@link Cache} object.
* The disk file is responsible for caching; each object contains a {@link Cache} object.
* Changes in the file are logged in a {@link LogSystem} object.
* Changes in the file are logged in a {@link LogSystem} object.
* Reading and writing to the file is delegated to the {@link FileStore} class.
* Reading and writing to the file is delegated to the {@link FileStore} class.
* <p>
* There are 'blocks' of 128 bytes (DiskFile.BLOCK_SIZE). Each objects own one or more pages;
* each page size is 64 blocks (DiskFile.BLOCKS_PER_PAGE). That is 8 KB page size.
* However pages are not read or written as one unit; only individual objects (multiple blocks at a time)
* are read or written.
* <p>
* Currently there are no in-place updates. Each row occupies one or multiple blocks.
* Row can occupy multiple pages. Rows are always contiguous (except LOBs, they are
* stored in their own files).
*/
*/
public
class
DiskFile
implements
CacheWriter
{
public
class
DiskFile
implements
CacheWriter
{
...
...
h2/src/main/org/h2/store/FileStore.java
浏览文件 @
5773980e
...
@@ -16,7 +16,7 @@ import org.h2.security.SecureFileStore;
...
@@ -16,7 +16,7 @@ import org.h2.security.SecureFileStore;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileObject
;
import
org.h2.store.fs.FileSystem
;
import
org.h2.store.fs.FileSystem
;
import
org.h2.util.ByteUtils
;
import
org.h2.util.ByteUtils
;
import
org.h2.util.
Delayed
FileDeleter
;
import
org.h2.util.
Temp
FileDeleter
;
/**
/**
* This class is an abstraction of a random access file.
* This class is an abstraction of a random access file.
...
@@ -163,7 +163,7 @@ public class FileStore {
...
@@ -163,7 +163,7 @@ public class FileStore {
public
void
closeAndDeleteSilently
()
{
public
void
closeAndDeleteSilently
()
{
if
(
file
!=
null
)
{
if
(
file
!=
null
)
{
closeSilently
();
closeSilently
();
DelayedFileDeleter
.
getInstance
().
autoD
eleteFile
(
autoDeleteReference
,
name
);
TempFileDeleter
.
d
eleteFile
(
autoDeleteReference
,
name
);
name
=
null
;
name
=
null
;
}
}
}
}
...
@@ -324,11 +324,11 @@ public class FileStore {
...
@@ -324,11 +324,11 @@ public class FileStore {
}
}
public
void
autoDelete
()
{
public
void
autoDelete
()
{
autoDeleteReference
=
DelayedFileDeleter
.
getInstance
().
addTemp
File
(
name
,
this
);
autoDeleteReference
=
TempFileDeleter
.
add
File
(
name
,
this
);
}
}
public
void
stopAutoDelete
()
{
public
void
stopAutoDelete
()
{
DelayedFileDeleter
.
getInstance
()
.
stopAutoDelete
(
autoDeleteReference
,
name
);
TempFileDeleter
.
stopAutoDelete
(
autoDeleteReference
,
name
);
autoDeleteReference
=
null
;
autoDeleteReference
=
null
;
}
}
...
...
h2/src/main/org/h2/store/WriterThread.java
浏览文件 @
5773980e
...
@@ -16,6 +16,7 @@ import org.h2.log.LogSystem;
...
@@ -16,6 +16,7 @@ import org.h2.log.LogSystem;
import
org.h2.message.Trace
;
import
org.h2.message.Trace
;
import
org.h2.message.TraceSystem
;
import
org.h2.message.TraceSystem
;
import
org.h2.table.Table
;
import
org.h2.table.Table
;
import
org.h2.util.FileUtils
;
import
org.h2.util.ObjectArray
;
import
org.h2.util.ObjectArray
;
/**
/**
...
@@ -38,6 +39,7 @@ public class WriterThread extends Thread {
...
@@ -38,6 +39,7 @@ public class WriterThread extends Thread {
private
int
writeDelay
;
private
int
writeDelay
;
private
long
lastIndexFlush
;
private
long
lastIndexFlush
;
private
volatile
boolean
stop
;
private
volatile
boolean
stop
;
private
String
oldLogFile
;
private
WriterThread
(
Database
database
,
int
writeDelay
)
{
private
WriterThread
(
Database
database
,
int
writeDelay
)
{
this
.
databaseRef
=
new
WeakReference
(
database
);
this
.
databaseRef
=
new
WeakReference
(
database
);
...
@@ -106,6 +108,14 @@ public class WriterThread extends Thread {
...
@@ -106,6 +108,14 @@ public class WriterThread extends Thread {
public
void
run
()
{
public
void
run
()
{
while
(!
stop
)
{
while
(!
stop
)
{
synchronized
(
this
)
{
if
(
oldLogFile
!=
null
)
{
FileUtils
.
tryDelete
(
oldLogFile
);
if
(!
FileUtils
.
exists
(
oldLogFile
))
{
oldLogFile
=
null
;
}
}
}
Database
database
=
(
Database
)
databaseRef
.
get
();
Database
database
=
(
Database
)
databaseRef
.
get
();
if
(
database
==
null
)
{
if
(
database
==
null
)
{
break
;
break
;
...
@@ -138,8 +148,16 @@ public class WriterThread extends Thread {
...
@@ -138,8 +148,16 @@ public class WriterThread extends Thread {
databaseRef
=
null
;
databaseRef
=
null
;
}
}
public
void
stopThread
()
{
public
void
stopThread
()
throws
SQLException
{
stop
=
true
;
stop
=
true
;
deleteLogFileLater
(
null
);
}
public
synchronized
void
deleteLogFileLater
(
String
fileName
)
throws
SQLException
{
if
(
oldLogFile
!=
null
)
{
FileUtils
.
delete
(
oldLogFile
);
}
oldLogFile
=
fileName
;
}
}
}
}
h2/src/main/org/h2/util/DelayedFileDeleter.java
deleted
100644 → 0
浏览文件 @
b790d91a
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
util
;
import
java.lang.ref.PhantomReference
;
import
java.lang.ref.Reference
;
import
java.lang.ref.ReferenceQueue
;
import
java.sql.SQLException
;
import
java.util.HashMap
;
import
java.util.Iterator
;
import
java.util.Map.Entry
;
import
org.h2.constant.SysProperties
;
import
org.h2.message.Message
;
/**
* Deletes files later on or if they are not used.
* This class deletes temporary files when they are not used any longer.
*/
public
class
DelayedFileDeleter
extends
Thread
{
private
static
DelayedFileDeleter
instance
;
private
final
ReferenceQueue
queue
=
new
ReferenceQueue
();
private
final
HashMap
refMap
=
new
HashMap
();
private
final
HashMap
deleteLater
=
new
HashMap
();
private
long
deleteNext
;
public
synchronized
void
deleteLater
(
String
fileName
)
throws
SQLException
{
int
delay
=
SysProperties
.
getLogFileDeleteDelay
();
if
(
delay
==
0
&&
deleteLater
.
size
()
==
0
)
{
// shortcut if delay is 0
FileUtils
.
delete
(
fileName
);
return
;
}
if
(
deleteLater
.
containsKey
(
fileName
))
{
return
;
}
long
at
=
System
.
currentTimeMillis
()
+
delay
;
if
(
deleteNext
!=
0
&&
at
<=
deleteNext
)
{
// make sure files are deleted in the correct order
at
=
deleteNext
+
1
;
}
deleteNext
=
at
;
deleteLater
.
put
(
fileName
,
ObjectUtils
.
getLong
(
at
));
}
/**
* Delete at most one old file (after the delay)
*/
private
void
deleteOld
()
{
long
now
=
System
.
currentTimeMillis
();
if
(
deleteNext
==
0
||
now
<
deleteNext
)
{
return
;
}
String
delete
=
null
;
long
oldest
=
0
;
for
(
Iterator
it
=
deleteLater
.
entrySet
().
iterator
();
it
.
hasNext
();)
{
Entry
entry
=
(
Entry
)
it
.
next
();
long
at
=
((
Long
)
entry
.
getValue
()).
longValue
();
if
(
at
<
now
&&
(
delete
==
null
||
at
<
oldest
))
{
delete
=
(
String
)
entry
.
getKey
();
oldest
=
at
;
}
}
if
(
delete
==
null
)
{
return
;
}
try
{
FileUtils
.
delete
(
delete
);
}
catch
(
SQLException
e
)
{
// ignore
}
deleteLater
.
remove
(
delete
);
}
public
static
synchronized
DelayedFileDeleter
getInstance
()
{
if
(
instance
==
null
)
{
instance
=
new
DelayedFileDeleter
();
instance
.
setDaemon
(
true
);
instance
.
setPriority
(
Thread
.
MIN_PRIORITY
);
instance
.
start
();
}
return
instance
;
}
private
DelayedFileDeleter
()
{
setName
(
"H2 FileDeleter"
);
}
public
void
run
()
{
while
(
true
)
{
try
{
Thread
.
sleep
(
100
);
}
catch
(
InterruptedException
e
)
{
// ignore
}
synchronized
(
this
)
{
if
(
refMap
.
size
()
!=
0
)
{
deleteUnused
();
}
else
if
(
deleteLater
.
size
()
!=
0
)
{
deleteOld
();
}
else
{
break
;
}
}
}
}
/**
* Add a temp file to the queue and delete it if it is no longer referenced.
*
* @param fileName the file name
* @param file the object to track
* @return the reference
*/
public
synchronized
Reference
addTempFile
(
String
fileName
,
Object
file
)
{
FileUtils
.
trace
(
"FileDeleter.addFile"
,
fileName
,
file
);
PhantomReference
ref
=
new
PhantomReference
(
file
,
queue
);
refMap
.
put
(
ref
,
fileName
);
return
ref
;
}
/**
* Delete a file now and remove it from the queue.
*
* @param the reference in the queue
* @param fileName the file name
*/
public
synchronized
void
autoDeleteFile
(
Reference
ref
,
String
fileName
)
{
if
(
ref
!=
null
)
{
String
f2
=
(
String
)
refMap
.
remove
(
ref
);
if
(
SysProperties
.
CHECK
&&
f2
!=
null
&&
fileName
!=
null
&&
!
f2
.
equals
(
fileName
))
{
throw
Message
.
getInternalError
(
"f2:"
+
f2
+
" f:"
+
fileName
);
}
}
if
(
fileName
!=
null
&&
FileUtils
.
exists
(
fileName
))
{
try
{
FileUtils
.
trace
(
"FileDeleter.deleteFile"
,
fileName
,
null
);
FileUtils
.
delete
(
fileName
);
}
catch
(
Exception
e
)
{
// TODO log such errors?
}
deleteUnused
();
}
}
/**
* Delete all unreferenced files that have been garbage collected now.
* This method is called from time to time by the application.
*/
private
void
deleteUnused
()
{
while
(
true
)
{
Reference
ref
=
queue
.
poll
();
if
(
ref
==
null
)
{
break
;
}
autoDeleteFile
(
ref
,
null
);
}
}
/**
* Remove a file from the list of files to be deleted.
*
* @param ref the reference
* @param fileName the file name
*/
public
synchronized
void
stopAutoDelete
(
Reference
ref
,
String
fileName
)
{
FileUtils
.
trace
(
"FileDeleter.stopAutoDelete"
,
fileName
,
ref
);
if
(
ref
!=
null
)
{
String
f2
=
(
String
)
refMap
.
remove
(
ref
);
if
(
SysProperties
.
CHECK
&&
(
f2
==
null
||
!
f2
.
equals
(
fileName
)))
{
throw
Message
.
getInternalError
(
"f2:"
+
f2
+
" f:"
+
fileName
);
}
}
}
}
h2/src/main/org/h2/util/TempFileDeleter.java
0 → 100644
浏览文件 @
5773980e
/*
* Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package
org
.
h2
.
util
;
import
java.lang.ref.PhantomReference
;
import
java.lang.ref.Reference
;
import
java.lang.ref.ReferenceQueue
;
import
java.util.HashMap
;
import
org.h2.constant.SysProperties
;
import
org.h2.message.Message
;
/**
* This class deletes temporary files when they are not used any longer.
*/
public
class
TempFileDeleter
{
private
static
final
ReferenceQueue
QUEUE
=
new
ReferenceQueue
();
private
static
final
HashMap
REF_MAP
=
new
HashMap
();
public
static
synchronized
Reference
addFile
(
String
fileName
,
Object
file
)
{
FileUtils
.
trace
(
"TempFileDeleter.addFile"
,
fileName
,
file
);
PhantomReference
ref
=
new
PhantomReference
(
file
,
QUEUE
);
REF_MAP
.
put
(
ref
,
fileName
);
deleteUnused
();
return
ref
;
}
public
static
synchronized
void
deleteFile
(
Reference
ref
,
String
fileName
)
{
if
(
ref
!=
null
)
{
String
f2
=
(
String
)
REF_MAP
.
remove
(
ref
);
if
(
SysProperties
.
CHECK
&&
f2
!=
null
&&
fileName
!=
null
&&
!
f2
.
equals
(
fileName
))
{
throw
Message
.
getInternalError
(
"f2:"
+
f2
+
" f:"
+
fileName
);
}
}
if
(
fileName
!=
null
&&
FileUtils
.
exists
(
fileName
))
{
try
{
FileUtils
.
trace
(
"TempFileDeleter.deleteFile"
,
fileName
,
null
);
FileUtils
.
delete
(
fileName
);
}
catch
(
Exception
e
)
{
// TODO log such errors?
}
deleteUnused
();
}
}
public
static
void
deleteUnused
()
{
// Mystery: I don't know how QUEUE could get null, but two independent
// people reported NullPointerException here - if somebody understands
// how it could happen please report it!
// Environment: web application under Tomcat, exception occurs during undeploy
while
(
QUEUE
!=
null
)
{
Reference
ref
=
QUEUE
.
poll
();
if
(
ref
==
null
)
{
break
;
}
deleteFile
(
ref
,
null
);
}
}
public
static
void
stopAutoDelete
(
Reference
ref
,
String
fileName
)
{
FileUtils
.
trace
(
"TempFileDeleter.stopAutoDelete"
,
fileName
,
ref
);
if
(
ref
!=
null
)
{
String
f2
=
(
String
)
REF_MAP
.
remove
(
ref
);
if
(
SysProperties
.
CHECK
&&
(
f2
==
null
||
!
f2
.
equals
(
fileName
)))
{
throw
Message
.
getInternalError
(
"f2:"
+
f2
+
" f:"
+
fileName
);
}
}
deleteUnused
();
}
}
h2/src/test/org/h2/test/TestAll.java
浏览文件 @
5773980e
...
@@ -156,7 +156,7 @@ java org.h2.test.TestAll timer
...
@@ -156,7 +156,7 @@ java org.h2.test.TestAll timer
test
.
printSystem
();
test
.
printSystem
();
int
test2
;
int
test2
;
// System.setProperty(SysProperties.H2_LOG_DELETE_DELAY, "2
0
");
// System.setProperty(SysProperties.H2_LOG_DELETE_DELAY, "2");
// TestRecover.main(new String[0]);
// TestRecover.main(new String[0]);
...
@@ -164,16 +164,20 @@ int test2;
...
@@ -164,16 +164,20 @@ int test2;
valentine
valentine
create force trigger : test & document
the user should be allowed to do everything with his own temp tables (and views).
read only databases without having to make the files read-only: test & document
CREATE USER IF NOT EXISTS READER PASSWORD 'READER';
<login as READER>
TestSessionsLocks
CREATE LOCAL TEMPORARY TABLE IF NOT EXISTS MY_TEST(ID INT);
...?
INSERT INTO MY_TEST VALUES(1);
SELECT * FROM MY_TEST;
DROP TABLE MY_TEST;
Automate real power off tests
Automate real power off tests
Extend tests that simulate power off
Extend tests that simulate power off
timer test
timer test
Can sometimes not delete log file?
Test delayed log files delete
Test delayed log files delete
link to new changelog and roadmap, remove pages from google groups
link to new changelog and roadmap, remove pages from google groups
...
@@ -187,6 +191,11 @@ Adjust cache memory usage
...
@@ -187,6 +191,11 @@ Adjust cache memory usage
Test Recovery with MAX_LOG_FILE_SIZE=1; test with various log file sizes
Test Recovery with MAX_LOG_FILE_SIZE=1; test with various log file sizes
History:
History:
Databases can now be opened even if trigger classes are not in the classpath.
The exception is thrown when trying to fire the trigger.
Opening databases with ACCESS_MODE_DATA=r is now supported.
In this case the database is read-only, but the files don't not need
to be read-only.
Security: The database now waits 200 ms before throwing an exception if
Security: The database now waits 200 ms before throwing an exception if
the user name or password don't match, to slow down dictionary attacks.
the user name or password don't match, to slow down dictionary attacks.
The value cache is now a soft reference cache. This should help save memory.
The value cache is now a soft reference cache. This should help save memory.
...
@@ -195,19 +204,7 @@ ALTER TABLE ALTER COLUMN RESTART and ALTER SEQUENCE now support an expressions.
...
@@ -195,19 +204,7 @@ ALTER TABLE ALTER COLUMN RESTART and ALTER SEQUENCE now support an expressions.
When setting the base directory on the command line, the user directory prefix ('~') was ignored.
When setting the base directory on the command line, the user directory prefix ('~') was ignored.
Roadmap:
Roadmap:
Support CREATE FORCE TRIGGER.
BIT VARYING
drop all objects;
CREATE TABLE INVOICE(ID INT PRIMARY KEY, AMOUNT DECIMAL);
CREATE TRIGGER INV_INS AFTER INSERT ON INVOICE FOR EACH ROW CALL "org.h2.samples.TriggerSample$MyTrigger" ;
DROP TRIGGER INV_INS;
CREATE TRIGGER INV_INS AFTER INSERT ON INVOICE FOR EACH ROW CALL "org.h2.samples.TriggerSample$MyTrigger" ;
insert into invoice values(1, 2);
disconnect
change to MyTrigger2
connect
insert into invoice values(2, 3);
DROP TRIGGER INV_INS;
*/
*/
...
@@ -408,7 +405,7 @@ DROP TRIGGER INV_INS;
...
@@ -408,7 +405,7 @@ DROP TRIGGER INV_INS;
*/
*/
private
void
test
()
throws
Exception
{
private
void
test
()
throws
Exception
{
System
.
out
.
println
();
System
.
out
.
println
();
System
.
out
.
println
(
"Test big:"
+
big
+
" net:"
+
networked
+
" cipher:"
+
cipher
+
" memory:"
+
memory
+
" log:"
+
logMode
+
" diskResult:"
+
diskResult
+
" mvcc:"
+
mvcc
);
System
.
out
.
println
(
"Test big:"
+
big
+
" net:"
+
networked
+
" cipher:"
+
cipher
+
" memory:"
+
memory
+
" log:"
+
logMode
+
" diskResult:"
+
diskResult
+
" mvcc:"
+
mvcc
+
" deleteIndex:"
+
deleteIndex
);
beforeTest
();
beforeTest
();
// db
// db
...
...
h2/src/test/org/h2/test/db/TestReadOnly.java
浏览文件 @
5773980e
...
@@ -24,15 +24,13 @@ public class TestReadOnly extends TestBase {
...
@@ -24,15 +24,13 @@ public class TestReadOnly extends TestBase {
if
(
config
.
memory
)
{
if
(
config
.
memory
)
{
return
;
return
;
}
}
testReadOnlyFileAccessMode
();
testReadOnlyFiles
(
true
);
testReadOnlyFiles
();
if
(!
config
.
deleteIndex
)
{
testReadOnlyFiles
(
false
);
}
}
private
void
testReadOnlyFileAccessMode
()
{
int
todo
;
}
}
private
void
testReadOnlyFiles
()
throws
Exception
{
private
void
testReadOnlyFiles
(
boolean
setReadOnly
)
throws
Exception
{
File
f
=
File
.
createTempFile
(
"test"
,
"temp"
);
File
f
=
File
.
createTempFile
(
"test"
,
"temp"
);
check
(
f
.
canWrite
());
check
(
f
.
canWrite
());
...
@@ -57,9 +55,12 @@ public class TestReadOnly extends TestBase {
...
@@ -57,9 +55,12 @@ public class TestReadOnly extends TestBase {
check
(!
conn
.
isReadOnly
());
check
(!
conn
.
isReadOnly
());
conn
.
close
();
conn
.
close
();
if
(
setReadOnly
)
{
setReadOnly
();
setReadOnly
();
conn
=
getConnection
(
"readonly"
);
conn
=
getConnection
(
"readonly"
);
}
else
{
conn
=
getConnection
(
"readonly;ACCESS_MODE_DATA=r"
);
}
check
(
conn
.
isReadOnly
());
check
(
conn
.
isReadOnly
());
stat
=
conn
.
createStatement
();
stat
=
conn
.
createStatement
();
stat
.
execute
(
"SELECT * FROM TEST"
);
stat
.
execute
(
"SELECT * FROM TEST"
);
...
@@ -71,7 +72,11 @@ public class TestReadOnly extends TestBase {
...
@@ -71,7 +72,11 @@ public class TestReadOnly extends TestBase {
}
}
conn
.
close
();
conn
.
close
();
if
(
setReadOnly
)
{
conn
=
getConnection
(
"readonly;DB_CLOSE_DELAY=1"
);
conn
=
getConnection
(
"readonly;DB_CLOSE_DELAY=1"
);
}
else
{
conn
=
getConnection
(
"readonly;DB_CLOSE_DELAY=1;ACCESS_MODE_DATA=r"
);
}
stat
=
conn
.
createStatement
();
stat
=
conn
.
createStatement
();
stat
.
execute
(
"SELECT * FROM TEST"
);
stat
.
execute
(
"SELECT * FROM TEST"
);
try
{
try
{
...
...
h2/src/test/org/h2/test/test.in.txt
浏览文件 @
5773980e
--- special grammar and test cases ---------------------------------------------------------------------------------------------
--- special grammar and test cases ---------------------------------------------------------------------------------------------
select rtrim() from dual;
> exception
CREATE TABLE COUNT(X INT);
CREATE TABLE COUNT(X INT);
> ok
> ok
CREATE FORCE TRIGGER T_COUNT BEFORE INSERT ON COUNT CALL "com.Unknown";
> ok
INSERT INTO COUNT VALUES(NULL);
> exception
DROP TRIGGER T_COUNT;
> ok
CREATE TABLE ITEMS(ID INT CHECK ID < SELECT MAX(ID) FROM COUNT);
CREATE TABLE ITEMS(ID INT CHECK ID < SELECT MAX(ID) FROM COUNT);
> ok
> ok
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论