/// <summary> /// Returns true if this task's graph sync data is a super set of the other /// </summary> /// <param name="other"></param> /// <returns></returns> private bool Contains(UpdateGraphAsyncTask other) { // Be more conservative here. Not only check ModifiedNodes, but // also check *all* nodes in graph sync data. For example, consider // a CBN outputs to a node, the node is a downstream node of cbn. // // Now if node is modified and request a run, task's ModifiedNodes // will cotain this node; then CBN is modified and request a run, // ModifiedNodes would contain both CBN and the node, and previous // task will be thrown away. if (!other.ModifiedNodes.All(ModifiedNodes.Contains)) { return(false); } if (graphSyncData == null) { return(other.graphSyncData == null); } else if (other.graphSyncData == null) { return(true); } return(other.graphSyncData.AddedNodeIDs.All(graphSyncData.AddedNodeIDs.Contains) && other.graphSyncData.ModifiedNodeIDs.All(graphSyncData.ModifiedNodeIDs.Contains) && other.graphSyncData.DeletedNodeIDs.All(graphSyncData.DeletedNodeIDs.Contains)); }
/// <summary> /// Returns true if this task's graph sync data is a super set of the other /// </summary> /// <param name="other"></param> /// <returns></returns> private bool CanReplace(UpdateGraphAsyncTask other) { // Be more conservative here. Not only check ModifiedNodes, but // also check *all* nodes in graph sync data. For example, consider // a CBN outputs to a node, the node is a downstream node of cbn. // // Now if node is modified and request a run, task's ModifiedNodes // will cotain this node; then CBN is modified and request a run, // ModifiedNodes would contain both CBN and the node, and previous // task will be thrown away. if (!other.ModifiedNodes.All(ModifiedNodes.Contains)) { return(false); } if (graphSyncData == null) { return(other.graphSyncData == null); } else if (other.graphSyncData == null) { return(true); } // Merging additions and removals can make the changeSetComputer internal state get corrupted. // Imagine a sequence of queued tasks with changes like these: +A | -A | +AB // Imagine a new task with change -A, ending up with the following sequence: -A | +A | -A | +AB // While the merge routine would simplify this sequence to: -A | +A | +AB // That creates an inconsistent sequence of changes where subtree A is added when it already exists! // Modifications are not susceptible to this problem. Imagine ~A incoming with sequence: +A | -A | ~A | +AB // The resulting sequence is: ~A | +A | -A | +AB, which is valid. // Because modifications do not create or remove entries in the changeSetComputer internal state, // if we remove one from anywhere in the sequence we remain consistent. return(other.graphSyncData.AddedNodeIDs.Count() == 0 && other.graphSyncData.ModifiedNodeIDs.All(graphSyncData.ModifiedNodeIDs.Contains) && other.graphSyncData.DeletedNodeIDs.Count() == 0); }
private bool IsScheduledAfter(UpdateGraphAsyncTask other) { return CreationTime > other.CreationTime; }
/// <summary> /// Returns true if this task's graph sync data is a super set of the other /// </summary> /// <param name="other"></param> /// <returns></returns> private bool Contains(UpdateGraphAsyncTask other) { // Be more conservative here. Not only check ModifiedNodes, but // also check *all* nodes in graph sync data. For example, consider // a CBN outputs to a node, the node is a downstream node of cbn. // // Now if node is modified and request a run, task's ModifiedNodes // will cotain this node; then CBN is modified and request a run, // ModifiedNodes would contain both CBN and the node, and previous // task will be thrown away. if (!other.ModifiedNodes.All(ModifiedNodes.Contains)) return false; if (graphSyncData == null) return other.graphSyncData == null; else if (other.graphSyncData == null) return true; return other.graphSyncData.AddedNodeIDs.All(graphSyncData.AddedNodeIDs.Contains) && other.graphSyncData.ModifiedNodeIDs.All(graphSyncData.ModifiedNodeIDs.Contains) && other.graphSyncData.DeletedNodeIDs.All(graphSyncData.DeletedNodeIDs.Contains); }
/// <summary> /// This method is typically called from the main application thread (as /// a result of user actions such as button click or node UI changes) to /// schedule an update of the graph. This call may or may not represent /// an actual update. In the event that the user action does not result /// in actual graph update (e.g. moving of node on UI), the update task /// will not be scheduled for execution. /// </summary> public void Run() { graphExecuted = true; // When Dynamo is shut down, the workspace is cleared, which results // in Modified() being called. But, we don't want to run when we are // shutting down so we check whether an engine controller is available. if (this.EngineController == null) { return; } var traceData = PreloadedTraceData; if ((traceData != null) && traceData.Any()) { // If we do have preloaded trace data, set it here first. var setTraceDataTask = new SetTraceDataAsyncTask(scheduler); if (setTraceDataTask.Initialize(EngineController, this)) scheduler.ScheduleForExecution(setTraceDataTask); } // If one or more custom node have been updated, make sure they // are compiled first before the home workspace gets evaluated. // EngineController.ProcessPendingCustomNodeSyncData(scheduler); var task = new UpdateGraphAsyncTask(scheduler, verboseLogging); if (task.Initialize(EngineController, this)) { task.Completed += OnUpdateGraphCompleted; RunSettings.RunEnabled = false; // Disable 'Run' button. // Reset node states foreach (var node in Nodes) { node.WasInvolvedInExecution = false; } // The workspace has been built for the first time silenceNodeModifications = false; OnEvaluationStarted(EventArgs.Empty); scheduler.ScheduleForExecution(task); } else { // Notify handlers that evaluation did not take place. var e = new EvaluationCompletedEventArgs(false); OnEvaluationCompleted(e); } }
private bool IsScheduledAfter(UpdateGraphAsyncTask other) { return(CreationTime > other.CreationTime); }
public void TestUpdateGraphyAsyncTaskMerge() { // Verify a UpdateGraphAysncTask can't be merged with the other one // if they modifiy different nodes. OpenModel(TestDirectory + @"\core\scheduler\simple.dyn"); var cbn = CurrentDynamoModel.CurrentWorkspace.Nodes.OfType<CodeBlockNodeModel>().FirstOrDefault(); var funcNode = CurrentDynamoModel.CurrentWorkspace.Nodes.OfType<DSFunction>().FirstOrDefault(); // Keep code block node be silent so that the graph won't be // executed automatically cbn.RaisesModificationEvents = false; var elementResolver = CurrentDynamoModel.CurrentWorkspace.ElementResolver; cbn.SetCodeContent("-22", elementResolver); // Invalid numeric value. cbn.MarkNodeAsModified(); // Get a UpdateGrapyAsyncTask for the modification of cbn var scheduler = new DynamoScheduler(new SampleSchedulerThread(), TaskProcessMode.Synchronous); UpdateGraphAsyncTask task1 = new UpdateGraphAsyncTask(scheduler, false); task1.Initialize(CurrentDynamoModel.EngineController, CurrentDynamoModel.CurrentWorkspace); // Get a UpdateGraphAsyncTask for the modification of Math.Sin() funcNode.MarkNodeAsModified(); UpdateGraphAsyncTask task2 = new UpdateGraphAsyncTask(scheduler, false); task2.Initialize(CurrentDynamoModel.EngineController, CurrentDynamoModel.CurrentWorkspace); // And both async tasks should be kept. var mergeResult = task1.CanMergeWith(task2); Assert.AreEqual(AsyncTask.TaskMergeInstruction.KeepBoth, mergeResult); mergeResult = task2.CanMergeWith(task1); Assert.AreEqual(AsyncTask.TaskMergeInstruction.KeepBoth, mergeResult); scheduler.Shutdown(); }