提交 923f4c87 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 693eb1bc
...@@ -27,7 +27,6 @@ import org.h2.value.Value; ...@@ -27,7 +27,6 @@ import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
import org.h2.value.ValueDouble; import org.h2.value.ValueDouble;
import org.h2.value.ValueInt;
import org.h2.value.ValueLong; import org.h2.value.ValueLong;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
import org.h2.value.ValueString; import org.h2.value.ValueString;
......
...@@ -18,7 +18,6 @@ import org.h2.store.RecordReader; ...@@ -18,7 +18,6 @@ import org.h2.store.RecordReader;
import org.h2.store.Storage; import org.h2.store.Storage;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.TableData; import org.h2.table.TableData;
import org.h2.util.MathUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
......
...@@ -61,12 +61,6 @@ public class ViewIndex extends Index { ...@@ -61,12 +61,6 @@ public class ViewIndex extends Index {
} }
public String getPlanSQL() { public String getPlanSQL() {
int testing;
// return sessionQuery.getPlanSQL();
// Query query = (Query)session.prepare(querySQL, true);
// return query.getPlanSQL();
return planSQL; return planSQL;
} }
...@@ -250,7 +244,14 @@ public class ViewIndex extends Index { ...@@ -250,7 +244,14 @@ public class ViewIndex extends Index {
} }
String sql = query.getPlanSQL(); String sql = query.getPlanSQL();
Query q2 = (Query)session.prepare(sql); Query q2 = (Query)session.prepare(sql, true);
ObjectArray a2 = q2.getParameters();
for(int i=0; i<a2.size(); i++) {
Parameter param = (Parameter) originalParameters.get(i);
Value value = param.getParamValue();
Parameter p = (Parameter) a2.get(i);
p.setValue(value);
}
LocalResult result = q2.query(0); LocalResult result = q2.query(0);
int testing2; int testing2;
......
...@@ -20,14 +20,17 @@ import org.h2.util.TempFileDeleter; ...@@ -20,14 +20,17 @@ import org.h2.util.TempFileDeleter;
public class FileStore { public class FileStore {
public static final int HEADER_LENGTH = 3 * Constants.FILE_BLOCK_SIZE; public static final int HEADER_LENGTH = 3 * Constants.FILE_BLOCK_SIZE;
private static final byte[] EMPTY = new byte[16 * 1024];
protected String name; protected String name;
protected DataHandler handler; protected DataHandler handler;
private byte[] magic; private byte[] magic;
private RandomAccessFile file; private RandomAccessFile file;
private long filePos; private long filePos;
private long fileLength;
private Reference autoDeleteReference; private Reference autoDeleteReference;
private boolean checkedWriting = true; private boolean checkedWriting = true;
private boolean synchronousMode;
public static FileStore open(DataHandler handler, String name, String mode, byte[] magic) throws SQLException { public static FileStore open(DataHandler handler, String name, String mode, byte[] magic) throws SQLException {
return open(handler, name, mode, magic, null, null, 0); return open(handler, name, mode, magic, null, null, 0);
...@@ -60,7 +63,11 @@ public class FileStore { ...@@ -60,7 +63,11 @@ public class FileStore {
file = FileUtils.openRandomAccessFile(name, "r"); file = FileUtils.openRandomAccessFile(name, "r");
} else { } else {
file = FileUtils.openRandomAccessFile(name, mode); file = FileUtils.openRandomAccessFile(name, mode);
if(mode.length() > 2) {
synchronousMode = true;
} }
}
fileLength = file.length();
} catch(IOException e) { } catch(IOException e) {
throw Message.convert(e); throw Message.convert(e);
} }
...@@ -216,6 +223,7 @@ public class FileStore { ...@@ -216,6 +223,7 @@ public class FileStore {
} }
} }
filePos += len; filePos += len;
fileLength = Math.max(filePos, fileLength);
} }
private boolean freeUpDiskSpace() throws SQLException { private boolean freeUpDiskSpace() throws SQLException {
...@@ -233,7 +241,23 @@ public class FileStore { ...@@ -233,7 +241,23 @@ public class FileStore {
checkPowerOff(); checkPowerOff();
checkWritingAllowed(); checkWritingAllowed();
try { try {
if(synchronousMode && newLength > fileLength) {
long pos = filePos;
file.seek(fileLength);
byte[] empty = EMPTY;
while(true) {
int p = (int) Math.min(newLength - fileLength, EMPTY.length);
if(p <= 0) {
break;
}
file.write(empty, 0, p);
fileLength += p;
}
file.seek(pos);
} else {
FileUtils.setLength(file, newLength); FileUtils.setLength(file, newLength);
}
fileLength = newLength;
} catch (IOException e) { } catch (IOException e) {
if(freeUpDiskSpace()) { if(freeUpDiskSpace()) {
try { try {
...@@ -249,12 +273,20 @@ public class FileStore { ...@@ -249,12 +273,20 @@ public class FileStore {
public long length() throws SQLException { public long length() throws SQLException {
try { try {
if(Constants.CHECK && file.length() % Constants.FILE_BLOCK_SIZE != 0) { long len = fileLength;
long newLength = file.length() + Constants.FILE_BLOCK_SIZE - (file.length() % Constants.FILE_BLOCK_SIZE); if(Constants.CHECK2) {
len = file.length();
if(len != fileLength) {
throw Message.getInternalError("file "+name+" length "+len+" expected " + fileLength);
}
}
if(Constants.CHECK2 && len % Constants.FILE_BLOCK_SIZE != 0) {
long newLength = len + Constants.FILE_BLOCK_SIZE - (len % Constants.FILE_BLOCK_SIZE);
FileUtils.setLength(file, newLength); FileUtils.setLength(file, newLength);
throw Message.getInternalError("unaligned file length "+name+" len "+file.length()); fileLength = newLength;
throw Message.getInternalError("unaligned file length "+name+" len "+len);
} }
return file.length(); return len;
} catch (IOException e) { } catch (IOException e) {
throw Message.convert(e); throw Message.convert(e);
} }
......
...@@ -333,8 +333,6 @@ public class LogFile { ...@@ -333,8 +333,6 @@ public class LogFile {
if(file == null) { if(file == null) {
throw Message.getSQLException(Message.SIMULATED_POWER_OFF); throw Message.getSQLException(Message.SIMULATED_POWER_OFF);
} }
int testing ;
//System.out.println("flush " + file.length() + " pos:"+file.getFilePointer()+" len:"+bufferPos);
file.write(buffer, 0, bufferPos); file.write(buffer, 0, bufferPos);
for(int i=0; i<unwritten.size(); i++) { for(int i=0; i<unwritten.size(); i++) {
Record r = (Record) unwritten.get(i); Record r = (Record) unwritten.get(i);
......
...@@ -13,6 +13,7 @@ import java.sql.ResultSet; ...@@ -13,6 +13,7 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.Collator; import java.text.Collator;
import java.util.Locale; import java.util.Locale;
import java.util.Properties;
import org.h2.constraint.Constraint; import org.h2.constraint.Constraint;
import org.h2.constraint.ConstraintCheck; import org.h2.constraint.ConstraintCheck;
...@@ -644,15 +645,33 @@ public class MetaTable extends Table { ...@@ -644,15 +645,33 @@ public class MetaTable extends Table {
value value
}); });
} }
add(rows, new String[]{"info.BUILD_ID", "" + Constants.BUILD_ID});
add(rows, new String[]{"info.VERSION_MAJOR", "" + Constants.VERSION_MAJOR});
add(rows, new String[]{"info.VERSION_MINOR", "" + Constants.VERSION_MINOR});
add(rows, new String[]{"info.VERSION", "" + Constants.getVersion()});
if(session.getUser().getAdmin()) {
Properties prop = System.getProperties();
String[] settings = new String[]{
"java.runtime.version",
"java.vm.name", "java.vendor",
"os.name", "os.arch", "os.version", "sun.os.patch.level",
"file.separator", "path.separator", "line.separator",
"user.country", "user.language", "user.variant", "file.encoding"
};
for(int i=0; i<settings.length; i++) {
String s = settings[i];
add(rows, new String[]{"property." + s, prop.getProperty(s, "")});
}
}
add(rows, new String[]{"MODE", Mode.getCurrentMode().getName()}); add(rows, new String[]{"MODE", Mode.getCurrentMode().getName()});
DiskFile dataFile = database.getDataFile(); DiskFile dataFile = database.getDataFile();
if(dataFile != null) { if(dataFile != null) {
add(rows, new String[]{"CACHE_TYPE", dataFile.getCache().getTypeName()}); add(rows, new String[]{"CACHE_TYPE", dataFile.getCache().getTypeName()});
if(session.getUser().getAdmin()) { if(session.getUser().getAdmin()) {
add(rows, new String[]{"FILE_DISK_WRITE", "" + dataFile.getWriteCount()}); add(rows, new String[]{"info.FILE_DISK_WRITE", "" + dataFile.getWriteCount()});
add(rows, new String[]{"FILE_DISK_READ", "" + dataFile.getReadCount()}); add(rows, new String[]{"info.FILE_DISK_READ", "" + dataFile.getReadCount()});
add(rows, new String[]{"FILE_INDEX_WRITE", "" + database.getIndexFile().getWriteCount()}); add(rows, new String[]{"info.FILE_INDEX_WRITE", "" + database.getIndexFile().getWriteCount()});
add(rows, new String[]{"FILE_INDEX_READ", "" + database.getIndexFile().getReadCount()}); add(rows, new String[]{"info.FILE_INDEX_READ", "" + database.getIndexFile().getReadCount()});
} }
} }
add(rows, new String[]{"h2.check", "" + Constants.CHECK}); add(rows, new String[]{"h2.check", "" + Constants.CHECK});
......
...@@ -114,7 +114,7 @@ public class ChangePassword { ...@@ -114,7 +114,7 @@ public class ChangePassword {
change.encrypt = encrypt; change.encrypt = encrypt;
// first, test only if the file can be renamed (to find errors with locked files early) // first, test only if the file can be renamed (to find errors with locked files early)
ArrayList files = FileLister.getDatabaseFiles(dir, db, true); ArrayList files = FileLister.getDatabaseFiles(dir, db, false);
for (int i = 0; i < files.size(); i++) { for (int i = 0; i < files.size(); i++) {
String fileName = (String) files.get(i); String fileName = (String) files.get(i);
String temp = dir + "/temp.db"; String temp = dir + "/temp.db";
......
...@@ -90,16 +90,6 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2 ...@@ -90,16 +90,6 @@ java -Xmx512m -Xrunhprof:cpu=samples,depth=8 org.h2.tools.RunScript -url jdbc:h2
/* /*
H2 CSV update
TestWriteFile
D:\pictures\2007-email
ftp://192.168.0.100:8021/
christmas lights tests
ftp: problem with multithreading?
News: add H2 Database News News: add H2 Database News
Email Subscription: If you like to get informed by email about new releases, Email Subscription: If you like to get informed by email about new releases,
...@@ -107,26 +97,24 @@ subscribe here. The email addresses of members are only used in this context. ...@@ -107,26 +97,24 @@ subscribe here. The email addresses of members are only used in this context.
Usually, only one mail every few weeks will be sent. Usually, only one mail every few weeks will be sent.
Email: Email:
send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide, improve error message:
MySQL, PostgreSQL Table TEST not found. Possible reasons: typo; the table is in another database or schema; case mismatch (use double quotes) [42S02-46]
http://semmle.com/ h2\src\docsrc\html\images\SQLInjection.txt
try out, find bugs
DROP TABLE TEST; document rws / rwd
CREATE TABLE TEST(ID INT);
@LOOP 10000 INSERT INTO TEST VALUES(?); christmas lights tests
-- derby: 5828, 5735
-- jdbc:h2:test;write_mode_log=rws;write_delay=0 D:\pictures\2007-email
-- h2: 15172
ftp: problem with multithreading?
DatDb: send http://thecodist.com/fiche/thecodist/article/sql-injections-how-not-to-get-stuck to JavaWorld, TheServerSide,
insert a varchar ('xxxx...m...') into a binary column is not legal, so I changed: MySQL, PostgreSQL
CREATE TABLE "+tableName+" (fname varchar(80) primary key, gendate bigint, dat binary)
to: http://semmle.com/
CREATE TABLE "+tableName+" (fname varchar(80) primary key, gendate bigint, dat varchar) try out, find bugs
Session sess1 = DBConnection.openSession(); Session sess1 = DBConnection.openSession();
//Wenn Die Transaction erst nach sess2.close() gestartet wird, dann funktioniert es //Wenn Die Transaction erst nach sess2.close() gestartet wird, dann funktioniert es
...@@ -144,82 +132,6 @@ t.commit(); ...@@ -144,82 +132,6 @@ t.commit();
sess1.close(); sess1.close();
download/trace*.log download/trace*.log
DatDb test
Short answer:
This database does not guarantee that all committed transactions survive a power failure.
While other databases (such as Derby) claim they can guarantee it, in reality they can't.
Testing shows that all databases lose transactions on power failure sometimes.
Where this is not acceptable, a laptop or UPS (uninterruptible power supply) should be used.
If durability is required for all possible cases of hardware failure, clustering should be used,
such as the H2 clustering mode.
Long answer:
Making sure that committed transaction are not lost is more complicated than it seems first.
To guarantee complete durability, a database must ensure that the log record is on the hard drive
before the commit call returns. To do that, different approaches are possible. The first option
is to use the 'synchronous write' option when opening a file. In Java, RandomAccessFile
supports the opening modes "rws" and "rwd":
Around 1000 write operations per second are possible when using one of those modes.
You can get the exact number for your system by running the test org.h2.test.poweroff.TestWrite.
This feature is used by Derby and PostgreSQL.
However, this alone does not force changes to disk, because it does not flush the operating system and hard drive buffers.
Even 7800 RPM hard drives can spin at 130 rounds per second only.
There are other ways force data to disk:
FileDescriptor.sync().
The documentation says that this will force all system buffers to synchronize with the underlying device.
Sync is supposed to return after all in-memory modified copies of buffers associated with this FileDescriptor have been written to the physical medium.
FileChannel.force() (since JDK 1.4).
This method is supposed to force any updates to this channel's file to be written to the storage device that contains it.
The test was made with this database, as well as with PostgreSQL, Derby, and HSQLDB.
None of those databases was able to guarantee complete transaction durability.
To test the durability / non-durability of this and other databases, you can use the test application in the package
org.h2.test.poweroff. Two computers with network connection are required to run this test.
One computer acts as the listener, the test application is run on the other computer.
The computer with the listener application opens a TCP/IP port and listens for an incoming connection.
The second computer first connects to the listener, and then created the databases and starts inserting records.
The connection is set to 'autocommit', which means after each inserted record a commit is performed automatically.
Afterwards, the test computer notifies the listener that this record was inserted successfully.
The listener computer displays the last inserted record number every 10 seconds.
Now, the power needs to be switched off manually while the test is still running.
Now you can restart the computer, and run the application again.
You will find out that in most cases, none of the databases contains all the records that the listener computer knows about.
For details, please consult the source code of the listener and test application.
The test was made using two computers, with computer A
writing to disk and then sending the transaction id over the network to computer B. After some time,
the power is switched off on computer A. After switching on computer A again, some committed
transactions where lost.
It is not enough to just send the write request to
the operating system, because the write cache may be enabled (which is the default for Windows XP).
Unfortunetly, it is also not enough to flush the buffers (fsync), because regular hard drives do not obey
this command. The only way to guarantee durability, according to a test, is to wait about one second
before returning from a commit call. This would mean the maximum number of transactions is 1 per second.
All databases tested achive a much higher transaction rate, which means all databases take some shortcuts.
H2 does not guarantee durability, and while other databases (such as Derby) claim they guarantee it,
in reality none of the tested databases achieve complete durability
There are multiple ways to
With regular hard drives, trying to
Durability means that
Mail P2P Mail P2P
......
...@@ -133,7 +133,8 @@ class Database { ...@@ -133,7 +133,8 @@ class Database {
Statement stat = null; Statement stat = null;
try { try {
stat = conn.createStatement(); stat = conn.createStatement();
stat.execute("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.storage.pageSize', '8192')"); // stat.execute("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.storage.pageCacheSize', '64')");
// stat.execute("CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.storage.pageSize', '8192')");
} finally { } finally {
JdbcUtils.closeSilently(stat); JdbcUtils.closeSilently(stat);
} }
......
db1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000, sa, sa db1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000, sa, sa
xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;CIPHER=XTEA, sa, sa 123 xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;CIPHER=XTEA, sa, sa 123
xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;CIPHER=AES, sa, sa 123 xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;CIPHER=AES, sa, sa 123
xdb4 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;write_mode_log=rws;write_delay=0, sa, sa
db2 = HSQLDB, org.hsqldb.jdbcDriver, jdbc:hsqldb:data/test;hsqldb.default_table_type=cached;sql.enforce_size=true, sa db2 = HSQLDB, org.hsqldb.jdbcDriver, jdbc:hsqldb:data/test;hsqldb.default_table_type=cached;sql.enforce_size=true, sa
db3 = Derby, org.apache.derby.jdbc.EmbeddedDriver, jdbc:derby:data/test;create=true, sa, sa db3 = Derby, org.apache.derby.jdbc.EmbeddedDriver, jdbc:derby:data/test;create=true, sa, sa
......
...@@ -4576,11 +4576,11 @@ SELECT * FROM TEST_ALL WHERE AID>=2; ...@@ -4576,11 +4576,11 @@ SELECT * FROM TEST_ALL WHERE AID>=2;
CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2; CREATE VIEW TEST_A_SUB AS SELECT * FROM TEST_A WHERE ID < 2;
> ok > ok
SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW'; SELECT TABLE_NAME, SQL FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE='VIEW';
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE STORAGE_TYPE SQL REMARKS ID > TABLE_NAME SQL
> ------------- ------------ ---------- ---------- ------------ ---------------------------------------------------------------------------------------------------------------------------------------------------------------- ------- --- > ---------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------
> SCRIPT PUBLIC TEST_ALL VIEW MEMORY CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AID, A.NAME A_NAME, B.ID BID, B.NAME B_NAME FROM TEST_A A, TEST_B B WHERE A.ID = B.ID 513 > TEST_ALL CREATE FORCE VIEW PUBLIC.TEST_ALL(AID, A_NAME, BID, B_NAME) AS SELECT A.ID AID, A.NAME A_NAME, B.ID BID, B.NAME B_NAME FROM TEST_A A, TEST_B B WHERE A.ID = B.ID
> SCRIPT PUBLIC TEST_A_SUB VIEW MEMORY CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT * FROM TEST_A WHERE ID < 2 515 > TEST_A_SUB CREATE FORCE VIEW PUBLIC.TEST_A_SUB(ID, NAME) AS SELECT * FROM TEST_A WHERE ID < 2
> rows: 2 > rows: 2
SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL; SELECT * FROM TEST_A_SUB WHERE NAME IS NOT NULL;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论