You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by pt...@apache.org on 2023/03/09 18:04:21 UTC
[ignite-3] branch main updated: IGNITE-18513 .NET: Ignore commit/rollback on completed tx (#1769)
This is an automated email from the ASF dual-hosted git repository.
ptupitsyn pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 5d05ac362a IGNITE-18513 .NET: Ignore commit/rollback on completed tx (#1769)
5d05ac362a is described below
commit 5d05ac362a746f996b19f36e8ee108febbf338b5
Author: Pavel Tupitsyn <pt...@apache.org>
AuthorDate: Thu Mar 9 21:04:15 2023 +0300
IGNITE-18513 .NET: Ignore commit/rollback on completed tx (#1769)
* Do not throw exception on `Commit` & `Rollback` when transaction is already completed (committed or rolled back).
* Add `TroString` override.
---
.../Transactions/TransactionsTests.cs | 36 ++++++++---
.../Internal/Transactions/Transaction.cs | 71 ++++++++--------------
2 files changed, 53 insertions(+), 54 deletions(-)
diff --git a/modules/platforms/dotnet/Apache.Ignite.Tests/Transactions/TransactionsTests.cs b/modules/platforms/dotnet/Apache.Ignite.Tests/Transactions/TransactionsTests.cs
index c7a0c3a699..ac85e20f77 100644
--- a/modules/platforms/dotnet/Apache.Ignite.Tests/Transactions/TransactionsTests.cs
+++ b/modules/platforms/dotnet/Apache.Ignite.Tests/Transactions/TransactionsTests.cs
@@ -19,6 +19,7 @@ namespace Apache.Ignite.Tests.Transactions
{
using System;
using System.Linq;
+ using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Transactions;
using Ignite.Transactions;
@@ -119,23 +120,23 @@ namespace Apache.Ignite.Tests.Transactions
}
[Test]
- public async Task TestCommitRollbackSameTxThrows()
+ public async Task TestCommitAfterRollbackIsIgnored()
{
await using var tx = await Client.Transactions.BeginAsync();
await tx.CommitAsync();
+ await tx.RollbackAsync();
- var ex = Assert.ThrowsAsync<TransactionException>(async () => await tx.RollbackAsync());
- Assert.AreEqual("Transaction is already committed.", ex?.Message);
+ StringAssert.Contains("State = Committed", tx.ToString());
}
[Test]
- public async Task TestRollbackCommitSameTxThrows()
+ public async Task TestRollbackAfterCommitIsIgnored()
{
await using var tx = await Client.Transactions.BeginAsync();
await tx.RollbackAsync();
+ await tx.CommitAsync();
- var ex = Assert.ThrowsAsync<TransactionException>(async () => await tx.CommitAsync());
- Assert.AreEqual("Transaction is already rolled back.", ex?.Message);
+ StringAssert.Contains("State = RolledBack", tx.ToString());
}
[Test]
@@ -145,9 +146,9 @@ namespace Apache.Ignite.Tests.Transactions
await tx.DisposeAsync();
await tx.DisposeAsync();
+ await tx.CommitAsync();
- var ex = Assert.ThrowsAsync<TransactionException>(async () => await tx.CommitAsync());
- Assert.AreEqual("Transaction is already rolled back.", ex?.Message);
+ StringAssert.Contains("State = RolledBack", tx.ToString());
}
[Test]
@@ -250,6 +251,7 @@ namespace Apache.Ignite.Tests.Transactions
await using var tx = await Client.Transactions.BeginAsync(new TransactionOptions { ReadOnly = true });
Assert.IsTrue(tx.IsReadOnly);
+ StringAssert.Contains("State = Open, IsReadOnly = True", tx.ToString());
}
[Test]
@@ -258,6 +260,24 @@ namespace Apache.Ignite.Tests.Transactions
await using var tx = await Client.Transactions.BeginAsync();
Assert.IsFalse(tx.IsReadOnly);
+ StringAssert.Contains("State = Open, IsReadOnly = False", tx.ToString());
+ }
+
+ [Test]
+ public async Task TestToString()
+ {
+ await using var tx1 = await Client.Transactions.BeginAsync();
+ await using var tx2 = await Client.Transactions.BeginAsync(new(ReadOnly: true));
+ await using var tx3 = await Client.Transactions.BeginAsync();
+
+ await tx2.RollbackAsync();
+ await tx3.CommitAsync();
+
+ var id = int.Parse(Regex.Match(tx1.ToString()!, @"\d+").Value);
+
+ Assert.AreEqual($"Transaction {{ Id = {id}, State = Open, IsReadOnly = False }}", tx1.ToString());
+ Assert.AreEqual($"Transaction {{ Id = {id + 1}, State = RolledBack, IsReadOnly = True }}", tx2.ToString());
+ Assert.AreEqual($"Transaction {{ Id = {id + 2}, State = Committed, IsReadOnly = False }}", tx3.ToString());
}
private class CustomTx : ITransaction
diff --git a/modules/platforms/dotnet/Apache.Ignite/Internal/Transactions/Transaction.cs b/modules/platforms/dotnet/Apache.Ignite/Internal/Transactions/Transaction.cs
index 312d149392..1a9676002f 100644
--- a/modules/platforms/dotnet/Apache.Ignite/Internal/Transactions/Transaction.cs
+++ b/modules/platforms/dotnet/Apache.Ignite/Internal/Transactions/Transaction.cs
@@ -19,7 +19,6 @@ namespace Apache.Ignite.Internal.Transactions
{
using System.Threading;
using System.Threading.Tasks;
- using System.Transactions;
using Ignite.Transactions;
using Proto;
using Proto.MsgPack;
@@ -77,41 +76,46 @@ namespace Apache.Ignite.Internal.Transactions
/// <inheritdoc/>
public async Task CommitAsync()
{
- SetState(StateCommitted);
-
- using var writer = ProtoCommon.GetMessageWriter();
- Write(writer.MessageWriter);
+ if (TrySetState(StateCommitted))
+ {
+ using var writer = ProtoCommon.GetMessageWriter();
+ Write(writer.MessageWriter);
- await Socket.DoOutInOpAsync(ClientOp.TxCommit, writer).ConfigureAwait(false);
+ await Socket.DoOutInOpAsync(ClientOp.TxCommit, writer).ConfigureAwait(false);
+ }
}
/// <inheritdoc/>
- public async Task RollbackAsync()
- {
- SetState(StateRolledBack);
+ public async Task RollbackAsync() => await RollbackAsyncInternal().ConfigureAwait(false);
- await RollbackAsyncInternal().ConfigureAwait(false);
- }
+ /// <inheritdoc/>
+ public async ValueTask DisposeAsync() => await RollbackAsyncInternal().ConfigureAwait(false);
/// <inheritdoc/>
- public async ValueTask DisposeAsync()
+ public override string ToString()
{
- // Roll back if the transaction is still open, otherwise do nothing.
- if (TrySetState(StateRolledBack))
+ var state = _state switch
{
- await RollbackAsyncInternal().ConfigureAwait(false);
- }
+ StateOpen => "Open",
+ StateCommitted => "Committed",
+ _ => "RolledBack"
+ };
+
+ return $"Transaction {{ Id = {Id}, State = {state}, IsReadOnly = {IsReadOnly} }}";
}
/// <summary>
/// Rolls back the transaction without state check.
/// </summary>
- private async Task RollbackAsyncInternal()
+ private async ValueTask RollbackAsyncInternal()
{
- using var writer = ProtoCommon.GetMessageWriter();
- Write(writer.MessageWriter);
+ if (TrySetState(StateRolledBack))
+ {
+ using var writer = ProtoCommon.GetMessageWriter();
+ Write(writer.MessageWriter);
- await Socket.DoOutInOpAsync(ClientOp.TxRollback, writer).ConfigureAwait(false);
+ await Socket.DoOutInOpAsync(ClientOp.TxRollback, writer).ConfigureAwait(false);
+ }
}
/// <summary>
@@ -119,32 +123,7 @@ namespace Apache.Ignite.Internal.Transactions
/// </summary>
/// <param name="state">State to set.</param>
/// <returns>True when specified state was set successfully; false otherwise.</returns>
- private bool TrySetState(int state)
- {
- return Interlocked.CompareExchange(ref _state, state, StateOpen) == StateOpen;
- }
-
- /// <summary>
- /// Sets the specified state. Throws <see cref="TransactionException"/> when current state is different from
- /// <see cref="StateOpen"/>.
- /// </summary>
- /// <param name="state">State to set.</param>
- /// <exception cref="TransactionException">When current state is not <see cref="StateOpen"/>.</exception>
- private void SetState(int state)
- {
- var oldState = Interlocked.CompareExchange(ref _state, state, StateOpen);
-
- if (oldState == StateOpen)
- {
- return;
- }
-
- var message = oldState == StateCommitted
- ? "Transaction is already committed."
- : "Transaction is already rolled back.";
-
- throw new TransactionException(message);
- }
+ private bool TrySetState(int state) => Interlocked.CompareExchange(ref _state, state, StateOpen) == StateOpen;
/// <summary>
/// Writes the transaction.