Пример #1
0
        /// <summary>
        /// Retrieves a request which has been assigned to a node and is in the executing, blocked or ready states.
        /// </summary>
        public SchedulableRequest GetScheduledRequest(int globalRequestId)
        {
            SchedulableRequest returnValue = InternalGetScheduledRequestByGlobalRequestId(globalRequestId);

            ErrorUtilities.VerifyThrow(returnValue != null, "Global Request Id {0} has not been assigned and cannot be retrieved.", globalRequestId);
            return(returnValue);
        }
Пример #2
0
        /// <summary>
        /// Marks this request as being blocked by the specified request.  Establishes the correct relationships between the requests.
        /// </summary>
        /// <param name="blockingRequest">The request which is blocking this one.</param>
        /// <param name="activeTargets">The list of targets this request was currently building at the time it became blocked.</param>
        /// <param name="blockerBlockingTarget">Target that we are blocked on which is being built by <paramref name="blockingRequest"/></param>
        public void BlockByRequest(SchedulableRequest blockingRequest, string[] activeTargets, string blockingTarget = null)
        {
            VerifyOneOfStates(new SchedulableRequestState[] { SchedulableRequestState.Blocked, SchedulableRequestState.Executing });
            ErrorUtilities.VerifyThrowArgumentNull(blockingRequest, "blockingRequest");
            ErrorUtilities.VerifyThrowArgumentNull(activeTargets, "activeTargets");
            ErrorUtilities.VerifyThrow(BlockingTarget == null, "Cannot block again if we're already blocked on a target");

            // Note that the blocking request will typically be our parent UNLESS it is a request we blocked on because it was executing a target we wanted to execute.
            // Thus, we do not assert the parent-child relationship here.
            BlockingRequestKey key = new BlockingRequestKey(blockingRequest.BuildRequest);

            ErrorUtilities.VerifyThrow(!_requestsWeAreBlockedBy.ContainsKey(key), "We are already blocked by this request.");
            ErrorUtilities.VerifyThrow(!blockingRequest._requestsWeAreBlocking.Contains(this), "The blocking request thinks it is already blocking us.");

            // This method is only called when a request reports that it is blocked on other requests.  If the request is being blocked by a brand new
            // request, that request will be unscheduled.  If this request is blocked by an in-progress request which was executing a target it needed
            // to also execute, then that request is not unscheduled (because it was running on the node) and it is not executing (because this condition
            // can only occur against requests which are executing on the same node and since the request which called this method is the one currently
            // executing on that node, that means the request it is blocked by must either be itself blocked or ready.)
            blockingRequest.VerifyOneOfStates(new SchedulableRequestState[] { SchedulableRequestState.Yielding, SchedulableRequestState.Blocked, SchedulableRequestState.Ready, SchedulableRequestState.Unscheduled });

            // Update our list of active targets.  This has to be done before we detect circular dependencies because we use this information to detect
            // re-entrancy circular dependencies.
            _activeTargetsWhenBlocked = activeTargets;

            BlockingTarget = blockingTarget;

            DetectCircularDependency(blockingRequest);

            _requestsWeAreBlockedBy[key] = blockingRequest;
            blockingRequest._requestsWeAreBlocking.Add(this);

            ChangeToState(SchedulableRequestState.Blocked);
        }
Пример #3
0
 /// <summary>
 /// Constructor.
 /// </summary>
 public SchedulingEvent(DateTime eventTime, SchedulableRequest request, SchedulableRequestState oldState, SchedulableRequestState newState)
 {
     _eventTime = eventTime;
     _request   = request;
     _oldState  = oldState;
     _newState  = newState;
 }
