Unable to instantiate MetaInstruction

Aug 21, 2015 at 2:28 PM
Hi,

I am using AddMetaInstruction to instantiate an instance. It is fine in a one message at a time environment.

However after restart host instance(s), multiple messages are submitted at once, there is an exception(s), "Unable to instantiate MetaInstruction - ... exception encountered - An item with the same key has already been added."

The problem happened by ResolveType(string fullyQualifiedClass) in ObjectCreator.cs file. This method adds an entry into a static dictionary via Add method, typeDictionary.Add(fullyQualifiedClass, resolvedType);, without a lock.

After replaced the original statement with an assignment, typeDictionary[fullyQualifiedClass] = resolvedType;, problem goes away. This solution lets an dictionary entry be overwritten multiple times, but I think it is better than a lock which may cost more.

However, I don't know if there is any other impact.

Thanks,

--Heng
Coordinator
Aug 21, 2015 at 11:02 PM
Hi Heng,

What version of the framework are you using? This was a known issue in older versions.

Cheers
Johann




Aug 21, 2015 at 11:37 PM
Hi, Johann

Sorry, I may not have the latest code. I'm using brepipelineframework-36952.zip.

Does brepipelineframework-37885.zip have the fix?

Thank you!

--Heng
Coordinator
Aug 22, 2015 at 1:37 AM
Hi Heng,

Can you please check the assembly file version of the various assembles in the solution?

Unless the bug has been reintroduced, it should be fixed in recent versions.

Cheers
Johann




Aug 22, 2015 at 5:58 PM
Hi, Johann

I'll check it out on Monday and let you know.

I believe that I'm using the one you resolved my last issue, remove a node along with its children.

Thanks,

--Heng

Coordinator
Aug 23, 2015 at 6:17 AM
Thanks Heng, also if you can please download the cat instrumentation tracing framework and run a pipeline component trace when you reproduce the error. That'll help me greatly to reproduce this.

Cheers
Johann



Aug 24, 2015 at 3:09 PM
Hi, Johann

The AssemblyInfo.cs have file version of 1.6.0.0.

Below is the CAT trace log. Do you have a latest version of ObjectCreator.cs?

EventTrace
[2]25C4.4AE4::08/24/2015-09:51:57.032 [Event]:TRACEIN: BREPipelineFramework.Component.BREPipelineFrameworkComponent.TraceIn() => [0c518066-bcb3-457f-af2c-fe7d88b696c2]
[2]25C4.4AE4::08/24/2015-09:51:57.033 [Event]:START -> 0c518066-bcb3-457f-af2c-fe7d88b696c2
[2]25C4.4AE4::08/24/2015-09:51:57.033 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - BRE Pipeline Framework pipeline component has started executing with an application context of SWIFT_MT_FILE, an Instruction Execution Order of RulesExecution and an XML Facts Application Stage of BeforeInstructionExecution.
[3]25C4.1710::08/24/2015-09:51:57.033 [Event]:TRACEIN: BREPipelineFramework.Component.BREPipelineFrameworkComponent.TraceIn() => [aa74ecbe-9f5a-4ad4-873e-56140e139e80]
[2]25C4.4AE4::08/24/2015-09:51:57.033 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - BRE Pipeline Framework pipeline component has an optional Instruction Loader policy paramater value set to Mercury.Statements.SWIFT.InstructionLoader.Policy.
[3]25C4.1710::08/24/2015-09:51:57.033 [Event]:START -> aa74ecbe-9f5a-4ad4-873e-56140e139e80
[2]25C4.4AE4::08/24/2015-09:51:57.033 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - BRE Pipeline Framework pipeline component has an optional Execution policy paramater value set to Mercury.Statements.SWIFT.Execution.Policy.
[3]25C4.1710::08/24/2015-09:51:57.033 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - BRE Pipeline Framework pipeline component has started executing with an application context of SWIFT_MT_FILE, an Instruction Execution Order of RulesExecution and an XML Facts Application Stage of BeforeInstructionExecution.
[3]25C4.1710::08/24/2015-09:51:57.033 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - BRE Pipeline Framework pipeline component has an optional Instruction Loader policy paramater value set to Mercury.Statements.SWIFT.InstructionLoader.Policy.
[3]25C4.1710::08/24/2015-09:51:57.033 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - BRE Pipeline Framework pipeline component has an optional Execution policy paramater value set to Mercury.Statements.SWIFT.Execution.Policy.
[3]25C4.1710::08/24/2015-09:51:57.038 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - Inbound message body had a stream type of System.IO.MemoryStream
[3]25C4.1710::08/24/2015-09:51:57.038 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - Inbound message body stream was seekable so no need to wrap it
[1]25C4.4AE4::08/24/2015-09:51:57.038 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Inbound message body had a stream type of System.IO.MemoryStream
[1]25C4.4AE4::08/24/2015-09:51:57.038 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Inbound message body stream was seekable so no need to wrap it
[3]25C4.1710::08/24/2015-09:51:57.040 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - No need to read stream as stream type does not match entries in StreamsToReadBeforeExecution parameter
[1]25C4.4AE4::08/24/2015-09:51:57.040 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - No need to read stream as stream type does not match entries in StreamsToReadBeforeExecution parameter
[1]25C4.1710::08/24/2015-09:51:58.545 [Event]:aa74ecbe-9f5a-4ad4-873e-56140e139e80 - Executing Policy Mercury.Statements.SWIFT.InstructionLoader.Policy 1.0
[2]25C4.4AE4::08/24/2015-09:51:58.545 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Executing Policy Mercury.Statements.SWIFT.InstructionLoader.Policy 1.0

