Unverified 提交 048f834c authored 作者: Andrei Tokar's avatar Andrei Tokar 提交者: GitHub

Merge pull request #1046 from h2database/txcommit-atomic

 Split off Transaction TransactionMap VersionedValue 
......@@ -33,7 +33,7 @@ import org.h2.message.TraceSystem;
import org.h2.mvstore.db.MVTable;
import org.h2.mvstore.db.MVTableEngine;
import org.h2.mvstore.tx.TransactionStore.Change;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.Transaction;
import org.h2.result.ResultInterface;
import org.h2.result.Row;
import org.h2.result.SortOrder;
......
......@@ -19,8 +19,8 @@ import org.h2.index.Cursor;
import org.h2.index.IndexType;
import org.h2.message.DbException;
import org.h2.mvstore.DataUtils;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.TransactionStore.TransactionMap;
import org.h2.mvstore.tx.Transaction;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
......
......@@ -20,8 +20,8 @@ import org.h2.index.Cursor;
import org.h2.index.IndexType;
import org.h2.message.DbException;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.TransactionStore.TransactionMap;
import org.h2.mvstore.tx.Transaction;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.result.Row;
import org.h2.result.SearchRow;
import org.h2.result.SortOrder;
......
......@@ -17,10 +17,9 @@ import org.h2.index.IndexType;
import org.h2.index.SpatialIndex;
import org.h2.index.SpatialTreeIndex;
import org.h2.message.DbException;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.TransactionStore.TransactionMap;
import org.h2.mvstore.tx.TransactionStore.VersionedValue;
import org.h2.mvstore.tx.TransactionStore.VersionedValueType;
import org.h2.mvstore.tx.Transaction;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.mvstore.tx.VersionedValue;
import org.h2.mvstore.rtree.MVRTreeMap;
import org.h2.mvstore.rtree.MVRTreeMap.RTreeCursor;
import org.h2.mvstore.rtree.SpatialKey;
......@@ -97,7 +96,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
}
mapName = "index." + getId();
ValueDataType vt = new ValueDataType(null, null, null);
VersionedValueType valueType = new VersionedValueType(vt);
VersionedValue.Type valueType = new VersionedValue.Type(vt);
MVRTreeMap.Builder<VersionedValue> mapBuilder =
new MVRTreeMap.Builder<VersionedValue>().
valueType(valueType);
......
......@@ -31,7 +31,7 @@ import org.h2.message.Trace;
import org.h2.mvstore.DataUtils;
import org.h2.mvstore.db.MVTableEngine.Store;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.Transaction;
import org.h2.result.Row;
import org.h2.result.SortOrder;
import org.h2.schema.SchemaObject;
......
......@@ -28,7 +28,7 @@ import org.h2.mvstore.FileStore;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.MVStoreTool;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.Transaction;
import org.h2.store.InDoubtTransaction;
import org.h2.store.fs.FileChannelInputStream;
import org.h2.store.fs.FileUtils;
......
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.mvstore.tx;
import org.h2.mvstore.DataUtils;
import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.type.DataType;
import java.util.Iterator;
/**
* A transaction.
*/
public class Transaction {
/**
* The status of a closed transaction (committed or rolled back).
*/
public static final int STATUS_CLOSED = 0;
/**
* The status of an open transaction.
*/
public static final int STATUS_OPEN = 1;
/**
* The status of a prepared transaction.
*/
public static final int STATUS_PREPARED = 2;
/**
* The status of a transaction that is being committed, but possibly not
* yet finished. A transactions can go into this state when the store is
* closed while the transaction is committing. When opening a store,
* such transactions should be committed.
*/
public static final int STATUS_COMMITTING = 3;
/**
* The transaction store.
*/
final TransactionStore store;
/**
* The transaction id.
*/
final int transactionId;
/**
* The log id of the last entry in the undo log map.
*/
long logId;
private int status;
private MVStore.TxCounter txCounter;
private String name;
Transaction(TransactionStore store, int transactionId, int status,
String name, long logId) {
this.store = store;
this.transactionId = transactionId;
this.status = status;
this.name = name;
this.logId = logId;
}
public int getId() {
return transactionId;
}
public int getStatus() {
return status;
}
void setStatus(int status) {
this.status = status;
}
public void setName(String name) {
checkNotClosed();
this.name = name;
store.storeTransaction(this);
}
public String getName() {
return name;
}
/**
* Create a new savepoint.
*
* @return the savepoint id
*/
public long setSavepoint() {
return logId;
}
public void markStatementStart() {
markStatementEnd();
txCounter = store.store.registerVersionUsage();
}
public void markStatementEnd() {
MVStore.TxCounter counter = txCounter;
txCounter = null;
if(counter != null) {
store.store.deregisterVersionUsage(counter);
}
}
/**
* Add a log entry.
*
* @param mapId the map id
* @param key the key
* @param oldValue the old value
*/
void log(int mapId, Object key, Object oldValue) {
store.log(this, logId, mapId, key, oldValue);
// only increment the log id if logging was successful
logId++;
}
/**
* Remove the last log entry.
*/
void logUndo() {
store.logUndo(this, --logId);
}
/**
* Open a data map.
*
* @param <K> the key type
* @param <V> the value type
* @param name the name of the map
* @return the transaction map
*/
public <K, V> TransactionMap<K, V> openMap(String name) {
return openMap(name, null, null);
}
/**
* Open the map to store the data.
*
* @param <K> the key type
* @param <V> the value type
* @param name the name of the map
* @param keyType the key data type
* @param valueType the value data type
* @return the transaction map
*/
public <K, V> TransactionMap<K, V> openMap(String name,
DataType keyType, DataType valueType) {
checkNotClosed();
MVMap<K, VersionedValue> map = store.openMap(name, keyType,
valueType);
int mapId = map.getId();
return new TransactionMap<>(this, map, mapId);
}
/**
* Open the transactional version of the given map.
*
* @param <K> the key type
* @param <V> the value type
* @param map the base map
* @return the transactional map
*/
public <K, V> TransactionMap<K, V> openMap(
MVMap<K, VersionedValue> map) {
checkNotClosed();
int mapId = map.getId();
return new TransactionMap<>(this, map, mapId);
}
/**
* Prepare the transaction. Afterwards, the transaction can only be
* committed or rolled back.
*/
public void prepare() {
checkNotClosed();
status = STATUS_PREPARED;
store.storeTransaction(this);
}
/**
* Commit the transaction. Afterwards, this transaction is closed.
*/
public void commit() {
checkNotClosed();
store.commit(this, logId);
}
/**
* Roll back to the given savepoint. This is only allowed if the
* transaction is open.
*
* @param savepointId the savepoint id
*/
public void rollbackToSavepoint(long savepointId) {
checkNotClosed();
store.rollbackTo(this, logId, savepointId);
logId = savepointId;
}
/**
* Roll the transaction back. Afterwards, this transaction is closed.
*/
public void rollback() {
checkNotClosed();
store.rollbackTo(this, logId, 0);
store.endTransaction(this, status);
}
/**
* Get the list of changes, starting with the latest change, up to the
* given savepoint (in reverse order than they occurred). The value of
* the change is the value before the change was applied.
*
* @param savepointId the savepoint id, 0 meaning the beginning of the
* transaction
* @return the changes
*/
public Iterator<TransactionStore.Change> getChanges(long savepointId) {
return store.getChanges(this, logId, savepointId);
}
/**
* Check whether this transaction is open or prepared.
*/
void checkNotClosed() {
if (status == STATUS_CLOSED) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_CLOSED, "Transaction is closed");
}
}
/**
* Remove the map.
*
* @param map the map
*/
public <K, V> void removeMap(TransactionMap<K, V> map) {
store.removeMap(map);
}
@Override
public String toString() {
return "" + transactionId;
}
}
/*
* Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
* and the EPL 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.mvstore.tx;
import org.h2.mvstore.DataUtils;
import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType;
import java.nio.ByteBuffer;
/**
* A versioned value (possibly null). It contains a pointer to the old
* value, and the value itself.
*/
public class VersionedValue {
/**
* The operation id.
*/
final long operationId;
/**
* The value.
*/
final Object value;
VersionedValue(long operationId, Object value) {
this.operationId = operationId;
this.value = value;
}
@Override
public String toString() {
return value + (operationId == 0 ? "" : (
" " +
TransactionStore.getTransactionId(operationId) + "/" +
TransactionStore.getLogId(operationId)));
}
/**
* The value type for a versioned value.
*/
public static class Type implements DataType {
private final DataType valueType;
public Type(DataType valueType) {
this.valueType = valueType;
}
@Override
public int getMemory(Object obj) {
VersionedValue v = (VersionedValue) obj;
return valueType.getMemory(v.value) + 8;
}
@Override
public int compare(Object aObj, Object bObj) {
if (aObj == bObj) {
return 0;
}
VersionedValue a = (VersionedValue) aObj;
VersionedValue b = (VersionedValue) bObj;
long comp = a.operationId - b.operationId;
if (comp == 0) {
return valueType.compare(a.value, b.value);
}
return Long.signum(comp);
}
@Override
public void read(ByteBuffer buff, Object[] obj, int len, boolean key) {
if (buff.get() == 0) {
// fast path (no op ids or null entries)
for (int i = 0; i < len; i++) {
obj[i] = new VersionedValue(0L, valueType.read(buff));
}
} else {
// slow path (some entries may be null)
for (int i = 0; i < len; i++) {
obj[i] = read(buff);
}
}
}
@Override
public Object read(ByteBuffer buff) {
long operationId = DataUtils.readVarLong(buff);
Object value;
if (buff.get() == 1) {
value = valueType.read(buff);
} else {
value = null;
}
return new VersionedValue(operationId, value);
}
@Override
public void write(WriteBuffer buff, Object[] obj, int len, boolean key) {
boolean fastPath = true;
for (int i = 0; i < len; i++) {
VersionedValue v = (VersionedValue) obj[i];
if (v.operationId != 0 || v.value == null) {
fastPath = false;
}
}
if (fastPath) {
buff.put((byte) 0);
for (int i = 0; i < len; i++) {
VersionedValue v = (VersionedValue) obj[i];
valueType.write(buff, v.value);
}
} else {
// slow path:
// store op ids, and some entries may be null
buff.put((byte) 1);
for (int i = 0; i < len; i++) {
write(buff, obj[i]);
}
}
}
@Override
public void write(WriteBuffer buff, Object obj) {
VersionedValue v = (VersionedValue) obj;
buff.putVarLong(v.operationId);
if (v.value == null) {
buff.put((byte) 0);
} else {
buff.put((byte) 1);
valueType.write(buff, v.value);
}
}
}
}
......@@ -43,7 +43,7 @@ import org.h2.mvstore.MVStore;
import org.h2.mvstore.MVStoreTool;
import org.h2.mvstore.StreamStore;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.mvstore.tx.TransactionStore.TransactionMap;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.mvstore.db.ValueDataType;
import org.h2.result.Row;
import org.h2.result.RowFactory;
......
......@@ -20,8 +20,8 @@ import org.h2.mvstore.MVMap;
import org.h2.mvstore.MVStore;
import org.h2.mvstore.tx.TransactionStore;
import org.h2.mvstore.tx.TransactionStore.Change;
import org.h2.mvstore.tx.TransactionStore.Transaction;
import org.h2.mvstore.tx.TransactionStore.TransactionMap;
import org.h2.mvstore.tx.Transaction;
import org.h2.mvstore.tx.TransactionMap;
import org.h2.mvstore.type.ObjectDataType;
import org.h2.store.fs.FileUtils;
import org.h2.test.TestBase;
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论