Пример #4
0
        /// <summary>
        /// Creates a new request and adds it to the system
        /// </summary>
        /// <remarks>
        /// New requests always go on the front of the queue, because we prefer to build the projects we just received first (depth first, absent
        /// any particular scheduling algorithm such as in the single-proc case.)
        /// </remarks>
        public SchedulableRequest CreateRequest(BuildRequest buildRequest, SchedulableRequest parent)
        {
            SchedulableRequest request = new SchedulableRequest(this, buildRequest, parent);

            request.CreationTime = EventTime;

            LinkedListNode <SchedulableRequest> requestNode = _unscheduledRequests.AddFirst(request);

            _unscheduledRequestNodesByRequest[request] = requestNode;

            // Update the configuration information.
            HashSet <SchedulableRequest> requests;

            if (!_configurationToRequests.TryGetValue(request.BuildRequest.ConfigurationId, out requests))
            {
                requests = new HashSet <SchedulableRequest>();
                _configurationToRequests[request.BuildRequest.ConfigurationId] = requests;
            }

            requests.Add(request);

            // Update the build hierarchy.
            if (!_buildHierarchy.ContainsKey(request))
            {
                _buildHierarchy[request] = new List <SchedulableRequest>(8);
            }

            if (parent != null)
            {
                ErrorUtilities.VerifyThrow(_buildHierarchy.ContainsKey(parent), "Parent doesn't exist in build hierarchy for request {0}", request.BuildRequest.GlobalRequestId);
                _buildHierarchy[parent].Add(request);
            }

            return(request);
        }
Пример #5
0
        /// <summary>
        /// Removes associations with all blocking requests and throws an exception.
        /// </summary>
        private void CleanupForCircularDependencyAndThrow(SchedulableRequest requestCausingFailure, List <SchedulableRequest> ancestors)
        {
            if (_requestsWeAreBlockedBy.Count != 0)
            {
                List <SchedulableRequest> tempRequests = new List <SchedulableRequest>(_requestsWeAreBlockedBy.Values);
                foreach (SchedulableRequest requestWeAreBlockedBy in tempRequests)
                {
                    BlockingRequestKey key = new BlockingRequestKey(requestWeAreBlockedBy.BuildRequest);
                    DisconnectRequestWeAreBlockedBy(key);
                }
            }
            else
            {
                ChangeToState(SchedulableRequestState.Ready);
            }

            _activeTargetsWhenBlocked = null;

            // The blocking request itself is no longer valid if it was unscheduled.
            if (requestCausingFailure.State == SchedulableRequestState.Unscheduled)
            {
                requestCausingFailure.Delete();
            }

            throw new SchedulerCircularDependencyException(requestCausingFailure.BuildRequest, ancestors);
        }
Пример #6
0
        /// <summary>
        /// Gets the name of the plan file for a specified submission.
        /// </summary>
        private string GetPlanName(SchedulableRequest rootRequest)
        {
            if (rootRequest == null)
            {
                return(null);
            }

            return(_configCache[rootRequest.BuildRequest.ConfigurationId].ProjectFullPath + ".buildplan");
        }
Пример #7
0
        /// <summary>
        /// Reads a plan for the specified submission Id.
        /// </summary>
        public void ReadPlan(int submissionId, ILoggingService loggingService, BuildEventContext buildEventContext)
        {
            if (!BuildParameters.EnableBuildPlan)
            {
                return;
            }

            SchedulableRequest rootRequest = GetRootRequest(submissionId);

            if (rootRequest == null)
            {
                return;
            }

            string planName = GetPlanName(rootRequest);

            if (String.IsNullOrEmpty(planName))
            {
                return;
            }

            if (!FileSystems.Default.FileExists(planName))
            {
                return;
            }

            try
            {
                using (StreamReader file = new StreamReader(File.Open(planName, FileMode.Open)))
                {
                    ReadTimes(file);
                    ReadHierarchy(file);
                }

                if (_configIdToData.Count > 0)
                {
                    AnalyzeData();
                }
            }
            catch (IOException)
            {
                loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceStringStripCodeAndKeyword("CantReadBuildPlan", planName));
            }
            catch (InvalidDataException)
            {
                loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceStringStripCodeAndKeyword("BuildPlanCorrupt", planName));
            }
            catch (FormatException)
            {
                loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceStringStripCodeAndKeyword("BuildPlanCorrupt", planName));
            }
        }
