Repository: reef Updated Branches: refs/heads/master d0bc8df3e -> c67391a1d
[REEF-1286] Forward .NET Exceptions from the Evaluator to the Driver This addressed the issue by * Adding Serializing of Evaluator Exceptions. * Modifying the FailedEvaluator test for both serializable and non-serializable Exceptions. JIRA: [REEF-1286](https://issues.apache.org/jira/browse/REEF-1286) This close #988 Project: http://git-wip-us.apache.org/repos/asf/reef/repo Commit: http://git-wip-us.apache.org/repos/asf/reef/commit/c67391a1 Tree: http://git-wip-us.apache.org/repos/asf/reef/tree/c67391a1 Diff: http://git-wip-us.apache.org/repos/asf/reef/diff/c67391a1 Branch: refs/heads/master Commit: c67391a1d494c4f73494bdbc612698ec3f66622c Parents: d0bc8df Author: Andrew Chung <[email protected]> Authored: Wed May 4 11:19:37 2016 -0700 Committer: Julia Wang <[email protected]> Committed: Tue May 10 10:34:26 2016 -0700 ---------------------------------------------------------------------- lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h | 7 +- .../FailedEvaluatorClr2Java.cpp | 23 ++++-- .../NonSerializableEvaluatorException.cs | 40 ++++++++++ .../Org.Apache.REEF.Common.csproj | 1 + .../Runtime/Evaluator/EvaluatorRuntime.cs | 33 +++++++-- .../Bridge/Clr2java/IFailedEvaluatorClr2Java.cs | 28 ++++++- .../Bridge/Events/FailedEvaluator.cs | 24 +++++- .../Evaluator/EvaluatorException.cs | 14 +++- .../Exceptions/TestNonSerializableException.cs | 29 ++++++++ .../Exceptions/TestSerializableException.cs | 36 +++++++++ .../ShouldThrowSerializableException.cs | 29 ++++++++ .../Bridge/TestFailedTaskEventHandler.cs | 32 +------- .../Bridge/TestUnhandledTaskException.cs | 78 +++++++++++++++++--- .../Org.Apache.REEF.Tests.csproj | 4 + .../reef/javabridge/FailedEvaluatorBridge.java | 32 ++++++++ .../exception/NonSerializableException.java | 42 +++++++++++ .../driver/evaluator/EvaluatorManager.java | 3 +- 17 files changed, 388 insertions(+), 67 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h b/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h index d00ae59..e3fef8a 100644 --- a/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h +++ b/lang/cs/Org.Apache.REEF.Bridge/Clr2JavaImpl.h @@ -158,12 +158,11 @@ namespace Org { virtual void OnError(String^ message); virtual IEvaluatorRequestorClr2Java^ GetEvaluatorRequestor(); virtual String^ GetId(); - virtual EvaluatorException^ GetException(); virtual array<IFailedContextClr2Java^>^ GetFailedContextsClr2Java(); virtual IFailedTaskClr2Java^ GetFailedTaskClr2Java(); - private: - String^ GetCause(); - String^ GetStackTrace(); + virtual array<byte>^ GetErrorBytes(); + virtual String^ GetJavaCause(); + virtual String^ GetJavaStackTrace(); }; public ref class HttpServerClr2Java : public IHttpServerBridgeClr2Java { http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp b/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp index 9f0c8f5..f033c24 100644 --- a/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp +++ b/lang/cs/Org.Apache.REEF.Bridge/FailedEvaluatorClr2Java.cpp @@ -76,12 +76,6 @@ namespace Org { return ManagedStringFromJavaString(env, _jstringId); } - EvaluatorException^ FailedEvaluatorClr2Java::GetException() { - String^ cause = this->GetCause(); - String^ stackTrace = this->GetStackTrace(); - return gcnew EvaluatorException(this->GetId(), cause, stackTrace); - } - array<IFailedContextClr2Java^>^ FailedEvaluatorClr2Java::GetFailedContextsClr2Java() { JNIEnv *env = RetrieveEnv(_jvm); jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator); @@ -122,7 +116,20 @@ namespace Org { HandleClr2JavaError(env, message, _jobjectFailedEvaluator); } - String^ FailedEvaluatorClr2Java::GetCause() { + array<byte>^ FailedEvaluatorClr2Java::GetErrorBytes() { + JNIEnv *env = RetrieveEnv(_jvm); + jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator); + jmethodID jmidGetError = env->GetMethodID(jclassFailedEvaluator, "getErrorBytes", "()[B"); + jobject methodCallReturn = env->CallObjectMethod(_jobjectFailedEvaluator, jmidGetError); + if (methodCallReturn == NULL) { + return nullptr; + } + + jbyteArray error = reinterpret_cast<jbyteArray>(methodCallReturn); + return ManagedByteArrayFromJavaByteArray(env, error); + } + + String^ FailedEvaluatorClr2Java::GetJavaCause() { JNIEnv *env = RetrieveEnv(_jvm); jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator); jmethodID jmidGetCause = env->GetMethodID(jclassFailedEvaluator, "getCause", "()Ljava/lang/String;"); @@ -135,7 +142,7 @@ namespace Org { return ManagedStringFromJavaString(env, cause); } - String^ FailedEvaluatorClr2Java::GetStackTrace() { + String^ FailedEvaluatorClr2Java::GetJavaStackTrace() { JNIEnv *env = RetrieveEnv(_jvm); jclass jclassFailedEvaluator = env->GetObjectClass(_jobjectFailedEvaluator); jmethodID jmidGetStackTrace = env->GetMethodID(jclassFailedEvaluator, "getStackTrace", "()Ljava/lang/String;"); http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs b/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs new file mode 100644 index 0000000..8ce0913 --- /dev/null +++ b/lang/cs/Org.Apache.REEF.Common/Exceptions/NonSerializableEvaluatorException.cs @@ -0,0 +1,40 @@ +// 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.Runtime.Serialization; + +namespace Org.Apache.REEF.Common.Exceptions +{ + /// <summary> + /// Encapsulates <see cref="Exception#ToString"/> for an Exception from a + /// REEF Evaluator that was not Serializable to the Job Driver. + /// </summary> + [Serializable] + public sealed class NonSerializableEvaluatorException : Exception + { + public NonSerializableEvaluatorException(string message, SerializationException serializationException) + : base(message, serializationException) + { + } + + public NonSerializableEvaluatorException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj b/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj index 313d06a..b48e0e2 100644 --- a/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj +++ b/lang/cs/Org.Apache.REEF.Common/Org.Apache.REEF.Common.csproj @@ -107,6 +107,7 @@ under the License. <Compile Include="Events\IContextStart.cs" /> <Compile Include="Events\IContextStop.cs" /> <Compile Include="Exceptions\JobException.cs" /> + <Compile Include="Exceptions\NonSerializableEvaluatorException.cs" /> <Compile Include="Exceptions\NonSerializableTaskException.cs" /> <Compile Include="Files\PathUtilities.cs" /> <Compile Include="IContextAndTaskSubmittable.cs" /> http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs index 4c86218..1c92192 100644 --- a/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs +++ b/lang/cs/Org.Apache.REEF.Common/Runtime/Evaluator/EvaluatorRuntime.cs @@ -17,10 +17,13 @@ using System; using System.Globalization; +using System.IO; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using Org.Apache.REEF.Common.Exceptions; using Org.Apache.REEF.Common.Protobuf.ReefProtocol; using Org.Apache.REEF.Common.Runtime.Evaluator.Context; using Org.Apache.REEF.Tang.Annotations; -using Org.Apache.REEF.Utilities; using Org.Apache.REEF.Utilities.Diagnostics; using Org.Apache.REEF.Utilities.Logging; using Org.Apache.REEF.Wake.Time; @@ -242,17 +245,31 @@ namespace Org.Apache.REEF.Common.Runtime.Evaluator Logger.Log(Level.Error, "Evaluator {0} failed with exception {1}.", _evaluatorId, e); _state = State.FAILED; - var errorMessage = string.Format( - CultureInfo.InvariantCulture, - "failed with error [{0}] with message [{1}] and stack trace [{2}]", - e, - e.Message, - e.StackTrace); + byte[] errorBytes = null; + + try + { + using (var memStream = new MemoryStream()) + { + var formatter = new BinaryFormatter(); + formatter.Serialize(memStream, e); + errorBytes = memStream.ToArray(); + } + } + catch (SerializationException se) + { + using (var memStream = new MemoryStream()) + { + var formatter = new BinaryFormatter(); + formatter.Serialize(memStream, new NonSerializableEvaluatorException(e.ToString(), se)); + errorBytes = memStream.ToArray(); + } + } var evaluatorStatusProto = new EvaluatorStatusProto() { evaluator_id = _evaluatorId, - error = ByteUtilities.StringToByteArrays(errorMessage), + error = errorBytes, state = _state }; http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs b/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs index 19b51b8..3dcd2ae 100644 --- a/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs +++ b/lang/cs/Org.Apache.REEF.Driver/Bridge/Clr2java/IFailedEvaluatorClr2Java.cs @@ -15,7 +15,6 @@ // specific language governing permissions and limitations // under the License. -using Org.Apache.REEF.Driver.Evaluator; using Org.Apache.REEF.Utilities.Attributes; namespace Org.Apache.REEF.Driver.Bridge.Clr2java @@ -23,14 +22,39 @@ namespace Org.Apache.REEF.Driver.Bridge.Clr2java [Private, Interop("FailedEvaluatorClr2Java.cpp", "Clr2JavaImpl.h")] public interface IFailedEvaluatorClr2Java { + /// <summary> + /// Gets the Evaluator requestor. + /// </summary> IEvaluatorRequestorClr2Java GetEvaluatorRequestor(); + /// <summary> + /// Gets the ID of the failed Evaluator. + /// </summary> string GetId(); + /// <summary> + /// Gets the failed Contexts on the Evaluator. + /// </summary> IFailedContextClr2Java[] GetFailedContextsClr2Java(); + /// <summary> + /// Gets the failed Task on the Evaluator. + /// </summary> IFailedTaskClr2Java GetFailedTaskClr2Java(); - EvaluatorException GetException(); + /// <summary> + /// Gets the Serialized Exception. + /// </summary> + byte[] GetErrorBytes(); + + /// <summary> + /// Gets the Java Exception message. + /// </summary> + string GetJavaCause(); + + /// <summary> + /// Gets the Java stack trace. + /// </summary> + string GetJavaStackTrace(); } } http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs b/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs index bf126c0..337b793 100644 --- a/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs +++ b/lang/cs/Org.Apache.REEF.Driver/Bridge/Events/FailedEvaluator.cs @@ -15,9 +15,12 @@ // specific language governing permissions and limitations // under the License. +using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; using Org.Apache.REEF.Driver.Bridge.Clr2java; using Org.Apache.REEF.Driver.Context; using Org.Apache.REEF.Driver.Evaluator; @@ -31,6 +34,7 @@ namespace Org.Apache.REEF.Driver.Bridge.Events { private readonly string _id; private readonly IList<IFailedContext> _failedContexts; + private readonly EvaluatorException _evaluatorException; public FailedEvaluator(IFailedEvaluatorClr2Java clr2Java) { @@ -39,6 +43,24 @@ namespace Org.Apache.REEF.Driver.Bridge.Events _failedContexts = new List<IFailedContext>( FailedEvaluatorClr2Java.GetFailedContextsClr2Java().Select(clr2JavaFailedContext => new FailedContext(clr2JavaFailedContext))); + + var errorBytes = FailedEvaluatorClr2Java.GetErrorBytes(); + if (errorBytes != null) + { + // When the Exception originates from the C# side. + var formatter = new BinaryFormatter(); + using (var memStream = new MemoryStream(errorBytes)) + { + var inner = (Exception)formatter.Deserialize(memStream); + _evaluatorException = new EvaluatorException(_id, inner.Message, inner); + } + } + else + { + // When the Exception originates from Java. + _evaluatorException = new EvaluatorException( + _id, FailedEvaluatorClr2Java.GetJavaCause(), FailedEvaluatorClr2Java.GetJavaStackTrace()); + } } [DataMember] @@ -51,7 +73,7 @@ namespace Org.Apache.REEF.Driver.Bridge.Events public EvaluatorException EvaluatorException { - get { return FailedEvaluatorClr2Java.GetException(); } + get { return _evaluatorException; } } public IList<IFailedContext> FailedContexts http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs b/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs index c21a113..5d67f38 100644 --- a/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs +++ b/lang/cs/Org.Apache.REEF.Driver/Evaluator/EvaluatorException.cs @@ -26,12 +26,20 @@ namespace Org.Apache.REEF.Driver.Evaluator private readonly string _evaluatorId; private readonly Optional<string> _javaStackTrace; - [Private] - public EvaluatorException(string evaluatorId, string message, string javaStackTrace) + internal EvaluatorException(string evaluatorId, string message, string javaStackTrace) : base(message) { _evaluatorId = evaluatorId; - _javaStackTrace = Optional<string>.OfNullable(javaStackTrace); + _javaStackTrace = string.IsNullOrWhiteSpace(javaStackTrace) + ? Optional<string>.Empty() + : Optional<string>.Of(javaStackTrace); + } + + internal EvaluatorException(string evaluatorId, string message, Exception inner) + : base(message, inner) + { + _evaluatorId = evaluatorId; + _javaStackTrace = Optional<string>.Empty(); } public string EvaluatorId http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs new file mode 100644 index 0000000..3fcea6c --- /dev/null +++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestNonSerializableException.cs @@ -0,0 +1,29 @@ +// 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; + +namespace Org.Apache.REEF.Tests.Functional.Bridge.Exceptions +{ + internal sealed class TestNonSerializableException : Exception + { + public TestNonSerializableException(string message) + : base(message) + { + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs new file mode 100644 index 0000000..ee9840e --- /dev/null +++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Exceptions/TestSerializableException.cs @@ -0,0 +1,36 @@ +// 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.Runtime.Serialization; + +namespace Org.Apache.REEF.Tests.Functional.Bridge.Exceptions +{ + [Serializable] + internal sealed class TestSerializableException : Exception + { + public TestSerializableException(string message) + : base(message) + { + } + + public TestSerializableException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs new file mode 100644 index 0000000..544026d --- /dev/null +++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/Parameters/ShouldThrowSerializableException.cs @@ -0,0 +1,29 @@ +// 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 Org.Apache.REEF.Tang.Annotations; + +namespace Org.Apache.REEF.Tests.Functional.Bridge.Parameters +{ + [NamedParameter(documentation: "Used to indicate whether FailTask should throw a Serializable or non-Serializable Exception.")] + internal sealed class ShouldThrowSerializableException : Name<bool> + { + private ShouldThrowSerializableException() + { + } + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs index dfcb9f6..251dc61 100644 --- a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs +++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestFailedTaskEventHandler.cs @@ -28,6 +28,8 @@ using Org.Apache.REEF.Tang.Implementations.Configuration; using Org.Apache.REEF.Tang.Implementations.Tang; using Org.Apache.REEF.Tang.Interface; using Org.Apache.REEF.Tang.Util; +using Org.Apache.REEF.Tests.Functional.Bridge.Exceptions; +using Org.Apache.REEF.Tests.Functional.Bridge.Parameters; using Org.Apache.REEF.Utilities.Logging; using Xunit; @@ -204,35 +206,5 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge throw new TestNonSerializableException(ExpectedExceptionMessage); } } - - [NamedParameter(documentation: "Used to indicate whether FailTask should throw a Serializable or non-Serializable Exception.")] - private sealed class ShouldThrowSerializableException : Name<bool> - { - private ShouldThrowSerializableException() - { - } - } - - [Serializable] - private sealed class TestSerializableException : Exception - { - public TestSerializableException(string message) - : base(message) - { - } - - public TestSerializableException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - } - } - - private sealed class TestNonSerializableException : Exception - { - public TestNonSerializableException(string message) - : base(message) - { - } - } } } http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs index ec8fc07..fda2c0c 100644 --- a/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs +++ b/lang/cs/Org.Apache.REEF.Tests/Functional/Bridge/TestUnhandledTaskException.cs @@ -17,13 +17,18 @@ using System; using System.Threading; +using Org.Apache.REEF.Common.Exceptions; using Org.Apache.REEF.Common.Tasks; using Org.Apache.REEF.Driver; using Org.Apache.REEF.Driver.Evaluator; using Org.Apache.REEF.Driver.Task; using Org.Apache.REEF.Tang.Annotations; +using Org.Apache.REEF.Tang.Implementations.Configuration; +using Org.Apache.REEF.Tang.Implementations.Tang; using Org.Apache.REEF.Tang.Interface; using Org.Apache.REEF.Tang.Util; +using Org.Apache.REEF.Tests.Functional.Bridge.Exceptions; +using Org.Apache.REEF.Tests.Functional.Bridge.Parameters; using Org.Apache.REEF.Utilities.Logging; using Xunit; @@ -34,21 +39,21 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge { private const string ExpectedEvaluatorFailureMessage = "Unhandled Exception."; private const string ExpectedTaskId = "TaskID"; - private const string SuccessMessage = "Evaluator successfully received unhandled Exception."; + private const string SerializableSuccessMessage = "Evaluator successfully received serializable unhandled Exception."; + private const string NonSerializableSuccessMessage = "Evaluator successfully received nonserializable unhandled Exception."; /// <summary> /// This test validates that an unhandled Task Exception crashes the Evaluator and the Evaluator /// does an attempt to send a final message to the Driver. - /// TODO[JIRA REEF-1286]: Currently, this only validates the first portion, but does not yet validate the final message. - /// TODO[JIRA REEF-1286]: The verification of the final message can be done when the Exceptions are serializable. /// </summary> [Fact] public void TestUnhandledTaskExceptionCrashesEvaluator() { var testFolder = DefaultRuntimeFolder + Guid.NewGuid().ToString("N").Substring(0, 4); TestRun(GetDriverConfiguration(), typeof(TestUnhandledTaskException), 1, "testUnhandledTaskException", "local", testFolder); - ValidateSuccessForLocalRuntime(0, numberOfEvaluatorsToFail: 1, testFolder: testFolder); - ValidateMessageSuccessfullyLoggedForDriver(SuccessMessage, testFolder, 1); + ValidateSuccessForLocalRuntime(0, numberOfEvaluatorsToFail: 2, testFolder: testFolder); + ValidateMessageSuccessfullyLoggedForDriver(SerializableSuccessMessage, testFolder, 1); + ValidateMessageSuccessfullyLoggedForDriver(NonSerializableSuccessMessage, testFolder, 1); } private static IConfiguration GetDriverConfiguration() @@ -68,16 +73,27 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge /// </summary> private sealed class UnhandledExceptionTestTask : ITask { + private readonly bool _shouldThrowSerializableException; + [Inject] - private UnhandledExceptionTestTask() + private UnhandledExceptionTestTask( + [Parameter(typeof(ShouldThrowSerializableException))] bool shouldThrowSerializableException) { + _shouldThrowSerializableException = shouldThrowSerializableException; } public byte[] Call(byte[] memento) { var thread = new Thread(() => { - throw new Exception(ExpectedEvaluatorFailureMessage); + if (_shouldThrowSerializableException) + { + throw new TestSerializableException(ExpectedEvaluatorFailureMessage); + } + else + { + throw new TestNonSerializableException(ExpectedEvaluatorFailureMessage); + } }); thread.Start(); @@ -105,6 +121,7 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge private static readonly Logger Logger = Logger.GetLogger(typeof(UnhandledExceptionTestDriver)); private readonly IEvaluatorRequestor _evaluatorRequestor; + private bool _shouldReceiveSerializableException = true; [Inject] private UnhandledExceptionTestDriver(IEvaluatorRequestor evaluatorRequestor) @@ -128,7 +145,12 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge .Set(TaskConfiguration.Task, GenericType<UnhandledExceptionTestTask>.Class) .Build(); - value.SubmitTask(taskConf); + var shouldThrowSerializableConfig = TangFactory.GetTang().NewConfigurationBuilder() + .BindNamedParameter<ShouldThrowSerializableException, bool>( + GenericType<ShouldThrowSerializableException>.Class, _shouldReceiveSerializableException.ToString()) + .Build(); + + value.SubmitTask(Configurations.Merge(taskConf, shouldThrowSerializableConfig)); } public void OnNext(ICompletedTask value) @@ -150,7 +172,7 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge if (!value.EvaluatorException.Message.Contains(ExpectedEvaluatorFailureMessage)) { - // TODO[JIRA REEF-1286]: Verify the Exception message and the type of Exception. + throw new Exception("Evaluator expected to contain the message " + ExpectedEvaluatorFailureMessage); } if (!value.FailedTask.IsPresent()) @@ -163,7 +185,43 @@ namespace Org.Apache.REEF.Tests.Functional.Bridge throw new Exception("Failed Task does not have the right Task ID."); } - Logger.Log(Level.Info, SuccessMessage); + if (_shouldReceiveSerializableException) + { + var serializableEx = value.EvaluatorException.InnerException as TestSerializableException; + if (serializableEx == null) + { + throw new Exception("Evaluator InnerException expected to be of type " + typeof(TestSerializableException).Name); + } + + if (!serializableEx.Message.Equals(ExpectedEvaluatorFailureMessage)) + { + throw new Exception("Evaluator InnerException.Message expected to be " + ExpectedEvaluatorFailureMessage); + } + + _shouldReceiveSerializableException = false; + Logger.Log(Level.Info, SerializableSuccessMessage); + + _evaluatorRequestor.Submit( + _evaluatorRequestor.NewBuilder() + .SetCores(1) + .SetNumber(1) + .Build()); + } + else + { + var nonSerializableEx = value.EvaluatorException.InnerException as NonSerializableEvaluatorException; + if (nonSerializableEx == null) + { + throw new Exception("Evaluator Exception expected to be of type " + typeof(NonSerializableEvaluatorException)); + } + + if (!nonSerializableEx.Message.Contains(ExpectedEvaluatorFailureMessage)) + { + throw new Exception("Evaluator InnerException.Message expected to contain the message " + ExpectedEvaluatorFailureMessage); + } + + Logger.Log(Level.Info, NonSerializableSuccessMessage); + } } public void OnError(Exception error) http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj ---------------------------------------------------------------------- diff --git a/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj b/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj index bf58810..293f8d4 100644 --- a/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj +++ b/lang/cs/Org.Apache.REEF.Tests/Org.Apache.REEF.Tests.csproj @@ -74,11 +74,14 @@ under the License. </ItemGroup> <ItemGroup> <Compile Include="Functional\Bridge\HelloSimpleEventHandlers.cs" /> + <Compile Include="Functional\Bridge\Parameters\ShouldThrowSerializableException.cs" /> <Compile Include="Functional\Bridge\TestBridgeClient.cs" /> <Compile Include="Functional\Bridge\TestCloseTask.cs" /> <Compile Include="Functional\Bridge\TestContextStack.cs" /> <Compile Include="Functional\Bridge\TestFailedEvaluatorEventHandler.cs" /> <Compile Include="Functional\Bridge\TestFailedTaskEventHandler.cs" /> + <Compile Include="Functional\Bridge\Exceptions\TestNonSerializableException.cs" /> + <Compile Include="Functional\Bridge\Exceptions\TestSerializableException.cs" /> <Compile Include="Functional\Bridge\TestSimpleContext.cs" /> <Compile Include="Functional\Bridge\TestSimpleEventHandlers.cs" /> <Compile Include="Functional\Bridge\TestSuspendTask.cs" /> @@ -181,6 +184,7 @@ under the License. <ItemGroup> <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> </ItemGroup> + <ItemGroup /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(SolutionDir)\.nuget\NuGet.targets" Condition="Exists('$(SolutionDir)\.nuget\NuGet.targets')" /> <Import Project="$(PackagesDir)\StyleCop.MSBuild.$(StyleCopVersion)\build\StyleCop.MSBuild.Targets" Condition="Exists('$(PackagesDir)\StyleCop.MSBuild.$(StyleCopVersion)\build\StyleCop.MSBuild.Targets')" /> http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java ---------------------------------------------------------------------- diff --git a/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java b/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java index 89be5f3..8acabce 100644 --- a/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java +++ b/lang/java/reef-bridge-java/src/main/java/org/apache/reef/javabridge/FailedEvaluatorBridge.java @@ -23,6 +23,7 @@ import org.apache.reef.annotations.audience.Interop; import org.apache.reef.annotations.audience.Private; import org.apache.reef.driver.evaluator.EvaluatorRequestor; import org.apache.reef.driver.evaluator.FailedEvaluator; +import org.apache.reef.exception.NonSerializableException; import org.apache.reef.io.naming.Identifiable; import org.apache.reef.util.logging.LoggingScopeFactory; @@ -55,14 +56,36 @@ public final class FailedEvaluatorBridge extends NativeBridge implements Identif this.activeContextBridgeFactory = activeContextBridgeFactory; } + /** + * @return the Evaluator number. + */ public int getNewlyRequestedEvaluatorNumber() { return evaluatorRequestorBridge.getEvaluatorNumber(); } + /** + * @return the Evaluator requestor. + */ public EvaluatorRequestorBridge getEvaluatorRequestorBridge() { return evaluatorRequestorBridge; } + /** + * @return the non-serializable error in bytes, may translate into a serialized C# Exception. + */ + public byte[] getErrorBytes() { + if (jfailedEvaluator.getEvaluatorException() != null && + jfailedEvaluator.getEvaluatorException().getCause() instanceof NonSerializableException) { + return ((NonSerializableException)jfailedEvaluator.getEvaluatorException().getCause()).getError(); + } + + // If not an instance of NonSerializableException, that means that the Exception is from Java. + return null; + } + + /** + * @return the localized message of the Evaluator Exception. + */ public String getCause() { if (jfailedEvaluator.getEvaluatorException() != null) { return jfailedEvaluator.getEvaluatorException().getLocalizedMessage(); @@ -71,6 +94,9 @@ public final class FailedEvaluatorBridge extends NativeBridge implements Identif return null; } + /** + * @return the stack trace of the Evaluator Exception. + */ public String getStackTrace() { if (jfailedEvaluator.getEvaluatorException() != null) { return ExceptionUtils.getStackTrace(jfailedEvaluator.getEvaluatorException()); @@ -79,6 +105,9 @@ public final class FailedEvaluatorBridge extends NativeBridge implements Identif return null; } + /** + * @return the list of failed Contexts associated with the Evaluator. + */ public FailedContextBridge[] getFailedContexts() { if (jfailedEvaluator.getFailedContextList() == null) { return new FailedContextBridge[0]; @@ -95,6 +124,9 @@ public final class FailedEvaluatorBridge extends NativeBridge implements Identif return failedContextBridges; } + /** + * @return the failed task running on the Evaluator, if any. + */ public FailedTaskBridge getFailedTask() { if (!jfailedEvaluator.getFailedTask().isPresent()) { return null; http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java ---------------------------------------------------------------------- diff --git a/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java b/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java new file mode 100644 index 0000000..3286c98 --- /dev/null +++ b/lang/java/reef-common/src/main/java/org/apache/reef/exception/NonSerializableException.java @@ -0,0 +1,42 @@ +/* + * 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. + */ +package org.apache.reef.exception; + +import org.apache.reef.annotations.audience.DriverSide; + +/** + * An {@link Exception} that indicates that an Exception from the Evaluator + * was not able to be serialized. + */ +@DriverSide +public final class NonSerializableException extends Exception { + private final byte[] error; + + public NonSerializableException(final String message, final byte[] error) { + super(message); + this.error = error; + } + + /** + * @return the Exception representation in a byte array. + */ + public byte[] getError() { + return error; + } +} http://git-wip-us.apache.org/repos/asf/reef/blob/c67391a1/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java ---------------------------------------------------------------------- diff --git a/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java b/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java index e364ff1..f483868 100644 --- a/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java +++ b/lang/java/reef-common/src/main/java/org/apache/reef/runtime/common/driver/evaluator/EvaluatorManager.java @@ -24,6 +24,7 @@ import org.apache.reef.driver.evaluator.FailedEvaluator; import org.apache.reef.driver.parameters.EvaluatorConfigurationProviders; import org.apache.reef.driver.restart.DriverRestartManager; import org.apache.reef.driver.restart.EvaluatorRestartState; +import org.apache.reef.exception.NonSerializableException; import org.apache.reef.runtime.common.driver.evaluator.pojos.ContextStatusPOJO; import org.apache.reef.runtime.common.driver.evaluator.pojos.EvaluatorStatusPOJO; import org.apache.reef.runtime.common.driver.evaluator.pojos.State; @@ -468,7 +469,7 @@ public final class EvaluatorManager implements Identifiable, AutoCloseable { evaluatorException = new EvaluatorException(getId(), exception.get()); } else { evaluatorException = new EvaluatorException(getId(), - new Exception("Exception sent, but can't be deserialized")); + new NonSerializableException("Exception sent, but can't be deserialized", evaluatorStatus.getError())); } } else { evaluatorException = new EvaluatorException(getId(), new Exception("No exception sent"));
