Esempio n. 1
0
 internal void PostStatus(NodeStatus nodeStatus, bool blockUntilSent)
 {
     try
     {
         PostStatusThrow(nodeStatus, blockUntilSent);
     }
     catch (Exception e)
     {
         ReportUnhandledError(e);
     }
 }
Esempio n. 2
0
 internal override void CreateFromStream(BinaryReader reader)
 {
     base.CreateFromStream(reader);
     if (reader.ReadByte() == 0)
     {
         nodeStatus = null;
     }
     else
     {
         nodeStatus = NodeStatus.CreateFromStream(reader);
     }
 }
Esempio n. 3
0
        internal static NodeStatus CreateFromStream(BinaryReader reader)
        {
            NodeStatus status = new NodeStatus(null);

            status.traversalType               = reader.ReadBoolean();
            status.statusTimeStamp             = reader.ReadInt64();
            status.requestId                   = reader.ReadInt32();
            status.isActive                    = reader.ReadBoolean();
            status.isLaunchInProgress          = reader.ReadBoolean();
            status.queueDepth                  = reader.ReadInt32();
            status.lastTaskActivityTimeStamp   = reader.ReadInt64();
            status.lastEngineActivityTimeStamp = reader.ReadInt64();

            if (reader.ReadByte() == 0)
            {
                status.stateOfInProgressTargets = null;
            }
            else
            {
                int numberOfInProgressTargets = reader.ReadInt32();
                status.stateOfInProgressTargets = new TargetInProgessState[numberOfInProgressTargets];
                for (int i = 0; i < numberOfInProgressTargets; i++)
                {
                    if (reader.ReadByte() == 0)
                    {
                        status.stateOfInProgressTargets[i] = null;
                    }
                    else
                    {
                        TargetInProgessState state = new TargetInProgessState();
                        state.CreateFromStream(reader);
                        status.stateOfInProgressTargets[i] = state;
                    }
                }
            }

            if (reader.ReadByte() == 0)
            {
                status.unhandledException = null;
            }
            else
            {
                status.unhandledException = (Exception)formatter.Deserialize(reader.BaseStream);
            }
            return(status);
        }
Esempio n. 4
0
        internal void PostNodeStatus(int nodeId, NodeStatus nodeStatus)
        {
            ErrorUtilities.VerifyThrow(nodeStatus.RequestId != NodeStatus.UnrequestedStatus,
                                       "Node manager should not receive unrequested status");

            NodeStatus[] currentStatus = statusForNodes;

            for (int i = 0; i < nodeList.Count; i++)
            {
                if (nodeList[i].NodeId == nodeId)
                {
                    currentStatus[i] = nodeStatus;
                    break;
                }
            }

            statusReplyCount++;
            statusMessageReceived.Set();
        }
Esempio n. 5
0
        /// <summary>
        /// Request status from all nodes in the system
        /// </summary>
        /// <param name="responseTimeout"></param>
        /// <returns></returns>
        internal NodeStatus[] RequestStatusForNodes(int responseTimeout)
        {
            int requestId = 0;

            statusForNodes   = new NodeStatus[nodeList.Count];
            statusReplyCount = 0;
            statusMessageReceived.Reset();

            // Request status from all registered nodes
            for (int i = 0; i < nodeList.Count; i++)
            {
                nodeList[i].NodeProvider.RequestNodeStatus(nodeList[i].NodeIndex, requestId);
            }

            long startTime = DateTime.Now.Ticks;

            while (statusReplyCount < nodeList.Count)
            {
                if (statusMessageReceived.WaitOne(responseTimeout, false))
                {
                    // We received another reply
                    statusMessageReceived.Reset();
                    // Calculate the time remaining and only continue if there is time left
                    TimeSpan timeSpent = new TimeSpan(DateTime.Now.Ticks - startTime);
                    startTime       = DateTime.Now.Ticks;
                    responseTimeout = responseTimeout - (int)timeSpent.TotalMilliseconds;
                    if (responseTimeout <= 0)
                    {
                        Console.WriteLine("Response time out out exceeded :" + DateTime.Now.Ticks);
                        break;
                    }
                }
                else
                {
                    // Timed out waiting for the response from the node
                    Console.WriteLine("Response time out out exceeded:" + DateTime.Now.Ticks);
                    break;
                }
            }

            return(statusForNodes);
        }
