Unverified 提交 8c10350d authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1250 from h2database/batch-append

Batch append mode for MVMap
...@@ -836,6 +836,8 @@ public abstract class Page implements Cloneable ...@@ -836,6 +836,8 @@ public abstract class Page implements Cloneable
} }
} }
public abstract CursorPos getAppendCursorPos(CursorPos cursorPos);
public abstract void removeAllRecursive(); public abstract void removeAllRecursive();
private Object[] createKeyStorage(int size) private Object[] createKeyStorage(int size)
...@@ -1083,6 +1085,13 @@ public abstract class Page implements Cloneable ...@@ -1083,6 +1085,13 @@ public abstract class Page implements Cloneable
removePage(); removePage();
} }
@Override
public CursorPos getAppendCursorPos(CursorPos cursorPos) {
int keyCount = getKeyCount();
Page childPage = getChildPage(keyCount);
return childPage.getAppendCursorPos(new CursorPos(this, keyCount, cursorPos));
}
@Override @Override
protected void readPayLoad(ByteBuffer buff) { protected void readPayLoad(ByteBuffer buff) {
int keyCount = getKeyCount(); int keyCount = getKeyCount();
...@@ -1322,6 +1331,12 @@ public abstract class Page implements Cloneable ...@@ -1322,6 +1331,12 @@ public abstract class Page implements Cloneable
removePage(); removePage();
} }
@Override
public CursorPos getAppendCursorPos(CursorPos cursorPos) {
int keyCount = getKeyCount();
return new CursorPos(this, -keyCount - 1, cursorPos);
}
@Override @Override
protected void readPayLoad(ByteBuffer buff) { protected void readPayLoad(ByteBuffer buff) {
int keyCount = getKeyCount(); int keyCount = getKeyCount();
......
...@@ -19,6 +19,7 @@ import org.h2.index.Cursor; ...@@ -19,6 +19,7 @@ import org.h2.index.Cursor;
import org.h2.index.IndexType; import org.h2.index.IndexType;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.tx.Transaction; import org.h2.mvstore.tx.Transaction;
import org.h2.mvstore.tx.TransactionMap; import org.h2.mvstore.tx.TransactionMap;
import org.h2.result.Row; import org.h2.result.Row;
...@@ -79,8 +80,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -79,8 +80,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
MVMap<ValueArray, Value> map = openMap(bufferName); MVMap<ValueArray, Value> map = openMap(bufferName);
for (Row row : rows) { for (Row row : rows) {
ValueArray key = convertToKey(row); ValueArray key = convertToKey(row);
map.put(key, ValueNull.INSTANCE); map.append(key, ValueNull.INSTANCE);
} }
map.flushAppendBuffer();
} }
private static final class Source { private static final class Source {
...@@ -154,9 +156,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -154,9 +156,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
} }
} }
} finally { } finally {
MVStore store = database.getMvStore().getStore();
for (String tempMapName : bufferNames) { for (String tempMapName : bufferNames) {
MVMap<ValueArray, Value> map = openMap(tempMapName); store.removeMap(tempMapName);
map.getStore().removeMap(map);
} }
} }
} }
...@@ -171,7 +173,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex { ...@@ -171,7 +173,9 @@ public final class MVSecondaryIndex extends BaseIndex implements MVIndex {
database.getCompareMode(), database, sortTypes); database.getCompareMode(), database, sortTypes);
ValueDataType valueType = new ValueDataType(null, null, null); ValueDataType valueType = new ValueDataType(null, null, null);
MVMap.Builder<ValueArray, Value> builder = MVMap.Builder<ValueArray, Value> builder =
new MVMap.Builder<ValueArray, Value>().keyType(keyType).valueType(valueType); new MVMap.Builder<ValueArray, Value>()
.singleWriter()
.keyType(keyType).valueType(valueType);
MVMap<ValueArray, Value> map = database.getMvStore(). MVMap<ValueArray, Value> map = database.getMvStore().
getStore().openMap(mapName, builder); getStore().openMap(mapName, builder);
if (!keyType.equals(map.getKeyType())) { if (!keyType.equals(map.getKeyType())) {
......
...@@ -300,7 +300,7 @@ public class Transaction { ...@@ -300,7 +300,7 @@ public class Transaction {
} }
int currentStatus = getStatus(currentState); int currentStatus = getStatus(currentState);
checkOpen(currentStatus); checkOpen(currentStatus);
store.removeUndoLogRecord(transactionId, logId); store.removeUndoLogRecord(transactionId);
} }
/** /**
......
...@@ -88,9 +88,9 @@ public class TransactionMap<K, V> { ...@@ -88,9 +88,9 @@ public class TransactionMap<K, V> {
for (int i = opentransactions.nextSetBit(0); i >= 0; i = opentransactions.nextSetBit(i+1)) { for (int i = opentransactions.nextSetBit(0); i >= 0; i = opentransactions.nextSetBit(i+1)) {
MVMap<Long, Object[]> undoLog = store.undoLogs[i]; MVMap<Long, Object[]> undoLog = store.undoLogs[i];
if (undoLog != null) { if (undoLog != null) {
MVMap.RootReference rootReference = undoLog.getRoot(); MVMap.RootReference rootReference = undoLog.flushAppendBuffer();
undoLogRootReferences[i] = rootReference; undoLogRootReferences[i] = rootReference;
undoLogSize += rootReference.root.getTotalCount(); undoLogSize += rootReference.root.getTotalCount() + rootReference.getAppendCounter();
} }
} }
} while(committingTransactions != store.committingTransactions.get() || } while(committingTransactions != store.committingTransactions.get() ||
......
...@@ -16,6 +16,7 @@ import org.h2.mvstore.Cursor; ...@@ -16,6 +16,7 @@ import org.h2.mvstore.Cursor;
import org.h2.mvstore.DataUtils; import org.h2.mvstore.DataUtils;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore; import org.h2.mvstore.MVStore;
import org.h2.mvstore.Page;
import org.h2.mvstore.WriteBuffer; import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.mvstore.type.ObjectDataType; import org.h2.mvstore.type.ObjectDataType;
...@@ -132,7 +133,9 @@ public class TransactionStore { ...@@ -132,7 +133,9 @@ public class TransactionStore {
ArrayType undoLogValueType = new ArrayType(new DataType[]{ ArrayType undoLogValueType = new ArrayType(new DataType[]{
new ObjectDataType(), dataType, oldValueType new ObjectDataType(), dataType, oldValueType
}); });
undoLogBuilder = new MVMap.Builder<Long, Object[]>().valueType(undoLogValueType); undoLogBuilder = new MVMap.Builder<Long, Object[]>()
.singleWriter()
.valueType(undoLogValueType);
} }
/** /**
...@@ -391,24 +394,16 @@ public class TransactionStore { ...@@ -391,24 +394,16 @@ public class TransactionStore {
"is still open: {0}", "is still open: {0}",
transactionId); transactionId);
} }
undoLog.put(undoKey, undoLogRecord); undoLog.append(undoKey, undoLogRecord);
return undoKey; return undoKey;
} }
/** /**
* Remove an undo log entry. * Remove an undo log entry.
* @param transactionId id of the transaction * @param transactionId id of the transaction
* @param logId sequential number of the log record within transaction
*/ */
public void removeUndoLogRecord(int transactionId, long logId) { void removeUndoLogRecord(int transactionId) {
Long undoKey = getOperationId(transactionId, logId); undoLogs[transactionId].trimLast();
Object[] old = undoLogs[transactionId].remove(undoKey);
if (old == null) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_TRANSACTION_ILLEGAL_STATE,
"Transaction {0} was concurrently rolled back",
transactionId);
}
} }
/** /**
...@@ -442,7 +437,9 @@ public class TransactionStore { ...@@ -442,7 +437,9 @@ public class TransactionStore {
store.renameMap(undoLog, getUndoLogName(true, transactionId)); store.renameMap(undoLog, getUndoLogName(true, transactionId));
} }
try { try {
Cursor<Long, Object[]> cursor = undoLog.cursor(null); MVMap.RootReference rootReference = undoLog.flushAppendBuffer();
Page rootPage = rootReference.root;
Cursor<Long, Object[]> cursor = new Cursor<>(rootPage, null);
while (cursor.hasNext()) { while (cursor.hasNext()) {
Long undoKey = cursor.next(); Long undoKey = cursor.next();
Object[] op = cursor.getValue(); Object[] op = cursor.getValue();
...@@ -597,6 +594,7 @@ public class TransactionStore { ...@@ -597,6 +594,7 @@ public class TransactionStore {
void rollbackTo(Transaction t, long maxLogId, long toLogId) { void rollbackTo(Transaction t, long maxLogId, long toLogId) {
int transactionId = t.getId(); int transactionId = t.getId();
MVMap<Long, Object[]> undoLog = undoLogs[transactionId]; MVMap<Long, Object[]> undoLog = undoLogs[transactionId];
undoLog.flushAppendBuffer();
RollbackDecisionMaker decisionMaker = new RollbackDecisionMaker(this, transactionId, toLogId, t.listener); RollbackDecisionMaker decisionMaker = new RollbackDecisionMaker(this, transactionId, toLogId, t.listener);
for (long logId = maxLogId - 1; logId >= toLogId; logId--) { for (long logId = maxLogId - 1; logId >= toLogId; logId--) {
Long undoKey = getOperationId(transactionId, logId); Long undoKey = getOperationId(transactionId, logId);
...@@ -618,6 +616,7 @@ public class TransactionStore { ...@@ -618,6 +616,7 @@ public class TransactionStore {
final long toLogId) { final long toLogId) {
final MVMap<Long, Object[]> undoLog = undoLogs[t.getId()]; final MVMap<Long, Object[]> undoLog = undoLogs[t.getId()];
undoLog.flushAppendBuffer();
return new Iterator<Change>() { return new Iterator<Change>() {
private long logId = maxLogId - 1; private long logId = maxLogId - 1;
......
...@@ -509,7 +509,7 @@ public class TestMultiThread extends TestDb implements Runnable { ...@@ -509,7 +509,7 @@ public class TestMultiThread extends TestDb implements Runnable {
@Override @Override
public void run() { public void run() {
try { try {
Connection c = getConnection("concurrentUpdate2"); Connection c = getConnection("concurrentUpdate2;LOCK_TIMEOUT=10000");
PreparedStatement ps = c.prepareStatement("UPDATE TEST SET V = ? WHERE " + column + " = ?"); PreparedStatement ps = c.prepareStatement("UPDATE TEST SET V = ? WHERE " + column + " = ?");
for (int test = 0; test < 1000; test++) { for (int test = 0; test < 1000; test++) {
for (int i = 0; i < 16; i++) { for (int i = 0; i < 16; i++) {
......
...@@ -76,7 +76,7 @@ public class TestMVTableEngine extends TestDb { ...@@ -76,7 +76,7 @@ public class TestMVTableEngine extends TestDb {
testMinMaxWithNull(); testMinMaxWithNull();
testTimeout(); testTimeout();
testExplainAnalyze(); testExplainAnalyze();
testTransactionLogUsuallyNotStored(); testTransactionLogEmptyAfterCommit();
testShrinkDatabaseFile(); testShrinkDatabaseFile();
testTwoPhaseCommit(); testTwoPhaseCommit();
testRecover(); testRecover();
...@@ -642,17 +642,16 @@ public class TestMVTableEngine extends TestDb { ...@@ -642,17 +642,16 @@ public class TestMVTableEngine extends TestDb {
conn.close(); conn.close();
} }
private void testTransactionLogUsuallyNotStored() throws Exception { private void testTransactionLogEmptyAfterCommit() throws Exception {
Connection conn; Connection conn;
Statement stat; Statement stat;
// we expect the transaction log is empty in at least some of the cases
for (int test = 0; test < 5; test++) {
deleteDb(getTestName()); deleteDb(getTestName());
String url = getTestName() + ";MV_STORE=TRUE"; String url = getTestName() + ";MV_STORE=TRUE";
url = getURL(url, true); url = getURL(url, true);
conn = getConnection(url); conn = getConnection(url);
stat = conn.createStatement(); stat = conn.createStatement();
stat.execute("create table test(id identity, name varchar)"); stat.execute("create table test(id identity, name varchar)");
stat.execute("set write_delay 0");
conn.setAutoCommit(false); conn.setAutoCommit(false);
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
"insert into test(name) values(space(10000))"); "insert into test(name) values(space(10000))");
...@@ -673,11 +672,9 @@ public class TestMVTableEngine extends TestDb { ...@@ -673,11 +672,9 @@ public class TestMVTableEngine extends TestDb {
t.init(); t.init();
int openTransactions = t.getOpenTransactions().size(); int openTransactions = t.getOpenTransactions().size();
store.close(); store.close();
if (openTransactions == 0) { if (openTransactions != 0) {
return; fail("transaction log was not empty");
}
} }
fail("transaction log was never empty");
} }
private void testShrinkDatabaseFile() throws Exception { private void testShrinkDatabaseFile() throws Exception {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论