提交 987c685e authored 作者: Thomas Mueller's avatar Thomas Mueller

Experimental feature to support very large transactions.

上级 93e5c6a0
...@@ -7,10 +7,12 @@ ...@@ -7,10 +7,12 @@
package org.h2.engine; package org.h2.engine;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import org.h2.constant.SysProperties; import org.h2.constant.SysProperties;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.store.Data; import org.h2.store.Data;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.table.Table;
import org.h2.util.New; import org.h2.util.New;
/** /**
...@@ -24,6 +26,7 @@ public class UndoLog { ...@@ -24,6 +26,7 @@ public class UndoLog {
private Data rowBuff; private Data rowBuff;
private int memoryUndo; private int memoryUndo;
private int storedEntries; private int storedEntries;
private HashMap<Integer, Table> tables;
/** /**
* Create a new undo log for the given session. * Create a new undo log for the given session.
...@@ -73,16 +76,22 @@ public class UndoLog { ...@@ -73,16 +76,22 @@ public class UndoLog {
public UndoLogRecord getLast() { public UndoLogRecord getLast() {
int i = records.size() - 1; int i = records.size() - 1;
if (SysProperties.LARGE_TRANSACTIONS) { if (SysProperties.LARGE_TRANSACTIONS) {
int test;
if (i <= 0 && storedEntries > 0) { if (i <= 0 && storedEntries > 0) {
int last = storedEntriesPos.size() - 1; int last = storedEntriesPos.size() - 1;
long pos = storedEntriesPos.get(last); long pos = storedEntriesPos.get(last);
storedEntriesPos.remove(last); storedEntriesPos.remove(last);
long end = file.length(); long end = file.length();
while (pos < end) { int bufferLength = (int) (end - pos);
int test; Data buff = Data.create(database, bufferLength);
// UndoLogRecord e = new UndoLogRecord(null, 0, null); seek(pos);
file.readFully(buff.getBytes(), 0, bufferLength);
while (buff.length() < bufferLength) {
UndoLogRecord e = UndoLogRecord.loadFromBuffer(buff, this);
records.add(e);
memoryUndo++;
} }
file.setLength(pos);
} }
} }
UndoLogRecord entry = records.get(i); UndoLogRecord entry = records.get(i);
...@@ -144,6 +153,26 @@ public class UndoLog { ...@@ -144,6 +153,26 @@ public class UndoLog {
memoryUndo++; memoryUndo++;
} }
if (memoryUndo > database.getMaxMemoryUndo() && database.isPersistent() && !database.isMultiVersion()) { if (memoryUndo > database.getMaxMemoryUndo() && database.isPersistent() && !database.isMultiVersion()) {
if (SysProperties.LARGE_TRANSACTIONS) {
int todo;
if (file == null) {
String fileName = database.createTempFile();
file = database.openFile(fileName, "rw", false);
file.setLength(FileStore.HEADER_LENGTH);
}
Data buff = Data.create(database, SysProperties.PAGE_SIZE);
for (int i = 0; i < records.size(); i++) {
UndoLogRecord r = records.get(i);
buff.checkCapacity(SysProperties.PAGE_SIZE);
r.append(buff, this);
}
storedEntriesPos.add(file.getFilePointer());
file.write(buff.getBytes(), 0, buff.length());
memoryUndo = 0;
records.clear();
file.autoDelete();
return;
}
if (file == null) { if (file == null) {
String fileName = database.createTempFile(); String fileName = database.createTempFile();
file = database.openFile(fileName, "rw", false); file = database.openFile(fileName, "rw", false);
...@@ -163,9 +192,24 @@ public class UndoLog { ...@@ -163,9 +192,24 @@ public class UndoLog {
private void saveIfPossible(UndoLogRecord r, Data buff) { private void saveIfPossible(UndoLogRecord r, Data buff) {
if (!r.isStored() && r.canStore()) { if (!r.isStored() && r.canStore()) {
r.save(buff, file); r.save(buff, file, this);
memoryUndo--; memoryUndo--;
} }
} }
int getTableId(Table table) {
int id = table.getId();
if (tables == null) {
tables = New.hashMap();
}
if (tables.get(id) == null) {
tables.put(id, table);
}
return id;
}
Table getTable(int id) {
return tables.get(id);
}
} }
...@@ -13,7 +13,6 @@ import org.h2.message.DbException; ...@@ -13,7 +13,6 @@ import org.h2.message.DbException;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.store.Data; import org.h2.store.Data;
import org.h2.store.FileStore; import org.h2.store.FileStore;
import org.h2.table.RegularTable;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.value.Value; import org.h2.value.Value;
...@@ -69,13 +68,12 @@ public class UndoLogRecord { ...@@ -69,13 +68,12 @@ public class UndoLogRecord {
* @return if it can be stored * @return if it can be stored
*/ */
boolean canStore() { boolean canStore() {
if (table.getUniqueIndex() != null) {
return true;
}
if (SysProperties.LARGE_TRANSACTIONS) { if (SysProperties.LARGE_TRANSACTIONS) {
if (table instanceof RegularTable) { // actually the method is not called in this case
return true; return true;
} }
if (table.getUniqueIndex() != null) {
return true;
} }
return false; return false;
} }
...@@ -136,18 +134,18 @@ public class UndoLogRecord { ...@@ -136,18 +134,18 @@ public class UndoLogRecord {
} }
/** /**
* Save the row in the file using a buffer. * Append the row to the buffer.
* *
* @param buff the buffer * @param buff the buffer
* @param file the file * @param log the undo log
*/ */
void save(Data buff, FileStore file) { void append(Data buff, UndoLog log) {
buff.reset(); int p = buff.length();
buff.writeInt(0); buff.writeInt(0);
buff.writeInt(operation); buff.writeInt(operation);
buff.writeByte(row.isDeleted() ? (byte) 1 : (byte) 0); buff.writeByte(row.isDeleted() ? (byte) 1 : (byte) 0);
if (SysProperties.LARGE_TRANSACTIONS) { if (SysProperties.LARGE_TRANSACTIONS) {
int table; buff.writeInt(log.getTableId(table));
} }
buff.writeLong(row.getKey()); buff.writeLong(row.getKey());
buff.writeInt(row.getSessionId()); buff.writeInt(row.getSessionId());
...@@ -158,13 +156,34 @@ public class UndoLogRecord { ...@@ -158,13 +156,34 @@ public class UndoLogRecord {
buff.writeValue(v); buff.writeValue(v);
} }
buff.fillAligned(); buff.fillAligned();
buff.setInt(0, buff.length() / Constants.FILE_BLOCK_SIZE); buff.setInt(p, buff.length() / Constants.FILE_BLOCK_SIZE);
}
/**
* Save the row in the file using a buffer.
*
* @param buff the buffer
* @param file the file
* @param log the undo log
*/
void save(Data buff, FileStore file, UndoLog log) {
buff.reset();
append(buff, log);
filePos = (int) (file.getFilePointer() / Constants.FILE_BLOCK_SIZE); filePos = (int) (file.getFilePointer() / Constants.FILE_BLOCK_SIZE);
file.write(buff.getBytes(), 0, buff.length()); file.write(buff.getBytes(), 0, buff.length());
row = null; row = null;
state = STORED; state = STORED;
} }
static UndoLogRecord loadFromBuffer(Data buff, UndoLog log) {
UndoLogRecord rec = new UndoLogRecord(null, (short) 0, null);
int pos = buff.length();
int len = buff.readInt() * Constants.FILE_BLOCK_SIZE;
rec.load(buff, log);
buff.setPos(pos + len);
return rec;
}
/** /**
* Load an undo log record row using a buffer. * Load an undo log record row using a buffer.
* *
...@@ -182,6 +201,10 @@ public class UndoLogRecord { ...@@ -182,6 +201,10 @@ public class UndoLogRecord {
if (len - min > 0) { if (len - min > 0) {
file.readFully(buff.getBytes(), min, len - min); file.readFully(buff.getBytes(), min, len - min);
} }
load(buff, log);
}
private void load(Data buff, UndoLog log) {
int op = buff.readInt(); int op = buff.readInt();
if (SysProperties.CHECK) { if (SysProperties.CHECK) {
if (operation != op) { if (operation != op) {
...@@ -190,7 +213,7 @@ public class UndoLogRecord { ...@@ -190,7 +213,7 @@ public class UndoLogRecord {
} }
boolean deleted = buff.readByte() == 1; boolean deleted = buff.readByte() == 1;
if (SysProperties.LARGE_TRANSACTIONS) { if (SysProperties.LARGE_TRANSACTIONS) {
int table; table = log.getTable(buff.readInt());
} }
long key = buff.readLong(); long key = buff.readLong();
int sessionId = buff.readInt(); int sessionId = buff.readInt();
......
...@@ -21,6 +21,8 @@ public class TestUndoLogMemory { ...@@ -21,6 +21,8 @@ public class TestUndoLogMemory {
* @param args ignored * @param args ignored
*/ */
public static void main(String... args) throws Exception { public static void main(String... args) throws Exception {
System.setProperty("h2.largeTransactions", "true");
// -Xmx1m -XX:+HeapDumpOnOutOfMemoryError // -Xmx1m -XX:+HeapDumpOnOutOfMemoryError
DeleteDbFiles.execute("data", "test", true); DeleteDbFiles.execute("data", "test", true);
Connection conn = DriverManager.getConnection("jdbc:h2:data/test"); Connection conn = DriverManager.getConnection("jdbc:h2:data/test");
...@@ -33,20 +35,21 @@ public class TestUndoLogMemory { ...@@ -33,20 +35,21 @@ public class TestUndoLogMemory {
stat.execute("create table test(id int)"); stat.execute("create table test(id int)");
stat.execute("insert into test select x from system_range(1, 100000)"); stat.execute("insert into test select x from system_range(1, 100000)");
// stat.execute("create table test(id int primary key)"); stat.execute("drop table test");
stat.execute("create table test(id int primary key)");
// INSERT problem // INSERT problem
// stat.execute( stat.execute(
// "insert into test select x from system_range(1, 400000)"); "insert into test select x from system_range(1, 400000)");
stat.execute("delete from test");
// DELETE problem // DELETE problem
// stat.execute( stat.execute(
// "insert into test select x from system_range(1, 50000)"); "insert into test select x from system_range(1, 50000)");
// stat.execute( stat.execute(
// "insert into test select x from system_range(50001, 100000)"); "insert into test select x from system_range(50001, 100000)");
// stat.execute( stat.execute(
// "insert into test select x from system_range(100001, 150000)"); "insert into test select x from system_range(100001, 150000)");
stat.execute("delete from test"); stat.execute("delete from test");
conn.close(); conn.close();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论