IGNITE-4117 .NET: Fix ClientReconnectTask completion timing This closes #1195
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/4495efc2 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/4495efc2 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/4495efc2 Branch: refs/heads/master Commit: 4495efc2aa37ca31214558968fa83598317e830a Parents: e7d7a59 Author: Pavel Tupitsyn <ptupit...@apache.org> Authored: Tue Nov 1 13:22:30 2016 +0300 Committer: Pavel Tupitsyn <ptupit...@apache.org> Committed: Tue Nov 1 13:22:30 2016 +0300 ---------------------------------------------------------------------- .../platform/PlatformProcessorImpl.java | 15 +++- .../Apache.Ignite.Core.Tests/ReconnectTest.cs | 81 ++++++++++++++++++-- 2 files changed, 88 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/4495efc2/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformProcessorImpl.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformProcessorImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformProcessorImpl.java index 548145e..d875c7e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformProcessorImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/PlatformProcessorImpl.java @@ -54,6 +54,7 @@ import org.apache.ignite.internal.processors.platform.services.PlatformServices; import org.apache.ignite.internal.processors.platform.transactions.PlatformTransactions; import org.apache.ignite.internal.processors.platform.utils.PlatformConfigurationUtils; import org.apache.ignite.internal.processors.platform.utils.PlatformUtils; +import org.apache.ignite.internal.util.typedef.CI1; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteFuture; @@ -101,6 +102,9 @@ public class PlatformProcessorImpl extends GridProcessorAdapter implements Platf /** Cache extensions. */ private final PlatformCacheExtension[] cacheExts; + /** Cluster restart flag for the reconnect callback. */ + private volatile boolean clusterRestarted; + /** * Constructor. * @@ -378,11 +382,20 @@ public class PlatformProcessorImpl extends GridProcessorAdapter implements Platf /** {@inheritDoc} */ @Override public void onDisconnected(IgniteFuture<?> reconnectFut) throws IgniteCheckedException { platformCtx.gateway().onClientDisconnected(); + + // 1) onReconnected is called on all grid components. + // 2) After all of grid components have completed their reconnection, reconnectFut is completed. + reconnectFut.listen(new CI1<IgniteFuture<?>>() { + @Override public void apply(IgniteFuture<?> future) { + platformCtx.gateway().onClientReconnected(clusterRestarted); + } + }); } /** {@inheritDoc} */ @Override public IgniteInternalFuture<?> onReconnected(boolean clusterRestarted) throws IgniteCheckedException { - platformCtx.gateway().onClientReconnected(clusterRestarted); + // Save the flag value for callback of reconnectFut. + this.clusterRestarted = clusterRestarted; return null; } http://git-wip-us.apache.org/repos/asf/ignite/blob/4495efc2/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs index 35bbca5..91e4c06 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs @@ -17,8 +17,12 @@ namespace Apache.Ignite.Core.Tests { + using System; + using System.Threading; using Apache.Ignite.Core.Cache; + using Apache.Ignite.Core.Cache.Configuration; using Apache.Ignite.Core.Common; + using Apache.Ignite.Core.Lifecycle; using Apache.Ignite.Core.Tests.Process; using NUnit.Framework; @@ -28,11 +32,71 @@ namespace Apache.Ignite.Core.Tests [Category(TestUtils.CategoryIntensive)] public class ReconnectTest { + /** */ + private const string CacheName = "cache"; + /// <summary> - /// Tests the disconnected exception. + /// Tests the cluster restart scenario, where client is alive, but all servers restart. /// </summary> [Test] - public void TestDisconnectedException() + public void TestClusterRestart() + { + var serverCfg = new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + CacheConfiguration = new[] {new CacheConfiguration(CacheName)} + }; + + var clientCfg = new IgniteConfiguration(TestUtils.GetTestConfiguration()) + { + GridName = "client", + ClientMode = true + }; + + var server = Ignition.Start(serverCfg); + var client = Ignition.Start(clientCfg); + + ClientReconnectEventArgs eventArgs = null; + + client.ClientReconnected += (sender, args) => { eventArgs = args; }; + + var cache = client.GetCache<int, int>(CacheName); + + cache[1] = 1; + + Ignition.Stop(server.Name, true); + + var cacheEx = Assert.Throws<CacheException>(() => cache.Get(1)); + var ex = cacheEx.InnerException as ClientDisconnectedException; + + Assert.IsNotNull(ex); + + // Start the server and wait for reconnect. + Ignition.Start(serverCfg); + Assert.IsTrue(ex.ClientReconnectTask.Result); + + // Check the event args. + Thread.Sleep(1); // Wait for event handler + + Assert.IsNotNull(eventArgs); + Assert.IsTrue(eventArgs.HasClusterRestarted); + + // Refresh the cache instance and check that it works. + var cache1 = client.GetCache<int, int>(CacheName); + Assert.AreEqual(0, cache1.GetSize()); + + cache1[1] = 2; + Assert.AreEqual(2, cache1[1]); + + // Check that old cache instance does not work. + var cacheEx1 = Assert.Throws<InvalidOperationException>(() => cache.Get(1)); + Assert.AreEqual("Cache has been closed or destroyed: " + CacheName, cacheEx1.Message); + } + + /// <summary> + /// Tests the failed connection scenario, where servers are alive, but can't be contacted. + /// </summary> + [Test] + public void TestFailedConnection() { var cfg = new IgniteConfiguration { @@ -54,7 +118,7 @@ namespace Apache.Ignite.Core.Tests Assert.IsTrue(ignite.GetCluster().ClientReconnectTask.IsCompleted); - var cache = ignite.CreateCache<int, int>("c"); + var cache = ignite.CreateCache<int, int>(CacheName); cache[1] = 1; @@ -69,6 +133,8 @@ namespace Apache.Ignite.Core.Tests var inner = (ClientDisconnectedException) ex.InnerException; + Assert.IsNotNull(inner); + var clientReconnectTask = inner.ClientReconnectTask; Assert.AreEqual(ignite.GetCluster().ClientReconnectTask, clientReconnectTask); @@ -78,7 +144,7 @@ namespace Apache.Ignite.Core.Tests // Resume process to reconnect proc.Resume(); - clientReconnectTask.Wait(); + Assert.IsFalse(clientReconnectTask.Result); Assert.AreEqual(1, cache[1]); Assert.AreEqual(1, disconnected); @@ -97,11 +163,12 @@ namespace Apache.Ignite.Core.Tests } /// <summary> - /// Fixture tear down. + /// Test tear down. /// </summary> - [TestFixtureTearDown] - public void FixtureTearDown() + [TearDown] + public void TearDown() { + Ignition.StopAll(true); IgniteProcess.KillAll(); Ignition.ClientMode = false; }