提交 14f07149 authored 作者: Thomas Mueller's avatar Thomas Mueller

Page store: a rollback of a relatively large transaction could fail.

上级 6e5c6ece
......@@ -18,7 +18,9 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>JaQu: the decompiler has been improved, and a few test cases already work. It is still incomplete however.
<ul><li>Page store: a rollback of a relatively large transaction could fail with an ArrayIndexOutOfBoundsException
or a 'row not found' exception in the PageBtreeIndex in some cases.
</li><li>JaQu: the decompiler has been improved, and a few test cases already work. It is still incomplete however.
</li><li>LIKE: any letter is now allowed after the escape character (which is still '\' by default).
Previously, an exception was thrown (unlike other databases) if it was not the escape character, '_' or '%'.
If the escape character appears at the end of the pattern, the result is it is ignored (like PostgreSQL and MS SQL Server).
......
......@@ -37,6 +37,7 @@ public class PageBtreeIndex extends PageIndex {
public PageBtreeIndex(TableData table, int id, String indexName, IndexColumn[] columns,
IndexType indexType, int headPos, Session session) throws SQLException {
initBaseIndex(table, id, indexName, columns, indexType);
// int test;
// trace.setLevel(TraceSystem.DEBUG);
tableData = table;
if (!database.isPersistent() || id < 0) {
......@@ -70,7 +71,7 @@ public class PageBtreeIndex extends PageIndex {
public void add(Session session, Row row) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("add " + row.getKey());
trace.debug(getName() + " add " + row);
}
// safe memory
SearchRow newRow = getSearchRow(row);
......@@ -210,7 +211,7 @@ public class PageBtreeIndex extends PageIndex {
public void remove(Session session, Row row) throws SQLException {
if (trace.isDebugEnabled()) {
trace.debug("remove " + row.getKey());
trace.debug(getName() + " remove " + row);
}
if (tableData.getContainsLargeObject()) {
for (int i = 0; i < row.getColumnCount(); i++) {
......
......@@ -50,7 +50,10 @@ public class PageDataIndex extends PageIndex implements RowIndex {
private int memorySizePerPage;
public PageDataIndex(TableData table, int id, IndexColumn[] columns, IndexType indexType, int headPos, Session session) throws SQLException {
int test;
// initBaseIndex(table, id, table.getName() + "_DATA", columns, indexType);
initBaseIndex(table, id, table.getName() + "_TABLE_SCAN", columns, indexType);
// trace = database.getTrace(Trace.PAGE_STORE + "_di");
// trace.setLevel(TraceSystem.DEBUG);
if (database.isMultiVersion()) {
......@@ -116,6 +119,9 @@ public class PageDataIndex extends PageIndex implements RowIndex {
}
// when using auto-generated values, it's possible that multiple
// tries are required (specially if there was originally a primary key)
if (trace.isDebugEnabled()) {
trace.debug(getName() + " add " + row);
}
long add = 0;
while (true) {
try {
......@@ -292,6 +298,9 @@ public class PageDataIndex extends PageIndex implements RowIndex {
}
}
}
if (trace.isDebugEnabled()) {
trace.debug(getName() + " remove " + row);
}
if (rowCount == 1) {
removeAllRows();
} else {
......
......@@ -11,6 +11,7 @@ import java.sql.SQLException;
import org.h2.constant.ErrorCode;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.engine.Database;
import org.h2.engine.Session;
import org.h2.index.Cursor;
import org.h2.index.Index;
......@@ -83,18 +84,22 @@ public class UndoLogRecord {
* @param session the session
*/
public void undo(Session session) throws SQLException {
Database db = session.getDatabase();
switch (operation) {
case INSERT:
if (state == IN_MEMORY_INVALID) {
Index index = table.getUniqueIndex();
Cursor cursor = index.find(session, row, row);
cursor.next();
// can not just set the position, because the row
// may already be in the cache
row = cursor.get();
if (!db.isPageStoreEnabled()) {
Index index = table.getUniqueIndex();
row.setPos(0);
Cursor cursor = index.find(session, row, row);
cursor.next();
// can not just set the position, because the row
// may already be in the cache
row = cursor.get();
}
state = IN_MEMORY;
}
if (session.getDatabase().getLockMode() == Constants.LOCK_MODE_OFF) {
if (db.getLockMode() == Constants.LOCK_MODE_OFF) {
if (row.isDeleted()) {
// it might have been deleted by another thread
return;
......@@ -115,7 +120,9 @@ public class UndoLogRecord {
break;
case DELETE:
try {
row.setKey(0);
if (!db.isPageStoreEnabled()) {
row.setKey(0);
}
table.addRow(session, row);
// reset session id, otherwise other session think
// that this row was inserted by this session
......@@ -155,6 +162,7 @@ public class UndoLogRecord {
buff.writeInt(0);
buff.writeInt(operation);
buff.writeByte(row.isDeleted() ? (byte) 1 : (byte) 0);
buff.writeLong(row.getKey());
buff.writeInt(row.getSessionId());
buff.writeInt(row.getColumnCount());
for (int i = 0; i < row.getColumnCount(); i++) {
......@@ -193,6 +201,7 @@ public class UndoLogRecord {
}
}
boolean deleted = buff.readByte() == 1;
long key = buff.readLong();
int sessionId = buff.readInt();
int columnCount = buff.readInt();
Value[] values = new Value[columnCount];
......@@ -200,6 +209,7 @@ public class UndoLogRecord {
values[i] = buff.readValue();
}
row = new Row(values, 0);
row.setKey(key);
row.setDeleted(deleted);
row.setSessionId(sessionId);
state = IN_MEMORY_INVALID;
......
......@@ -120,6 +120,7 @@ import org.h2.test.unit.TestIntArray;
import org.h2.test.unit.TestIntIntHashMap;
import org.h2.test.unit.TestMathUtils;
import org.h2.test.unit.TestOverflow;
import org.h2.test.unit.TestPageStore;
import org.h2.test.unit.TestPattern;
import org.h2.test.unit.TestPgServer;
import org.h2.test.unit.TestReader;
......@@ -297,24 +298,26 @@ java org.h2.test.TestAll timer
/*
memory usage:
script: create primary key before inserting data
readonly database: throw exception if lock file exists
drop table test;
create table test(username varchar, city varchar);
create index test_user on test(username);
create index test_city on test(city);
insert into test select x || ' user', (x / 20) ||
' city' from system_range(1, 500000);
create table test(id int) as select x from system_range(1, 10);
insert into test select null from system_range(1, 2000);
create index idx_id on test(id);
analyze;
select * from test t1, test t2 where t1.id = t2.id;
reserveMemory no longer needed
console: blob: write 'binary' and '(... bytes)'
504b0304000000... (binary, 3015712 bytes)
Document Shell tool
outer join bug
// System.setProperty("h2.pageSize", "64");
test with small freeList pages, page size 64
test if compact always works as expected
check memory usage when inserting a lot of rows
http://www.apache.org/dev/contrib-email-tips.html
google app engine
......@@ -606,6 +609,7 @@ kill -9 `jps -l | grep "org.h2.test." | cut -d " " -f 1`
new TestMathUtils().runTest(this);
new TestMultiThreadedKernel().runTest(this);
new TestOverflow().runTest(this);
new TestPageStore().runTest(this);
new TestPattern().runTest(this);
new TestPgServer().runTest(this);
new TestReader().runTest(this);
......
......@@ -93,8 +93,24 @@ public class TestCases extends TestBase {
}
private void testLargeRollback() throws SQLException {
Connection conn;
Statement stat;
deleteDb("cases");
Connection conn = getConnection("cases");
conn = getConnection("cases");
stat = conn.createStatement();
stat.execute("set max_operation_memory 1");
stat.execute("create table test(id int)");
stat.execute("insert into test values(1), (2)");
stat.execute("create index idx on test(id)");
conn.setAutoCommit(false);
stat.execute("update test set id = id where id=2");
stat.execute("update test set id = id");
conn.rollback();
conn.close();
deleteDb("cases");
conn = getConnection("cases");
conn.createStatement().execute("set MAX_MEMORY_UNDO 1");
conn.createStatement().execute("create table test(id number primary key)");
conn.createStatement().execute("insert into test(id) select x from system_range(1, 2)");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论