IGNITE-4119 .NET: add TransactionDeadlockException
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/474f22fd Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/474f22fd Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/474f22fd Branch: refs/heads/ignite-2693 Commit: 474f22fda4c7cf4d7b2623c451cd7c10f0d8c636 Parents: df670c7 Author: Pavel Tupitsyn <[email protected]> Authored: Mon Nov 7 12:55:20 2016 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Mon Nov 7 12:55:20 2016 +0300 ---------------------------------------------------------------------- .../platform/cache/PlatformCache.java | 12 ++++ .../Cache/CacheAbstractTest.cs | 44 +++++++++++- .../Apache.Ignite.Core.Tests/ExceptionsTest.cs | 3 + .../Apache.Ignite.Core.csproj | 3 +- .../Apache.Ignite.Core/Impl/ExceptionUtils.cs | 1 + .../TransactionDeadlockException.cs | 71 ++++++++++++++++++++ 6 files changed, 132 insertions(+), 2 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/474f22fd/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/PlatformCache.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/PlatformCache.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/PlatformCache.java index be50e5d..6f23682 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/PlatformCache.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/cache/PlatformCache.java @@ -58,6 +58,8 @@ import org.apache.ignite.internal.util.typedef.C1; import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.lang.IgniteBiInClosure; import org.apache.ignite.lang.IgniteFuture; +import org.apache.ignite.transactions.TransactionDeadlockException; +import org.apache.ignite.transactions.TransactionTimeoutException; import org.jetbrains.annotations.Nullable; import javax.cache.Cache; @@ -1095,6 +1097,16 @@ public class PlatformCache extends PlatformAbstractTarget { if (e.getCause() instanceof EntryProcessorException) return (Exception)e.getCause(); + TransactionDeadlockException deadlockException = X.cause(e, TransactionDeadlockException.class); + + if (deadlockException != null) + return deadlockException; + + TransactionTimeoutException timeoutException = X.cause(e, TransactionTimeoutException.class); + + if (timeoutException != null) + return timeoutException; + return super.convertException(e); } http://git-wip-us.apache.org/repos/asf/ignite/blob/474f22fd/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs index 9fd1f1d..63e236a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Cache/CacheAbstractTest.cs @@ -2458,7 +2458,49 @@ namespace Apache.Ignite.Core.Tests.Cache // Expected } } - + + /// <summary> + /// Tests the transaction deadlock detection. + /// </summary> + [Test] + public void TestTxDeadlockDetection() + { + if (!TxEnabled()) + return; + + var cache = Cache(); + + var keys0 = Enumerable.Range(1, 100).ToArray(); + + cache.PutAll(keys0.ToDictionary(x => x, x => x)); + + var barrier = new Barrier(2); + + Action<int[]> increment = keys => + { + using (var tx = Transactions.TxStart(TransactionConcurrency.Pessimistic, + TransactionIsolation.RepeatableRead, TimeSpan.FromSeconds(0.5), 0)) + { + foreach (var key in keys) + cache[key]++; + + barrier.SignalAndWait(500); + + tx.Commit(); + } + }; + + // Increment keys within tx in different order to cause a deadlock. + var aex = Assert.Throws<AggregateException>(() => + Task.WaitAll(Task.Factory.StartNew(() => increment(keys0)), + Task.Factory.StartNew(() => increment(keys0.Reverse().ToArray())))); + + Assert.AreEqual(2, aex.InnerExceptions.Count); + + var deadlockEx = aex.InnerExceptions.OfType<TransactionDeadlockException>().First(); + Assert.IsTrue(deadlockEx.Message.Trim().StartsWith("Deadlock detected:"), deadlockEx.Message); + } + /// <summary> /// Test thraed-locals leak. /// </summary> http://git-wip-us.apache.org/repos/asf/ignite/blob/474f22fd/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs index e766f5a..052ff6f 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ExceptionsTest.cs @@ -65,6 +65,8 @@ namespace Apache.Ignite.Core.Tests var e = Assert.Throws<ClusterGroupEmptyException>(() => grid.GetCluster().ForRemotes().GetMetrics()); + Assert.IsNotNull(e.InnerException); + Assert.IsTrue(e.InnerException.Message.StartsWith( "class org.apache.ignite.cluster.ClusterGroupEmptyException: Cluster group is empty.")); @@ -163,6 +165,7 @@ namespace Apache.Ignite.Core.Tests ex = (Exception) msgCauseCtor.Invoke(new object[] {"myMessage", new Exception("innerEx")}); Assert.AreEqual("myMessage", ex.Message); + Assert.IsNotNull(ex.InnerException); Assert.AreEqual("innerEx", ex.InnerException.Message); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/474f22fd/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj index 2973bb3..66253f6 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -75,7 +75,7 @@ <Optimize>true</Optimize> <PlatformTarget>AnyCPU</PlatformTarget> <CodeAnalysisRuleSet>Apache.Ignite.Core.ruleset</CodeAnalysisRuleSet> - <DebugType>none</DebugType> + <DebugType>none</DebugType> </PropertyGroup> <ItemGroup> <Reference Include="System" /> @@ -477,6 +477,7 @@ <Compile Include="Transactions\Package-Info.cs" /> <Compile Include="Transactions\TransactionConcurrency.cs" /> <Compile Include="Transactions\TransactionConfiguration.cs" /> + <Compile Include="Transactions\TransactionDeadlockException.cs" /> <Compile Include="Transactions\TransactionHeuristicException.cs" /> <Compile Include="Transactions\TransactionIsolation.cs" /> <Compile Include="Transactions\TransactionOptimisticException.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/474f22fd/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs index a59ca5f..ddbdd86 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/ExceptionUtils.cs @@ -97,6 +97,7 @@ namespace Apache.Ignite.Core.Impl Exs["org.apache.ignite.transactions.TransactionTimeoutException"] = (i, m, e) => new TransactionTimeoutException(m, e); Exs["org.apache.ignite.transactions.TransactionRollbackException"] = (i, m, e) => new TransactionRollbackException(m, e); Exs["org.apache.ignite.transactions.TransactionHeuristicException"] = (i, m, e) => new TransactionHeuristicException(m, e); + Exs["org.apache.ignite.transactions.TransactionDeadlockException"] = (i, m, e) => new TransactionDeadlockException(m, e); // Security exceptions. Exs["org.apache.ignite.IgniteAuthenticationException"] = (i, m, e) => new SecurityException(m, e); http://git-wip-us.apache.org/repos/asf/ignite/blob/474f22fd/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/TransactionDeadlockException.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/TransactionDeadlockException.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/TransactionDeadlockException.cs new file mode 100644 index 0000000..b0ba5de --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/TransactionDeadlockException.cs @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +namespace Apache.Ignite.Core.Transactions +{ + using System; + using System.Runtime.Serialization; + using Apache.Ignite.Core.Common; + + /// <summary> + /// Indicates a deadlock within Ignite transaction. + /// <para /> + /// This exception can be thrown from any cache method that modifies or reads data within a transaction + /// with timeout (see + /// <see cref="ITransactions.TxStart(TransactionConcurrency, TransactionIsolation, TimeSpan, int)"/> overload). + /// </summary> + [Serializable] + public class TransactionDeadlockException : IgniteException + { + /// <summary> + /// Initializes a new instance of the <see cref="TransactionDeadlockException"/> class. + /// </summary> + public TransactionDeadlockException() + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="TransactionDeadlockException"/> class. + /// </summary> + /// <param name="message">The message that describes the error.</param> + public TransactionDeadlockException(string message) : base(message) + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="TransactionDeadlockException"/> class. + /// </summary> + /// <param name="message">The message.</param> + /// <param name="cause">The cause.</param> + public TransactionDeadlockException(string message, Exception cause) : base(message, cause) + { + // No-op. + } + + /// <summary> + /// Initializes a new instance of the <see cref="TransactionDeadlockException"/> class. + /// </summary> + /// <param name="info">Serialization information.</param> + /// <param name="ctx">Streaming context.</param> + protected TransactionDeadlockException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) + { + // No-op. + } + } +}
