提交 c12cf0a7 authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 83b8c103
......@@ -116,6 +116,16 @@
<fileset dir="src/test" includes="**/*.properties"/>
</copy>
</target>
<target name="compileCoverage" depends="compile">
<copy todir="bin" overwrite="true">
<fileset dir="src/main"/>
</copy>
<java classname="org.h2.test.coverage.Coverage" classpath="bin" dir="bin" fork="true">
<arg line="-e org/h2/web -e org/h2/jdbcx -e org/h2/bnf -r org/h2"/>
</java>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="bin" destdir="bin" debug="true" includes="org/h2/**"/>
</target>
<target name="compileTest" unless="java.version.ok">
<echo message="Java version is ${java.specification.version} but source code is switched to ${jdk}."/>
......@@ -303,14 +313,7 @@
<java classname="org.h2.test.TestAll" fork="true" classpath="bin" />
</target>
<target name="testCoverage" depends="compile">
<copy todir="bin" overwrite="true">
<fileset dir="src/main"/>
</copy>
<java classname="org.h2.test.coverage.Coverage" classpath="bin" dir="bin" fork="true">
<arg line="-e org/h2/web -e org/h2/jdbcx -e org/h2/bnf -r org/h2"/>
</java>
<javac target="${jdk}" source="${jdk}" executable="${javac}" srcdir="bin" destdir="bin" debug="true" includes="org/h2/**"/>
<target name="testCoverage" depends="compileCoverage">
<java classname="org.h2.test.TestAll" fork="true" classpath="bin" dir="bin">
<arg line="codeCoverage"/>
</java>
......
......@@ -3302,6 +3302,9 @@ public class Parser {
long increment = readLong();
command.setIncrement(increment);
}
if (readIf("CACHE")) {
command.setCacheSize(readLong());
}
if (readIf("BELONGS_TO_TABLE")) {
command.setBelongsToTable(true);
}
......
......@@ -19,6 +19,7 @@ public class CreateSequence extends SchemaCommand {
private boolean ifNotExists;
private long start = 1;
private long increment = 1;
private long cacheSize = Sequence.DEFAULT_CACHE_SIZE;
private boolean belongsToTable;
public CreateSequence(Session session, Schema schema) {
......@@ -46,6 +47,7 @@ public class CreateSequence extends SchemaCommand {
Sequence sequence = new Sequence(getSchema(), id, sequenceName, belongsToTable);
sequence.setStartValue(start);
sequence.setIncrement(increment);
sequence.setCacheSize(cacheSize);
db.addSchemaObject(session, sequence);
return 0;
}
......@@ -65,5 +67,9 @@ public class CreateSequence extends SchemaCommand {
public void setBelongsToTable(boolean belongsToTable) {
this.belongsToTable = belongsToTable;
}
public void setCacheSize(long cacheSize) {
this.cacheSize = cacheSize;
}
}
......@@ -21,7 +21,6 @@ import org.h2.message.TraceSystem;
*/
public class SysProperties {
public static final boolean MVCC = getBooleanSetting("h2.mvcc", false);
public static final int MIN_WRITE_DELAY = getIntSetting("h2.minWriteDelay", 5);
public static final boolean CHECK = getBooleanSetting("h2.check", true);
public static final boolean CHECK2 = getBooleanSetting("h2.check2", false);
......
......@@ -176,7 +176,7 @@ public class Database implements DataHandler {
if (ignoreSummary != null) {
this.recovery = true;
}
this.multiVersion = ci.removeProperty("MVCC", false) || SysProperties.MVCC;
this.multiVersion = ci.removeProperty("MVCC", false);
boolean closeAtVmShutdown = ci.removeProperty("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,
......
......@@ -71,6 +71,7 @@ public class Session implements SessionInterface {
private boolean autoCommitAtTransactionEnd;
private String currentTransactionName;
private boolean isClosed;
private boolean rollbackMode;
public Session() {
}
......@@ -252,7 +253,12 @@ public class Session implements SessionInterface {
public void rollbackTo(int index) throws SQLException {
while (undoLog.size() > index) {
UndoLogRecord entry = undoLog.getAndRemoveLast();
entry.undo(this);
rollbackMode = true;
try {
entry.undo(this);
} finally {
rollbackMode = false;
}
}
if (savepoints != null) {
String[] names = new String[savepoints.size()];
......@@ -588,4 +594,8 @@ public class Session implements SessionInterface {
autoCommit = false;
}
public boolean getRollbackMode() {
return rollbackMode;
}
}
......@@ -237,7 +237,9 @@ public class LinkedIndex extends BaseIndex {
j++;
}
}
prep.executeUpdate();
int count = prep.executeUpdate();
// this has no effect but at least it allows to debug the update count
rowCount = rowCount + count - count;
} catch (SQLException e) {
throw wrapException(sql, e);
}
......
......@@ -120,6 +120,9 @@ public class MultiVersionCursor implements Cursor {
return true;
}
}
int test;
this.index.debug("error", session, deltaRow);
System.exit(1);
throw Message.getInternalError();
}
int compare = index.compareRows(deltaRow, baseRow);
......
......@@ -30,14 +30,16 @@ public class MultiVersionIndex implements Index {
IndexType deltaIndexType = IndexType.createNonUnique(false);
this.delta = new TreeIndex(table, -1, "DELTA", base.getIndexColumns(), deltaIndexType);
this.sync = base.getDatabase();
}
}
public void add(Session session, Row row) throws SQLException {
int test;
debug("add", session, row);
synchronized (sync) {
base.add(session, row);
// for example rolling back an delete operation
removeIfExists(session, row);
if (row.getSessionId() != 0) {
if (removeIfExists(session, row)) {
// for example rolling back an delete operation
} else if (row.getSessionId() != 0) {
// don't insert rows that are added when creating an index
delta.add(session, row);
}
......@@ -51,6 +53,8 @@ public class MultiVersionIndex implements Index {
}
public Cursor find(Session session, SearchRow first, SearchRow last) throws SQLException {
int test;
debug("find", session, first);
synchronized (sync) {
Cursor baseCursor = base.find(session, first, last);
Cursor deltaCursor = delta.find(session, first, last);
......@@ -59,6 +63,7 @@ public class MultiVersionIndex implements Index {
}
public boolean canGetFirstOrLast(boolean first) {
// TODO in many cases possible, but more complicated
return false;
}
......@@ -75,19 +80,26 @@ public class MultiVersionIndex implements Index {
}
private boolean removeIfExists(Session session, Row row) throws SQLException {
int test;
debug("removeIfExists ", session, row);
// maybe it was inserted by the same session just before
Cursor c = delta.find(session, row, row);
while (c.next()) {
Row r = c.get();
if (r.getPos() == row.getPos()) {
debug(" >remove", session, null);
delta.remove(session, row);
debug(" >return true", session, null);
return true;
}
}
debug(" >return false", session, null);
return false;
}
public void remove(Session session, Row row) throws SQLException {
int test;
debug("remove", session, row);
synchronized (sync) {
base.remove(session, row);
if (removeIfExists(session, row)) {
......@@ -105,6 +117,8 @@ public class MultiVersionIndex implements Index {
}
public void truncate(Session session) throws SQLException {
int test;
debug("truncate", session, null);
synchronized (sync) {
delta.truncate(session);
base.truncate(session);
......@@ -112,6 +126,8 @@ public class MultiVersionIndex implements Index {
}
public void commit(int operation, Row row) throws SQLException {
int test;
debug("commit", null, row);
synchronized (sync) {
removeIfExists(null, row);
}
......@@ -255,5 +271,9 @@ public class MultiVersionIndex implements Index {
public void setTemporary(boolean temporary) {
base.setTemporary(temporary);
}
void debug(String s, Session session, SearchRow row) throws SQLException {
// System.out.println(this + " " + s + " sess:" + (session == null ? -1: session.getId()) + " " + (row == null ? "" : row.getValue(0).getString()));
}
}
......@@ -177,6 +177,8 @@ public class ScanIndex extends BaseIndex {
firstFree = key;
}
if (database.isMultiVersion()) {
// if storage is null, the delete flag is not yet set
row.setDeleted(true);
if (delta == null) {
delta = new HashSet();
}
......
......@@ -423,8 +423,11 @@ CREATE SCHEMA TEST_SCHEMA AUTHORIZATION SA
CREATE SEQUENCE [IF NOT EXISTS] newSequenceName
[START WITH long]
[INCREMENT BY long]
[CACHE long]
","
Creates a new sequence. The data type of a sequence is BIGINT.
The cache is the number of pre-allocated numbers. If the system crashes without closing the
database, at most this many numbers are lost. The default cache size is 32.
","
CREATE SEQUENCE SEQ_ID
"
......
......@@ -15,10 +15,11 @@ import org.h2.message.Trace;
import org.h2.table.Table;
public class Sequence extends SchemaObjectBase {
private static final int BLOCK_INCREMENT = 32;
public static final int DEFAULT_CACHE_SIZE = 32;
private long value = 1;
private long valueWithMargin;
private long increment = 1;
private long cacheSize = DEFAULT_CACHE_SIZE;
private boolean belongsToTable;
public Sequence(Schema schema, int id, String name, boolean belongsToTable) {
......@@ -67,6 +68,10 @@ public class Sequence extends SchemaObjectBase {
buff.append(" INCREMENT BY ");
buff.append(increment);
}
if (cacheSize != DEFAULT_CACHE_SIZE) {
buff.append(" CACHE ");
buff.append(cacheSize);
}
if (belongsToTable) {
buff.append(" BELONGS_TO_TABLE");
}
......@@ -75,7 +80,7 @@ public class Sequence extends SchemaObjectBase {
public synchronized long getNext() throws SQLException {
if ((increment > 0 && value >= valueWithMargin) || (increment < 0 && value <= valueWithMargin)) {
valueWithMargin += increment * BLOCK_INCREMENT;
valueWithMargin += increment * cacheSize;
flush();
}
long v = value;
......@@ -125,4 +130,12 @@ public class Sequence extends SchemaObjectBase {
this.belongsToTable = b;
}
public void setCacheSize(long cacheSize) {
this.cacheSize = cacheSize;
}
public long getCacheSize() {
return cacheSize;
}
}
......@@ -202,6 +202,7 @@ public class MetaTable extends Table {
"INCREMENT BIGINT",
"IS_GENERATED BIT",
"REMARKS",
"CACHE BIGINT",
"ID INT"
});
break;
......@@ -783,6 +784,7 @@ public class MetaTable extends Table {
String.valueOf(s.getIncrement()), // INCREMENT
s.getBelongsToTable() ? "TRUE" : "FALSE", // IS_GENERATED
replaceNullWithEmpty(s.getComment()), // REMARKS
String.valueOf(s.getCacheSize()), // CACHE
"" + s.getId() // ID
});
}
......
......@@ -59,6 +59,7 @@ import org.h2.test.jdbc.TestTransactionIsolation;
import org.h2.test.jdbc.TestUpdatableResultSet;
import org.h2.test.jdbc.TestZloty;
import org.h2.test.jdbc.xa.TestXA;
import org.h2.test.mvcc.TestMVCC;
import org.h2.test.server.TestNestedLoop;
import org.h2.test.synth.TestBtreeIndex;
import org.h2.test.synth.TestKillRestart;
......@@ -125,7 +126,7 @@ java org.h2.test.TestAll timer
*/
public boolean smallLog, big, networked, memory, ssl, textStorage, diskUndo, diskResult, deleteIndex, traceSystemOut;
public boolean codeCoverage;
public boolean codeCoverage, mvcc;
public int logMode = 1, traceLevelFile, throttle;
public String cipher;
......@@ -139,20 +140,17 @@ java org.h2.test.TestAll timer
TestAll test = new TestAll();
test.printSystem();
//int testMVCC;
// System.setProperty("h2.mvcc", "true");
/*
----
A file is sent although the Japanese translation has not been completed yet.
----
Code coverage
At startup, when corrupted, say if LOG=0 was used before
add MVCC
add more MVCC tests
slow:
select ta.attname, ia.attnum, ic.relname
......@@ -369,6 +367,7 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = throttle = 0;
logMode = 1;
cipher = null;
mvcc = false;
testAll();
diskUndo = false;
......@@ -382,6 +381,7 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = throttle = 0;
logMode = 1;
cipher = null;
mvcc = false;
testAll();
big = false;
......@@ -397,6 +397,7 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = 0;
throttle = 0;
cipher = null;
mvcc = false;
testAll();
diskUndo = true;
......@@ -410,6 +411,7 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = 3;
throttle = 1;
cipher = "XTEA";
mvcc = false;
testAll();
diskUndo = false;
......@@ -426,6 +428,7 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = 1;
throttle = 0;
cipher = null;
mvcc = false;
testAll();
big = true;
......@@ -441,6 +444,7 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = 2;
throttle = 0;
cipher = null;
mvcc = false;
testAll();
big = true;
......@@ -456,14 +460,18 @@ write tests using the PostgreSQL JDBC driver
traceLevelFile = 0;
throttle = 0;
cipher = "AES";
mvcc = false;
testAll();
smallLog = big = networked = memory = ssl = textStorage = diskResult = deleteIndex = traceSystemOut = false;
traceLevelFile = throttle = 0;
logMode = 1;
cipher = null;
mvcc = true;
testAll();
}
public boolean isMVCC() {
return SysProperties.MVCC;
}
void testAll() throws Exception {
DeleteDbFiles.execute(TestBase.baseDir, null, true);
testDatabase();
......@@ -495,8 +503,11 @@ write tests using the PostgreSQL JDBC driver
}
void testDatabase() throws Exception {
System.out.println("test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult);
System.out.println("test big:"+big+" net:"+networked+" cipher:"+cipher+" memory:"+memory+" log:"+logMode+" diskResult:"+diskResult + " mvcc:" + mvcc);
beforeTest();
// int testMvcc;
// mvcc = true;
// db
new TestScriptSimple().runTest(this);
......@@ -514,18 +525,14 @@ write tests using the PostgreSQL JDBC driver
new TestCsv().runTest(this);
new TestFunctions().runTest(this);
new TestIndex().runTest(this);
if (!SysProperties.MVCC) {
new TestLinkedTable().runTest(this);
}
new TestLinkedTable().runTest(this);
new TestListener().runTest(this);
new TestLob().runTest(this);
new TestLogFile().runTest(this);
new TestMemoryUsage().runTest(this);
new TestMultiConn().runTest(this);
new TestMultiDimension().runTest(this);
if (!SysProperties.MVCC) {
new TestMultiThread().runTest(this);
}
new TestMultiThread().runTest(this);
new TestOpenClose().runTest(this);
new TestOptimizations().runTest(this);
new TestPowerOff().runTest(this);
......@@ -560,6 +567,9 @@ write tests using the PostgreSQL JDBC driver
new TestXA().runTest(this);
new TestZloty().runTest(this);
// mvcc
new TestMVCC().runTest(this);
// synthetic
new TestKillRestart().runTest(this);
......
......@@ -135,6 +135,9 @@ public abstract class TestBase {
if (config.diskUndo && admin) {
url += ";MAX_MEMORY_UNDO=3";
}
if (config.mvcc) {
url += ";MVCC=TRUE";
}
if (config.diskResult && admin) {
url += ";MAX_MEMORY_ROWS=100;CACHE_SIZE=0";
}
......
db1 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3, sa, sa
#db1 = H2 (MVCC), org.h2.Driver, jdbc:h2:data/test_mvcc;MVCC=TRUE, sa, sa
#db2 = H2 (MVCC), org.h2.Driver, jdbc:h2:data/test_mvcc;MVCC=TRUE, sa, sa
#xdb2 = H2 (XTEA), org.h2.Driver, jdbc:h2:data/test_xtea;LOCK_TIMEOUT=10000;LOCK_MODE=3;CIPHER=XTEA, sa, sa 123
#xdb3 = H2 (AES), org.h2.Driver, jdbc:h2:data/test_aes;LOCK_TIMEOUT=10000;LOCK_MODE=3;CIPHER=AES, sa, sa 123
#xdb4 = H2, org.h2.Driver, jdbc:h2:data/test;LOCK_TIMEOUT=10000;LOCK_MODE=3;write_mode_log=rws;write_delay=0, sa, sa
......
......@@ -131,6 +131,25 @@ public class TestLinkedTable extends TestBase {
stat2.executeUpdate("UPDATE TEST_LINK_DI SET ID=ID+1");
stat2.executeUpdate("UPDATE TEST_LINK_U SET NAME=NAME || ID");
ResultSet rs;
rs = stat2.executeQuery("SELECT * FROM TEST_LINK_DI ORDER BY ID");
rs.next();
check(rs.getInt(1), 2);
check(rs.getString(2), "Hello2");
rs.next();
check(rs.getInt(1), 3);
check(rs.getString(2), "World3");
checkFalse(rs.next());
rs = stat2.executeQuery("SELECT * FROM TEST_LINK_U ORDER BY ID");
rs.next();
check(rs.getInt(1), 2);
check(rs.getString(2), "Hello2");
rs.next();
check(rs.getInt(1), 3);
check(rs.getString(2), "World3");
checkFalse(rs.next());
rs = stat.executeQuery("SELECT * FROM TEST ORDER BY ID");
rs.next();
check(rs.getInt(1), 2);
......
......@@ -13,6 +13,36 @@ import org.h2.test.TestBase;
public class TestSequence extends TestBase {
public void test() throws Exception {
testCache();
testTwo();
}
private void testCache() throws Exception {
if (config.memory) {
return;
}
deleteDb("sequence");
Connection conn = getConnection("sequence");
Statement stat = conn.createStatement();
stat.execute("create sequence testSequence");
stat.execute("create sequence testSequence3 cache 3");
conn.close();
conn = getConnection("sequence");
stat = conn.createStatement();
stat.execute("call next value for testSequence");
stat.execute("call next value for testSequence3");
ResultSet rs = stat.executeQuery("select * from information_schema.sequences");
rs.next();
check(rs.getString("SEQUENCE_NAME"), "TESTSEQUENCE3");
check(rs.getString("CACHE"), "3");
rs.next();
check(rs.getString("SEQUENCE_NAME"), "TESTSEQUENCE");
check(rs.getString("CACHE"), "32");
checkFalse(rs.next());
conn.close();
}
private void testTwo() throws Exception {
deleteDb("sequence");
Connection conn = getConnection("sequence");
Statement stat = conn.createStatement();
......
......@@ -14,7 +14,7 @@ public class TestTransactionIsolation extends TestBase {
Connection conn1, conn2;
public void test() throws Exception {
if (config.isMVCC()) {
if (config.mvcc) {
// no tests yet
} else {
testTableLevelLocking();
......
......@@ -7,22 +7,23 @@ package org.h2.test.mvcc;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Random;
import org.h2.constant.ErrorCode;
import org.h2.test.TestBase;
import org.h2.tools.DeleteDbFiles;
public class TestMVCC {
public class TestMVCC extends TestBase {
Connection c1, c2;
Statement s1, s2;
public static void main(String[] args) throws Exception {
TestMVCC app = new TestMVCC();
app.test();
}
void test() throws Exception {
public void test() throws Exception {
if (!config.mvcc) {
return;
}
// TODO Prio 1: make unit test work
// TODO Prio 1: document: exclusive table lock still used when altering tables, adding indexes, select ... for update; table level locks are checked
// TODO Prio 1: free up disk space (for deleted rows and old versions of updated rows) on commit
......@@ -36,8 +37,7 @@ public class TestMVCC {
// TODO Prio 2: snapshot isolation (currently read-committed, not repeatable read)
// TODO test: one thread appends, the other selects new data (select * from test where id > ?) and deletes
// System.setProperty("h2.mvcc", "true");
DeleteDbFiles.execute(null, "test", true);
Class.forName("org.h2.Driver");
c1 = DriverManager.getConnection("jdbc:h2:test;MVCC=TRUE", "sa", "sa");
......@@ -47,7 +47,6 @@ public class TestMVCC {
c1.setAutoCommit(false);
c2.setAutoCommit(false);
s1.execute("create table test(id int primary key, name varchar(255))");
s2.execute("insert into test values(4, 'Hello')");
c2.rollback();
......@@ -196,7 +195,11 @@ public class TestMVCC {
s.execute("INSERT INTO TEST VALUES(" + i + ", 'Hello')");
break;
case 1:
s.execute("UPDATE TEST SET NAME=" + i + " WHERE ID=" + random.nextInt(i));
try {
s.execute("UPDATE TEST SET NAME=" + i + " WHERE ID=" + random.nextInt(i));
} catch (SQLException e) {
check(e.getErrorCode(), ErrorCode.CONCURRENT_UPDATE_1);
}
break;
case 2:
s.execute("DELETE FROM TEST WHERE ID=" + random.nextInt(i));
......@@ -249,6 +252,37 @@ public class TestMVCC {
c1.commit();
c2.commit();
s1.execute("create table test(id int primary key, name varchar(255))");
s1.execute("insert into test values(1, 'Hello'), (2, 'World')");
c1.commit();
try {
s1.execute("update test set id=2 where id=1");
error("unexpected success");
} catch (SQLException e) {
checkNotGeneralException(e);
}
ResultSet rs = s1.executeQuery("select * from test order by id");
check(rs.next());
check(rs.getInt(1), 1);
check(rs.getString(2), "Hello");
check(rs.next());
check(rs.getInt(1), 2);
check(rs.getString(2), "World");
checkFalse(rs.next());
rs = s2.executeQuery("select * from test order by id");
check(rs.next());
check(rs.getInt(1), 1);
check(rs.getString(2), "Hello");
check(rs.next());
check(rs.getInt(1), 2);
check(rs.getString(2), "World");
checkFalse(rs.next());
s1.execute("drop table test");
c1.commit();
c2.commit();
c1.close();
c2.close();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论