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;
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) {
for (int i = 0; i < len; i++) {
obj[i] = VersionedValueCommitted.getInstance(valueType.read(buff));
}
} else {
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 {
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);
}
}
}
}