diff --git a/AerospikeClient/Async/AsyncClient.cs b/AerospikeClient/Async/AsyncClient.cs index e1647a5b..ce6e4db9 100644 --- a/AerospikeClient/Async/AsyncClient.cs +++ b/AerospikeClient/Async/AsyncClient.cs @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 Aerospike, Inc. + * Copyright 2012-2025 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements. @@ -183,8 +183,7 @@ public void Commit(CommitListener listener, Txn txn) break; case Txn.TxnState.ABORTED: - listener.OnSuccess(CommitStatus.CommitStatusType.ALREADY_ABORTED); - break; + throw new AerospikeException(ResultCode.TXN_ALREADY_ABORTED, "Transaction already aborted"); } } @@ -227,8 +226,7 @@ public void Abort(AbortListener listener, Txn txn) break; case Txn.TxnState.COMMITTED: - listener.OnSuccess(AbortStatus.AbortStatusType.ALREADY_COMMITTED); - break; + throw new AerospikeException(ResultCode.TXN_ALREADY_COMMITTED, "Transaction already committed"); case Txn.TxnState.ABORTED: listener.OnSuccess(AbortStatus.AbortStatusType.ALREADY_ABORTED); diff --git a/AerospikeClient/Main/AbortStatus.cs b/AerospikeClient/Main/AbortStatus.cs index 94f2dee2..41bbb4db 100644 --- a/AerospikeClient/Main/AbortStatus.cs +++ b/AerospikeClient/Main/AbortStatus.cs @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 Aerospike, Inc. + * Copyright 2012-2025 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements. @@ -25,7 +25,6 @@ public static class AbortStatus public enum AbortStatusType { OK, - ALREADY_COMMITTED, ALREADY_ABORTED, ROLL_BACK_ABANDONED, CLOSE_ABANDONED @@ -36,7 +35,6 @@ public static string AbortErrorToString(AbortStatusType status) return status switch { AbortStatusType.OK => "Abort succeeded.", - AbortStatusType.ALREADY_COMMITTED => "Already committed.", AbortStatusType.ALREADY_ABORTED => "Already aborted.", AbortStatusType.ROLL_BACK_ABANDONED => "MRT client roll back abandoned. Server will eventually abort the MRT.", AbortStatusType.CLOSE_ABANDONED => "MRT has been rolled back, but MRT client close was abandoned. Server will eventually close the MRT.", diff --git a/AerospikeClient/Main/AerospikeClient.cs b/AerospikeClient/Main/AerospikeClient.cs index a91de549..678b8201 100644 --- a/AerospikeClient/Main/AerospikeClient.cs +++ b/AerospikeClient/Main/AerospikeClient.cs @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 Aerospike, Inc. + * Copyright 2012-2025 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements. @@ -516,7 +516,7 @@ public CommitStatus.CommitStatusType Commit(Txn txn) return CommitStatus.CommitStatusType.ALREADY_COMMITTED; case Txn.TxnState.ABORTED: - return CommitStatus.CommitStatusType.ALREADY_ABORTED; + throw new AerospikeException(ResultCode.TXN_ALREADY_ABORTED, "Transaction already aborted"); } } @@ -540,8 +540,8 @@ public AbortStatus.AbortStatusType Abort(Txn txn) return tr.Abort(txnRollPolicyDefault); case Txn.TxnState.COMMITTED: - return AbortStatus.AbortStatusType.ALREADY_COMMITTED; - + throw new AerospikeException(ResultCode.TXN_ALREADY_COMMITTED, "Transaction already committed"); + case Txn.TxnState.ABORTED: return AbortStatus.AbortStatusType.ALREADY_ABORTED; } diff --git a/AerospikeClient/Main/CommitStatus.cs b/AerospikeClient/Main/CommitStatus.cs index 50c9a7d2..1386b303 100644 --- a/AerospikeClient/Main/CommitStatus.cs +++ b/AerospikeClient/Main/CommitStatus.cs @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 Aerospike, Inc. + * Copyright 2012-2025 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements. @@ -28,7 +28,6 @@ public enum CommitStatusType { OK, ALREADY_COMMITTED, - ALREADY_ABORTED, ROLL_FORWARD_ABANDONED, CLOSE_ABANDONED } @@ -39,7 +38,6 @@ public static string CommitErrorToString(CommitStatusType status) { CommitStatusType.OK => "Commit succeeded.", CommitStatusType.ALREADY_COMMITTED => "Already committed.", - CommitStatusType.ALREADY_ABORTED => "Already aborted.", CommitStatusType.ROLL_FORWARD_ABANDONED => "MRT client roll forward abandoned. Server will eventually commit the MRT.", CommitStatusType.CLOSE_ABANDONED => "MRT has been rolled forward, but MRT client close was abandoned. Server will eventually close the MRT.", _ => "Unexpected AbortStatusType." diff --git a/AerospikeClient/Main/ResultCode.cs b/AerospikeClient/Main/ResultCode.cs index 9e701fb6..65b6924e 100644 --- a/AerospikeClient/Main/ResultCode.cs +++ b/AerospikeClient/Main/ResultCode.cs @@ -1,5 +1,5 @@ /* - * Copyright 2012-2024 Aerospike, Inc. + * Copyright 2012-2025 Aerospike, Inc. * * Portions may be licensed to Aerospike, Inc. under one or more contributor * license agreements. @@ -22,7 +22,19 @@ namespace Aerospike.Client /// Database operation error codes. /// public sealed class ResultCode - { + { + /// + /// Multi-record transaction commit called, but the transaction was already aborted. + /// Value: -19 + /// + public const int TXN_ALREADY_ABORTED = -19; + + /// + /// Multi-record transaction abort called, but the transaction was already committed. + /// Value: -18 + /// + public const int TXN_ALREADY_COMMITTED = -18; + /// /// Multi-record transaction failed. /// Value: -17 @@ -592,7 +604,13 @@ public static bool KeepConnection(int resultCode) public static string GetResultString(int resultCode) { switch (resultCode) - { + { + case TXN_ALREADY_ABORTED: + return "Multi-record transaction already aborted"; + + case TXN_ALREADY_COMMITTED: + return "Multi-record transaction already committed"; + case TXN_FAILED: return "Multi-record transaction failed"; diff --git a/AerospikeTest/Async/TestAsyncTxn.cs b/AerospikeTest/Async/TestAsyncTxn.cs index 6d4fb21d..f29e35a2 100644 --- a/AerospikeTest/Async/TestAsyncTxn.cs +++ b/AerospikeTest/Async/TestAsyncTxn.cs @@ -357,7 +357,7 @@ public void AsyncTxnWriteCommitAbort() new Put(txn, key, "val2"), new Commit(txn), new GetExpect(null, key, "val2"), - new Abort(txn, AbortStatus.AbortStatusType.ALREADY_COMMITTED) + new Abort(txn, ResultCode.TXN_ALREADY_COMMITTED) }; Execute(cmds); @@ -578,6 +578,7 @@ public class Abort : Runner { private readonly Txn txn; private readonly AbortStatusType status; + private readonly int resultCode = 0; public Abort(Txn txn) { @@ -591,9 +592,22 @@ public Abort(Txn txn, AbortStatusType abortStatus) this.status = abortStatus; } + public Abort(Txn txn, int resultCode) + { + this.txn = txn; + this.resultCode = resultCode; + } + public void Run(TestAsyncTxn parent, Listener listener) { - client.Abort(new AbortHandler(listener, status), txn); + try + { + client.Abort(new AbortHandler(listener, status), txn); + } + catch (Exception e) + { + parent.OnError(e, resultCode); + } } private class AbortHandler : AbortListener diff --git a/AerospikeTest/Sync/Basic/TestTxn.cs b/AerospikeTest/Sync/Basic/TestTxn.cs index e02d3cb0..c9f625d1 100644 --- a/AerospikeTest/Sync/Basic/TestTxn.cs +++ b/AerospikeTest/Sync/Basic/TestTxn.cs @@ -498,8 +498,17 @@ public void TxnWriteCommitAbort() record = client.Get(null, key); AssertBinEqual(key, record, binName, "val2"); - var abortStatus = client.Abort(txn); - Assert.AreEqual(AbortStatus.AbortStatusType.ALREADY_COMMITTED, abortStatus); + try + { + var abortStatus = client.Abort(txn); + } + catch (AerospikeException ae) + { + if (ae.Result != ResultCode.TXN_ALREADY_COMMITTED) + { + throw; + } + } } [TestMethod]