/// <summary> /// Add a child request to this record. Child requests block the parent. /// </summary> /// <param name="childRecord"></param> internal void AddChildRecord(ScheduleRecord childRecord) { if (requestIdToChildRecord == null) { requestIdToChildRecord = new Dictionary <ScheduleRecordKey, ScheduleRecord>(); } requestIdToChildRecord.Add(childRecord.RecordKey, childRecord); }
/// <summary> /// This method is called to update the datastructures to reflect that given request will /// be built on a given node. /// </summary> /// <param name="currentRequest"></param> /// <param name="nodeUsed"></param> internal void NotifyOfSchedulingDecision(BuildRequest currentRequest, int nodeUsed) { // Don't update structures on the child node or in single proc mode if (childMode || nodes.Length == 1) { return; } // Update the count of requests being build on the node totalRequestsPerNode[nodeUsed]++; // Ignore host requests if (currentRequest.HandleId == EngineCallback.invalidEngineHandle) { return; } if (Engine.debugMode) { string targetnames = currentRequest.TargetNames != null?String.Join(";", currentRequest.TargetNames) : "null"; Console.WriteLine("Sending project " + currentRequest.ProjectFileName + " Target " + targetnames + " to " + nodeUsed); } // Update the records ScheduleRecordKey recordKey = new ScheduleRecordKey(currentRequest.HandleId, currentRequest.RequestId); ScheduleRecordKey parentKey = new ScheduleRecordKey(currentRequest.ParentHandleId, currentRequest.ParentRequestId); ScheduleRecord record = new ScheduleRecord(recordKey, parentKey, nodeUsed, currentRequest.ProjectFileName, currentRequest.ToolsetVersion, currentRequest.TargetNames); lock (scheduleTableLock) { ErrorUtilities.VerifyThrow(!handleIdToScheduleRecord.ContainsKey(recordKey), "Schedule record should not be in the table"); handleIdToScheduleRecord.Add(recordKey, record); // The ParentHandleId is an invalidEngineHandle when the host is the one who created // the current request if (currentRequest.ParentHandleId != EngineCallback.invalidEngineHandle) { ErrorUtilities.VerifyThrow(handleIdToScheduleRecord.ContainsKey(parentKey), "Parent schedule record should be in the table"); ScheduleRecord parentRecord = handleIdToScheduleRecord[parentKey]; if (!parentRecord.Blocked) { blockedRequestsPerNode[parentRecord.EvaluationNode]++; } parentRecord.AddChildRecord(record); } } }
/// <summary> /// Used by the introspector to dump the state when the nodes are being shutdown due to an error. /// </summary> internal void DumpState() { for (int i = 0; i < totalRequestsPerNode.Length; i++) { Console.WriteLine("Node " + i + " Outstanding " + totalRequestsPerNode[i] + " Blocked " + blockedRequestsPerNode[i]); } foreach (ScheduleRecordKey key in handleIdToScheduleRecord.Keys) { ScheduleRecord record = handleIdToScheduleRecord[key]; Console.WriteLine(key.HandleId + ":" + key.RequestId + " " + record.ProjectName + " on node " + record.EvaluationNode); } }
/// <summary> /// This method is called when a build request is completed on a particular node. NodeId is never used instead we look up the node from the build request /// and the schedule record table /// </summary> internal void NotifyOfBuildResult(int nodeId, BuildResult buildResult) { if (!childMode && nodes.Length > 1) { // Ignore host requests if (buildResult.HandleId == EngineCallback.invalidEngineHandle) { return; } ScheduleRecordKey recordKey = new ScheduleRecordKey(buildResult.HandleId, buildResult.RequestId); ScheduleRecord scheduleRecord = null; lock (scheduleTableLock) { ErrorUtilities.VerifyThrow(handleIdToScheduleRecord.ContainsKey(recordKey), "Schedule record should be in the table"); scheduleRecord = handleIdToScheduleRecord[recordKey]; totalRequestsPerNode[scheduleRecord.EvaluationNode]--; handleIdToScheduleRecord.Remove(recordKey); if (scheduleRecord.ParentKey.HandleId != EngineCallback.invalidEngineHandle) { ErrorUtilities.VerifyThrow(handleIdToScheduleRecord.ContainsKey(scheduleRecord.ParentKey), "Parent schedule record should be in the table"); ScheduleRecord parentRecord = handleIdToScheduleRecord[scheduleRecord.ParentKey]; // As long as there are child requests under the parent request the parent request is considered blocked // Remove this build request from the list of requests the parent request is waiting on. This may unblock the parent request parentRecord.ReportChildCompleted(recordKey); // If completing the child request has unblocked the parent request due to all of the the Child requests being completed // decrement the number of blocked requests. if (!parentRecord.Blocked) { blockedRequestsPerNode[parentRecord.EvaluationNode]--; } } } // Dump some interesting information to the console if profile build is turned on by an environment variable if (parentEngine.ProfileBuild && scheduleRecord != null && buildResult.TaskTime != 0) { Console.WriteLine("N " + scheduleRecord.EvaluationNode + " Name " + scheduleRecord.ProjectName + ":" + scheduleRecord.ParentKey.HandleId + ":" + scheduleRecord.ParentKey.RequestId + " Total " + buildResult.TotalTime + " Engine " + buildResult.EngineTime + " Task " + buildResult.TaskTime); } } }
/// <summary> /// Add a child request to this record. Child requests block the parent. /// </summary> /// <param name="childRecord"></param> internal void AddChildRecord(ScheduleRecord childRecord) { if (requestIdToChildRecord == null) { requestIdToChildRecord = new Dictionary<ScheduleRecordKey, ScheduleRecord>(); } requestIdToChildRecord.Add(childRecord.RecordKey, childRecord); }
/// <summary> /// This method is called to update the datastructures to reflect that given request will /// be built on a given node. /// </summary> /// <param name="currentRequest"></param> /// <param name="nodeUsed"></param> internal void NotifyOfSchedulingDecision(BuildRequest currentRequest, int nodeUsed) { // Don't update structures on the child node or in single proc mode if (childMode || nodes.Length == 1) { return; } // Update the count of requests being build on the node totalRequestsPerNode[nodeUsed]++; // Ignore host requests if (currentRequest.HandleId == EngineCallback.invalidEngineHandle) { return; } if (Engine.debugMode) { string targetnames = currentRequest.TargetNames != null ? String.Join(";", currentRequest.TargetNames) : "null"; Console.WriteLine("Sending project " + currentRequest.ProjectFileName + " Target " + targetnames + " to " + nodeUsed); } // Update the records ScheduleRecordKey recordKey = new ScheduleRecordKey(currentRequest.HandleId, currentRequest.RequestId); ScheduleRecordKey parentKey = new ScheduleRecordKey(currentRequest.ParentHandleId, currentRequest.ParentRequestId); ScheduleRecord record = new ScheduleRecord(recordKey, parentKey, nodeUsed, currentRequest.ProjectFileName, currentRequest.ToolsetVersion, currentRequest.TargetNames); lock (scheduleTableLock) { ErrorUtilities.VerifyThrow(!handleIdToScheduleRecord.ContainsKey(recordKey), "Schedule record should not be in the table"); handleIdToScheduleRecord.Add(recordKey, record); // The ParentHandleId is an invalidEngineHandle when the host is the one who created // the current request if (currentRequest.ParentHandleId != EngineCallback.invalidEngineHandle) { ErrorUtilities.VerifyThrow(handleIdToScheduleRecord.ContainsKey(parentKey), "Parent schedule record should be in the table"); ScheduleRecord parentRecord = handleIdToScheduleRecord[parentKey]; if (!parentRecord.Blocked) { blockedRequestsPerNode[parentRecord.EvaluationNode]++; } parentRecord.AddChildRecord(record); } } }