/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var actionVertex = vertex as ExecutingActionVertex; if (actionVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return ScheduleExecutionState.IncorrectProcessorForVertex; } if (executionInfo.Cancellation.IsCancellationRequested) { return ScheduleExecutionState.Canceled; } if (executionInfo.PauseHandler.IsPaused) { executionInfo.PauseHandler.WaitForUnPause(executionInfo.Cancellation); } var id = actionVertex.ActionToExecute; if (!m_Storage.Contains(id)) { throw new UnknownScheduleActionException(); } var action = m_Storage.Action(id); action.Execute(executionInfo.Cancellation); return ScheduleExecutionState.Executing; }
/// <summary> /// Links the given start vertex to the end vertex. /// </summary> /// <param name="start">The start vertex.</param> /// <param name="end">The end vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from <paramref name="start"/> to <paramref name="end"/>. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="start"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownScheduleVertexException"> /// Thrown if <paramref name="start"/> does not exist in the current schedule. /// </exception> /// <exception cref="CannotExplicitlyLinkStartVertexException"> /// Thrown if <paramref name="start"/> is equal to the start vertex of the schedule. /// </exception> /// <exception cref="CannotExplicitlyLinkStartVertexException"> /// Thrown if <paramref name="start"/> is equal to the end vertex of the schedule. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="end"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownScheduleVertexException"> /// Thrown if <paramref name="end"/> does not exist in the current schedule. /// </exception> /// <exception cref="CannotExplicitlyLinkStartVertexException"> /// Thrown if <paramref name="end"/> is equal to the start vertex of the schedule. /// </exception> /// <exception cref="CannotExplicitlyLinkStartVertexException"> /// Thrown if <paramref name="end"/> is equal to the end vertex of the schedule. /// </exception> /// <exception cref="CannotLinkAVertexToItselfException"> /// Thrown if <paramref name="start"/> and <paramref name="end"/> are the same vertex. /// </exception> public void LinkTo(IScheduleVertex start, IScheduleVertex end, ScheduleElementId traverseCondition = null) { { Lokad.Enforce.Argument(() => start); Lokad.Enforce.With <UnknownScheduleVertexException>( m_Schedule.ContainsVertex(start), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.With <CannotExplicitlyLinkStartVertexException>( !ReferenceEquals(m_Start, start), Resources.Exceptions_Messages_CannotExplicitlyLinkStartVertex); Lokad.Enforce.With <CannotExplicitlyLinkEndVertexException>( !ReferenceEquals(m_End, start), Resources.Exceptions_Messages_CannotExplicitlyLinkEndVertex); Lokad.Enforce.Argument(() => end); Lokad.Enforce.With <UnknownScheduleVertexException>( m_Schedule.ContainsVertex(end), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.With <CannotExplicitlyLinkStartVertexException>( !ReferenceEquals(m_Start, end), Resources.Exceptions_Messages_CannotExplicitlyLinkStartVertex); Lokad.Enforce.With <CannotExplicitlyLinkEndVertexException>( !ReferenceEquals(m_End, end), Resources.Exceptions_Messages_CannotExplicitlyLinkEndVertex); Lokad.Enforce.With <CannotLinkAVertexToItselfException>( !ReferenceEquals(start, end), Resources.Exceptions_Messages_CannotLinkAVertexToItself); } m_Schedule.AddEdge(new ScheduleEdge(start, end, traverseCondition)); }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var markVertex = vertex as MarkHistoryVertex; if (markVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return(ScheduleExecutionState.IncorrectProcessorForVertex); } if (executionInfo.Cancellation.IsCancellationRequested) { return(ScheduleExecutionState.Canceled); } if (executionInfo.PauseHandler.IsPaused) { executionInfo.PauseHandler.WaitForUnPause(executionInfo.Cancellation); } var marker = m_Timeline.Mark(); m_OnMarkerStorage(marker); return(ScheduleExecutionState.Executing); }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var actionVertex = vertex as ExecutingActionVertex; if (actionVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return(ScheduleExecutionState.IncorrectProcessorForVertex); } if (executionInfo.Cancellation.IsCancellationRequested) { return(ScheduleExecutionState.Canceled); } if (executionInfo.PauseHandler.IsPaused) { executionInfo.PauseHandler.WaitForUnPause(executionInfo.Cancellation); } var id = actionVertex.ActionToExecute; if (!m_Storage.Contains(id)) { throw new UnknownScheduleActionException(); } var action = m_Storage.Action(id); action.Execute(executionInfo.Cancellation); return(ScheduleExecutionState.Executing); }
/// <summary> /// Traverses the schedule and applies an action to each vertex visited. /// </summary> /// <param name="start">The vertex where the traverse should be started.</param> /// <param name="vertexAction"> /// The action taken for each vertex that is encountered. The function is provided with the current vertex and /// a collection of all outbound, if <paramref name="traverseViaOutboundVertices"/> is <see langword="true" />, /// or inbound vertices and the ID of the traversing condition. The function should return <see langword="false" /> /// to terminate the traverse. /// </param> /// <param name="directionAction"> /// The function that determines in which direction the traverse should proceed. The function is provided with /// a collection of all outbound, if <paramref name="traverseViaOutboundVertices"/> is <see langword="true" />, /// or inbound vertices and the ID of the traversing condition. The function should return the next vertex /// that should be traversed, or <see langword="null" /> if the traverse should be terminated. /// </param> /// <param name="traverseViaOutboundVertices"> /// A flag indicating if the schedule should be traversed via the outbound edges of the vertices, or the inbound ones. /// </param> public void TraverseSchedule( IScheduleVertex start, Func <IScheduleVertex, bool> vertexAction, Func <IEnumerable <Tuple <ScheduleElementId, IScheduleVertex> >, IScheduleVertex> directionAction, bool traverseViaOutboundVertices = true) { { Lokad.Enforce.Argument(() => start); Lokad.Enforce.With <UnknownScheduleVertexException>( m_Graph.ContainsVertex(start), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.Argument(() => vertexAction); Lokad.Enforce.Argument(() => directionAction); } var source = start; while (source != null) { var result = vertexAction(source); if (!result) { return; } var outEdges = traverseViaOutboundVertices ? m_Graph.OutEdges(source) : m_Graph.InEdges(source); var traverseMap = from edge in outEdges select new Tuple <ScheduleElementId, IScheduleVertex>( edge.TraversingCondition, traverseViaOutboundVertices ? edge.Target : edge.Source); source = directionAction(traverseMap); } }
/// <summary> /// Initializes a new instance of the <see cref="Schedule"/> class. /// </summary> /// <param name="information">The serialization information containing the data for the schedule.</param> /// <param name="context">The serialization context.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="information"/> is <see langword="null" />. /// </exception> public Schedule(SerializationInfo information, StreamingContext context) { { Lokad.Enforce.Argument(() => information); } m_Graph = new BidirectionalGraph <IScheduleVertex, ScheduleEdge>(); var vertices = new List <IScheduleVertex>(); var vertexCount = information.GetInt32(SerializationVertexCount); for (int i = 0; i < vertexCount; i++) { var type = (Type)information.GetValue( string.Format( CultureInfo.InvariantCulture, SerializationVertexType, i), typeof(Type)); var vertex = (IScheduleVertex)information.GetValue( string.Format( CultureInfo.InvariantCulture, SerializationVertex, i), type); vertices.Add(vertex); m_Graph.AddVertex(vertex); } var edgeCount = information.GetInt32(SerializationEdgeCount); for (int i = 0; i < edgeCount; i++) { var tuple = (Tuple <int, int, ScheduleElementId>)information.GetValue( string.Format( CultureInfo.InvariantCulture, SerializationEdge, i), typeof(Tuple <int, int, ScheduleElementId>)); m_Graph.AddEdge( new ScheduleEdge( vertices[tuple.Item1], vertices[tuple.Item2], tuple.Item3)); } var startIndex = information.GetInt32(SerializationStartVertex); m_Start = vertices[startIndex]; var endIndex = information.GetInt32(SerializationEndVertex); m_End = vertices[endIndex]; }
/// <summary> /// Links the given vertex to the end point of the schedule. /// </summary> /// <param name="source">The vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from <paramref name="source"/> to the end point. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="source"/> is <see langword="null" />. /// </exception> public void LinkToEnd(IScheduleVertex source, ScheduleConditionRegistrationId traverseCondition = null) { { Lokad.Enforce.Argument(() => source); } ScheduleElementId condition = ToScheduleCondition(traverseCondition); m_Builder.LinkToEnd(source, condition); }
/// <summary> /// Links the start point of the schedule to the given vertex. /// </summary> /// <param name="target">The vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from the start point to <paramref name="target"/>. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="target"/> is <see langword="null" />. /// </exception> public void LinkFromStart(IScheduleVertex target, ScheduleConditionRegistrationId traverseCondition = null) { { Lokad.Enforce.Argument(() => target); } ScheduleElementId condition = ToScheduleCondition(traverseCondition); m_Builder.LinkFromStart(target, condition); }
/// <summary> /// Initializes a new instance of the <see cref="FixedScheduleBuilder"/> class. /// </summary> public FixedScheduleBuilder() { m_Schedule = new BidirectionalGraph <IScheduleVertex, ScheduleEdge>(false); m_Start = new StartVertex(m_Schedule.VertexCount); m_Schedule.AddVertex(m_Start); m_End = new EndVertex(m_Schedule.VertexCount); m_Schedule.AddVertex(m_End); }
/// <summary> /// Initializes a new instance of the <see cref="FixedScheduleBuilder"/> class. /// </summary> /// <param name="scheduleToStartWith">The schedule that will be copied as base schedule.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="scheduleToStartWith"/> is <see langword="null" />. /// </exception> public FixedScheduleBuilder(ISchedule scheduleToStartWith) { { Lokad.Enforce.Argument(() => scheduleToStartWith); } var tuple = CopySchedule(scheduleToStartWith); m_Schedule = tuple.Item1; m_Start = tuple.Item2; m_End = tuple.Item3; }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var endVertex = vertex as EndVertex; if (endVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return ScheduleExecutionState.IncorrectProcessorForVertex; } // We don't check for pause or cancel here, we're done anyway return ScheduleExecutionState.Completed; }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var endVertex = vertex as EndVertex; if (endVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return(ScheduleExecutionState.IncorrectProcessorForVertex); } // We don't check for pause or cancel here, we're done anyway return(ScheduleExecutionState.Completed); }
public bool Equals(IScheduleVertex other) { if (ReferenceEquals(this, other)) { return(true); } // Check if other is a null reference by using ReferenceEquals because // we overload the == operator. If other isn't actually null then // we get an infinite loop where we're constantly trying to compare to null. return(!ReferenceEquals(other, null) && Index == other.Index && GetType().Equals(other.GetType())); }
private static Tuple <BidirectionalGraph <IScheduleVertex, ScheduleEdge>, IScheduleVertex, IScheduleVertex> CopyGraph( BidirectionalGraph <IScheduleVertex, ScheduleEdge> graph, IScheduleVertex start) { var map = new Dictionary <IScheduleVertex, IScheduleVertex>(); var newGraph = new BidirectionalGraph <IScheduleVertex, ScheduleEdge>(false); var startVertex = CloneVertex(start); newGraph.AddVertex(startVertex); map.Add(start, startVertex); var nodeCounter = new List <IScheduleVertex>(); var uncheckedVertices = new Queue <IScheduleVertex>(); uncheckedVertices.Enqueue(start); while (uncheckedVertices.Count > 0) { var source = uncheckedVertices.Dequeue(); if (nodeCounter.Contains(source)) { continue; } nodeCounter.Add(source); var outEdges = graph.OutEdges(source); foreach (var outEdge in outEdges) { var target = outEdge.Target; if (!map.ContainsKey(target)) { var targetVertex = CloneVertex(target); newGraph.AddVertex(targetVertex); map.Add(target, targetVertex); } var edgeSource = map[source]; var edgeTarget = map[target]; newGraph.AddEdge(new ScheduleEdge(edgeSource, edgeTarget, outEdge.TraversingCondition)); uncheckedVertices.Enqueue(outEdge.Target); } } var endVertex = map.First(p => p.Value is EndVertex).Value; return(new Tuple <BidirectionalGraph <IScheduleVertex, ScheduleEdge>, IScheduleVertex, IScheduleVertex>(newGraph, startVertex, endVertex)); }
private IScheduleVertex DetermineNextScheduleStep( IEnumerable <Tuple <ScheduleElementId, IScheduleVertex> > availableNodes, ref ScheduleExecutionState state) { IScheduleVertex nextVertex = null; foreach (var pair in availableNodes) { if (m_ExecutionInfo.Cancellation.IsCancellationRequested) { state = ScheduleExecutionState.Canceled; break; } // If we need to pause we do it here m_ExecutionInfo.PauseHandler.WaitForUnPause(m_ExecutionInfo.Cancellation); bool canTraverse = true; if (pair.Item1 != null) { Debug.Assert(m_Conditions.Contains(pair.Item1), "The traversing condition for the edge does not exist"); var condition = m_Conditions.Condition(pair.Item1); try { canTraverse = condition.CanTraverse(m_ExecutionInfo.Cancellation); } catch (Exception) { state = ScheduleExecutionState.UnhandledException; break; } } if (canTraverse) { nextVertex = pair.Item2; break; } } // If we get here then there were no edges we could traverse. Fail the execution if ((nextVertex == null) && (state == ScheduleExecutionState.Executing)) { state = ScheduleExecutionState.NoTraversableEdgeFound; } return(nextVertex); }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var startVertex = vertex as StartVertex; if (startVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return ScheduleExecutionState.IncorrectProcessorForVertex; } if (executionInfo.Cancellation.IsCancellationRequested) { return ScheduleExecutionState.Canceled; } return ScheduleExecutionState.Executing; }
/// <summary> /// Traverses the schedule and applies an action to each vertex visited. /// </summary> /// <param name="start">The vertex where the traverse should be started.</param> /// <param name="vertexAction"> /// The action taken for each vertex that is encountered. The action is provided with the current vertex and /// a collection of all outbound, if <paramref name="traverseViaOutBoundVertices"/> is <see langword="true" />, /// or inbound vertices and the ID of the traversing condition. The function should return <see langword="false" /> /// to terminate the traverse. /// </param> /// <param name="traverseViaOutBoundVertices"> /// A flag indicating if the schedule should be traversed via the outbound edges of the vertices, or the inbound ones. /// </param> public void TraverseAllScheduleVertices( IScheduleVertex start, Func <IScheduleVertex, IEnumerable <Tuple <ScheduleElementId, IScheduleVertex> >, bool> vertexAction, bool traverseViaOutBoundVertices = true) { { Lokad.Enforce.Argument(() => start); Lokad.Enforce.With <UnknownScheduleVertexException>( m_Graph.ContainsVertex(start), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.Argument(() => vertexAction); } var nodeCounter = new List <IScheduleVertex>(); var uncheckedVertices = new Queue <IScheduleVertex>(); uncheckedVertices.Enqueue(start); while (uncheckedVertices.Count > 0) { var source = uncheckedVertices.Dequeue(); if (nodeCounter.Contains(source)) { continue; } nodeCounter.Add(source); var outEdges = traverseViaOutBoundVertices ? m_Graph.OutEdges(source) : m_Graph.InEdges(source); var traverseMap = from edge in outEdges select new Tuple <ScheduleElementId, IScheduleVertex>( edge.TraversingCondition, traverseViaOutBoundVertices ? edge.Target : edge.Source); var result = vertexAction(source, traverseMap); if (!result) { return; } foreach (var outEdge in outEdges) { uncheckedVertices.Enqueue(traverseViaOutBoundVertices ? outEdge.Target : outEdge.Source); } } }
private static ISchedule BuildThreeVertexSchedule(IScheduleVertex middle) { var graph = new BidirectionalGraph <IScheduleVertex, ScheduleEdge>(); var start = new StartVertex(1); graph.AddVertex(start); var end = new EndVertex(2); graph.AddVertex(end); graph.AddVertex(middle); graph.AddEdge(new ScheduleEdge(start, middle)); graph.AddEdge(new ScheduleEdge(middle, end)); return(new Schedule(graph, start, end)); }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var startVertex = vertex as StartVertex; if (startVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return(ScheduleExecutionState.IncorrectProcessorForVertex); } if (executionInfo.Cancellation.IsCancellationRequested) { return(ScheduleExecutionState.Canceled); } return(ScheduleExecutionState.Executing); }
/// <summary> /// Links the start point of the schedule to the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from the start point to <paramref name="vertex"/>. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="vertex"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownScheduleVertexException"> /// Thrown if <paramref name="vertex"/> does not exist in the current schedule. /// </exception> /// <exception cref="CannotExplicitlyLinkStartVertexException"> /// Thrown if <paramref name="vertex"/> is equal to the end vertex of the schedule. /// </exception> /// <exception cref="CannotLinkAVertexToItselfException"> /// Thrown if the start vertex of the schedule and <paramref name="vertex"/> are the same vertex. /// </exception> public void LinkFromStart(IScheduleVertex vertex, ScheduleElementId traverseCondition = null) { { Lokad.Enforce.Argument(() => vertex); Lokad.Enforce.With <UnknownScheduleVertexException>( m_Schedule.ContainsVertex(vertex), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.With <CannotExplicitlyLinkEndVertexException>( !ReferenceEquals(m_End, vertex), Resources.Exceptions_Messages_CannotExplicitlyLinkEndVertex); Lokad.Enforce.With <CannotLinkAVertexToItselfException>( !ReferenceEquals(m_Start, vertex), Resources.Exceptions_Messages_CannotLinkAVertexToItself); } m_Schedule.AddEdge(new ScheduleEdge(m_Start, vertex, traverseCondition)); }
private bool ProcessScheduleStep(IScheduleVertex current, ref ScheduleExecutionState state) { if (m_ExecutionInfo.Cancellation.IsCancellationRequested) { state = ScheduleExecutionState.Canceled; return(false); } // If we need to pause we do it here m_ExecutionInfo.PauseHandler.WaitForUnPause(m_ExecutionInfo.Cancellation); // Get the executor for the current node type and run it // on the current node. If we fail then we exit the loop { var type = current.GetType(); if (!m_Executors.ContainsKey(type)) { state = ScheduleExecutionState.NoProcessorForVertex; return(false); } RaiseOnVertexProcess(Schedule, current.Index); var processor = m_Executors[type]; try { ScheduleExecutionState shouldContinue = processor.Process(current, m_ExecutionInfo); if (shouldContinue != ScheduleExecutionState.Executing) { state = shouldContinue; return(false); } RaiseOnExecutionProgress(-1, Resources.Progress_ExecutingSchedule, false); } catch (Exception) { state = ScheduleExecutionState.UnhandledException; return(false); } return(true); } }
/// <summary> /// Initializes a new instance of the <see cref="Schedule"/> class. /// </summary> /// <param name="graph">The graph that describes the current schedule.</param> /// <param name="start">The start node for the schedule.</param> /// <param name="end">The end node for the schedule.</param> public Schedule( BidirectionalGraph <IScheduleVertex, ScheduleEdge> graph, IScheduleVertex start, IScheduleVertex end) { { Debug.Assert(graph != null, "The graph should not be a null reference."); Debug.Assert(start != null, "The start vertex should not be a null reference."); Debug.Assert(start is StartVertex, "The start vertex should be an editable start vertex."); Debug.Assert(graph.ContainsVertex(start), "The start vertex should be part of the graph."); Debug.Assert(end != null, "The end vertex should not be a null reference."); Debug.Assert(end is EndVertex, "The end vertex should be an editable end vertex."); Debug.Assert(graph.ContainsVertex(end), "The end vertex should be part of the graph."); } m_Start = start; m_End = end; m_Graph = graph; }
private static bool AreVerticesEqual(IScheduleVertex first, IScheduleVertex second) { if (first.GetType() != second.GetType()) { return(false); } var executingActionVertex = first as ExecutingActionVertex; if (executingActionVertex != null) { return(executingActionVertex.ActionToExecute == ((ExecutingActionVertex)second).ActionToExecute); } var subScheduleVertex = first as SubScheduleVertex; if (subScheduleVertex != null) { return(subScheduleVertex.ScheduleToExecute == ((SubScheduleVertex)second).ScheduleToExecute); } return(true); }
/// <summary> /// Links the given vertex to the end point of the schedule. /// </summary> /// <param name="source">The vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from <paramref name="source"/> to the end point. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="source"/> is <see langword="null" />. /// </exception> public void LinkToEnd(IScheduleVertex source, ScheduleConditionRegistrationId traverseCondition = null) { { Lokad.Enforce.Argument(() => source); } ScheduleElementId condition = ToScheduleCondition(traverseCondition); m_Builder.LinkToEnd(source, condition); }
/// <summary> /// Initializes a new instance of the <see cref="Schedule"/> class. /// </summary> /// <param name="information">The serialization information containing the data for the schedule.</param> /// <param name="context">The serialization context.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="information"/> is <see langword="null" />. /// </exception> public Schedule(SerializationInfo information, StreamingContext context) { { Lokad.Enforce.Argument(() => information); } m_Graph = new BidirectionalGraph<IScheduleVertex, ScheduleEdge>(); var vertices = new List<IScheduleVertex>(); var vertexCount = information.GetInt32(SerializationVertexCount); for (int i = 0; i < vertexCount; i++) { var type = (Type)information.GetValue( string.Format( CultureInfo.InvariantCulture, SerializationVertexType, i), typeof(Type)); var vertex = (IScheduleVertex)information.GetValue( string.Format( CultureInfo.InvariantCulture, SerializationVertex, i), type); vertices.Add(vertex); m_Graph.AddVertex(vertex); } var edgeCount = information.GetInt32(SerializationEdgeCount); for (int i = 0; i < edgeCount; i++) { var tuple = (Tuple<int, int, ScheduleElementId>)information.GetValue( string.Format( CultureInfo.InvariantCulture, SerializationEdge, i), typeof(Tuple<int, int, ScheduleElementId>)); m_Graph.AddEdge( new ScheduleEdge( vertices[tuple.Item1], vertices[tuple.Item2], tuple.Item3)); } var startIndex = information.GetInt32(SerializationStartVertex); m_Start = vertices[startIndex]; var endIndex = information.GetInt32(SerializationEndVertex); m_End = vertices[endIndex]; }
private static bool AreVerticesEqual(IScheduleVertex first, IScheduleVertex second) { if (first.GetType() != second.GetType()) { return false; } var executingActionVertex = first as ExecutingActionVertex; if (executingActionVertex != null) { return executingActionVertex.ActionToExecute == ((ExecutingActionVertex)second).ActionToExecute; } var subScheduleVertex = first as SubScheduleVertex; if (subScheduleVertex != null) { return subScheduleVertex.ScheduleToExecute == ((SubScheduleVertex)second).ScheduleToExecute; } return true; }
public bool Equals(IScheduleVertex other) { if (ReferenceEquals(this, other)) { return true; } // Check if other is a null reference by using ReferenceEquals because // we overload the == operator. If other isn't actually null then // we get an infinite loop where we're constantly trying to compare to null. return !ReferenceEquals(other, null) && Index == other.Index && GetType().Equals(other.GetType()); }
/// <summary> /// Initializes a new instance of the <see cref="FixedScheduleBuilder"/> class. /// </summary> /// <param name="scheduleToStartWith">The schedule that will be copied as base schedule.</param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="scheduleToStartWith"/> is <see langword="null" />. /// </exception> public FixedScheduleBuilder(ISchedule scheduleToStartWith) { { Lokad.Enforce.Argument(() => scheduleToStartWith); } var tuple = CopySchedule(scheduleToStartWith); m_Schedule = tuple.Item1; m_Start = tuple.Item2; m_End = tuple.Item3; }
/// <summary> /// Inserts the given vertex in the position of the given insert vertex. The insert vertex will /// be removed if it has no more inserts left. /// </summary> /// <param name="insertVertex">The vertex which will be replaced.</param> /// <param name="vertexToInsert">The new vertex.</param> /// <returns>A tuple containing the insert vertices that were place before and after the newly inserted vertex.</returns> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="insertVertex"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownScheduleVertexException"> /// Thrown if <paramref name="insertVertex"/> does not exist in the current schedule. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="vertexToInsert"/> is <see langword="null" />. /// </exception> /// <exception cref="CannotInsertExistingVertexException"> /// Thrown if <paramref name="vertexToInsert"/> already exists in the schedule. /// </exception> /// <exception cref="NoInsertsLeftOnVertexException"> /// Thrown if <paramref name="insertVertex"/> has no more inserts left. /// </exception> public Tuple<InsertVertex, InsertVertex> InsertIn( InsertVertex insertVertex, IScheduleVertex vertexToInsert) { { Lokad.Enforce.Argument(() => insertVertex); Lokad.Enforce.With<UnknownScheduleVertexException>( m_Schedule.ContainsVertex(insertVertex), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.Argument(() => vertexToInsert); Lokad.Enforce.With<CannotInsertExistingVertexException>( !m_Schedule.ContainsVertex(vertexToInsert), Resources.Exceptions_Messages_CannotInsertExistingVertex); Lokad.Enforce.With<NoInsertsLeftOnVertexException>( (insertVertex.RemainingInserts == -1) || (insertVertex.RemainingInserts > 0), Resources.Exceptions_Messages_NoInsertsLeftOnVertex); } // Find the inbound and outbound edges var inbound = from edge in m_Schedule.InEdges(insertVertex) select edge; var outbound = from edge in m_Schedule.OutEdges(insertVertex) select edge; // Add the new node m_Schedule.AddVertex(vertexToInsert); // Create two new insert vertices to be placed on either side of the new vertex var count = (insertVertex.RemainingInserts != -1) ? insertVertex.RemainingInserts - 1 : -1; InsertVertex inboundInsert = null; InsertVertex outboundInsert = null; if ((count == -1) || (count > 0)) { inboundInsert = new InsertVertex(m_Schedule.VertexCount, count); m_Schedule.AddVertex(inboundInsert); m_Schedule.AddEdge(new ScheduleEdge(inboundInsert, vertexToInsert, null)); outboundInsert = new InsertVertex(m_Schedule.VertexCount, count); m_Schedule.AddVertex(outboundInsert); m_Schedule.AddEdge(new ScheduleEdge(vertexToInsert, outboundInsert, null)); } // Reconnect all the edges var inboundTarget = inboundInsert ?? vertexToInsert; var outboundSource = outboundInsert ?? vertexToInsert; foreach (var inboundEdge in inbound) { m_Schedule.AddEdge(new ScheduleEdge(inboundEdge.Source, inboundTarget, inboundEdge.TraversingCondition)); } foreach (var outboundEdge in outbound) { m_Schedule.AddEdge(new ScheduleEdge(outboundSource, outboundEdge.Target, outboundEdge.TraversingCondition)); } // Lastly remove the current insert node, which also destroys all the edges that are // connected to it. m_Schedule.RemoveVertex(insertVertex); return new Tuple<InsertVertex, InsertVertex>(inboundInsert, outboundInsert); }
private static IScheduleVertex CloneVertex(IScheduleVertex vertex) { return(s_VertexBuilder[vertex.GetType()](vertex, vertex.Index)); }
/// <summary> /// Returns the number of vertices to which the current vertex connects. /// </summary> /// <param name="origin">The vertex for which the number of outbound connections should be returned.</param> /// <returns>The number of outbound connections for the current vertex.</returns> public int NumberOfOutboundConnections(IScheduleVertex origin) { return(m_Graph.OutDegree(origin)); }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var subScheduleVertex = vertex as SubScheduleVertex; if (subScheduleVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return(ScheduleExecutionState.IncorrectProcessorForVertex); } if (executionInfo.Cancellation.IsCancellationRequested) { return(ScheduleExecutionState.Canceled); } if (executionInfo.PauseHandler.IsPaused) { executionInfo.PauseHandler.WaitForUnPause(executionInfo.Cancellation); } // And how do we deal with loops? We'll cache the schedule if we're in-process but what about being out-of-process? We'll need to // keep the remote app alive ... // --> We'll need some kind of class that handles making the decision for in-process / out-of-process. // * If it's small then we want to do in-process because the loading of a new dataset takes a while // * If it's a parametrized thing then we might want to do out-of-process because we can run many more in one go // // Determine if we're running the sub-simulation synchronous (in-process) or ascynchronous (out-of-process) // Depends on: // - If the original schedule is allowed to split out sub-schedules out-of-process (when running in interactive mode we may // not allow this) // - 'size' of the sub-schedule // // Determine if we should go out of process here // Going out of process only makes sense if the overhead of going out of process is less than // the overhead of staying in process. // The overhead of going out of process is: // * Serialize all the data we need // * Load an application // * Stream the data across // * Deserialize data // * Re-serialize the data that we need (this may be less than what we send across) // * Send data across // * Deserialize data in original app // The overhead for staying in process is given by the fact that we can only run one schedule // at the time // // So going out of process makes sense when: // * There are multiple sub-schedules before the next sync block // ==> that means we can run all of them in parallel and the sync block indicates when we'll need the data // * We want to run the same sub-schedule with multiple parameters // ==> Run the parameter values all at the same time // * We want to split the current calculation out into multiple bits (domain decomposition type) // // Can we determine this when we build the schedule? // Possibly for some sections? bool executeOutOfProcess = false; IEnumerable <IScheduleVariable> parameters = null; var executor = m_Executor.Execute(subScheduleVertex.ScheduleToExecute, parameters, executionInfo, executeOutOfProcess); // if we're running in-process then we probably have to wait for the sub-schedule to // finish executing because we don't want to have to make the schedule execution thread safe // If it's running out-of-process then we don't bother waiting. There should be a sync block // around this section that will sort out the variable synchronization. if (executor.IsLocal) { var resetEvent = new AutoResetEvent(false); var wrapperWait = Observable.FromEventPattern <ScheduleExecutionStateEventArgs>( h => executor.OnFinish += h, h => executor.OnFinish -= h) .Take(1) .Subscribe(args => resetEvent.Set()); using (wrapperWait) { resetEvent.WaitOne(); } } return(ScheduleExecutionState.Executing); }
/// <summary> /// Traverses the schedule and applies an action to each vertex visited. /// </summary> /// <param name="start">The vertex where the traverse should be started.</param> /// <param name="vertexAction"> /// The action taken for each vertex that is encountered. The action is provided with the current vertex and /// a collection of all outbound, if <paramref name="traverseViaOutBoundVertices"/> is <see langword="true" />, /// or inbound vertices and the ID of the traversing condition. The function should return <see langword="false" /> /// to terminate the traverse. /// </param> /// <param name="traverseViaOutBoundVertices"> /// A flag indicating if the schedule should be traversed via the outbound edges of the vertices, or the inbound ones. /// </param> public void TraverseAllScheduleVertices( IScheduleVertex start, Func<IScheduleVertex, IEnumerable<Tuple<ScheduleElementId, IScheduleVertex>>, bool> vertexAction, bool traverseViaOutBoundVertices = true) { { Lokad.Enforce.Argument(() => start); Lokad.Enforce.With<UnknownScheduleVertexException>( m_Graph.ContainsVertex(start), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.Argument(() => vertexAction); } var nodeCounter = new List<IScheduleVertex>(); var uncheckedVertices = new Queue<IScheduleVertex>(); uncheckedVertices.Enqueue(start); while (uncheckedVertices.Count > 0) { var source = uncheckedVertices.Dequeue(); if (nodeCounter.Contains(source)) { continue; } nodeCounter.Add(source); var outEdges = traverseViaOutBoundVertices ? m_Graph.OutEdges(source) : m_Graph.InEdges(source); var traverseMap = from edge in outEdges select new Tuple<ScheduleElementId, IScheduleVertex>( edge.TraversingCondition, traverseViaOutBoundVertices ? edge.Target : edge.Source); var result = vertexAction(source, traverseMap); if (!result) { return; } foreach (var outEdge in outEdges) { uncheckedVertices.Enqueue(traverseViaOutBoundVertices ? outEdge.Target : outEdge.Source); } } }
/// <summary> /// Inserts the given vertex in the position of the given insert vertex. The insert vertex will /// be removed if it has no more inserts left. /// </summary> /// <param name="insertVertex">The vertex which will be replaced.</param> /// <param name="vertexToInsert">The new vertex.</param> /// <returns>A tuple containing the insert vertices that were place before and after the newly inserted vertex.</returns> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="insertVertex"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownScheduleVertexException"> /// Thrown if <paramref name="insertVertex"/> does not exist in the current schedule. /// </exception> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="vertexToInsert"/> is <see langword="null" />. /// </exception> /// <exception cref="CannotInsertExistingVertexException"> /// Thrown if <paramref name="vertexToInsert"/> already exists in the schedule. /// </exception> /// <exception cref="NoInsertsLeftOnVertexException"> /// Thrown if <paramref name="insertVertex"/> has no more inserts left. /// </exception> public Tuple <InsertVertex, InsertVertex> InsertIn( InsertVertex insertVertex, IScheduleVertex vertexToInsert) { { Lokad.Enforce.Argument(() => insertVertex); Lokad.Enforce.With <UnknownScheduleVertexException>( m_Schedule.ContainsVertex(insertVertex), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.Argument(() => vertexToInsert); Lokad.Enforce.With <CannotInsertExistingVertexException>( !m_Schedule.ContainsVertex(vertexToInsert), Resources.Exceptions_Messages_CannotInsertExistingVertex); Lokad.Enforce.With <NoInsertsLeftOnVertexException>( (insertVertex.RemainingInserts == -1) || (insertVertex.RemainingInserts > 0), Resources.Exceptions_Messages_NoInsertsLeftOnVertex); } // Find the inbound and outbound edges var inbound = from edge in m_Schedule.InEdges(insertVertex) select edge; var outbound = from edge in m_Schedule.OutEdges(insertVertex) select edge; // Add the new node m_Schedule.AddVertex(vertexToInsert); // Create two new insert vertices to be placed on either side of the new vertex var count = (insertVertex.RemainingInserts != -1) ? insertVertex.RemainingInserts - 1 : -1; InsertVertex inboundInsert = null; InsertVertex outboundInsert = null; if ((count == -1) || (count > 0)) { inboundInsert = new InsertVertex(m_Schedule.VertexCount, count); m_Schedule.AddVertex(inboundInsert); m_Schedule.AddEdge(new ScheduleEdge(inboundInsert, vertexToInsert, null)); outboundInsert = new InsertVertex(m_Schedule.VertexCount, count); m_Schedule.AddVertex(outboundInsert); m_Schedule.AddEdge(new ScheduleEdge(vertexToInsert, outboundInsert, null)); } // Reconnect all the edges var inboundTarget = inboundInsert ?? vertexToInsert; var outboundSource = outboundInsert ?? vertexToInsert; foreach (var inboundEdge in inbound) { m_Schedule.AddEdge(new ScheduleEdge(inboundEdge.Source, inboundTarget, inboundEdge.TraversingCondition)); } foreach (var outboundEdge in outbound) { m_Schedule.AddEdge(new ScheduleEdge(outboundSource, outboundEdge.Target, outboundEdge.TraversingCondition)); } // Lastly remove the current insert node, which also destroys all the edges that are // connected to it. m_Schedule.RemoveVertex(insertVertex); return(new Tuple <InsertVertex, InsertVertex>(inboundInsert, outboundInsert)); }
/// <summary> /// Links the start point of the schedule to the given vertex. /// </summary> /// <param name="target">The vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from the start point to <paramref name="target"/>. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="target"/> is <see langword="null" />. /// </exception> public void LinkFromStart(IScheduleVertex target, ScheduleConditionRegistrationId traverseCondition = null) { { Lokad.Enforce.Argument(() => target); } ScheduleElementId condition = ToScheduleCondition(traverseCondition); m_Builder.LinkFromStart(target, condition); }
/// <summary> /// Links the given vertex to the end point of the schedule. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="traverseCondition"> /// The ID of the condition that determines if it is possible to move from <paramref name="vertex"/> to the end point. /// </param> /// <exception cref="ArgumentNullException"> /// Thrown if <paramref name="vertex"/> is <see langword="null" />. /// </exception> /// <exception cref="UnknownScheduleVertexException"> /// Thrown if <paramref name="vertex"/> does not exist in the current schedule. /// </exception> /// <exception cref="CannotExplicitlyLinkStartVertexException"> /// Thrown if <paramref name="vertex"/> is equal to the start vertex of the schedule. /// </exception> /// <exception cref="CannotLinkAVertexToItselfException"> /// Thrown if the end vertex of the schedule and <paramref name="vertex"/> are the same vertex. /// </exception> public void LinkToEnd(IScheduleVertex vertex, ScheduleElementId traverseCondition = null) { { Lokad.Enforce.Argument(() => vertex); Lokad.Enforce.With<UnknownScheduleVertexException>( m_Schedule.ContainsVertex(vertex), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.With<CannotExplicitlyLinkStartVertexException>( !ReferenceEquals(m_Start, vertex), Resources.Exceptions_Messages_CannotExplicitlyLinkStartVertex); Lokad.Enforce.With<CannotLinkAVertexToItselfException>( !ReferenceEquals(m_End, vertex), Resources.Exceptions_Messages_CannotLinkAVertexToItself); } m_Schedule.AddEdge(new ScheduleEdge(vertex, m_End, traverseCondition)); }
private static bool AreVerticesEqual(IScheduleVertex first, IScheduleVertex second) { return first.Equals(second); }
private static IScheduleVertex CloneVertex(IScheduleVertex vertex) { return s_VertexBuilder[vertex.GetType()](vertex, vertex.Index); }
private static bool AreVerticesEqual(IScheduleVertex first, IScheduleVertex second) { return(first.Equals(second)); }
private static Tuple<BidirectionalGraph<IScheduleVertex, ScheduleEdge>, IScheduleVertex, IScheduleVertex> CopyGraph( BidirectionalGraph<IScheduleVertex, ScheduleEdge> graph, IScheduleVertex start) { var map = new Dictionary<IScheduleVertex, IScheduleVertex>(); var newGraph = new BidirectionalGraph<IScheduleVertex, ScheduleEdge>(false); var startVertex = CloneVertex(start); newGraph.AddVertex(startVertex); map.Add(start, startVertex); var nodeCounter = new List<IScheduleVertex>(); var uncheckedVertices = new Queue<IScheduleVertex>(); uncheckedVertices.Enqueue(start); while (uncheckedVertices.Count > 0) { var source = uncheckedVertices.Dequeue(); if (nodeCounter.Contains(source)) { continue; } nodeCounter.Add(source); var outEdges = graph.OutEdges(source); foreach (var outEdge in outEdges) { var target = outEdge.Target; if (!map.ContainsKey(target)) { var targetVertex = CloneVertex(target); newGraph.AddVertex(targetVertex); map.Add(target, targetVertex); } var edgeSource = map[source]; var edgeTarget = map[target]; newGraph.AddEdge(new ScheduleEdge(edgeSource, edgeTarget, outEdge.TraversingCondition)); uncheckedVertices.Enqueue(outEdge.Target); } } var endVertex = map.First(p => p.Value is EndVertex).Value; return new Tuple<BidirectionalGraph<IScheduleVertex, ScheduleEdge>, IScheduleVertex, IScheduleVertex>(newGraph, startVertex, endVertex); }
private static ISchedule BuildThreeVertexSchedule(IScheduleVertex middle) { var graph = new BidirectionalGraph<IScheduleVertex, ScheduleEdge>(); var start = new StartVertex(1); graph.AddVertex(start); var end = new EndVertex(2); graph.AddVertex(end); graph.AddVertex(middle); graph.AddEdge(new ScheduleEdge(start, middle)); graph.AddEdge(new ScheduleEdge(middle, end)); return new Schedule(graph, start, end); }
/// <summary> /// Initializes a new instance of the <see cref="FixedScheduleBuilder"/> class. /// </summary> public FixedScheduleBuilder() { m_Schedule = new BidirectionalGraph<IScheduleVertex, ScheduleEdge>(false); m_Start = new StartVertex(m_Schedule.VertexCount); m_Schedule.AddVertex(m_Start); m_End = new EndVertex(m_Schedule.VertexCount); m_Schedule.AddVertex(m_End); }
/// <summary> /// Initializes a new instance of the <see cref="Schedule"/> class. /// </summary> /// <param name="graph">The graph that describes the current schedule.</param> /// <param name="start">The start node for the schedule.</param> /// <param name="end">The end node for the schedule.</param> public Schedule( BidirectionalGraph<IScheduleVertex, ScheduleEdge> graph, IScheduleVertex start, IScheduleVertex end) { { Debug.Assert(graph != null, "The graph should not be a null reference."); Debug.Assert(start != null, "The start vertex should not be a null reference."); Debug.Assert(start is StartVertex, "The start vertex should be an editable start vertex."); Debug.Assert(graph.ContainsVertex(start), "The start vertex should be part of the graph."); Debug.Assert(end != null, "The end vertex should not be a null reference."); Debug.Assert(end is EndVertex, "The end vertex should be an editable end vertex."); Debug.Assert(graph.ContainsVertex(end), "The end vertex should be part of the graph."); } m_Start = start; m_End = end; m_Graph = graph; }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var markVertex = vertex as MarkHistoryVertex; if (markVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return ScheduleExecutionState.IncorrectProcessorForVertex; } if (executionInfo.Cancellation.IsCancellationRequested) { return ScheduleExecutionState.Canceled; } if (executionInfo.PauseHandler.IsPaused) { executionInfo.PauseHandler.WaitForUnPause(executionInfo.Cancellation); } var marker = m_Timeline.Mark(); m_OnMarkerStorage(marker); return ScheduleExecutionState.Executing; }
/// <summary> /// Returns the number of vertices to which the current vertex connects. /// </summary> /// <param name="origin">The vertex for which the number of outbound connections should be returned.</param> /// <returns>The number of outbound connections for the current vertex.</returns> public int NumberOfOutboundConnections(IScheduleVertex origin) { return m_Graph.OutDegree(origin); }
private bool ProcessScheduleStep(IScheduleVertex current, ref ScheduleExecutionState state) { if (m_ExecutionInfo.Cancellation.IsCancellationRequested) { state = ScheduleExecutionState.Canceled; return false; } // If we need to pause we do it here m_ExecutionInfo.PauseHandler.WaitForUnPause(m_ExecutionInfo.Cancellation); // Get the executor for the current node type and run it // on the current node. If we fail then we exit the loop { var type = current.GetType(); if (!m_Executors.ContainsKey(type)) { state = ScheduleExecutionState.NoProcessorForVertex; return false; } RaiseOnVertexProcess(Schedule, current.Index); var processor = m_Executors[type]; try { ScheduleExecutionState shouldContinue = processor.Process(current, m_ExecutionInfo); if (shouldContinue != ScheduleExecutionState.Executing) { state = shouldContinue; return false; } RaiseOnExecutionProgress(-1, Resources.Progress_ExecutingSchedule, false); } catch (Exception) { state = ScheduleExecutionState.UnhandledException; return false; } return true; } }
/// <summary> /// Traverses the schedule and applies an action to each vertex visited. /// </summary> /// <param name="start">The vertex where the traverse should be started.</param> /// <param name="vertexAction"> /// The action taken for each vertex that is encountered. The function is provided with the current vertex and /// a collection of all outbound, if <paramref name="traverseViaOutboundVertices"/> is <see langword="true" />, /// or inbound vertices and the ID of the traversing condition. The function should return <see langword="false" /> /// to terminate the traverse. /// </param> /// <param name="directionAction"> /// The function that determines in which direction the traverse should proceed. The function is provided with /// a collection of all outbound, if <paramref name="traverseViaOutboundVertices"/> is <see langword="true" />, /// or inbound vertices and the ID of the traversing condition. The function should return the next vertex /// that should be traversed, or <see langword="null" /> if the traverse should be terminated. /// </param> /// <param name="traverseViaOutboundVertices"> /// A flag indicating if the schedule should be traversed via the outbound edges of the vertices, or the inbound ones. /// </param> public void TraverseSchedule( IScheduleVertex start, Func<IScheduleVertex, bool> vertexAction, Func<IEnumerable<Tuple<ScheduleElementId, IScheduleVertex>>, IScheduleVertex> directionAction, bool traverseViaOutboundVertices = true) { { Lokad.Enforce.Argument(() => start); Lokad.Enforce.With<UnknownScheduleVertexException>( m_Graph.ContainsVertex(start), Resources.Exceptions_Messages_UnknownScheduleVertex); Lokad.Enforce.Argument(() => vertexAction); Lokad.Enforce.Argument(() => directionAction); } var source = start; while (source != null) { var result = vertexAction(source); if (!result) { return; } var outEdges = traverseViaOutboundVertices ? m_Graph.OutEdges(source) : m_Graph.InEdges(source); var traverseMap = from edge in outEdges select new Tuple<ScheduleElementId, IScheduleVertex>( edge.TraversingCondition, traverseViaOutboundVertices ? edge.Target : edge.Source); source = directionAction(traverseMap); } }
/// <summary> /// Processes action provided by the given vertex. /// </summary> /// <param name="vertex">The vertex.</param> /// <param name="executionInfo">The object that stores the information about the execution of the schedule.</param> /// <returns>A value indicating if the execution of the schedule should continue.</returns> public ScheduleExecutionState Process(IScheduleVertex vertex, ScheduleExecutionInfo executionInfo) { var subScheduleVertex = vertex as SubScheduleVertex; if (subScheduleVertex == null) { Debug.Assert(false, "The vertex is of the incorrect type."); return ScheduleExecutionState.IncorrectProcessorForVertex; } if (executionInfo.Cancellation.IsCancellationRequested) { return ScheduleExecutionState.Canceled; } if (executionInfo.PauseHandler.IsPaused) { executionInfo.PauseHandler.WaitForUnPause(executionInfo.Cancellation); } // And how do we deal with loops? We'll cache the schedule if we're in-process but what about being out-of-process? We'll need to // keep the remote app alive ... // --> We'll need some kind of class that handles making the decision for in-process / out-of-process. // * If it's small then we want to do in-process because the loading of a new dataset takes a while // * If it's a parametrized thing then we might want to do out-of-process because we can run many more in one go // // Determine if we're running the sub-simulation synchronous (in-process) or ascynchronous (out-of-process) // Depends on: // - If the original schedule is allowed to split out sub-schedules out-of-process (when running in interactive mode we may // not allow this) // - 'size' of the sub-schedule // // Determine if we should go out of process here // Going out of process only makes sense if the overhead of going out of process is less than // the overhead of staying in process. // The overhead of going out of process is: // * Serialize all the data we need // * Load an application // * Stream the data across // * Deserialize data // * Re-serialize the data that we need (this may be less than what we send across) // * Send data across // * Deserialize data in original app // The overhead for staying in process is given by the fact that we can only run one schedule // at the time // // So going out of process makes sense when: // * There are multiple sub-schedules before the next sync block // ==> that means we can run all of them in parallel and the sync block indicates when we'll need the data // * We want to run the same sub-schedule with multiple parameters // ==> Run the parameter values all at the same time // * We want to split the current calculation out into multiple bits (domain decomposition type) // // Can we determine this when we build the schedule? // Possibly for some sections? bool executeOutOfProcess = false; IEnumerable<IScheduleVariable> parameters = null; var executor = m_Executor.Execute(subScheduleVertex.ScheduleToExecute, parameters, executionInfo, executeOutOfProcess); // if we're running in-process then we probably have to wait for the sub-schedule to // finish executing because we don't want to have to make the schedule execution thread safe // If it's running out-of-process then we don't bother waiting. There should be a sync block // around this section that will sort out the variable synchronization. if (executor.IsLocal) { var resetEvent = new AutoResetEvent(false); var wrapperWait = Observable.FromEventPattern<ScheduleExecutionStateEventArgs>( h => executor.OnFinish += h, h => executor.OnFinish -= h) .Take(1) .Subscribe(args => resetEvent.Set()); using (wrapperWait) { resetEvent.WaitOne(); } } return ScheduleExecutionState.Executing; }