Esempio n. 6
0
        /// <summary>
        /// The coordinating engine is requesting status
        /// </summary>
        internal void RequestStatus(int requestId)
        {
            // Check if the status has been requested before the local
            // engine has been started.
            if (localEngine == null)
            {
                NodeStatus nodeStatus = null;

                lock (buildRequests)
                {
                    nodeStatus = new NodeStatus(requestId, true, buildRequests.Count, 0, 0, false);
                }

                parentCallback.PostStatus(nodeId, nodeStatus, false);
            }
            else
            {
                // Since the local engine has been started - ask it for status
                RequestStatusEngineCommand requestStatus = new RequestStatusEngineCommand(requestId);
                localEngine.PostEngineCommand(requestStatus);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// This function can be used by the node provider to report a failure which doesn't prevent further
        /// communication with the parent node. The node will attempt to notify the parent of the failure,
        /// send all outstanding logging events and shutdown.
        /// </summary>
        /// <param name="originalException"></param>
        /// <exception cref="Exception">Throws exception (with nested original exception) if reporting to parent fails.</exception>
        internal void ReportUnhandledError(Exception originalException)
        {
            NodeStatus nodeStatus = new NodeStatus(originalException);

            if (Engine.debugMode)
            {
                Console.WriteLine("Node.ReportUnhandledError: " + originalException.Message);
            }

            try
            {
                try
                {
                    PostStatusThrow(nodeStatus, true /* wait for the message to be sent before returning */);
                }
                catch (Exception ex)
                {
                    // If an error occurred while trying to send the original exception to the parent
                    // rethrow the original exception
                    string message = ResourceUtilities.FormatResourceString("FatalErrorOnChildNode", nodeId, ex.Message);

                    ErrorUtilities.LaunchMsBuildDebuggerOnFatalError();

                    throw new Exception(message, originalException);
                }
            }
            finally
            {
                // Makesure we write the exception to a file so even if something goes wrong with the logging or transfer to the parent
                // then we will atleast get the message on disk.
                LocalNode.DumpExceptionToFile(originalException);
            }

            if (localEngine != null)
            {
                localEngine.Shutdown();
            }
        }
Esempio n. 8
0
        /// <summary>
        /// This method is called to post the status of the node. Because status is used
        /// to report errors and to respond to inactivity notices, we use a separate queue
        /// to deliver status event to the shared memory. Otherwise status maybe be delayed
        /// if it is stuck behind a large number of other events. We also wait for the status
        /// to be sent before returning.
        /// </summary>
        public void PostStatus(int nodeId, NodeStatus nodeStatus, bool blockUntilSent)
        {
            // We should not be on the running on the callback writer thread
            ErrorUtilities.VerifyThrow(Thread.CurrentThread != writerThread, "Should never call this function from the writer thread");

            LocalCallDescriptorForPostStatus callDescriptor =
                new LocalCallDescriptorForPostStatus(nodeStatus);

            nodeHiPriCommandQueue.Enqueue(callDescriptor);

            // We need to block until the event we posted has been processed, but if the writer thread
            // exit due to an error the shared memory is no longer valid so there is no way to send the message
            while (blockUntilSent && !writerThreadHasExited && nodeHiPriCommandQueue.Count > 0)
            {
                nodeHiPriCommandQueue.QueueEmptyEvent.WaitOne(1000, false);

                // Check if the communication threads are supposed to exit
                if (exitCommunicationThreads.WaitOne(0, false))
                {
                    break;
                }
            }
        }
Esempio n. 9
0
 internal override void CreateFromStream(BinaryReader reader)
 {
     base.CreateFromStream(reader);
     if (reader.ReadByte() == 0)
     {
         nodeStatus = null;
     }
     else
     {
         nodeStatus = NodeStatus.CreateFromStream(reader);
     }
 }
Esempio n. 10
0
 internal LocalCallDescriptorForPostStatus(NodeStatus nodeStatus)
     : base(LocalCallType.PostStatus)
 {
     this.nodeStatus = nodeStatus;
 }
Esempio n. 11
0
 /// <summary>
 /// This method is called to post the status of the node
 /// </summary>
 public void PostStatus(int nodeId, NodeStatus nodeStatus, bool blockUntilSent)
 {
     parentEngine.PostNodeStatus(nodeId, nodeStatus);
 }
Esempio n. 12
0
        /// <summary>
        /// Adds a set of nodeStatus's to the cycle graph 
        /// </summary>
        private void AddTargetStatesToCycleDetector(NodeStatus[] nodeStatus, TargetCycleDetector cycleDetector)
        {

            for (int i = 0; i < nodeStatus.Length; i++)
            {
               cycleDetector.AddTargetsToGraph(nodeStatus[i].StateOfInProgressTargets);
            }
        }
Esempio n. 13
0
 internal LocalCallDescriptorForPostStatus(NodeStatus nodeStatus)
     : base(LocalCallType.PostStatus)
 {
     this.nodeStatus = nodeStatus;
 }
Esempio n. 14
0
        /// <summary>
        /// The coordinating engine is requesting status
        /// </summary>
        internal void RequestStatus(int requestId)
        {
            // Check if the status has been requested before the local
            // engine has been started.
            if (localEngine == null)
            {
                NodeStatus nodeStatus = null;

                lock (buildRequests)
                {
                    nodeStatus = new NodeStatus(requestId, true, buildRequests.Count, 0, 0, false);
                }

                parentCallback.PostStatus(nodeId, nodeStatus, false);
            }
            else
            {
                // Since the local engine has been started - ask it for status
                RequestStatusEngineCommand requestStatus = new RequestStatusEngineCommand(requestId);
                localEngine.PostEngineCommand(requestStatus);
            }
        }
Esempio n. 15
0
 internal void PostStatus(NodeStatus nodeStatus, bool blockUntilSent)
 {
     try
     {
         PostStatusThrow(nodeStatus, blockUntilSent);
     }
     catch (Exception e)
     {
         ReportUnhandledError(e);
     }
 }
Esempio n. 16
0
        /// <summary>
        /// This function collects status about the inprogress targets and engine operations. 
        /// This function should always run from the engine domain because it touch engine data
        /// structures.
        /// </summary>
        internal NodeStatus RequestStatus(int requestId)
        {
            // Find out the list of the inprogress waiting targets
            List<BuildRequest []> outstandingRequests = new List<BuildRequest []>();
            int [] handleIds = NodeManager.TaskExecutionModule.GetWaitingTaskData(outstandingRequests);
            Target [] waitingTargets = EngineCallback.GetListOfTargets(handleIds);

            // Find out the list of targets waiting due to dependency or onerror call but not actively in progress
            List<Project> inProgressProject = cacheOfBuildingProjects.GetInProgressProjects();
            List<Target> inProgressTargets = new List<Target>();
            foreach (Project project in inProgressProject)
            {
                foreach (Target target in project.Targets)
                {
                    if (target.ExecutionState != null && target.ExecutionState.BuildingRequiredTargets)
                    {
                        inProgressTargets.Add(target);
                    }
                }
            }
            TargetInProgessState[] stateOfInProgressTargets = 
                    new TargetInProgessState[waitingTargets.Length + inProgressTargets.Count];
            for (int i = 0; i < waitingTargets.Length; i++)
            {
                stateOfInProgressTargets[i] = null;
                // Skip if the in progress task has already completed (the task is running in the TEM domain)
                if (waitingTargets[i] != null)
                {
                    TargetExecutionWrapper executionState = waitingTargets[i].ExecutionState;
                    // Skip the target if it has already completed
                    if (executionState != null)
                    {
                        stateOfInProgressTargets[i] =
                            new TargetInProgessState(EngineCallback, waitingTargets[i], executionState.GetWaitingBuildContexts(),
                                                     executionState.InitiatingBuildContext,
                                                     outstandingRequests[i], waitingTargets[i].ParentProject.FullFileName);
                    }
                }
            }
            for (int i = 0; i < inProgressTargets.Count; i++)
            {
                TargetExecutionWrapper executionState = inProgressTargets[i].ExecutionState;
                ErrorUtilities.VerifyThrow(executionState != null,
                                           "Engine thread is blocked so target state should not change");

                stateOfInProgressTargets[waitingTargets.Length + i] =
                    new TargetInProgessState(EngineCallback, inProgressTargets[i], executionState.GetWaitingBuildContexts(),
                                             executionState.InitiatingBuildContext,
                                             null, inProgressTargets[i].ParentProject.FullFileName);
            }

            NodeStatus nodeStatus = new NodeStatus(requestId, true, buildRequests.Count + taskOutputUpdates.Count,
                                                   NodeManager.TaskExecutionModule.LastTaskActivity(),
                                                   lastLoopActivity, false);

            nodeStatus.StateOfInProgressTargets = stateOfInProgressTargets;

            return nodeStatus;
        }
Esempio n. 17
0
 /// <summary>
 /// A variation of PostStatus that throws instead of calling ReportUnhandledError
 /// if there's a problem. This allows ReportUnhandledError itself to post status
 /// without the possibility of a loop.
 /// </summary>
 internal void PostStatusThrow(NodeStatus nodeStatus, bool blockUntilSent)
 {
     parentCallback.PostStatus(nodeId, nodeStatus, blockUntilSent);
 }
Esempio n. 18
0
        internal void PostNodeStatus(int postingNodeId, NodeStatus nodeStatus)
        {
            if (nodeStatus.RequestId != NodeStatus.UnrequestedStatus)
            {
                nodeManager.PostNodeStatus(postingNodeId, nodeStatus);
            }
            else if (nodeStatus.UnhandledException != null)
            {
                PostEngineCommand(new ReportExceptionEngineCommand(nodeStatus.UnhandledException));
            }
            else
            {
                if (!Router.ChildMode)
                {
                    // If we are changing to breadth first traversal it means we are out of work. Traversal type is false when depth first is requested
                    if (nodeStatus.TraversalType)
                    {
                        Scheduler.NotifyOfBlockedNode(postingNodeId);
                    }
                    else if (Engine.debugMode && !nodeStatus.TraversalType)
                    {
                        Console.WriteLine("Switch to Depth first traversal is requested by " + postingNodeId);
                    }
                }

                PostEngineCommand(new ChangeTraversalTypeCommand(nodeStatus.TraversalType, false));
            }
        }
Esempio n. 19
0
        internal static NodeStatus CreateFromStream(BinaryReader reader)
        {
            NodeStatus status = new NodeStatus(null);
            status.traversalType = reader.ReadBoolean();
            status.statusTimeStamp = reader.ReadInt64();
            status.requestId = reader.ReadInt32();
            status.isActive = reader.ReadBoolean();
            status.isLaunchInProgress = reader.ReadBoolean();
            status.queueDepth = reader.ReadInt32();
            status.lastTaskActivityTimeStamp = reader.ReadInt64();
            status.lastEngineActivityTimeStamp = reader.ReadInt64();

            if (reader.ReadByte() == 0)
            {
                status.stateOfInProgressTargets = null;
            }
            else
            {
                int numberOfInProgressTargets = reader.ReadInt32();
                status.stateOfInProgressTargets = new TargetInProgessState[numberOfInProgressTargets];
                for (int i = 0; i < numberOfInProgressTargets; i++)
                {
                    if (reader.ReadByte() == 0)
                    {
                        status.stateOfInProgressTargets[i] = null;
                    }
                    else
                    {
                        TargetInProgessState state = new TargetInProgessState();
                        state.CreateFromStream(reader);
                        status.stateOfInProgressTargets[i] = state;
                    }
                }
            }

            if (reader.ReadByte() == 0)
            {
                status.unhandledException = null;
            }
            else
            {
                status.unhandledException = (Exception)formatter.Deserialize(reader.BaseStream);
            }
            return status;
        }
Esempio n. 20
0
        /// <summary>
        /// This method is called when the parent engine doesn't see activity for a preset time period to
        /// determine if the whole system is making forward progress. In order to that, status is collected
        /// from every node in the system. If no node is making forward progress then the graph of all the
        /// inprogress targets is analyzed for cycles. If a cycle is found the appropriate node is instructed
        /// to break it. If no cause for deadlock can be determined the system is shutdown.
        /// </summary>
        /// <returns>New inactivity timeout</returns>
        internal int DetectDeadlock(int queueCounts, long lastLoopActivity, int currentTimeout)
        {
            // Don't try to detect deadlock in single threaded mode or on a child node
            if (parentEngine.Router.ChildMode || parentEngine.Router.SingleThreadedMode)
            {
                return(Timeout.Infinite);
            }

            // Calculate time since last loop activity
            TimeSpan timeSinceLastLoopActivity =
                new TimeSpan(DateTime.Now.Ticks - lastLoopActivity);

            // If there are items in the queue waiting to be processed or there was loop activity
            // not so long ago - continue
            if (queueCounts > 0 || timeSinceLastLoopActivity.TotalMilliseconds < currentTimeout)
            {
                return(currentTimeout);
            }

            if (nodeManager.TaskExecutionModule == null)
            {
                return(currentTimeout);
            }

            // Calculate the time since the last task activity
            TimeSpan timeSinceLastTEMActivity =
                new TimeSpan(DateTime.Now.Ticks - nodeManager.TaskExecutionModule.LastTaskActivity());

            // If there was not task activity for the whole time period - check with individual nodes
            // to see if there was activity there
            if (timeSinceLastTEMActivity.TotalMilliseconds < currentTimeout)
            {
                // Increase the timeout since tasks are taking a long time
                return(calculateNewLoopTimeout(currentTimeout));
            }

            // Check if we are waiting on an outcome of an operation
            if ((ignoreTimeout - DateTime.Now.Ticks) > 0)
            {
                return(currentTimeout);
            }

            long requestStartTime = DateTime.Now.Ticks;

            NodeStatus[] nodeStatus          = nodeManager.RequestStatusForNodes(nodeStatusReplyTimeout);
            long         requestDurationTime = DateTime.Now.Ticks - requestStartTime;

            for (int i = 0; i < nodeStatus.Length; i++)
            {
                if (nodeStatus[i] == null)
                {
                    // A node failed to respond to the request for status. The only option is to shutdown
                    // the build and error out
                    LogOrDumpError("FailedToReceiveChildStatus", i + 1, nodeStatusReplyTimeout);

                    SystemShutdown();
                    return(currentTimeout);
                }
                else if (nodeStatus[i].HasExited)
                {
                    // A node has exited prematurely. The only option is to shutdown
                    LogOrDumpError("ChildExitedPrematurely", i + 1);

                    SystemShutdown();
                    return(currentTimeout);
                }
                else if (nodeStatus[i].IsActive)
                {
                    // Calculate the time since last node activity
                    TimeSpan timeSinceLastNodeTaskActivity = new TimeSpan(nodeStatus[i].TimeSinceLastTaskActivity);
                    TimeSpan timeSinceLastNodeLoopActivity = new TimeSpan(nodeStatus[i].TimeSinceLastLoopActivity);

                    // Check if there was activity on the node within the timeout
                    if (nodeStatus[i].QueueDepth > 0 ||
                        timeSinceLastNodeTaskActivity.TotalMilliseconds < currentTimeout ||
                        timeSinceLastNodeLoopActivity.TotalMilliseconds < currentTimeout)
                    {
                        // If the time out has been exceeded while one of the nodes was
                        // active lets increase the timeout
                        return(calculateNewLoopTimeout(currentTimeout));
                    }
                }
                else if (nodeStatus[i].IsLaunchInProgress)
                {
                    // If there is a node in process of being launched, only the NodeProvider
                    // knows how long that should take so the decision to error out can
                    // only be made by the node provider.
                    return(currentTimeout);
                }
            }

            // There was no detected activity within the system for the whole time period. Check
            // if there is a cycle in the in progress targets
            TargetCycleDetector cycleDetector = new TargetCycleDetector(parentEngine.LoggingServices, parentEngine.EngineCallback);

            AddTargetStatesToCycleDetector(nodeStatus, cycleDetector);
            NodeStatus localStatus = parentEngine.RequestStatus(0);

            cycleDetector.AddTargetsToGraph(localStatus.StateOfInProgressTargets);


            if (cycleDetector.FindCycles())
            {
                if (Engine.debugMode)
                {
                    Console.WriteLine("Breaking cycle between " + cycleDetector.CycleEdgeChild.TargetId.name + " and " +
                                      cycleDetector.CycleEdgeParent.TargetId.name);
                }
                // A cycle has been detected - it needs to be broken for the build to continue
                nodeManager.PostCycleNotification(cycleDetector.CycleEdgeChild.TargetId.nodeId,
                                                  cycleDetector.CycleEdgeChild,
                                                  cycleDetector.CycleEdgeParent);
                // Use the amount of time it took us to receive the NodeStatus and buffer it a little because node status is sent via a faster code path
                ignoreTimeout = DateTime.Now.Ticks + requestDurationTime + (cycleBreakTimeout * TimeSpan.TicksPerMillisecond);
                return(currentTimeout);
            }

            // The system doesn't appear to be making progress. Switch to a largest sampling interval.
            if (currentTimeout != maxLoopTimeout)
            {
                return(maxLoopTimeout);
            }

            // Should make at least two observations before assuming that no forward progress is being made
            if (previousStatus == null || previousLocalStatus == null || nodeStatus.Length != previousStatus.Length)
            {
                previousStatus      = nodeStatus;
                previousLocalStatus = localStatus;
                return(currentTimeout);
            }

            // There was some activity between previous and current status checks on the local node
            if (localStatus.LastLoopActivity != previousLocalStatus.LastLoopActivity ||
                localStatus.LastTaskActivity != previousLocalStatus.LastTaskActivity)
            {
                previousStatus      = nodeStatus;
                previousLocalStatus = localStatus;
                return(currentTimeout);
            }

            for (int i = 0; i < nodeStatus.Length; i++)
            {
                // There was some activity between previous and current status checks on the child node
                if (nodeStatus[i].LastTaskActivity != previousStatus[i].LastTaskActivity ||
                    nodeStatus[i].LastLoopActivity != previousStatus[i].LastLoopActivity)
                {
                    previousStatus      = nodeStatus;
                    previousLocalStatus = localStatus;
                    return(currentTimeout);
                }
            }

            // The system is not making forward progress for an unknown reason. The
            // only recourse to is to collect as much data as possible and shutdown with
            // an error message
            // UNDONE - using logging and resource string to output the state dump

            GatherNodeInformationForShutdown(nodeStatus, localStatus);
            SystemShutdown();
            return(currentTimeout);
        }
Esempio n. 21
0
        /// <summary>
        /// The system is not making forward progress for an unknown reason. The
        /// only recourse to is to collect as much data as possible and shutdown with
        /// an error message
        /// </summary>
        private void GatherNodeInformationForShutdown(NodeStatus[] nodeStatus, NodeStatus localStatus)
        {
            for (int i = 0; i < nodeStatus.Length; i++)
            {

                TimeSpan timeSinceLastNodeTaskActivity = new TimeSpan(nodeStatus[i].TimeSinceLastTaskActivity);
                TimeSpan timeSinceLastNodeLoopActivity = new TimeSpan(nodeStatus[i].TimeSinceLastLoopActivity);
 
                Console.WriteLine("Status: " + i + " Task Activity " + timeSinceLastNodeTaskActivity.TotalMilliseconds +
                                  " Loop Activity " + timeSinceLastNodeLoopActivity.TotalMilliseconds + " Queue depth " +
                                  nodeStatus[i].QueueDepth);
                for (int j = 0; j < nodeStatus[i].StateOfInProgressTargets.Length; j++)
                {
                    Console.WriteLine(nodeStatus[i].StateOfInProgressTargets[j].ProjectName + ":" + nodeStatus[i].StateOfInProgressTargets[j].TargetId.name);
                }
            }

            Console.WriteLine("Status: LocalNode Task Activity " + localStatus.TimeSinceLastTaskActivity +
                                  " Loop Activity " + localStatus.TimeSinceLastLoopActivity + " Queue depth " +
                                  localStatus.QueueDepth);

            for (int j = 0; j < localStatus.StateOfInProgressTargets.Length; j++)
            {
                Console.WriteLine(localStatus.StateOfInProgressTargets[j].ProjectName + ":" + localStatus.StateOfInProgressTargets[j].TargetId.name);
            }

            parentEngine.Scheduler.DumpState();

        }
Esempio n. 22
0
 /// <summary>
 /// This method is called to post the status of the node
 /// </summary>
 public void PostStatus(int nodeId, NodeStatus nodeStatus, bool blockUntilSent)
 {
     parentEngine.PostNodeStatus(nodeId, nodeStatus);
 }
Esempio n. 23
0
        /// <summary>
        /// This method is called to post the status of the node. Because status is used
        /// to report errors and to respond to inactivity notices, we use a separate queue
        /// to deliver status event to the shared memory. Otherwise status maybe be delayed
        /// if it is stuck behind a large number of other events. We also wait for the status
        /// to be sent before returning.
        /// </summary>
        public void PostStatus(int nodeId, NodeStatus nodeStatus, bool blockUntilSent)
        {
            // We should not be on the running on the callback writer thread
            ErrorUtilities.VerifyThrow(Thread.CurrentThread != writerThread, "Should never call this function from the writer thread");

            LocalCallDescriptorForPostStatus callDescriptor =
                new LocalCallDescriptorForPostStatus(nodeStatus);
            nodeHiPriCommandQueue.Enqueue(callDescriptor);

            // We need to block until the event we posted has been processed, but if the writer thread
            // exit due to an error the shared memory is no longer valid so there is no way to send the message
            while (blockUntilSent && !writerThreadHasExited && nodeHiPriCommandQueue.Count > 0)
            {
                nodeHiPriCommandQueue.QueueEmptyEvent.WaitOne(1000, false);

                // Check if the communication threads are supposed to exit
                if (exitCommunicationThreads.WaitOne(0, false))
                {
                    break;
                }
            }
        }
Esempio n. 24
0
        /// <summary>
        /// Report communication failure and update internal state
        /// </summary>
        private void ReportNodeCommunicationFailure
        (
            int nodeIndex,
            Exception innerException, 
            bool decreaseActiveNodeCount
        )
        {
            // Indicate that communication with a particular node has failed
            if (nodeIndex >= 0 && nodeIndex < nodeData.Length)
            {
                if (decreaseActiveNodeCount && !nodeData[nodeIndex].CommunicationFailed)
                {
                    DecreaseActiveNodeCount(nodeData[nodeIndex].NodeId);
                }

                nodeData[nodeIndex].CommunicationFailed = true;
            }

            string message = ResourceUtilities.FormatResourceString("NodeProviderFailure");
            RemoteErrorException wrappedException = new RemoteErrorException(message, innerException, null);
            NodeStatus nodeStatus = new NodeStatus(wrappedException);

            if (nodeIndex < 0 || nodeIndex >= nodeData.Length)
            {
                // Bogus node index came out of the wait handle, perhaps due to memory pressure
                // We can't really do anything except re-throw so this problem can be diagnosed.
                throw wrappedException;
            }
            
            engineCallback.PostStatus(nodeData[nodeIndex].NodeId, nodeStatus, false);
        }
Esempio n. 25
0
 /// <summary>
 /// A variation of PostStatus that throws instead of calling ReportUnhandledError
 /// if there's a problem. This allows ReportUnhandledError itself to post status 
 /// without the possibility of a loop.
 /// </summary>
 internal void PostStatusThrow(NodeStatus nodeStatus, bool blockUntilSent)
 {
     parentCallback.PostStatus(nodeId, nodeStatus, blockUntilSent);
 }
Esempio n. 26
0
        internal void PostNodeStatus(int nodeId, NodeStatus nodeStatus)
        {
            ErrorUtilities.VerifyThrow( nodeStatus.RequestId != NodeStatus.UnrequestedStatus,
                                        "Node manager should not receive unrequested status");

            NodeStatus[] currentStatus = statusForNodes;

            for (int i = 0; i < nodeList.Count; i++)
            {
                if (nodeList[i].NodeId == nodeId)
                {
                    currentStatus[i] = nodeStatus;
                    break;
                }
            }

            statusReplyCount++;
            statusMessageReceived.Set();
        }
Esempio n. 27
0
        /// <summary>
        /// This function can be used by the node provider to report a failure which doesn't prevent further
        /// communication with the parent node. The node will attempt to notify the parent of the failure,
        /// send all outstanding logging events and shutdown.
        /// </summary>
        /// <param name="originalException"></param>
        /// <exception cref="Exception">Throws exception (with nested original exception) if reporting to parent fails.</exception>
        internal void ReportUnhandledError(Exception originalException)
        {
            NodeStatus nodeStatus = new NodeStatus(originalException);

            if (Engine.debugMode)
            {
                Console.WriteLine("Node.ReportUnhandledError: " + originalException.Message);
            }

            try
            {
                try
                {

                    PostStatusThrow(nodeStatus, true /* wait for the message to be sent before returning */);
                }
                catch (Exception ex)
                {
                    // If an error occured while trying to send the orginal exception to the parent 
                    // rethrow the original exception
                    string message = ResourceUtilities.FormatResourceString("FatalErrorOnChildNode", nodeId, ex.Message);

                    ErrorUtilities.LaunchMsBuildDebuggerOnFatalError();

                    throw new Exception(message, originalException);
                }
            }
            finally
            {
                // Makesure we write the exception to a file so even if something goes wrong with the logging or transfer to the parent
                // then we will atleast get the message on disk.
                LocalNode.DumpExceptionToFile(originalException);
            }

            if (localEngine != null)
            {
                localEngine.Shutdown();
            }
        }
Esempio n. 28
0
        /// <summary>
        /// Request status from all nodes in the system
        /// </summary>
        /// <param name="responseTimeout"></param>
        /// <returns></returns>
        internal NodeStatus[] RequestStatusForNodes(int responseTimeout)
        {
            int requestId = 0;

            statusForNodes = new NodeStatus[nodeList.Count];
            statusReplyCount = 0;
            statusMessageReceived.Reset();

            // Request status from all registered nodes
            for (int i = 0; i < nodeList.Count; i++)
            {
                nodeList[i].NodeProvider.RequestNodeStatus(nodeList[i].NodeIndex, requestId);
            }

            long startTime = DateTime.Now.Ticks;

            while (statusReplyCount < nodeList.Count)
            {
                if (statusMessageReceived.WaitOne(responseTimeout, false))
                {
                    // We received another reply
                    statusMessageReceived.Reset();
                    // Calculate the time remaining and only continue if there is time left
                    TimeSpan timeSpent = new TimeSpan(DateTime.Now.Ticks - startTime);
                    startTime = DateTime.Now.Ticks;
                    responseTimeout = responseTimeout - (int)timeSpent.TotalMilliseconds;
                    if (responseTimeout <= 0)
                    {
                        Console.WriteLine("Response time out out exceeded :" + DateTime.Now.Ticks);
                        break;
                    }
                }
                else
                {
                    // Timed out waiting for the response from the node
                    Console.WriteLine("Response time out out exceeded:" + DateTime.Now.Ticks);
                    break;
                }
            }

            return statusForNodes;
        }
Esempio n. 29
0
        public void RequestNodeStatus(int nodeIndex, int requestId)
        {
            ErrorUtilities.VerifyThrow(nodeLoggers != null, "Must call Initialize first");
            ErrorUtilities.VerifyThrow(nodeIndex < nodeData.Length && nodeIndex >= 0, "Node index must be within array boundaries");

            // If the node has not been launched we need to create a reply
            // on its behalf
            if (nodeData[nodeIndex].NodeState != NodeState.Launched)
            {
                NodeStatus nodeStatus = new NodeStatus(requestId, false, 0, 0, 0, (nodeData[nodeIndex].NodeState == NodeState.LaunchInProgress));
                engineCallback.PostStatus(nodeData[nodeIndex].NodeId, nodeStatus, false);
            }
            else if (!IsNodeProcessAliveOrUninitialized(nodeIndex))
            {
                NodeStatus nodeStatus = new NodeStatus(requestId); // Indicate that the node has exited
                engineCallback.PostStatus(nodeData[nodeIndex].NodeId, nodeStatus, false);
            }
            else
            {
                // Send the request to the node
                LocalCallDescriptorForRequestStatus callDescriptor =
                    new LocalCallDescriptorForRequestStatus(requestId);
                nodeData[nodeIndex].NodeCommandQueue.Enqueue(callDescriptor);
            }
        }
Esempio n. 30
0
        public void NodeStatusCustomSerialization()
        {
            // Stream, writer and reader where the events will be serialized and deserialized from
            MemoryStream stream = new MemoryStream();
            BinaryWriter writer = new BinaryWriter(stream);
            BinaryReader reader = new BinaryReader(stream);
            try
            {
                NodeStatus nodeStatus1 = new NodeStatus(1, true, 4, 1928374, 384923834, true);

                Exception except = new Exception("I am bad");
                NodeStatus nodeStatus2 = new NodeStatus(except);

                stream.Position = 0;
                // Serialize
                nodeStatus1.WriteToStream(writer);
                // Get position of stream after write so it can be compared to the position after read
                long streamWriteEndPosition = stream.Position;

                // Deserialize and Verify
                stream.Position = 0;
                NodeStatus newNodeStatus = NodeStatus.CreateFromStream(reader);
                long streamReadEndPosition = stream.Position;
                Assert.IsTrue(streamWriteEndPosition == streamReadEndPosition, "Stream End Positions Should Match");
                Assert.IsTrue(newNodeStatus.IsActive == newNodeStatus.IsActive);
                Assert.IsTrue(newNodeStatus.IsLaunchInProgress == nodeStatus1.IsLaunchInProgress);
                Assert.IsTrue(newNodeStatus.TimeSinceLastLoopActivity == nodeStatus1.TimeSinceLastLoopActivity);
                Assert.IsTrue(newNodeStatus.TimeSinceLastTaskActivity == nodeStatus1.TimeSinceLastTaskActivity);
                Assert.IsTrue(newNodeStatus.QueueDepth == nodeStatus1.QueueDepth);
                Assert.IsTrue(newNodeStatus.RequestId == nodeStatus1.RequestId);
                Assert.IsTrue(newNodeStatus.UnhandledException == null);

                stream.Position = 0;
                // Serialize
                nodeStatus2.WriteToStream(writer);
                // Get position of stream after write so it can be compared to the position after read
                streamWriteEndPosition = stream.Position;

                // Deserialize and Verify
                stream.Position = 0;
                newNodeStatus = NodeStatus.CreateFromStream(reader);
                streamReadEndPosition = stream.Position;
                Assert.IsTrue(streamWriteEndPosition == streamReadEndPosition, "Stream End Positions Should Match");
                Assert.IsTrue(newNodeStatus.IsActive == nodeStatus2.IsActive);
                Assert.IsTrue(newNodeStatus.IsLaunchInProgress == nodeStatus2.IsLaunchInProgress);
                Assert.IsTrue(newNodeStatus.TimeSinceLastLoopActivity == nodeStatus2.TimeSinceLastLoopActivity);
                Assert.IsTrue(newNodeStatus.TimeSinceLastTaskActivity == nodeStatus2.TimeSinceLastTaskActivity);
                Assert.IsTrue(newNodeStatus.QueueDepth == nodeStatus2.QueueDepth);
                Assert.IsTrue(newNodeStatus.RequestId == nodeStatus2.RequestId);
                Assert.IsTrue(newNodeStatus.UnhandledException.Message == nodeStatus2.UnhandledException.Message);
            }
            finally
            {
                // Close will close the writer/reader and the underlying stream
                writer.Close();
                reader.Close();
                reader = null;
                stream = null;
                writer = null;
            }
        }