[1]25C4.1710::08/24/2015-09:51:58.668 [Event]:ERROR: PipelineComponent Exception Summary:

Timestamp: 24/08/2015 09:51:58.663
Machine Name: FTWVSDSPHUB
Assembly Full Name: BREPipelineFramework.Helpers, Version=1.6.0.0, Culture=neutral, PublicKeyToken=ce0b636c4c7dcae8
Assembly Version: 1.6.0.0
App Domain Name: DefaultDomain
Application Base Path: P:\Program Files (x86)\Microsoft BizTalk Server 2013\
Windows Identity: INVESTMENTS\sabztkDVM.BTSAppSvc

Exception Information Details:

Exception Type: System.Exception
Message: Unable to instantiate MetaInstruction - Mercury.Statements.Utilities.Common.BREPipeline.MetaInstruction,Mercury.Statements.Utilities.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=ce0b636c4c7dcae8, exception encountered - An item with the same key has already been added.
TargetSite: Microsoft.BizTalk.Message.Interop.IBaseMessage Execute(Microsoft.BizTalk.Component.Interop.IPipelineContext, Microsoft.BizTalk.Message.Interop.IBaseMessage)
Source: BREPipelineFramework.Component
HResult: -2146233088

Stack Trace Information Details:

at BREPipelineFramework.Component.BREPipelineFrameworkComponent.Execute(IPipelineContext pc, IBaseMessage inmsg) in c:\Builds\50\BizTalkHub\Mercury_Shared_Release_Deploy\Sources\Main\Source\Shared\Mercury.Shared\PipelineComponents\BREPipelineFramework\BREPipelineFramework.Component\BREPipelineFrameworkComponent.cs:line 553 <= [aa74ecbe-9f5a-4ad4-873e-56140e139e80]
[1]25C4.1710::08/24/2015-09:51:58.669 [Event]:END <- aa74ecbe-9f5a-4ad4-873e-56140e139e80: 1635ms
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.CachingMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.ContextMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.HelperMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.HttpHeadersMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.MessagePartMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.PipelineMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction BREPipelineFramework.SampleInstructions.MetaInstructions.XMLTranslatorMetaInstructions to Execution Policy facts.
[3]25C4.4AE4::08/24/2015-09:51:58.670 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Adding MetaInstruction Mercury.Statements.Utilities.Common.BREPipeline.MetaInstruction to Execution Policy facts.
[1]25C4.1710::08/24/2015-09:51:58.671 [Event]:TRACEOUT: BREPipelineFramework.Component.BREPipelineFrameworkComponent.Execute(...) = "aa74ecbe-9f5a-4ad4-873e-56140e139e80"
[0]25C4.4AE4::08/24/2015-09:51:58.748 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Executing Policy Mercury.Statements.SWIFT.Execution.Policy 1.0
[0]25C4.4AE4::08/24/2015-09:51:58.756 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Got value 940 for context property http://schemas.microsoft.com/A4SWIFT/Property#A4SWIFT_MessageType
[0]25C4.4AE4::08/24/2015-09:51:58.756 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Got value 940 for context property http://schemas.microsoft.com/A4SWIFT/Property#A4SWIFT_MessageType
[0]25C4.4AE4::08/24/2015-09:51:58.763 [Event]:0c518066-bcb3-457f-af2c-fe7d88b696c2 - Starting to execute all MetaInstructions.
[0]25C4.4AE4::08/24/2015-09:51:58.765 [Event]:END <- 0c518066-bcb3-457f-af2c-fe7d88b696c2: 1732ms
[0]25C4.4AE4::08/24/2015-09:51:58.765 [Event]:TRACEOUT: BREPipelineFramework.Component.BREPipelineFrameworkComponent.Execute(...) = "0c518066-bcb3-457f-af2c-fe7d88b696c2"
Thank you!
--Heng
Nov 23, 2015 at 8:48 PM
Edited Nov 23, 2015 at 8:49 PM
Hi Guys,

