Repository: reef Updated Branches: refs/heads/master a304daac9 -> 4f786095d
[REEF-1340] Creating Context manager for Fault Tolerant Adding ContextManager which manages IActiveContext Add/Remove, etc operations Adding test cases for it JIRA: [REEF-1340](https://issues.apache.org/jira/browse/REEF-1340) This closes #977 Project: http://git-wip-us.apache.org/repos/asf/reef/repo Commit: http://git-wip-us.apache.org/repos/asf/reef/commit/4f786095 Tree: http://git-wip-us.apache.org/repos/asf/reef/tree/4f786095 Diff: http://git-wip-us.apache.org/repos/asf/reef/diff/4f786095 Branch: refs/heads/master Commit: 4f786095d4f54a7016b4a9df61e05a904f129732 Parents: a304daa Author: Julia Wang <[email protected]> Authored: Thu Apr 28 14:26:24 2016 -0700 Committer: Andrew Chung <[email protected]> Committed: Mon May 2 17:03:20 2016 -0700 ---------------------------------------------------------------------- .../Org.Apache.REEF.IMRU.Tests.csproj | 17 ++ .../TestActiveContextManager.cs | 175 +++++++++++++++++++ .../Org.Apache.REEF.IMRU.Tests/packages.config | 1 + .../OnREEF/Driver/ActiveContextManager.cs | 152 ++++++++++++++++ .../Org.Apache.REEF.IMRU.csproj | 1 + 5 files changed, 346 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/reef/blob/4f786095/lang/cs/Org.Apache.REEF.IMRU.Tests/Org.Apache.REEF.IMRU.Tests.csproj ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.IMRU.Tests/Org.Apache.REEF.IMRU.Tests.csproj b/lang/cs/Org.Apache.REEF.IMRU.Tests/Org.Apache.REEF.IMRU.Tests.csproj index d9c4668..5c50039 100644 --- a/lang/cs/Org.Apache.REEF.IMRU.Tests/Org.Apache.REEF.IMRU.Tests.csproj +++ b/lang/cs/Org.Apache.REEF.IMRU.Tests/Org.Apache.REEF.IMRU.Tests.csproj @@ -42,11 +42,16 @@ under the License. <Reference Include="Microsoft.CSharp" /> <Reference Include="System.Data" /> <Reference Include="System.Xml" /> + <Reference Include="NSubstitute, Version=$(NSubstituteVersion), Culture=neutral, PublicKeyToken=92dd2e9066daa5ca, processorArchitecture=MSIL"> + <HintPath>$(PackagesDir)\NSubstitute.$(NSubstituteVersion)\lib\net45\NSubstitute.dll</HintPath> + <Private>True</Private> + </Reference> </ItemGroup> <ItemGroup> <Compile Include="MapInputWithControlMessageTests.cs" /> <Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="MapperCountTest.cs" /> + <Compile Include="TestActiveContextManager.cs" /> <Compile Include="TestSystemStates.cs" /> <Compile Include="TestTaskStates.cs" /> </ItemGroup> @@ -71,6 +76,18 @@ under the License. <Project>{6dc3b04e-2b99-4fda-bd23-2c7864f4c477}</Project> <Name>Org.Apache.REEF.IMRU.Examples</Name> </ProjectReference> + <ProjectReference Include="$(SolutionDir)\Org.Apache.REEF.Common\Org.Apache.REEF.Common.csproj"> + <Project>{545a0582-4105-44ce-b99c-b1379514a630}</Project> + <Name>Org.Apache.REEF.Common</Name> + </ProjectReference> + <ProjectReference Include="$(SolutionDir)\Org.Apache.REEF.Driver\Org.Apache.REEF.Driver.csproj"> + <Project>{a6baa2a7-f52f-4329-884e-1bcf711d6805}</Project> + <Name>Org.Apache.REEF.Driver</Name> + </ProjectReference> + <ProjectReference Include="$(SolutionDir)\Org.Apache.REEF.Utilities\Org.Apache.REEF.Utilities.csproj"> + <Project>{79e7f89a-1dfb-45e1-8d43-d71a954aeb98}</Project> + <Name>Org.Apache.REEF.Utilities</Name> + </ProjectReference> </ItemGroup> <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> http://git-wip-us.apache.org/repos/asf/reef/blob/4f786095/lang/cs/Org.Apache.REEF.IMRU.Tests/TestActiveContextManager.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.IMRU.Tests/TestActiveContextManager.cs b/lang/cs/Org.Apache.REEF.IMRU.Tests/TestActiveContextManager.cs new file mode 100644 index 0000000..f2c01ad --- /dev/null +++ b/lang/cs/Org.Apache.REEF.IMRU.Tests/TestActiveContextManager.cs @@ -0,0 +1,175 @@ +// 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. + +using System; +using System.Collections.Generic; +using NSubstitute; +using Org.Apache.REEF.Driver.Context; +using Org.Apache.REEF.Driver.Evaluator; +using Org.Apache.REEF.IMRU.OnREEF.Driver; +using Xunit; + +namespace Org.Apache.REEF.IMRU.Tests +{ + /// <summary> + /// Test methods in ActiveContextManager + /// </summary> + public class TestActiveContextManager + { + private const string EvaluatorIdPrefix = "EvaluatorId"; + private const string ContextIdPrefix = "ContextId"; + + /// <summary> + /// Create a ActiveContextManager and add some IActiveContexts to it. + /// </summary> + /// <returns></returns> + private ActiveContextManager InitializeActiveContextManager() + { + const int totalEvaluators = 5; + var activeContextManager = new ActiveContextManager(totalEvaluators); + for (int i = 0; i < totalEvaluators; i++) + { + activeContextManager.Add(CreateMockActiveContext(i)); + } + Assert.True(activeContextManager.AreAllContextsReceived); + Assert.Equal(totalEvaluators, activeContextManager.NumberOfActiveContexts); + + return activeContextManager; + } + + /// <summary> + /// Test add, Remove, RemovedFailedContextInFailedEvaluator, NumberOfMissingContexts and NumberOfActiveContext + /// in ActiveContexManager + /// </summary> + [Fact] + public void TestValidAddRemoveCases() + { + var activeContextManager = InitializeActiveContextManager(); + activeContextManager.RemoveFailedContextInFailedEvaluator(CreateMockFailedEvaluator(new List<int> { 3 })); + Assert.Equal(1, activeContextManager.NumberOfMissingContexts); + + activeContextManager.Remove(ContextIdPrefix + 4); + Assert.Equal(3, activeContextManager.NumberOfActiveContexts); + } + + /// <summary> + /// Test invalid Add and Remove + /// </summary> + public void TestInvalidAddRemoveCases() + { + var activeContextManager = new ActiveContextManager(3); + activeContextManager.Add(CreateMockActiveContext(1)); + + Action add = () => activeContextManager.Add(CreateMockActiveContext(1)); + Assert.Throws<IMRUSystemException>(add); + + Action remove = () => activeContextManager.Remove(ContextIdPrefix + 2); + Assert.Throws<IMRUSystemException>(remove); + + activeContextManager.Add(CreateMockActiveContext(2)); + activeContextManager.Add(CreateMockActiveContext(3)); + + add = () => activeContextManager.Add(CreateMockActiveContext(4)); + Assert.Throws<IMRUSystemException>(add); + } + + /// <summary> + /// Test removing a failed evaluator which has two contexts associated. + /// In current IMRU driver, assume there is only one context associated to the IFailedEvalutor + /// </summary> + [Fact] + public void TestRemoveFailedEvaluatorWithTwoContexts() + { + var activeContextManager = InitializeActiveContextManager(); + + Action remove = () => activeContextManager.RemoveFailedContextInFailedEvaluator(CreateMockFailedEvaluator(new List<int> { 3, 4 })); + Assert.Throws<IMRUSystemException>(remove); + } + + /// <summary> + /// Test removing a failed evaluator which has a context but it doesn't exist. + /// </summary> + [Fact] + public void TestRemoveFailedEvaluatorWithNoExistsContexts() + { + var activeContextManager = InitializeActiveContextManager(); + + Action remove = () => activeContextManager.RemoveFailedContextInFailedEvaluator(CreateMockFailedEvaluator(new List<int> { 5 })); + Assert.Throws<IMRUSystemException>(remove); + } + + /// <summary> + /// Test removing a failed evaluator which has no context associated. + /// The scenario may happen when an evaluator failed but context has not created yet. + /// </summary> + [Fact] + public void TestRemoveFailedEvaluatorWithNoContext() + { + var activeContextManager = InitializeActiveContextManager(); + + activeContextManager.RemoveFailedContextInFailedEvaluator(CreateMockFailedEvaluator(null)); + Assert.Equal(0, activeContextManager.NumberOfMissingContexts); + } + + /// <summary> + /// Create a mock IActiveContext + /// </summary> + /// <param name="id"></param> + /// <returns></returns> + private static IActiveContext CreateMockActiveContext(int id) + { + IActiveContext mockActiveContext = Substitute.For<IActiveContext>(); + mockActiveContext.Id.Returns(ContextIdPrefix + id); + mockActiveContext.EvaluatorId.Returns(EvaluatorIdPrefix + ContextIdPrefix + id); + return mockActiveContext; + } + + /// <summary> + /// Create a mock IFailedContext + /// </summary> + /// <param name="id"></param> + /// <returns></returns> + private static IFailedContext CreateMockFailedContext(int id) + { + IFailedContext mockFailedContext = Substitute.For<IFailedContext>(); + mockFailedContext.Id.Returns(ContextIdPrefix + id); + mockFailedContext.EvaluatorId.Returns(EvaluatorIdPrefix + ContextIdPrefix + id); + return mockFailedContext; + } + + /// <summary> + /// Create a mock IFailedEvaluator + /// </summary> + /// <param name="ids"></param> + /// <returns></returns> + private static IFailedEvaluator CreateMockFailedEvaluator(IList<int> ids) + { + IFailedEvaluator mockFailedEvalutor = Substitute.For<IFailedEvaluator>(); + IList<IFailedContext> failedContexts = null; + if (ids != null) + { + failedContexts = new List<IFailedContext>(); + foreach (var id in ids) + { + failedContexts.Add(CreateMockFailedContext(id)); + } + } + mockFailedEvalutor.FailedContexts.Returns(failedContexts); + return mockFailedEvalutor; + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/reef/blob/4f786095/lang/cs/Org.Apache.REEF.IMRU.Tests/packages.config ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.IMRU.Tests/packages.config b/lang/cs/Org.Apache.REEF.IMRU.Tests/packages.config index df4e5ea..a57dabf 100644 --- a/lang/cs/Org.Apache.REEF.IMRU.Tests/packages.config +++ b/lang/cs/Org.Apache.REEF.IMRU.Tests/packages.config @@ -18,6 +18,7 @@ specific language governing permissions and limitations under the License. --> <packages> + <package id="NSubstitute" version="1.8.2.0" targetFramework="net45" /> <package id="StyleCop.MSBuild" version="4.7.49.1" targetFramework="net45" developmentDependency="true" /> <package id="xunit" version="2.1.0" targetFramework="net45" /> <package id="xunit.abstractions" version="2.0.0" targetFramework="net45" /> http://git-wip-us.apache.org/repos/asf/reef/blob/4f786095/lang/cs/Org.Apache.REEF.IMRU/OnREEF/Driver/ActiveContextManager.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.IMRU/OnREEF/Driver/ActiveContextManager.cs b/lang/cs/Org.Apache.REEF.IMRU/OnREEF/Driver/ActiveContextManager.cs new file mode 100644 index 0000000..36c54ce --- /dev/null +++ b/lang/cs/Org.Apache.REEF.IMRU/OnREEF/Driver/ActiveContextManager.cs @@ -0,0 +1,152 @@ +// 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. + +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Globalization; +using System.Linq; +using Org.Apache.REEF.Driver.Context; +using Org.Apache.REEF.Driver.Evaluator; +using Org.Apache.REEF.Utilities.Attributes; +using Org.Apache.REEF.Utilities.Diagnostics; +using Org.Apache.REEF.Utilities.Logging; + +namespace Org.Apache.REEF.IMRU.OnREEF.Driver +{ + /// <summary> + /// Manages active contexts for the driver + /// </summary> + [NotThreadSafe] + internal sealed class ActiveContextManager + { + private static readonly Logger Logger = Logger.GetLogger(typeof(ActiveContextManager)); + private readonly IDictionary<string, IActiveContext> _activeContexts = new Dictionary<string, IActiveContext>(); + private readonly int _totalExpectedContexts; + + /// <summary> + /// Constructor of ActiveContextManager + /// totalContexts specify the total number of expected active contexts that driver needs + /// </summary> + /// <param name="totalContexts"></param> + internal ActiveContextManager(int totalContexts) + { + _totalExpectedContexts = totalContexts; + } + + /// <summary> + /// Returns the collection of IActiveContext + /// </summary> + internal IReadOnlyCollection<IActiveContext> ActiveContexts + { + get { return new ReadOnlyCollection<IActiveContext>(_activeContexts.Values.ToList()); } + } + + /// <summary> + /// Returns the difference between the number of expected IActiveContext and actually number of IActiveContext. + /// </summary> + internal int NumberOfMissingContexts + { + get { return _totalExpectedContexts - NumberOfActiveContexts; } + } + + /// <summary> + /// Checks if all the requested contexts are received. + /// </summary> + internal bool AreAllContextsReceived + { + get { return _totalExpectedContexts == NumberOfActiveContexts; } + } + + /// <summary> + /// Adding an IActiveContext to the ActiveContext collection + /// Throw IMRUSystemException if the IActiveContext already exists or NumberOfActiveContexts has exceeded the total expected contexts + /// </summary> + /// <param name="activeContext"></param> + internal void Add(IActiveContext activeContext) + { + if (_activeContexts.ContainsKey(activeContext.Id)) + { + var msg = string.Format(CultureInfo.InvariantCulture, "The context [{0}] received already exists.", activeContext.Id); + Exceptions.Throw(new IMRUSystemException(msg), Logger); + } + + if (NumberOfActiveContexts >= _totalExpectedContexts) + { + var msg = string.Format(CultureInfo.InvariantCulture, "Trying to add an extra active context {0}. The total number of the active contexts has reached to the expected number {1}.", activeContext.Id, _totalExpectedContexts); + Exceptions.Throw(new IMRUSystemException(msg), Logger); + } + + _activeContexts.Add(activeContext.Id, activeContext); + } + + /// <summary> + /// Remove an IActiveContext from the ActiveContext collection + /// Throw IMRUSystemException if the IActiveContext doesn't exist. + /// </summary> + /// <param name="activeContextId"></param> + internal void Remove(string activeContextId) + { + if (!_activeContexts.ContainsKey(activeContextId)) + { + var msg = string.Format(CultureInfo.InvariantCulture, "The context [{0}] to be removed does not exist.", activeContextId); + Exceptions.Throw(new IMRUSystemException(msg), Logger); + } + _activeContexts.Remove(activeContextId); + } + + /// <summary> + /// Returns the current number of IActiveContext in the ActiveContext collection + /// </summary> + internal int NumberOfActiveContexts + { + get { return _activeContexts.Count; } + } + + /// <summary> + /// Given an IFailedEvaluator, remove associated IActiveContext from the collection + /// Throw IMRUSystemException if associated IActiveContext doesn't exist or + /// if more than one IActiveContexts are associated with the IFailedEvaluator + /// as current IMRU driver assumes that there is only one context associated with the IFailedEvalutor + /// </summary> + /// <param name="value"></param> + internal void RemoveFailedContextInFailedEvaluator(IFailedEvaluator value) + { + if (value.FailedContexts != null && value.FailedContexts.Count > 0) + { + if (value.FailedContexts.Count == 1) + { + var failedContextId = value.FailedContexts[0].Id; + if (!_activeContexts.Remove(failedContextId)) + { + var msg = string.Format(CultureInfo.InvariantCulture, + "The active context [{0}] attached in IFailedEvaluator [{1}] is not in the Active Contexts collection.", + failedContextId, + value.Id); + Exceptions.Throw(new IMRUSystemException(msg), Logger); + } + } + else + { + var msg = string.Format(CultureInfo.InvariantCulture, + "There are [{0}] contexts attached in the failed evaluator. Expected number is 1.", + value.FailedContexts.Count); + Exceptions.Throw(new IMRUSystemException(msg), Logger); + } + } + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/reef/blob/4f786095/lang/cs/Org.Apache.REEF.IMRU/Org.Apache.REEF.IMRU.csproj ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.IMRU/Org.Apache.REEF.IMRU.csproj b/lang/cs/Org.Apache.REEF.IMRU/Org.Apache.REEF.IMRU.csproj index d893d49..958040a 100644 --- a/lang/cs/Org.Apache.REEF.IMRU/Org.Apache.REEF.IMRU.csproj +++ b/lang/cs/Org.Apache.REEF.IMRU/Org.Apache.REEF.IMRU.csproj @@ -70,6 +70,7 @@ under the License. <Compile Include="OnREEF\Client\REEFIMRUClient.cs" /> <Compile Include="OnREEF\Driver\ConfigurationManager.cs" /> <Compile Include="OnREEF\Driver\ContextAndServiceConfiguration.cs" /> + <Compile Include="OnREEF\Driver\ActiveContextManager.cs" /> <Compile Include="OnREEF\Driver\DataLoadingContext.cs" /> <Compile Include="OnREEF\Driver\MaximumNumberOfEvalutorFailuresExceededException.cs" /> <Compile Include="OnREEF\Driver\IMRUSystemException.cs" />
