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

Merge pull request #1622 from h2database/vv-null

Reuse VersionedValue value for NULL, encapsulate "value" field
...@@ -34,7 +34,7 @@ import org.h2.mvstore.db.MVTable; ...@@ -34,7 +34,7 @@ import org.h2.mvstore.db.MVTable;
import org.h2.mvstore.db.MVTableEngine; import org.h2.mvstore.db.MVTableEngine;
import org.h2.mvstore.tx.Transaction; import org.h2.mvstore.tx.Transaction;
import org.h2.mvstore.tx.TransactionStore; import org.h2.mvstore.tx.TransactionStore;
import org.h2.mvstore.tx.VersionedValue; import org.h2.value.VersionedValue;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
...@@ -1830,7 +1830,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -1830,7 +1830,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
private static Row getRowFromVersionedValue(MVTable table, long recKey, private static Row getRowFromVersionedValue(MVTable table, long recKey,
VersionedValue versionedValue) { VersionedValue versionedValue) {
Object value = versionedValue == null ? null : versionedValue.value; Object value = versionedValue == null ? null : versionedValue.getCurrentValue();
if (value == null) { if (value == null) {
return null; return null;
} }
......
...@@ -28,7 +28,8 @@ import org.h2.mvstore.rtree.MVRTreeMap.RTreeCursor; ...@@ -28,7 +28,8 @@ import org.h2.mvstore.rtree.MVRTreeMap.RTreeCursor;
import org.h2.mvstore.rtree.SpatialKey; import org.h2.mvstore.rtree.SpatialKey;
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.mvstore.tx.VersionedValue; import org.h2.mvstore.tx.VersionedValueType;
import org.h2.value.VersionedValue;
import org.h2.result.Row; import org.h2.result.Row;
import org.h2.result.SearchRow; import org.h2.result.SearchRow;
import org.h2.result.SortOrder; import org.h2.result.SortOrder;
...@@ -98,7 +99,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex { ...@@ -98,7 +99,7 @@ public class MVSpatialIndex extends BaseIndex implements SpatialIndex, MVIndex {
} }
String mapName = "index." + getId(); String mapName = "index." + getId();
ValueDataType vt = new ValueDataType(db, null); ValueDataType vt = new ValueDataType(db, null);
VersionedValue.Type valueType = new VersionedValue.Type(vt); VersionedValueType valueType = new VersionedValueType(vt);
MVRTreeMap.Builder<VersionedValue> mapBuilder = MVRTreeMap.Builder<VersionedValue> mapBuilder =
new MVRTreeMap.Builder<VersionedValue>(). new MVRTreeMap.Builder<VersionedValue>().
valueType(valueType); valueType(valueType);
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.mvstore.tx; package org.h2.mvstore.tx;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.value.VersionedValue;
/** /**
* Class CommitDecisionMaker makes a decision during post-commit processing * Class CommitDecisionMaker makes a decision during post-commit processing
...@@ -36,7 +37,7 @@ final class CommitDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -36,7 +37,7 @@ final class CommitDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// see TxDecisionMaker.decide() // see TxDecisionMaker.decide()
decision = MVMap.Decision.ABORT; decision = MVMap.Decision.ABORT;
} else /* this is final undo log entry for this key */ if (existingValue.value == null) { } else /* this is final undo log entry for this key */ if (existingValue.getCurrentValue() == null) {
decision = MVMap.Decision.REMOVE; decision = MVMap.Decision.REMOVE;
} else { } else {
decision = MVMap.Decision.PUT; decision = MVMap.Decision.PUT;
...@@ -49,7 +50,7 @@ final class CommitDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -49,7 +50,7 @@ final class CommitDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
public VersionedValue selectValue(VersionedValue existingValue, VersionedValue providedValue) { public VersionedValue selectValue(VersionedValue existingValue, VersionedValue providedValue) {
assert decision == MVMap.Decision.PUT; assert decision == MVMap.Decision.PUT;
assert existingValue != null; assert existingValue != null;
return VersionedValue.getInstance(existingValue.value); return VersionedValueCommitted.getInstance(existingValue.getCurrentValue());
} }
@Override @Override
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.mvstore.tx; package org.h2.mvstore.tx;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.value.VersionedValue;
/** /**
* Class RollbackDecisionMaker process undo log record during transaction rollback. * Class RollbackDecisionMaker process undo log record during transaction rollback.
......
...@@ -9,6 +9,7 @@ import org.h2.mvstore.DataUtils; ...@@ -9,6 +9,7 @@ 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.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.value.VersionedValue;
import java.util.Iterator; import java.util.Iterator;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
......
...@@ -10,6 +10,7 @@ import org.h2.mvstore.DataUtils; ...@@ -10,6 +10,7 @@ import org.h2.mvstore.DataUtils;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.mvstore.Page; import org.h2.mvstore.Page;
import org.h2.mvstore.type.DataType; import org.h2.mvstore.type.DataType;
import org.h2.value.VersionedValue;
import java.util.AbstractMap; import java.util.AbstractMap;
import java.util.AbstractSet; import java.util.AbstractSet;
...@@ -146,7 +147,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -146,7 +147,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
int txId = TransactionStore.getTransactionId(operationId); int txId = TransactionStore.getTransactionId(operationId);
boolean isVisible = txId == transaction.transactionId || boolean isVisible = txId == transaction.transactionId ||
committingTransactions.get(txId); committingTransactions.get(txId);
Object v = isVisible ? currentValue.value : currentValue.getCommittedValue(); Object v = isVisible ? currentValue.getCurrentValue() : currentValue.getCommittedValue();
if (v == null) { if (v == null) {
--size; --size;
} }
...@@ -177,7 +178,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -177,7 +178,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
int txId = TransactionStore.getTransactionId(operationId); int txId = TransactionStore.getTransactionId(operationId);
boolean isVisible = txId == transaction.transactionId || boolean isVisible = txId == transaction.transactionId ||
committingTransactions.get(txId); committingTransactions.get(txId);
Object v = isVisible ? currentValue.value : currentValue.getCommittedValue(); Object v = isVisible ? currentValue.getCurrentValue() : currentValue.getCommittedValue();
if (v == null) { if (v == null) {
--size; --size;
} }
...@@ -264,10 +265,10 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -264,10 +265,10 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
*/ */
public V putCommitted(K key, V value) { public V putCommitted(K key, V value) {
DataUtils.checkArgument(value != null, "The value may not be null"); DataUtils.checkArgument(value != null, "The value may not be null");
VersionedValue newValue = VersionedValue.getInstance(value); VersionedValue newValue = VersionedValueCommitted.getInstance(value);
VersionedValue oldValue = map.put(key, newValue); VersionedValue oldValue = map.put(key, newValue);
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
V result = (V) (oldValue == null ? null : oldValue.value); V result = (V) (oldValue == null ? null : oldValue.getCurrentValue());
return result; return result;
} }
...@@ -300,7 +301,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -300,7 +301,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
transaction.blockingMap = null; transaction.blockingMap = null;
transaction.blockingKey = null; transaction.blockingKey = null;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
V res = result == null ? null : (V) result.value; V res = result == null ? null : (V) result.getCurrentValue();
return res; return res;
} }
decisionMaker.reset(); decisionMaker.reset();
...@@ -383,12 +384,12 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -383,12 +384,12 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
long id = data.getOperationId(); long id = data.getOperationId();
if (id == 0) { if (id == 0) {
// it is committed // it is committed
return (V)data.value; return (V)data.getCurrentValue();
} }
int tx = TransactionStore.getTransactionId(id); int tx = TransactionStore.getTransactionId(id);
if (tx == transaction.transactionId || transaction.store.committingTransactions.get().get(tx)) { if (tx == transaction.transactionId || transaction.store.committingTransactions.get().get(tx)) {
// added by this transaction or another transaction which is committed by now // added by this transaction or another transaction which is committed by now
return (V)data.value; return (V) data.getCurrentValue();
} else { } else {
return (V) data.getCommittedValue(); return (V) data.getCommittedValue();
} }
...@@ -657,7 +658,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -657,7 +658,7 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected Map.Entry<K, V> registerCurrent(K key, VersionedValue data) { protected Map.Entry<K, V> registerCurrent(K key, VersionedValue data) {
return new AbstractMap.SimpleImmutableEntry<>(key, (V) data.value); return new AbstractMap.SimpleImmutableEntry<>(key, (V) data.getCurrentValue());
} }
} }
...@@ -712,12 +713,12 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> { ...@@ -712,12 +713,12 @@ public class TransactionMap<K, V> extends AbstractMap<K, V> {
// current value comes from another uncommitted transaction // current value comes from another uncommitted transaction
// take committed value instead // take committed value instead
Object committedValue = data.getCommittedValue(); Object committedValue = data.getCommittedValue();
data = committedValue == null ? null : VersionedValue.getInstance(committedValue); data = committedValue == null ? null : VersionedValueCommitted.getInstance(committedValue);
} }
} }
} }
} }
if (data != null && (data.value != null || if (data != null && (data.getCurrentValue() != null ||
includeAllUncommitted && transactionId != includeAllUncommitted && transactionId !=
TransactionStore.getTransactionId(data.getOperationId()))) { TransactionStore.getTransactionId(data.getOperationId()))) {
current = registerCurrent(key, data); current = registerCurrent(key, data);
......
...@@ -20,6 +20,7 @@ import org.h2.mvstore.WriteBuffer; ...@@ -20,6 +20,7 @@ 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;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.VersionedValue;
/** /**
* A store that supports concurrent MVCC read-committed transactions. * A store that supports concurrent MVCC read-committed transactions.
...@@ -128,14 +129,14 @@ public class TransactionStore { ...@@ -128,14 +129,14 @@ public class TransactionStore {
this.timeoutMillis = timeoutMillis; this.timeoutMillis = timeoutMillis;
preparedTransactions = store.openMap("openTransactions", preparedTransactions = store.openMap("openTransactions",
new MVMap.Builder<Integer, Object[]>()); new MVMap.Builder<Integer, Object[]>());
DataType oldValueType = new VersionedValue.Type(dataType); DataType oldValueType = new VersionedValueType(dataType);
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[]>() undoLogBuilder = new MVMap.Builder<Long, Object[]>()
.singleWriter() .singleWriter()
.valueType(undoLogValueType); .valueType(undoLogValueType);
DataType vt = new VersionedValue.Type(dataType); DataType vt = new VersionedValueType(dataType);
mapBuilder = new MVMap.Builder<Object, VersionedValue>() mapBuilder = new MVMap.Builder<Object, VersionedValue>()
.keyType(dataType).valueType(vt); .keyType(dataType).valueType(vt);
} }
...@@ -494,7 +495,7 @@ public class TransactionStore { ...@@ -494,7 +495,7 @@ public class TransactionStore {
if (valueType == null) { if (valueType == null) {
valueType = new ObjectDataType(); valueType = new ObjectDataType();
} }
VersionedValue.Type vt = new VersionedValue.Type(valueType); VersionedValueType vt = new VersionedValueType(valueType);
MVMap<K, VersionedValue> map; MVMap<K, VersionedValue> map;
MVMap.Builder<K, VersionedValue> builder = MVMap.Builder<K, VersionedValue> builder =
new MVMap.Builder<K, VersionedValue>(). new MVMap.Builder<K, VersionedValue>().
...@@ -640,7 +641,7 @@ public class TransactionStore { ...@@ -640,7 +641,7 @@ public class TransactionStore {
MVMap<Object, VersionedValue> m = openMap(mapId); MVMap<Object, VersionedValue> m = openMap(mapId);
if (m != null) { // could be null if map was removed later on if (m != null) { // could be null if map was removed later on
VersionedValue oldValue = (VersionedValue) op[2]; VersionedValue oldValue = (VersionedValue) op[2];
current = new Change(m.getName(), op[1], oldValue == null ? null : oldValue.value); current = new Change(m.getName(), op[1], oldValue == null ? null : oldValue.getCurrentValue());
return; return;
} }
} }
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.mvstore.tx; package org.h2.mvstore.tx;
import org.h2.mvstore.MVMap; import org.h2.mvstore.MVMap;
import org.h2.value.VersionedValue;
/** /**
* Class TxDecisionMaker. * Class TxDecisionMaker.
...@@ -47,7 +48,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -47,7 +48,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// We assume that we are looking at the final value for this transaction, // We assume that we are looking at the final value for this transaction,
// and if it's not the case, then it will fail later, // and if it's not the case, then it will fail later,
// because a tree root has definitely been changed. // because a tree root has definitely been changed.
logIt(existingValue.value == null ? null : VersionedValue.getInstance(existingValue.value)); logIt(existingValue.getCurrentValue() == null ? null : VersionedValueCommitted.getInstance(existingValue.getCurrentValue()));
decision = MVMap.Decision.PUT; decision = MVMap.Decision.PUT;
} else if (getBlockingTransaction() != null) { } else if (getBlockingTransaction() != null) {
// this entry comes from a different transaction, and this // this entry comes from a different transaction, and this
...@@ -63,7 +64,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -63,7 +64,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
// was written but not undo log), and will effectively roll it back // was written but not undo log), and will effectively roll it back
// (just assume committed value and overwrite). // (just assume committed value and overwrite).
Object committedValue = existingValue.getCommittedValue(); Object committedValue = existingValue.getCommittedValue();
logIt(committedValue == null ? null : VersionedValue.getInstance(committedValue)); logIt(committedValue == null ? null : VersionedValueCommitted.getInstance(committedValue));
decision = MVMap.Decision.PUT; decision = MVMap.Decision.PUT;
} else { } else {
// transaction has been committed/rolled back and is closed by now, so // transaction has been committed/rolled back and is closed by now, so
...@@ -138,7 +139,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -138,7 +139,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public final VersionedValue selectValue(VersionedValue existingValue, VersionedValue providedValue) { public final VersionedValue selectValue(VersionedValue existingValue, VersionedValue providedValue) {
return VersionedValue.getInstance(undoKey, value, return VersionedValueUncommitted.getInstance(undoKey, value,
existingValue == null ? null : existingValue.getCommittedValue()); existingValue == null ? null : existingValue.getCommittedValue());
} }
} }
...@@ -163,7 +164,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -163,7 +164,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
if (id == 0 // entry is a committed one if (id == 0 // entry is a committed one
// or it came from the same transaction // or it came from the same transaction
|| isThisTransaction(blockingId = TransactionStore.getTransactionId(id))) { || isThisTransaction(blockingId = TransactionStore.getTransactionId(id))) {
if(existingValue.value != null) { if(existingValue.getCurrentValue() != null) {
return setDecision(MVMap.Decision.ABORT); return setDecision(MVMap.Decision.ABORT);
} }
logIt(existingValue); logIt(existingValue);
...@@ -171,7 +172,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -171,7 +172,7 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
} else if (isCommitted(blockingId)) { } else if (isCommitted(blockingId)) {
// entry belongs to a committing transaction // entry belongs to a committing transaction
// and therefore will be committed soon // and therefore will be committed soon
if(existingValue.value != null) { if(existingValue.getCurrentValue() != null) {
return setDecision(MVMap.Decision.ABORT); return setDecision(MVMap.Decision.ABORT);
} }
logIt(null); logIt(null);
...@@ -228,8 +229,8 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> { ...@@ -228,8 +229,8 @@ abstract class TxDecisionMaker extends MVMap.DecisionMaker<VersionedValue> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public VersionedValue selectValue(VersionedValue existingValue, VersionedValue providedValue) { public VersionedValue selectValue(VersionedValue existingValue, VersionedValue providedValue) {
return VersionedValue.getInstance(undoKey, return VersionedValueUncommitted.getInstance(undoKey,
existingValue == null ? null : existingValue.value, existingValue == null ? null : existingValue.getCurrentValue(),
existingValue == null ? null : existingValue.getCommittedValue()); existingValue == null ? null : existingValue.getCommittedValue());
} }
} }
......
/*
* 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.engine.Constants;
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 current value and latest committed value if current one is uncommitted.
* Also for uncommitted values it contains operationId - a combination of
* transactionId and logId.
*/
public class VersionedValue {
public static final VersionedValue DUMMY = new VersionedValue(new Object());
/**
* The current value.
*/
public final Object value;
static VersionedValue getInstance(Object value) {
assert value != null;
return new VersionedValue(value);
}
public static VersionedValue getInstance(long operationId, Object value, Object committedValue) {
return new Uncommitted(operationId, value, committedValue);
}
VersionedValue(Object value) {
this.value = value;
}
public boolean isCommitted() {
return true;
}
public long getOperationId() {
return 0L;
}
public Object getCommittedValue() {
return value;
}
@Override
public String toString() {
return String.valueOf(value);
}
private static class Uncommitted extends VersionedValue
{
private final long operationId;
private final Object committedValue;
Uncommitted(long operationId, Object value, Object committedValue) {
super(value);
assert operationId != 0;
this.operationId = operationId;
this.committedValue = committedValue;
}
@Override
public boolean isCommitted() {
return false;
}
@Override
public long getOperationId() {
return operationId;
}
@Override
public Object getCommittedValue() {
return committedValue;
}
@Override
public String toString() {
return super.toString() +
" " + TransactionStore.getTransactionId(operationId) + "/" +
TransactionStore.getLogId(operationId) + " " + committedValue;
}
}
/**
* 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) {
if(obj == null) return 0;
VersionedValue v = (VersionedValue) obj;
int res = Constants.MEMORY_OBJECT + 8 + 2 * Constants.MEMORY_POINTER +
getValMemory(v.value);
if (v.getOperationId() != 0) {
res += getValMemory(v.getCommittedValue());
}
return res;
}
private int getValMemory(Object obj) {
return obj == null ? 0 : valueType.getMemory(obj);
}
@Override
public int compare(Object aObj, Object bObj) {
if (aObj == bObj) {
return 0;
} else if (aObj == null) {
return -1;
} else if (bObj == null) {
return 1;
}
VersionedValue a = (VersionedValue) aObj;
VersionedValue b = (VersionedValue) bObj;
long comp = a.getOperationId() - b.getOperationId();
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(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);
if (operationId == 0) {
return new VersionedValue(valueType.read(buff));
} else {
byte flags = buff.get();
Object value = (flags & 1) != 0 ? valueType.read(buff) : null;
Object committedValue = (flags & 2) != 0 ? valueType.read(buff) : null;
return new Uncommitted(operationId, value, committedValue);
}
}
@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.getOperationId() != 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;
long operationId = v.getOperationId();
buff.putVarLong(operationId);
if (operationId == 0) {
valueType.write(buff, v.value);
} else {
Object committedValue = v.getCommittedValue();
int flags = (v.value == null ? 0 : 1) | (committedValue == null ? 0 : 2);
buff.put((byte) flags);
if (v.value != null) {
valueType.write(buff, v.value);
}
if (committedValue != null) {
valueType.write(buff, committedValue);
}
}
}
}
}
/*
* 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.value.VersionedValue;
/**
* Class CommittedVersionedValue.
*
* @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/
class VersionedValueCommitted extends VersionedValue {
/**
* The current value.
*/
public final Object value;
VersionedValueCommitted(Object value) {
this.value = value;
}
static VersionedValue getInstance(Object value) {
assert value != null;
return value instanceof VersionedValue ? (VersionedValue) value : new VersionedValueCommitted(value);
}
public Object getCurrentValue() {
return value;
}
public Object getCommittedValue() {
return value;
}
@Override
public String toString() {
return String.valueOf(value);
}
}
/*
* 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.engine.Constants;
import org.h2.mvstore.DataUtils;
import org.h2.mvstore.WriteBuffer;
import org.h2.mvstore.type.DataType;
import org.h2.value.VersionedValue;
import java.nio.ByteBuffer;
/**
* The value type for a versioned value.
*/
public class VersionedValueType implements DataType {
private final DataType valueType;
public VersionedValueType(DataType valueType) {
this.valueType = valueType;
}
@Override
public int getMemory(Object obj) {
if(obj == null) return 0;
VersionedValue v = (VersionedValue) obj;
int res = Constants.MEMORY_OBJECT + 8 + 2 * Constants.MEMORY_POINTER +
getValMemory(v.getCurrentValue());
if (v.getOperationId() != 0) {
res += getValMemory(v.getCommittedValue());
}
return res;
}
private int getValMemory(Object obj) {
return obj == null ? 0 : valueType.getMemory(obj);
}
@Override
public int compare(Object aObj, Object bObj) {
if (aObj == bObj) {
return 0;
} else if (aObj == null) {
return -1;
} else if (bObj == null) {
return 1;
}
VersionedValue a = (VersionedValue) aObj;
VersionedValue b = (VersionedValue) bObj;
long comp = a.getOperationId() - b.getOperationId();
if (comp == 0) {
return valueType.compare(a.getCurrentValue(), b.getCurrentValue());
}
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] = VersionedValueCommitted.getInstance(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);
if (operationId == 0) {
return VersionedValueCommitted.getInstance(valueType.read(buff));
} else {
byte flags = buff.get();
Object value = (flags & 1) != 0 ? valueType.read(buff) : null;
Object committedValue = (flags & 2) != 0 ? valueType.read(buff) : null;
return VersionedValueUncommitted.getInstance(operationId, value, committedValue);
}
}
@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.getOperationId() != 0 || v.getCurrentValue() == 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.getCurrentValue());
}
} 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;
long operationId = v.getOperationId();
buff.putVarLong(operationId);
if (operationId == 0) {
valueType.write(buff, v.getCurrentValue());
} else {
Object committedValue = v.getCommittedValue();
int flags = (v.getCurrentValue() == null ? 0 : 1) | (committedValue == null ? 0 : 2);
buff.put((byte) flags);
if (v.getCurrentValue() != null) {
valueType.write(buff, v.getCurrentValue());
}
if (committedValue != null) {
valueType.write(buff, committedValue);
}
}
}
}
/*
* 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.value.VersionedValue;
/**
* Class VersionedValueUncommitted.
*
* @author <a href='mailto:andrei.tokar@gmail.com'>Andrei Tokar</a>
*/
class VersionedValueUncommitted extends VersionedValueCommitted {
private final long operationId;
private final Object committedValue;
private VersionedValueUncommitted(long operationId, Object value, Object committedValue) {
super(value);
assert operationId != 0;
this.operationId = operationId;
this.committedValue = committedValue;
}
static VersionedValue getInstance(long operationId, Object value, Object committedValue) {
return new VersionedValueUncommitted(operationId, value, committedValue);
}
@Override
public boolean isCommitted() {
return false;
}
@Override
public long getOperationId() {
return operationId;
}
@Override
public Object getCommittedValue() {
return committedValue;
}
@Override
public String toString() {
return super.toString() +
" " + TransactionStore.getTransactionId(operationId) + "/" +
TransactionStore.getLogId(operationId) + " " + committedValue;
}
}
...@@ -40,7 +40,7 @@ import org.h2.util.StringUtils; ...@@ -40,7 +40,7 @@ import org.h2.util.StringUtils;
* @author Noel Grandin * @author Noel Grandin
* @author Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888 * @author Nicolas Fortin, Atelier SIG, IRSTV FR CNRS 24888
*/ */
public abstract class Value { public abstract class Value extends VersionedValue {
/** /**
* The data type is unknown at this time. * The data type is unknown at this time.
......
/*
* 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.value;
/**
* A versioned value (possibly null).
* It contains current value and latest committed value if current one is uncommitted.
* Also for uncommitted values it contains operationId - a combination of
* transactionId and logId.
*/
public class VersionedValue {
public static final VersionedValue DUMMY = new VersionedValue();
protected VersionedValue() {}
public boolean isCommitted() {
return true;
}
public long getOperationId() {
return 0L;
}
public Object getCurrentValue() {
return this;
}
public Object getCommittedValue() {
return this;
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论