/// <summary> /// Indicates that there are results which can be used to unblock this request. Updates the relationships between requests. /// </summary> public void UnblockWithResult(BuildResult result) { VerifyOneOfStates(new SchedulableRequestState[] { SchedulableRequestState.Blocked, SchedulableRequestState.Unscheduled }); ErrorUtilities.VerifyThrowArgumentNull(result, "result"); BlockingRequestKey key = new BlockingRequestKey(result); DisconnectRequestWeAreBlockedBy(key); _activeTargetsWhenBlocked = null; BlockingTarget = null; }
/// <summary> /// Equals override. /// </summary> public override bool Equals(object obj) { if (obj != null) { BlockingRequestKey other = obj as BlockingRequestKey; if (other != null) { return((other._globalRequestId == _globalRequestId) && (other._nodeRequestId == _nodeRequestId)); } } return(base.Equals(obj)); }
/// <summary> /// Removes the association between this request and the one we are blocked by. /// </summary> internal void DisconnectRequestWeAreBlockedBy(BlockingRequestKey blockingRequestKey) { ErrorUtilities.VerifyThrow(_requestsWeAreBlockedBy.TryGetValue(blockingRequestKey, out SchedulableRequest unblockingRequest), "We are not blocked by the specified request."); 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); } }
/// <summary> /// Removes the association between this request and the one we are blocked by. /// </summary> private 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); } }
/// <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); }
/// <summary> /// Indicates that there are results which can be used to unblock this request. Updates the relationships between requests. /// </summary> public void UnblockWithResult(BuildResult result) { VerifyOneOfStates(new SchedulableRequestState[] { SchedulableRequestState.Blocked, SchedulableRequestState.Unscheduled }); ErrorUtilities.VerifyThrowArgumentNull(result, "result"); BlockingRequestKey key = new BlockingRequestKey(result); DisconnectRequestWeAreBlockedBy(key); _activeTargetsWhenBlocked = null; }
/// <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> public void BlockByRequest(SchedulableRequest blockingRequest, string[] activeTargets) { VerifyOneOfStates(new SchedulableRequestState[] { SchedulableRequestState.Blocked, SchedulableRequestState.Executing }); ErrorUtilities.VerifyThrowArgumentNull(blockingRequest, "blockingRequest"); ErrorUtilities.VerifyThrowArgumentNull(activeTargets, "activeTargets"); // 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; DetectCircularDependency(blockingRequest); _requestsWeAreBlockedBy[key] = blockingRequest; blockingRequest._requestsWeAreBlocking.Add(this); ChangeToState(SchedulableRequestState.Blocked); }