I am also encountering this issue in version 1.6.0.

In my scenario I have a pipeline with a flat file disassembler that de-batches records into multiple messages which then go to the next pipeline stage which is a BREPipelineFramework component. This uses an InstructionLoader policy to load a helper .NET assembly.

The error doesn't always happen but can under high load. I can see the issue is with the non-threadsafe static Dictionary declared in ObjectCreator.cs and the way it is used.
private static Dictionary<string, Type> typeDictionary = new Dictionary<string, Type>();
        public static Type ResolveType(string fullyQualifiedClass)
        {
            Type resolvedType;

            //Check to see if the type already exists in the static typeDictionary, if so then use that type, 
            //if not then get the type and add it to the typeDictionary
            if (typeDictionary.TryGetValue(fullyQualifiedClass, out resolvedType))
            {
                resolvedType = typeDictionary[fullyQualifiedClass];
            }
            else
            {
                resolvedType = Type.GetType(fullyQualifiedClass);

                if (resolvedType != null)
                {
                    typeDictionary.Add(fullyQualifiedClass, resolvedType);
                }
                else
                {
                    throw new Exception("Unable to instantiate object of type - " + fullyQualifiedClass);
                }
            }

            return resolvedType;
        }
This potentially could be fixed with a thread safe ConcurrentDictionary which has an AddOrUpdate method.

Cheers,
Simon

P.S. This problem is different to a previous issue in BREPipelineFrameworkComponent.cs that was solved in 1.5.2 (http://brepipelineframework.codeplex.com/discussions/567510)
P.P.S. I didn't feed back on that other issue that the fix worked :-)
Dec 20, 2015 at 8:09 PM
FYI, here is the updated ObjectCreator.cs code that resolved the problem for me.
using System;
using System.Collections.Concurrent;
using System.Reflection.Emit;
using System.Reflection;

namespace BREPipelineFramework.Helpers
{
    /// <summary>
    /// Class which can aid in quickly instantiating an object with a parameter-less constructor
    /// Idea for this class comes from http://www.ozcandegirmenci.com/post/2008/02/Create-object-instances-Faster-than-Reflection.aspx
    /// </summary>
    public class ObjectCreator
    {
        delegate object MethodInvoker();
        MethodInvoker methodHandler = null;
        private static ConcurrentDictionary<string, Type> typeDictionary = new ConcurrentDictionary<string, Type>();
        
        public ObjectCreator(ConstructorInfo target)
        {
            CreateObject(target);
        }

        public object CreateInstance()
        {
            return methodHandler();
        }

        public static Type ResolveType(string fullyQualifiedClass)
        {
            Type resolvedType;

            //Check to see if the type already exists in the static typeDictionary, if so then use that type, 
            //if not then get the type and add it to the typeDictionary
            if (typeDictionary.TryGetValue(fullyQualifiedClass, out resolvedType))
            {
                resolvedType = typeDictionary[fullyQualifiedClass];
            }
            else
            {
                resolvedType = Type.GetType(fullyQualifiedClass);

                if (resolvedType != null)
                {
                    typeDictionary.AddOrUpdate(fullyQualifiedClass, resolvedType, (s, type) => resolvedType);
                }
                else
                {
                    throw new Exception("Unable to instantiate object of type - " + fullyQualifiedClass);
                }
            }

            return resolvedType;
        }

        public static object CreateConstructorlessInstance(Type type)
        {
            ConstructorInfo info = type.GetConstructor(Type.EmptyTypes);
            ObjectCreator inv = new ObjectCreator(info);
            object o = null;
            o = inv.CreateInstance();
            return o;
        }

        void CreateObject(ConstructorInfo target)
        {
            DynamicMethod dynamic = new DynamicMethod(string.Empty, typeof(object), new Type[0], target.DeclaringType);
            ILGenerator il = dynamic.GetILGenerator();
            il.DeclareLocal(target.DeclaringType);
            il.Emit(OpCodes.Newobj, target);
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Ret);

            methodHandler = (MethodInvoker)dynamic.CreateDelegate(typeof(MethodInvoker));
        }
     }
}
Coordinator
Dec 20, 2015 at 8:22 PM
Hi Simon,

Great, thanks for sorting that out since I never got a chance. Will run that through the test frameworks and release a new installer. Will credit your work :)

Cheers
Johann