IGNITE-3076 .NET: Add lifecycle events to IIgnite This closes #683
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/5b4ac374 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/5b4ac374 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/5b4ac374 Branch: refs/heads/ignite-1232 Commit: 5b4ac3743aae8c638f2b70a528a15dc563ae0ffb Parents: 8f28382 Author: Pavel Tupitsyn <[email protected]> Authored: Wed Jun 22 12:29:10 2016 +0300 Committer: Pavel Tupitsyn <[email protected]> Committed: Wed Jun 22 12:29:10 2016 +0300 ---------------------------------------------------------------------- .../Apache.Ignite.Core.Tests/LifecycleTest.cs | 9 ++++ .../Apache.Ignite.Core.Tests/ReconnectTest.cs | 9 ++++ .../Apache.Ignite.Core.Tests/TestUtils.cs | 4 +- .../Apache.Ignite.Core.csproj | 1 + .../dotnet/Apache.Ignite.Core/IIgnite.cs | 25 +++++++++++ .../dotnet/Apache.Ignite.Core/Ignition.cs | 23 +++++++++- .../dotnet/Apache.Ignite.Core/Impl/Ignite.cs | 38 +++++++++++++++- .../Apache.Ignite.Core/Impl/IgniteProxy.cs | 37 +++++++++++++-- .../Impl/LifecycleBeanHolder.cs | 2 +- .../Lifecycle/ClientReconnectEventArgs.cs | 47 ++++++++++++++++++++ 10 files changed, 186 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core.Tests/LifecycleTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/LifecycleTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/LifecycleTest.cs index dd79d43..256ce46 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/LifecycleTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/LifecycleTest.cs @@ -83,6 +83,7 @@ namespace Apache.Ignite.Core.Tests { // 1. Test start events. IIgnite grid = Start(CfgNoBeans); + Assert.AreEqual(2, grid.GetConfiguration().LifecycleBeans.Count); Assert.AreEqual(2, BeforeStartEvts.Count); CheckEvent(BeforeStartEvts[0], null, null, 0, null); @@ -93,8 +94,15 @@ namespace Apache.Ignite.Core.Tests CheckEvent(AfterStartEvts[1], grid, grid, 0, null); // 2. Test stop events. + var stoppingCnt = 0; + var stoppedCnt = 0; + grid.Stopping += (sender, args) => { stoppingCnt++; }; + grid.Stopped += (sender, args) => { stoppedCnt++; }; Ignition.Stop(grid.Name, false); + Assert.AreEqual(1, stoppingCnt); + Assert.AreEqual(1, stoppedCnt); + Assert.AreEqual(2, BeforeStartEvts.Count); Assert.AreEqual(2, AfterStartEvts.Count); @@ -115,6 +123,7 @@ namespace Apache.Ignite.Core.Tests { // 1. Test .Net start events. IIgnite grid = Start(CfgBeans); + Assert.AreEqual(2, grid.GetConfiguration().LifecycleBeans.Count); Assert.AreEqual(4, BeforeStartEvts.Count); CheckEvent(BeforeStartEvts[0], null, null, 0, null); http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/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 2f8b205..6032ef3 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/ReconnectTest.cs @@ -47,6 +47,11 @@ namespace Apache.Ignite.Core.Tests using (var ignite = Ignition.Start(cfg)) { + var reconnected = 0; + var disconnected = 0; + ignite.ClientDisconnected += (sender, args) => { disconnected++; }; + ignite.ClientReconnected += (sender, args) => { reconnected += args.HasClusterRestarted ? 10 : 1; }; + Assert.IsTrue(ignite.GetCluster().ClientReconnectTask.IsCompleted); var cache = ignite.CreateCache<int, int>("c"); @@ -63,6 +68,8 @@ namespace Apache.Ignite.Core.Tests var clientReconnectTask = inner.ClientReconnectTask; Assert.AreEqual(ignite.GetCluster().ClientReconnectTask, clientReconnectTask); + Assert.AreEqual(1, disconnected); + Assert.AreEqual(0, reconnected); // Resume process to reconnect proc.Resume(); @@ -70,6 +77,8 @@ namespace Apache.Ignite.Core.Tests clientReconnectTask.Wait(); Assert.AreEqual(1, cache[1]); + Assert.AreEqual(1, disconnected); + Assert.AreEqual(1, reconnected); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs index 4eef803..529b320 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs @@ -273,10 +273,12 @@ namespace Apache.Ignite.Core.Tests { var handleRegistry = ((Ignite)grid).HandleRegistry; + expectedCount++; // Skip default lifecycle bean + if (WaitForCondition(() => handleRegistry.Count == expectedCount, timeout)) return; - var items = handleRegistry.GetItems(); + var items = handleRegistry.GetItems().Where(x => !(x.Value is LifecycleBeanHolder)).ToList(); if (items.Any()) Assert.Fail("HandleRegistry is not empty in grid '{0}':\n '{1}'", grid.Name, http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/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 34c5ddb..46dbd94 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Apache.Ignite.Core.csproj @@ -414,6 +414,7 @@ <Compile Include="Impl\Unmanaged\UnmanagedTarget.cs" /> <Compile Include="Impl\Unmanaged\UnmanagedUtils.cs" /> <Compile Include="Interop\JavaObject.cs" /> + <Compile Include="Lifecycle\ClientReconnectEventArgs.cs" /> <Compile Include="Lifecycle\Package-Info.cs" /> <Compile Include="Messaging\Package-Info.cs" /> <Compile Include="Package-Info.cs" /> http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs index b45c625..a16ae3a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/IIgnite.cs @@ -29,6 +29,7 @@ namespace Apache.Ignite.Core using Apache.Ignite.Core.Datastream; using Apache.Ignite.Core.DataStructures; using Apache.Ignite.Core.Events; + using Apache.Ignite.Core.Lifecycle; using Apache.Ignite.Core.Messaging; using Apache.Ignite.Core.Services; using Apache.Ignite.Core.Transactions; @@ -274,5 +275,29 @@ namespace Apache.Ignite.Core /// </summary> /// <returns>Collection of names of currently available caches.</returns> ICollection<string> GetCacheNames(); + + /// <summary> + /// Occurs when node begins to stop. Node is fully functional at this point. + /// See also: <see cref="LifecycleEventType.BeforeNodeStop"/>. + /// </summary> + event EventHandler Stopping; + + /// <summary> + /// Occurs when node has stopped. Node can't be used at this point. + /// See also: <see cref="LifecycleEventType.AfterNodeStop"/>. + /// </summary> + event EventHandler Stopped; + + /// <summary> + /// Occurs when client node disconnects from the cluster. This event can only occur when this instance + /// runs in client mode (<see cref="IgniteConfiguration.ClientMode"/>). + /// </summary> + event EventHandler ClientDisconnected; + + /// <summary> + /// Occurs when client node reconnects to the cluster. This event can only occur when this instance + /// runs in client mode (<see cref="IgniteConfiguration.ClientMode"/>). + /// </summary> + event EventHandler<ClientReconnectEventArgs> ClientReconnected; } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs index c551735..7dc103c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Ignition.cs @@ -36,6 +36,7 @@ namespace Apache.Ignite.Core using Apache.Ignite.Core.Impl.Memory; using Apache.Ignite.Core.Impl.Unmanaged; using Apache.Ignite.Core.Lifecycle; + using Apache.Ignite.Core.Resource; using BinaryReader = Apache.Ignite.Core.Impl.Binary.BinaryReader; using UU = Apache.Ignite.Core.Impl.Unmanaged.UnmanagedUtils; @@ -308,7 +309,10 @@ namespace Apache.Ignite.Core private static void PrepareLifecycleBeans(BinaryReader reader, PlatformMemoryStream outStream, HandleRegistry handleRegistry) { - IList<LifecycleBeanHolder> beans = new List<LifecycleBeanHolder>(); + IList<LifecycleBeanHolder> beans = new List<LifecycleBeanHolder> + { + new LifecycleBeanHolder(new InternalLifecycleBean()) // add internal bean for events + }; // 1. Read beans defined in Java. int cnt = reader.ReadInt(); @@ -689,5 +693,22 @@ namespace Apache.Ignite.Core /// </summary> internal Ignite Ignite { get; set; } } + + /// <summary> + /// Internal bean for event notification. + /// </summary> + private class InternalLifecycleBean : ILifecycleBean + { + /** */ + #pragma warning disable 649 // unused field + [InstanceResource] private readonly IIgnite _ignite; + + /** <inheritdoc /> */ + public void OnLifecycleEvent(LifecycleEventType evt) + { + if (evt == LifecycleEventType.BeforeNodeStop) + ((IgniteProxy) _ignite).Target.BeforeNodeStop(); + } + } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs index 5e2a5d7..d516056 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Ignite.cs @@ -356,12 +356,26 @@ namespace Apache.Ignite.Core.Impl } /// <summary> + /// Called before node has stopped. + /// </summary> + internal void BeforeNodeStop() + { + var handler = Stopping; + if (handler != null) + handler.Invoke(this, EventArgs.Empty); + } + + /// <summary> /// Called after node has stopped. /// </summary> internal void AfterNodeStop() { foreach (var bean in _lifecycleBeans) bean.OnLifecycleEvent(LifecycleEventType.AfterNodeStop); + + var handler = Stopped; + if (handler != null) + handler.Invoke(this, EventArgs.Empty); } /** <inheritdoc /> */ @@ -651,6 +665,18 @@ namespace Apache.Ignite.Core.Impl } } + /** <inheritdoc /> */ + public event EventHandler Stopping; + + /** <inheritdoc /> */ + public event EventHandler Stopped; + + /** <inheritdoc /> */ + public event EventHandler ClientDisconnected; + + /** <inheritdoc /> */ + public event EventHandler<ClientReconnectEventArgs> ClientReconnected; + /// <summary> /// Gets or creates near cache. /// </summary> @@ -757,18 +783,26 @@ namespace Apache.Ignite.Core.Impl /// <summary> /// Called when local client node has been disconnected from the cluster. /// </summary> - public void OnClientDisconnected() + internal void OnClientDisconnected() { _clientReconnectTaskCompletionSource = new TaskCompletionSource<bool>(); + + var handler = ClientDisconnected; + if (handler != null) + handler.Invoke(this, EventArgs.Empty); } /// <summary> /// Called when local client node has been reconnected to the cluster. /// </summary> /// <param name="clusterRestarted">Cluster restarted flag.</param> - public void OnClientReconnected(bool clusterRestarted) + internal void OnClientReconnected(bool clusterRestarted) { _clientReconnectTaskCompletionSource.TrySetResult(clusterRestarted); + + var handler = ClientReconnected; + if (handler != null) + handler.Invoke(this, new ClientReconnectEventArgs(clusterRestarted)); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs index 957018e..949d31c 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/IgniteProxy.cs @@ -31,6 +31,7 @@ namespace Apache.Ignite.Core.Impl using Apache.Ignite.Core.Events; using Apache.Ignite.Core.Impl.Binary; using Apache.Ignite.Core.Impl.Cluster; + using Apache.Ignite.Core.Lifecycle; using Apache.Ignite.Core.Messaging; using Apache.Ignite.Core.Services; using Apache.Ignite.Core.Transactions; @@ -43,7 +44,7 @@ namespace Apache.Ignite.Core.Impl { /** */ [NonSerialized] - private readonly IIgnite _ignite; + private readonly Ignite _ignite; /// <summary> /// Default ctor for marshalling. @@ -57,7 +58,7 @@ namespace Apache.Ignite.Core.Impl /// Constructor. /// </summary> /// <param name="ignite">Grid.</param> - public IgniteProxy(IIgnite ignite) + public IgniteProxy(Ignite ignite) { _ignite = ignite; } @@ -385,6 +386,34 @@ namespace Apache.Ignite.Core.Impl } /** <inheritdoc /> */ + public event EventHandler Stopping + { + add { _ignite.Stopping += value; } + remove { _ignite.Stopping -= value; } + } + + /** <inheritdoc /> */ + public event EventHandler Stopped + { + add { _ignite.Stopped += value; } + remove { _ignite.Stopped -= value; } + } + + /** <inheritdoc /> */ + public event EventHandler ClientDisconnected + { + add { _ignite.ClientDisconnected += value; } + remove { _ignite.ClientDisconnected -= value; } + } + + /** <inheritdoc /> */ + public event EventHandler<ClientReconnectEventArgs> ClientReconnected + { + add { _ignite.ClientReconnected += value; } + remove { _ignite.ClientReconnected -= value; } + } + + /** <inheritdoc /> */ public IAtomicSequence GetAtomicSequence(string name, long initialValue, bool create) { return _ignite.GetAtomicSequence(name, initialValue, create); @@ -405,7 +434,7 @@ namespace Apache.Ignite.Core.Impl /// <summary> /// Target grid. /// </summary> - internal IIgnite Target + internal Ignite Target { get { @@ -416,7 +445,7 @@ namespace Apache.Ignite.Core.Impl /** <inheritdoc /> */ public IBinaryType GetBinaryType(int typeId) { - return ((IClusterGroupEx)_ignite).GetBinaryType(typeId); + return _ignite.GetBinaryType(typeId); } } } http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs index cce4ec5..7544bf1 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/LifecycleBeanHolder.cs @@ -23,7 +23,7 @@ namespace Apache.Ignite.Core.Impl /// <summary> /// Lifecycle bean holder. /// </summary> - internal class LifecycleBeanHolder : ILifecycleBean + internal class LifecycleBeanHolder { /** Target bean. */ private readonly ILifecycleBean _target; http://git-wip-us.apache.org/repos/asf/ignite/blob/5b4ac374/modules/platforms/dotnet/Apache.Ignite.Core/Lifecycle/ClientReconnectEventArgs.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Lifecycle/ClientReconnectEventArgs.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Lifecycle/ClientReconnectEventArgs.cs new file mode 100644 index 0000000..57f537a --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Lifecycle/ClientReconnectEventArgs.cs @@ -0,0 +1,47 @@ +/* + * 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.Lifecycle +{ + using System; + + /// <summary> + /// Contains client reconnect event data. + /// </summary> + public class ClientReconnectEventArgs : EventArgs + { + /** */ + private readonly bool _hasClusterRestarted; + + /// <summary> + /// Initializes a new instance of the <see cref="ClientReconnectEventArgs"/> class. + /// </summary> + /// <param name="hasClusterRestarted">Cluster restarted flag.</param> + public ClientReconnectEventArgs(bool hasClusterRestarted) + { + _hasClusterRestarted = hasClusterRestarted; + } + + /// <summary> + /// Gets a value indicating whether this cluster has been restarted during reconnect. + /// </summary> + public bool HasClusterRestarted + { + get { return _hasClusterRestarted; } + } + } +}
