oracle.kv.Version Maven / Gradle / Ivy
Show all versions of oracle-nosql-server Show documentation
/*-
* Copyright (C) 2011, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This file was distributed by Oracle as part of a version of Oracle NoSQL
* Database made available at:
*
* http://www.oracle.com/technetwork/database/database-technologies/nosqldb/downloads/index.html
*
* Please see the LICENSE file included in the top-level directory of the
* appropriate version of Oracle NoSQL Database for a copy of the license and
* additional information.
*/
package oracle.kv;
import static oracle.kv.impl.util.ObjectUtil.checkNull;
import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.nio.ByteBuffer;
import java.util.UUID;
import oracle.kv.impl.topo.RepNodeId;
import oracle.kv.impl.topo.ResourceId;
import oracle.kv.impl.util.FastExternalizable;
import oracle.kv.impl.util.SerialVersion;
import com.sleepycat.je.utilint.DbLsn;
import com.sleepycat.je.utilint.VLSN;
/**
* A Version refers to a specific version of a key-value pair.
*
* When a key-value pair is initially inserted in the KV Store, and each time
* it is updated, it is assigned a unique version token. The version is always
* returned by the put method, for example, {@link KVStore#put put}, and is
* also returned by get methods, for example, {@link KVStore#get get}. The
* version is important for two reasons:
*
* -
* When an update or delete is to be performed, it may be important to only
* perform the update or delete if the last known value has not changed. For
* example, if an integer field in a previously known value is to be
* incremented, it is important that the previous value has not changed in
* the KV Store since it was obtained by the client. This can be guaranteed
* by passing the version of the previously known value to the {@link
* KVStore#putIfVersion putIfVersion} or {@link KVStore#deleteIfVersion
* deleteIfVersion} method. If the version specified does not match the
* current version of the value in the KV Store, these methods will not
* perform the update or delete operation and will return an indication of
* failure. Optionally, they will also return the current version and/or
* value so the client can retry the operation or take a different action.
*
* -
* When a client reads a value that was previously written, it may be
* important to ensure that the KV Store node servicing the read operation
* has been updated with the information previously written. This can be
* accomplished by passing the version of the previously written value as
* a {@link Consistency} parameter to the read operation, for example, {@link
* KVStore#get get}. See {@link Consistency.Version} for more information.
*
*
*
* It is important to be aware that the system may infrequently assign a new
* Version to a key-value pair, for example, when migrating data for better
* resource usage. Therefore, when using the {@link KVStore#putIfVersion
* putIfVersion} or {@link KVStore#deleteIfVersion deleteIfVersion} methods,
* one cannot assume that the Version will remain constant until it is changed
* by the application.
*
*
* @hiddensee {@link #writeFastExternal FastExternalizable format}
*/
public class Version implements FastExternalizable, Serializable {
private static final long serialVersionUID = 1;
final static short MAGIC = (short)0x04db;
/*
* The UUID associated with the replicated environment.
*/
private final UUID repGroupUuid;
private final long repGroupVlsn;
private final RepNodeId repNodeId;
private final long repNodeLsn;
/**
* For internal use only.
* @hidden
*
* Creates a Version with a logical VLSN but without a physical LSN.
*/
public Version(UUID repGroupUuid, long repGroupVlsn) {
this(repGroupUuid, repGroupVlsn, null, 0);
}
/**
* For internal use only.
* @hidden
*
* Creates a Version with a logical VLSN and physical LSN.
*/
public Version(UUID repGroupUuid,
long repGroupVlsn,
RepNodeId repNodeId,
long repNodeLsn) {
this.repGroupUuid = repGroupUuid;
this.repGroupVlsn = repGroupVlsn;
this.repNodeId = repNodeId;
this.repNodeLsn = repNodeLsn;
checkValidFields();
}
private void checkValidFields() {
checkNull("repGroupUuid", repGroupUuid);
if (repGroupVlsn <= 0) {
throw new IllegalArgumentException(
"The repGroupVLSN must be greater than 0, found: " +
repGroupVlsn);
}
}
/**
* Writes this object to the output stream. Format:
*
* - ({@link DataOutput#writeLong long}) {@link #getRepGroupUUID
* repGroupUuid} // most significant bytes
*
- ({@link DataOutput#writeLong long}) {@link #getRepGroupUUID
* repGroupUuid} // least significant bytes
*
- ({@link DataOutput#writeLong long}) {@link #getVLSN repGroupVlsn}
*
- ({@link DataOutput#writeBoolean boolean}) whether repNodeId and
* repNodeLsn are present
*
- [Optional] ({@link RepNodeId}) {@code repNodeId}
*
- [Optional] ({@link DataOutput#writeLong long}) {@code
* repNodeLsn}
*
*
* @hidden For internal use only
*/
@Override
public void writeFastExternal(DataOutput out, short serialVersion)
throws IOException {
out.writeLong(repGroupUuid.getMostSignificantBits());
out.writeLong(repGroupUuid.getLeastSignificantBits());
out.writeLong(repGroupVlsn);
if (repNodeId == null) {
out.writeBoolean(false);
} else {
out.writeBoolean(true);
repNodeId.writeFastExternal(out, serialVersion);
out.writeLong(repNodeLsn);
}
}
/**
* Returns this Version as a serialized byte array, such that {@link
* #fromByteArray} may be used to reconstitute the Version. Values
* returned by calls to this method can be used with current and newer
* releases, but are not guaranteed to be compatible with earlier releases.
*/
public byte[] toByteArray() {
/*
* This format is compatible with that created by ObjectOutputStream.
* The array has 2 components, the header information required by
* ObjectOutputStream and the actual payload.
*
* The total size is 33 or 50 bytes, depending on repNodeId. The
* first 6 bytes is the ObjectOutputStream header and the remaining
* bytes are the serialized Version.
*/
final int headerSize = 6;
/* totalSize - headerSize */
final byte payloadSize = (repNodeId == null ? (byte)27 : (byte)44);
ByteBuffer bb = ByteBuffer.allocate(headerSize + payloadSize);
bb.putShort(ObjectOutputStream.STREAM_MAGIC);
bb.putShort(ObjectOutputStream.STREAM_VERSION);
bb.put(ObjectOutputStream.TC_BLOCKDATA);
/* remaining length */
bb.put(payloadSize);
bb.putShort(SerialVersion.CURRENT);
bb.putLong(repGroupUuid.getMostSignificantBits());
bb.putLong(repGroupUuid.getLeastSignificantBits());
bb.putLong(repGroupVlsn);
if (repNodeId == null) {
bb.put((byte)0);
} else {
bb.put((byte)1);
bb.put((byte)(repNodeId.getType().ordinal()));
bb.putInt(repNodeId.getGroupId());
bb.putInt(repNodeId.getNodeNum());
bb.putLong(repNodeLsn);
}
return bb.array();
}
/**
* Deserializes the given bytes that were returned earlier by {@link
* #toByteArray} and returns the resulting Version. Values created with
* either the current or earlier releases can be used with this method, but
* values created by later releases are not guaranteed to be compatible.
*/
public static Version fromByteArray(byte[] keyBytes) {
final ByteArrayInputStream bais = new ByteArrayInputStream(keyBytes);
try {
final ObjectInputStream ois = new ObjectInputStream(bais);
final short serialVersion = ois.readShort();
return createVersion(ois, serialVersion);
} catch (IOException e) {
/* Should never happen. */
throw new FaultException(e, false /*isRemote*/);
}
}
/**
* For internal use only.
* @hidden
*/
public UUID getRepGroupUUID() {
return repGroupUuid;
}
/**
* For internal use only.
* @hidden
*/
public RepNodeId getRepNodeId() {
return repNodeId;
}
/**
* For internal use only.
* @hidden
*/
public long getVLSN() {
return repGroupVlsn;
}
/**
* This method is hidden and deprecated, and should not be used. It will
* probably be removed entirely in a future release.
*
* This method returns the VLSN associated with a version, which only
* identifies the version relative to a particular shard. If applications
* need a way to compare versions to determine which one is newer, we could
* provide a method that compares VLSNs but throws IllegalArgumentException
* if the shards differ. [#23526]
*
* @hidden
* @deprecated
*/
@Deprecated
public long getVersion() {
return repGroupVlsn;
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Version)) {
return false;
}
final Version o = (Version) other;
return repGroupVlsn == o.repGroupVlsn &&
repGroupUuid.equals(o.repGroupUuid);
}
@Override
public int hashCode() {
return repGroupUuid.hashCode() + (int) repGroupVlsn;
}
@Override
public String toString() {
return "