public DtsPipelinePerformance(string ID, string Name, MainPipe pipeline, int Indent)
            : base(ID, Name, typeof(MainPipe), Indent)
        {
            DefaultBufferMaxRows = pipeline.DefaultBufferMaxRows;
            foreach (IDTSComponentMetaDataXX component in pipeline.ComponentMetaDataCollection)
            {
                DtsObjectPerformance perf = new DtsObjectPerformance(component.ID.ToString(), component.Name, component.GetType(), Indent + 1);
                Children.Add(perf);
                listTransformsPerformanceLookup.Add(component.ID, perf);
            }
            foreach (IDTSPathXX path in pipeline.PathCollection)
            {
                PipelinePath p = new PipelinePath();
                p.ID                  = path.ID;
                p.UniqueId            = ID + "Path" + path.ID;
                p.OutputID            = path.StartPoint.ID;
                p.OutputName          = path.StartPoint.Name;
                p.OutputTransformID   = path.StartPoint.Component.ID;
                p.OutputTransformName = path.StartPoint.Component.Name;
                p.OutputTransformType = path.StartPoint.Component.ObjectType;
                p.InputID             = path.EndPoint.ID;
                p.InputName           = path.EndPoint.Name;
                p.InputTransformID    = path.EndPoint.Component.ID;
                p.InputTransformName  = path.EndPoint.Component.Name;
                p.InputTransformType  = path.EndPoint.Component.ObjectType;
                p.Indent              = this.Indent + 2; //TODO: indent the paths recursively? probably good enough for now
                InputOutputLookup.Add(p.InputID, p);
                InputOutputLookup.Add(p.OutputID, p);

                foreach (IDTSOutputColumnXX col in path.StartPoint.OutputColumnCollection)
                {
                    if (!p.dictLineageIDColumnSizes.ContainsKey(col.LineageID))
                    {
                        p.dictLineageIDColumnSizes.Add(col.LineageID, GetColumnSizeInBytes(col));
                    }
                }
            }

            //hook up PreviousPath
            foreach (IDTSPathXX path in pipeline.PathCollection)
            {
                if (path.StartPoint.SynchronousInputID != 0)
                {
                    PipelinePath p = InputOutputLookup[path.StartPoint.ID];
                    p.PreviousPath = InputOutputLookup[path.StartPoint.SynchronousInputID];
                }
            }
        }
        public void LoadEvent(DtsLogEvent e)
        {
            if (!listComponentsPerformanceLookup.ContainsKey(e.SourceId)) return;
            DtsObjectPerformance perf = listComponentsPerformanceLookup[e.SourceId];
            if (e.Event == BidsHelperCapturedDtsLogEvent.OnPipelineRowsSent)
            {
                //<ignore> : <ignore> : PathID : PathName : TransformID : TransformName : InputID : InputName : RowsSent
                //Denali includes the following at the end... DestinationTransformName : Paths[SourceName.SourceOutputName] : DestinationTransformName.Inputs[InputName]
                DtsPipelinePerformance pipePerf = (DtsPipelinePerformance)perf;
                string[] parts = e.Message.Split(new string[] { " : " }, StringSplitOptions.None);
                int iPathID = int.Parse(parts[2]);
                int iInputID = int.Parse(parts[6]);
                if (pipePerf.InputOutputLookup.ContainsKey(iInputID))
                {
                    PipelinePath path = pipePerf.InputOutputLookup[iInputID];
                    path.DateRanges.Add(new DateRange(e.StartTime, e.EndTime));
                    path.RowCount += int.Parse(parts[8]);
                    path.BufferCount++;
                    
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.OnPipelinePrePrimeOutput)
            {
                //PrimeOutput will be called on a component. : 28490 : Flat File Source 1
                //<ignore> : TransformID : TransformName
                DtsPipelinePerformance pipePerf = (DtsPipelinePerformance)perf;
                string[] parts = e.Message.Split(new string[] { " : " }, StringSplitOptions.None);
                int iTransformID = int.Parse(parts[1]);
                foreach (ExecutionTree tree in pipePerf.ExecutionTrees)
                {
                    if (tree.Paths.Count > 0)
                    {
                        PipelinePath path = tree.Paths[0]; //only look for the component on the output of the first path
                        if (path.OutputTransformID == iTransformID)
                        {
                            tree.DateRanges.Add(new DateRange(e.StartTime));
                            //break; //there could be multiple execution trees started by the same component?
                        }
                    }
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.OnPipelinePostEndOfRowset)
            {
                //A component has finished processing all of its rows. : 30341 : Multicast : 30342 : Multicast Input 1
                //<ignore> : TransformID : TransformName : InputID : InputName
                DtsPipelinePerformance pipePerf = (DtsPipelinePerformance)perf;
                string[] parts = e.Message.Split(new string[] { " : " }, StringSplitOptions.None);
                int iInputID = int.Parse(parts[3]);

                foreach (ExecutionTree tree in pipePerf.ExecutionTrees)
                {
                    foreach (PipelinePath path in tree.Paths)
                    {
                        if (path.InputID == iInputID)
                        {
                            if (tree.DateRanges.Count > 0) //this is to avoid an error on issue 31275 where OnPipelinePrePrimeOutput wasn't ever called so we didn't start a date range
                            {
                                DateRange lastDateRange = tree.DateRanges[tree.DateRanges.Count - 1];
                                if (lastDateRange.EndDate == DateTime.MinValue)
                                {
                                    lastDateRange.EndDate = e.EndTime;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.OnPreExecute)
            {
                perf.DateRanges.Add(new DateRange(e.StartTime));
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.OnPostExecute)
            {
                if (perf.DateRanges.Count > 0)
                {
                    DateRange lastDateRange = perf.DateRanges[perf.DateRanges.Count - 1];
                    if (lastDateRange.EndDate == DateTime.MinValue)
                    {
                        lastDateRange.EndDate = e.EndTime;
                    }
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.PipelineExecutionTrees)
            {
                DtsPipelinePerformance pipePerf = (DtsPipelinePerformance)perf;
                ExecutionTree tree = null;
                foreach (string line in e.Message.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
                {
                    if (line.StartsWith(EXECUTION_TREE_START_PHRASE))
                    {
                        int iTreeID = int.Parse(line.Substring(EXECUTION_TREE_START_PHRASE.Length));
                        tree = new ExecutionTree();
                        tree.ID = iTreeID;
                        tree.UniqueId = pipePerf.ID + "ExecutionTree" + iTreeID;
                        tree.Name = "Execution Tree " + iTreeID;

                        bool bFoundTree = false;
                        foreach (ExecutionTree t in pipePerf.ExecutionTrees)
                        {
                            if (t.ID == tree.ID)
                            {
                                bFoundTree = true;
                                break;
                            }
                        }
                        if (!bFoundTree)
                            pipePerf.ExecutionTrees.Add(tree);
                    }
                    else if (line.StartsWith(EXECUTION_TREE_END_PHRASE))
                    {
                        //skip line
                    }
                    else
                    {
                        Match match = regexExecutionTreeOutput.Match(line);

#if DENALI || SQL2014
                        if (match.Groups.Count == 3)
                        {
                            string sComponent = match.Groups[1].Value;
                            string sOutput = match.Groups[2].Value;
                            foreach (PipelinePath path in pipePerf.InputOutputLookup.Values)
                            {
                                if (path.OutputName == sOutput && path.OutputTransformName == sComponent && !tree.Paths.Contains(path))
                                {
                                    tree.Paths.Add(path);
                                }
                            }
                        }
#else
                        if (match.Groups.Count == 2)
                        {
                            int iOutputID = int.Parse(match.Groups[1].Value);
                            if (pipePerf.InputOutputLookup.ContainsKey(iOutputID) && !tree.Paths.Contains(pipePerf.InputOutputLookup[iOutputID]))
                                tree.Paths.Add(pipePerf.InputOutputLookup[iOutputID]);
                        }
#endif
                    }
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.PipelineExecutionPlan)
            {
                DtsPipelinePerformance pipePerf = (DtsPipelinePerformance)perf;
                foreach (string line in e.Message.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries))
                {
                    Match match = regexCreateBuffer.Match(line);
                    if (match.Groups.Count == 3)
                    {
                        int iBufferID = int.Parse(match.Groups[1].Value) - 1;
                        int iBufferRowCount = pipePerf.GetBufferRowCount(iBufferID);
                        int iOutputID = int.Parse(match.Groups[2].Value);
                        foreach (ExecutionTree tree in pipePerf.ExecutionTrees)
                        {
                            foreach (PipelinePath path in tree.Paths)
                            {
                                if (path.OutputID == iOutputID)
                                {
                                    tree.BufferRowCount = iBufferRowCount;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.BufferSizeTuning)
            {
                DtsPipelinePerformance pipePerf = (DtsPipelinePerformance)perf;
                Match match = regexBufferSizeTuning.Match(e.Message);
                if (match.Groups.Count == 3)
                {
                    int iBufferID = int.Parse(match.Groups[1].Value);
                    int iBufferRowCount = int.Parse(match.Groups[2].Value);
                    pipePerf.SetBufferRowCount(iBufferID, iBufferRowCount);
                }
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.OnError)
            {
                perf.IsError = true;
                this.Errors.Add(e.Message);
            }
            else if (e.Event == BidsHelperCapturedDtsLogEvent.PackageEnd)
            {
                this.PackageEndReceived = true;
            }
        }
        public DtsPipelinePerformance(string ID, string Name, MainPipe pipeline, int Indent)
            : base(ID, Name, typeof(MainPipe), Indent)
        {
            DefaultBufferMaxRows = pipeline.DefaultBufferMaxRows;
            foreach (IDTSComponentMetaDataXX component in pipeline.ComponentMetaDataCollection)
            {
                DtsObjectPerformance perf = new DtsObjectPerformance(component.ID.ToString(), component.Name, component.GetType(), Indent + 1);
                Children.Add(perf);
                listTransformsPerformanceLookup.Add(component.ID, perf);
            }
            foreach (IDTSPathXX path in pipeline.PathCollection)
            {
                PipelinePath p = new PipelinePath();
                p.ID = path.ID;
                p.UniqueId = ID + "Path" + path.ID;
                p.OutputID = path.StartPoint.ID;
                p.OutputName = path.StartPoint.Name;
                p.OutputTransformID = path.StartPoint.Component.ID;
                p.OutputTransformName = path.StartPoint.Component.Name;
                p.OutputTransformType = path.StartPoint.Component.ObjectType;
                p.InputID = path.EndPoint.ID;
                p.InputName = path.EndPoint.Name;
                p.InputTransformID = path.EndPoint.Component.ID;
                p.InputTransformName = path.EndPoint.Component.Name;
                p.InputTransformType = path.EndPoint.Component.ObjectType;
                p.Indent = this.Indent + 2; //TODO: indent the paths recursively? probably good enough for now
                InputOutputLookup.Add(p.InputID, p);
                InputOutputLookup.Add(p.OutputID, p);

                foreach (IDTSOutputColumnXX col in path.StartPoint.OutputColumnCollection)
                {
                    if (!p.dictLineageIDColumnSizes.ContainsKey(col.LineageID))
                        p.dictLineageIDColumnSizes.Add(col.LineageID, GetColumnSizeInBytes(col));
                }
            }

            //hook up PreviousPath
            foreach (IDTSPathXX path in pipeline.PathCollection)
            {
                if (path.StartPoint.SynchronousInputID != 0)
                {
                    PipelinePath p = InputOutputLookup[path.StartPoint.ID];
                    p.PreviousPath = InputOutputLookup[path.StartPoint.SynchronousInputID];
                }
            }
        }