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

Experimental feature to support very large transactions.

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