Пример #8
0
        /// <summary>
        /// Verifies that the request is scheduled and in the expected state.
        /// </summary>
        private void ExpectScheduledRequestState(int globalRequestId, SchedulableRequestState state)
        {
            SchedulableRequest request = InternalGetScheduledRequestByGlobalRequestId(globalRequestId);

            if (request == null)
            {
                ErrorUtilities.ThrowInternalError("Request {0} was expected to be in state {1} but is not scheduled at all (it may be unscheduled or may be unknown to the system.)", globalRequestId, state);
            }
            else
            {
                request.VerifyState(state);
            }
        }
Пример #9
0
        /// <summary>
        /// Detects a circular dependency where the request which is about to block us is already blocked by us, usually as a result
        /// of it having been previously scheduled in a multiproc scenario, but before this request was able to execute.
        /// </summary>
        /// <remarks>
        /// Let A be 'this' project and B be 'blockingRequest' (the request which is going to block A.)
        /// An indirect circular dependency exists if there is a dependency path from B to A.  If there is no
        /// existing blocked request B' with the same global request id as B, then there can be no path from B to A because B is a brand new
        /// request with no other dependencies.  If there is an existing blocked request B' with the same global request ID as B, then we
        /// walk the set of dependencies recursively searching for A.  If A is found, we have a circular dependency.
        /// </remarks>
        private void DetectIndirectCircularDependency(SchedulableRequest blockingRequest)
        {
            // If there is already a blocked request which has the same configuration id as the blocking request and that blocked request is (recursively)
            // waiting on this request, then that is an indirect circular dependency.
            SchedulableRequest alternateRequest = _schedulingData.GetBlockedRequestIfAny(blockingRequest.BuildRequest.GlobalRequestId);

            if (alternateRequest == null)
            {
                return;
            }

            Stack <SchedulableRequest>   requestsToEvaluate = new Stack <SchedulableRequest>(16);
            HashSet <SchedulableRequest> evaluatedRequests  = new HashSet <SchedulableRequest>();

            requestsToEvaluate.Push(alternateRequest);

            while (requestsToEvaluate.Count > 0)
            {
                SchedulableRequest requestToEvaluate = requestsToEvaluate.Pop();

                // If we make it to a child which is us, then it's a circular dependency.
                if (requestToEvaluate.BuildRequest.GlobalRequestId == this.BuildRequest.GlobalRequestId)
                {
                    ThrowIndirectCircularDependency(blockingRequest, requestToEvaluate);
                }

                evaluatedRequests.Add(requestToEvaluate);

                // If the request is not scheduled, it's possible that is because it's been scheduled elsewhere and is blocked.
                // Follow that path if it exists.
                if (requestToEvaluate.State == SchedulableRequestState.Unscheduled)
                {
                    requestToEvaluate = _schedulingData.GetBlockedRequestIfAny(requestToEvaluate.BuildRequest.GlobalRequestId);

                    // If there was no scheduled request to evaluate, move on.
                    if (requestToEvaluate == null || evaluatedRequests.Contains(requestToEvaluate))
                    {
                        continue;
                    }
                }

                // This request didn't cause a circular dependency, check its children.
                foreach (SchedulableRequest childRequest in requestToEvaluate.RequestsWeAreBlockedBy)
                {
                    if (!evaluatedRequests.Contains(childRequest))
                    {
                        requestsToEvaluate.Push(childRequest);
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Recursively accumulates the amount of time spent in each configuration.
        /// </summary>
        private void RecursiveAccumulateConfigurationTimes(SchedulableRequest request, Dictionary <int, double> accumulatedTimeByConfiguration)
        {
            double accumulatedTime;

            // NOTE: Do we want to count it each time the config appears in the hierarchy?  This will inflate the
            // cost of frequently referenced configurations.
            accumulatedTimeByConfiguration.TryGetValue(request.BuildRequest.ConfigurationId, out accumulatedTime);
            accumulatedTimeByConfiguration[request.BuildRequest.ConfigurationId] = accumulatedTime + request.GetTimeSpentInState(SchedulableRequestState.Executing).TotalMilliseconds;

            foreach (SchedulableRequest childRequest in _schedulingData.GetRequestsByHierarchy(request))
            {
                RecursiveAccumulateConfigurationTimes(childRequest, accumulatedTimeByConfiguration);
            }
        }
Пример #11
0
        /// <summary>
        /// Build our ancestor list then throw the circular dependency error.
        /// </summary>
        private void ThrowIndirectCircularDependency(SchedulableRequest blockingRequest, SchedulableRequest requestToEvaluate)
        {
            // We found a request which has the same global request ID as us in a chain which leads from the (already blocked) request
            // which is trying to block us.  Calculate its list of ancestors by walking up the parent list.
            List <SchedulableRequest> ancestors = new List <SchedulableRequest>(16);

            while (requestToEvaluate.Parent != null)
            {
                ancestors.Add(requestToEvaluate.Parent);
                requestToEvaluate = requestToEvaluate.Parent;
            }

            ancestors.Reverse(); // Because the list should be in the order from root to child.
            CleanupForCircularDependencyAndThrow(blockingRequest, ancestors);
        }
Пример #12
0
        /// <summary>
        /// Writes out all of the dependencies for a specified request, recursively.
        /// </summary>
        private void RecursiveWriteDependencies(StreamWriter file, SchedulableRequest request)
        {
            file.Write(request.BuildRequest.ConfigurationId);
            foreach (SchedulableRequest child in _schedulingData.GetRequestsByHierarchy(request))
            {
                file.Write(" {0}", child.BuildRequest.ConfigurationId);
            }

            file.WriteLine();

            foreach (SchedulableRequest child in _schedulingData.GetRequestsByHierarchy(request))
            {
                RecursiveWriteDependencies(file, child);
            }
        }
Пример #13
0
        /// <summary>
        /// Writes a plan for the specified submission id.
        /// </summary>
        public void WritePlan(int submissionId, ILoggingService loggingService, BuildEventContext buildEventContext)
        {
            if (!BuildParameters.EnableBuildPlan)
            {
                return;
            }

            SchedulableRequest rootRequest = GetRootRequest(submissionId);

            if (rootRequest == null)
            {
                return;
            }

            string planName = GetPlanName(rootRequest);

            if (String.IsNullOrEmpty(planName))
            {
                return;
            }

            try
            {
                using (StreamWriter file = new StreamWriter(File.Open(planName, FileMode.Create)))
                {
                    // Write the accumulated configuration times.
                    Dictionary <int, double> accumulatedTimeByConfiguration = new Dictionary <int, double>();
                    RecursiveAccumulateConfigurationTimes(rootRequest, accumulatedTimeByConfiguration);

                    List <int> configurationsInOrder = new List <int>(accumulatedTimeByConfiguration.Keys);
                    configurationsInOrder.Sort();
                    foreach (int configId in configurationsInOrder)
                    {
                        file.WriteLine(String.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", configId, accumulatedTimeByConfiguration[configId], _configCache[configId].ProjectFullPath));
                    }

                    file.WriteLine();

                    // Write out the dependency information.
                    RecursiveWriteDependencies(file, rootRequest);
                }
            }
            catch (IOException)
            {
                loggingService.LogCommentFromText(buildEventContext, MessageImportance.Low, ResourceUtilities.FormatResourceStringStripCodeAndKeyword("CantWriteBuildPlan", planName));
            }
        }
Пример #14
0
        /// <summary>
        /// Retrieves a set of build requests which have the specified parent.  If root is null, this will retrieve all of the
        /// top-level requests.
        /// </summary>
        public IEnumerable <SchedulableRequest> GetRequestsByHierarchy(SchedulableRequest root)
        {
            if (root == null)
            {
                // Retrieve all requests which are roots of the tree.
                List <SchedulableRequest> roots = new List <SchedulableRequest>();
                foreach (SchedulableRequest key in _buildHierarchy.Keys)
                {
                    if (key.Parent == null)
                    {
                        roots.Add(key);
                    }
                }

                return(roots);
            }

            return(_buildHierarchy[root]);
        }
Пример #15
0
        /// <summary>
        /// Detects a circular dependency where the blocking request is in our direct ancestor chain.
        /// </summary>
        private void DetectDirectCircularDependency(SchedulableRequest blockingRequest)
        {
            // A circular dependency occurs when this project (or any of its ancestors) has the same global request id as the
            // blocking request.
            List <SchedulableRequest> ancestors      = new List <SchedulableRequest>(16);
            SchedulableRequest        currentRequest = this;

            do
            {
                ancestors.Add(currentRequest);
                if (currentRequest.BuildRequest.GlobalRequestId == blockingRequest.BuildRequest.GlobalRequestId)
                {
                    // We are directly conflicting with an instance of ourselves.
                    CleanupForCircularDependencyAndThrow(blockingRequest, ancestors);
                }

                currentRequest = currentRequest.Parent;
            }while (currentRequest != null);
        }
Пример #16
0
        /// <summary>
        /// Constructor.
        /// </summary>
        public SchedulableRequest(SchedulingData collection, BuildRequest request, SchedulableRequest parent)
        {
            ErrorUtilities.VerifyThrowArgumentNull(collection, "collection");
            ErrorUtilities.VerifyThrowArgumentNull(request, "request");
            ErrorUtilities.VerifyThrow((parent == null) || (parent._schedulingData == collection), "Parent request does not belong to the same collection.");

            _schedulingData         = collection;
            _request                = request;
            _parent                 = parent;
            _assignedNodeId         = -1;
            _requestsWeAreBlockedBy = new Dictionary <BlockingRequestKey, SchedulableRequest>();
            _requestsWeAreBlocking  = new HashSet <SchedulableRequest>();

            _timeRecords = new Dictionary <SchedulableRequestState, ScheduleTimeRecord>(5);
            _timeRecords[SchedulableRequestState.Unscheduled] = new ScheduleTimeRecord();
            _timeRecords[SchedulableRequestState.Blocked]     = new ScheduleTimeRecord();
            _timeRecords[SchedulableRequestState.Yielding]    = new ScheduleTimeRecord();
            _timeRecords[SchedulableRequestState.Executing]   = new ScheduleTimeRecord();
            _timeRecords[SchedulableRequestState.Ready]       = new ScheduleTimeRecord();
            _timeRecords[SchedulableRequestState.Completed]   = new ScheduleTimeRecord();

            ChangeToState(SchedulableRequestState.Unscheduled);
        }
Пример #17
0
        /// <summary>
        /// Removes the association between this request and the one we are blocked by.
        /// </summary>
        internal void DisconnectRequestWeAreBlockedBy(BlockingRequestKey blockingRequestKey)
        {
            ErrorUtilities.VerifyThrow(_requestsWeAreBlockedBy.ContainsKey(blockingRequestKey), "We are not blocked by the specified request.");

            SchedulableRequest unblockingRequest = _requestsWeAreBlockedBy[blockingRequestKey];

            ErrorUtilities.VerifyThrow(unblockingRequest._requestsWeAreBlocking.Contains(this), "The request unblocking us doesn't think it is blocking us.");

            _requestsWeAreBlockedBy.Remove(blockingRequestKey);
            unblockingRequest._requestsWeAreBlocking.Remove(this);

            // If the request we are blocked by also happens to be unscheduled, remove it as well so we don't try to run it later.  This is
            // because circular dependency errors cause us to fail all outstanding requests on the current request.  See BuildRequsetEntry.ReportResult.
            if (unblockingRequest.State == SchedulableRequestState.Unscheduled)
            {
                unblockingRequest.Delete();
            }

            if (_requestsWeAreBlockedBy.Count == 0)
            {
                ChangeToState(SchedulableRequestState.Ready);
            }
        }
Пример #18
0
        /// <summary>
        /// Returns true if the request can be scheduled to the specified node.
        /// </summary>
        public bool CanScheduleRequestToNode(SchedulableRequest request, int nodeId)
        {
            int requiredNodeId = GetAssignedNodeForRequestConfiguration(request.BuildRequest.ConfigurationId);

            return(requiredNodeId == Scheduler.InvalidNodeId || requiredNodeId == nodeId);
        }
Пример #19
0
 /// <summary>
 /// Determines if the specified request is currently scheduled.
 /// </summary>
 public bool IsRequestScheduled(SchedulableRequest request)
 {
     return(InternalGetScheduledRequestByGlobalRequestId(request.BuildRequest.GlobalRequestId) != null);
 }
Пример #20
0
        /// <summary>
        /// Updates the state of the specified request.
        /// </summary>
        public void UpdateFromState(SchedulableRequest request, SchedulableRequestState previousState)
        {
            // Remove from its old collection
            switch (previousState)
            {
            case SchedulableRequestState.Blocked:
                _blockedRequests.Remove(request.BuildRequest.GlobalRequestId);
                break;

            case SchedulableRequestState.Yielding:
                _yieldingRequests.Remove(request.BuildRequest.GlobalRequestId);
                break;

            case SchedulableRequestState.Completed:
                ErrorUtilities.ThrowInternalError("Should not be updating a request after it has reached the Completed state.");
                break;

            case SchedulableRequestState.Executing:
                _executingRequests.Remove(request.BuildRequest.GlobalRequestId);
                _executingRequestByNode[request.AssignedNode] = null;
                break;

            case SchedulableRequestState.Ready:
                _readyRequests.Remove(request.BuildRequest.GlobalRequestId);
                _readyRequestsByNode[request.AssignedNode].Remove(request);
                break;

            case SchedulableRequestState.Unscheduled:
                LinkedListNode <SchedulableRequest> requestNode = _unscheduledRequestNodesByRequest[request];
                _unscheduledRequestNodesByRequest.Remove(request);
                _unscheduledRequests.Remove(requestNode);

                if (request.State != SchedulableRequestState.Completed)
                {
                    // Map the request to the node.
                    HashSet <SchedulableRequest> requestsAssignedToNode;
                    if (!_scheduledRequestsByNode.TryGetValue(request.AssignedNode, out requestsAssignedToNode))
                    {
                        requestsAssignedToNode = new HashSet <SchedulableRequest>();
                        _scheduledRequestsByNode[request.AssignedNode] = requestsAssignedToNode;
                    }

                    ErrorUtilities.VerifyThrow(!requestsAssignedToNode.Contains(request), "Request {0} is already scheduled to node {1}", request.BuildRequest.GlobalRequestId, request.AssignedNode);
                    requestsAssignedToNode.Add(request);

                    // Map the configuration to the node.
                    HashSet <int> configurationsAssignedToNode;
                    if (!_configurationsByNode.TryGetValue(request.AssignedNode, out configurationsAssignedToNode))
                    {
                        configurationsAssignedToNode = new HashSet <int>();
                        _configurationsByNode[request.AssignedNode] = configurationsAssignedToNode;
                    }

                    if (!configurationsAssignedToNode.Contains(request.BuildRequest.ConfigurationId))
                    {
                        configurationsAssignedToNode.Add(request.BuildRequest.ConfigurationId);
                    }
                }

                break;
            }

            // Add it to its new location
            switch (request.State)
            {
            case SchedulableRequestState.Blocked:
                ErrorUtilities.VerifyThrow(!_blockedRequests.ContainsKey(request.BuildRequest.GlobalRequestId), "Request with global id {0} is already blocked!");
                _blockedRequests[request.BuildRequest.GlobalRequestId] = request;
                break;

            case SchedulableRequestState.Yielding:
                ErrorUtilities.VerifyThrow(!_yieldingRequests.ContainsKey(request.BuildRequest.GlobalRequestId), "Request with global id {0} is already yielded!");
                _yieldingRequests[request.BuildRequest.GlobalRequestId] = request;
                break;

            case SchedulableRequestState.Completed:
                ErrorUtilities.VerifyThrow(_configurationToRequests.ContainsKey(request.BuildRequest.ConfigurationId), "Configuration {0} never had requests assigned to it.", request.BuildRequest.ConfigurationId);
                ErrorUtilities.VerifyThrow(_configurationToRequests[request.BuildRequest.ConfigurationId].Count > 0, "Configuration {0} has no requests assigned to it.", request.BuildRequest.ConfigurationId);
                _configurationToRequests[request.BuildRequest.ConfigurationId].Remove(request);
                if (_scheduledRequestsByNode.ContainsKey(request.AssignedNode))
                {
                    _scheduledRequestsByNode[request.AssignedNode].Remove(request);
                }

                request.EndTime = EventTime;
                break;

            case SchedulableRequestState.Executing:
                ErrorUtilities.VerifyThrow(!_executingRequests.ContainsKey(request.BuildRequest.GlobalRequestId), "Request with global id {0} is already executing!");
                ErrorUtilities.VerifyThrow(!_executingRequestByNode.ContainsKey(request.AssignedNode) || _executingRequestByNode[request.AssignedNode] == null, "Node {0} is currently executing a request.", request.AssignedNode);

                _executingRequests[request.BuildRequest.GlobalRequestId]   = request;
                _executingRequestByNode[request.AssignedNode]              = request;
                _configurationToNode[request.BuildRequest.ConfigurationId] = request.AssignedNode;
                if (previousState == SchedulableRequestState.Unscheduled)
                {
                    request.StartTime = EventTime;
                }

                break;

            case SchedulableRequestState.Ready:
                ErrorUtilities.VerifyThrow(!_readyRequests.ContainsKey(request.BuildRequest.GlobalRequestId), "Request with global id {0} is already ready!");
                _readyRequests[request.BuildRequest.GlobalRequestId] = request;
                HashSet <SchedulableRequest> readyRequestsOnNode;
                if (!_readyRequestsByNode.TryGetValue(request.AssignedNode, out readyRequestsOnNode))
                {
                    readyRequestsOnNode = new HashSet <SchedulableRequest>();
                    _readyRequestsByNode[request.AssignedNode] = readyRequestsOnNode;
                }

                ErrorUtilities.VerifyThrow(!readyRequestsOnNode.Contains(request), "Request with global id {0} is already marked as ready on node {1}", request.BuildRequest.GlobalRequestId, request.AssignedNode);
                readyRequestsOnNode.Add(request);
                break;

            case SchedulableRequestState.Unscheduled:
                ErrorUtilities.ThrowInternalError("Request with global id {0} cannot transition to the Unscheduled state", request.BuildRequest.GlobalRequestId);
                break;
            }

            _buildEvents.Add(new SchedulingEvent(EventTime, request, previousState, request.State));
        }
Пример #21
0
 /// <summary>
 /// Detects a circular dependency.  Throws a CircularDependencyException if one exists.  Circular dependencies can occur
 /// under the following conditions:
 /// 1. If the blocking request's global request ID appears in the ancestor chain (Direct).
 /// 2. If a request appears in the ancestor chain and has a different global request ID but has an active target that
 ///    matches one of the targets specified in the blocking request (Direct).
 /// 3. If the blocking request exists elsewhere as a blocked request with the same global request ID, and one of its children
 ///    (recursively) matches this request's global request ID (Indirect).
 /// 4. If the blocking request's configuration is part of another request elsewhere which is also blocked, and that request
 ///    is building targets this blocking request is building, and one of that blocked request's children (recursively)
 ///    matches this request's global request ID (Indirect).
 /// </summary>
 private void DetectCircularDependency(SchedulableRequest blockingRequest)
 {
     DetectDirectCircularDependency(blockingRequest);
     DetectIndirectCircularDependency(blockingRequest);
 }