com.aerospike.client.command.TxnRoll Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aerospike-client-jdk8 Show documentation
Show all versions of aerospike-client-jdk8 Show documentation
Aerospike Java client interface to Aerospike database server
The newest version!
/*
* Copyright 2012-2024 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.aerospike.client.command;
import com.aerospike.client.AbortStatus;
import com.aerospike.client.AerospikeException;
import com.aerospike.client.BatchRecord;
import com.aerospike.client.Key;
import com.aerospike.client.ResultCode;
import com.aerospike.client.Txn;
import com.aerospike.client.CommitError;
import com.aerospike.client.CommitStatus;
import com.aerospike.client.cluster.Cluster;
import com.aerospike.client.policy.BatchPolicy;
import com.aerospike.client.policy.WritePolicy;
import java.util.List;
import java.util.Map;
import java.util.Set;
public final class TxnRoll {
private final Cluster cluster;
private final Txn txn;
private BatchRecord[] verifyRecords;
private BatchRecord[] rollRecords;
public TxnRoll(Cluster cluster, Txn txn) {
this.cluster = cluster;
this.txn = txn;
}
public void verify(BatchPolicy verifyPolicy, BatchPolicy rollPolicy) {
try {
// Verify read versions in batch.
verifyRecordVersions(verifyPolicy);
}
catch (Throwable t) {
// Verify failed. Abort.
txn.setState(Txn.State.ABORTED);
try {
roll(rollPolicy, Command.INFO4_MRT_ROLL_BACK);
}
catch (Throwable t2) {
// Throw combination of verify and roll exceptions.
t.addSuppressed(t2);
throw createCommitException(CommitError.VERIFY_FAIL_ABORT_ABANDONED, t);
}
if (txn.monitorMightExist()) {
try {
WritePolicy writePolicy = new WritePolicy(rollPolicy);
Key txnKey = TxnMonitor.getTxnMonitorKey(txn);
close(writePolicy, txnKey);
}
catch (Throwable t3) {
// Throw combination of verify and close exceptions.
t.addSuppressed(t3);
throw createCommitException(CommitError.VERIFY_FAIL_CLOSE_ABANDONED, t);
}
}
// Throw original exception when abort succeeds.
throw createCommitException(CommitError.VERIFY_FAIL, t);
}
txn.setState(Txn.State.VERIFIED);
}
public CommitStatus commit(BatchPolicy rollPolicy) {
WritePolicy writePolicy = new WritePolicy(rollPolicy);
Key txnKey = TxnMonitor.getTxnMonitorKey(txn);
if (txn.monitorExists()) {
// Tell MRT monitor that a roll-forward will commence.
try {
markRollForward(writePolicy, txnKey);
}
catch (AerospikeException ae) {
AerospikeException.Commit aec = createCommitException(CommitError.MARK_ROLL_FORWARD_ABANDONED, ae);
if (ae.getResultCode() == ResultCode.MRT_ABORTED) {
aec.setInDoubt(false);
txn.setInDoubt(false);
txn.setState(Txn.State.ABORTED);
}
else if (txn.getInDoubt()) {
// The transaction was already inDoubt and just failed again,
// so the new exception should also be inDoubt.
aec.setInDoubt(true);
}
else if (ae.getInDoubt()){
// The current exception is inDoubt.
aec.setInDoubt(true);
txn.setInDoubt(true);
}
throw aec;
}
catch (Throwable t) {
AerospikeException.Commit aec = createCommitException(CommitError.MARK_ROLL_FORWARD_ABANDONED, t);
if (txn.getInDoubt()) {
aec.setInDoubt(true);
}
throw aec;
}
}
txn.setState(Txn.State.COMMITTED);
txn.setInDoubt(false);
// Roll-forward writes in batch.
try {
roll(rollPolicy, Command.INFO4_MRT_ROLL_FORWARD);
}
catch (Throwable t) {
return CommitStatus.ROLL_FORWARD_ABANDONED;
}
if (txn.monitorMightExist()) {
// Remove MRT monitor.
try {
close(writePolicy, txnKey);
}
catch (Throwable t) {
return CommitStatus.CLOSE_ABANDONED;
}
}
return CommitStatus.OK;
}
private AerospikeException.Commit createCommitException(CommitError error, Throwable cause) {
AerospikeException.Commit aec = new AerospikeException.Commit(error, verifyRecords, rollRecords, cause);
if (cause instanceof AerospikeException) {
AerospikeException src = (AerospikeException)cause;
aec.setNode(src.getNode());
aec.setPolicy(src.getPolicy());
aec.setIteration(src.getIteration());
aec.setInDoubt(src.getInDoubt());
}
return aec;
}
public AbortStatus abort(BatchPolicy rollPolicy) {
txn.setState(Txn.State.ABORTED);
try {
roll(rollPolicy, Command.INFO4_MRT_ROLL_BACK);
}
catch (Throwable t) {
return AbortStatus.ROLL_BACK_ABANDONED;
}
if (txn.monitorMightExist()) {
try {
WritePolicy writePolicy = new WritePolicy(rollPolicy);
Key txnKey = TxnMonitor.getTxnMonitorKey(txn);
close(writePolicy, txnKey);
}
catch (Throwable t) {
return AbortStatus.CLOSE_ABANDONED;
}
}
return AbortStatus.OK;
}
private void verifyRecordVersions(BatchPolicy verifyPolicy) {
// Validate record versions in a batch.
Set> reads = txn.getReads();
int max = reads.size();
if (max == 0) {
return;
}
BatchRecord[] records = new BatchRecord[max];
Key[] keys = new Key[max];
Long[] versions = new Long[max];
int count = 0;
for (Map.Entry entry : reads) {
Key key = entry.getKey();
keys[count] = key;
records[count] = new BatchRecord(key, false);
versions[count] = entry.getValue();
count++;
}
this.verifyRecords = records;
BatchStatus status = new BatchStatus(true);
List bns = BatchNodeList.generate(cluster, verifyPolicy, keys, records, false, status);
IBatchCommand[] commands = new IBatchCommand[bns.size()];
count = 0;
for (BatchNode bn : bns) {
if (bn.offsetsSize == 1) {
int i = bn.offsets[0];
commands[count++] = new BatchSingle.TxnVerify(
cluster, verifyPolicy, versions[i], records[i], status, bn.node);
}
else {
commands[count++] = new Batch.TxnVerify(
cluster, bn, verifyPolicy, keys, versions, records, status);
}
}
BatchExecutor.execute(cluster, verifyPolicy, commands, status);
if (!status.getStatus()) {
throw new RuntimeException("Failed to verify one or more record versions");
}
}
private void markRollForward(WritePolicy writePolicy, Key txnKey) {
// Tell MRT monitor that a roll-forward will commence.
TxnMarkRollForward cmd = new TxnMarkRollForward(cluster, writePolicy, txnKey);
cmd.execute();
}
private void roll(BatchPolicy rollPolicy, int txnAttr) {
Set keySet = txn.getWrites();
if (keySet.isEmpty()) {
return;
}
Key[] keys = keySet.toArray(new Key[keySet.size()]);
BatchRecord[] records = new BatchRecord[keys.length];
for (int i = 0; i < keys.length; i++) {
records[i] = new BatchRecord(keys[i], true);
}
this.rollRecords = records;
BatchAttr attr = new BatchAttr();
attr.setTxn(txnAttr);
BatchStatus status = new BatchStatus(true);
List bns = BatchNodeList.generate(cluster, rollPolicy, keys, records, true, status);
IBatchCommand[] commands = new IBatchCommand[bns.size()];
int count = 0;
for (BatchNode bn : bns) {
if (bn.offsetsSize == 1) {
int i = bn.offsets[0];
commands[count++] = new BatchSingle.TxnRoll(
cluster, rollPolicy, txn, records[i], status, bn.node, txnAttr);
}
else {
commands[count++] = new Batch.TxnRoll(
cluster, bn, rollPolicy, txn, keys, records, attr, status);
}
}
BatchExecutor.execute(cluster, rollPolicy, commands, status);
if (!status.getStatus()) {
String rollString = txnAttr == Command.INFO4_MRT_ROLL_FORWARD? "commit" : "abort";
throw new RuntimeException("Failed to " + rollString + " one or more records");
}
}
private void close(WritePolicy writePolicy, Key txnKey) {
// Delete MRT monitor on server.
TxnClose cmd = new TxnClose(cluster, txn, writePolicy, txnKey);
cmd.execute();
// Reset MRT on client.
txn.clear();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy