private void JobShopScheduling(OrderOperationGraph orderOperationGraph) { IDbTransactionData dbTransactionData = ZppConfiguration.CacheManager.GetDbTransactionData(); IAggregator aggregator = ZppConfiguration.CacheManager.GetAggregator(); // some validations if (dbTransactionData.ProductionOrderGetAll().Any() == false) { // no JobShopScheduling needed, all Demands were satisfied without the need for a productionOrder return; } foreach (var productionOrder in dbTransactionData.ProductionOrderGetAll()) { List <ProductionOrderOperation> operations = aggregator.GetProductionOrderOperationsOfProductionOrder( (ProductionOrder)productionOrder); if (operations == null || operations.Any() == false) { throw new MrpRunException( "How could it happen, that a productionOrder without operations exists ?"); } } // start ! IDirectedGraph <INode> operationGraph = new OperationGraph(orderOperationGraph); _jobShopScheduler.ScheduleWithGifflerThompsonAsZaepfel( new PriorityRule(operationGraph), operationGraph); }
private void TraverseDemandToProviderGraph(INode node, IStackSet <INode> visitedProductionOrders) { if (node.GetEntity().GetType() == typeof(ProductionOrderBom)) { // remove, ProductionOrderBoms will be ignored and replaced by operations RemoveNode(node, true); } else if (node.GetEntity().GetType() == typeof(ProductionOrder) && visitedProductionOrders.Contains(node) == false) { // insert it like it is in ProductionOrderToOperationGraph OperationGraph operationGraph = new OperationGraph((ProductionOrder)node.GetEntity()); ReplaceNodeByDirectedGraph(node, operationGraph); visitedProductionOrders.Push(node); } INodes successorNodes = GetSuccessorNodes(node); if (successorNodes == null) { return; } foreach (var successor in successorNodes) { TraverseDemandToProviderGraph(successor, visitedProductionOrders); } }
public static void Serialize(OperationGraph state, System.IO.BinaryWriter writer) { // Write the File Header with version writer.Write(new char[] { 'B', 'O', 'G', '\0' }); writer.Write(FileVersion); // Write out the set of files var files = state.GetReferencedFiles(); writer.Write(new char[] { 'F', 'I', 'S', '\0' }); writer.Write((uint)files.Count); foreach (var file in files) { // Write the file id + path length + path writer.Write(file.FileId.value); WriteValue(writer, file.Path.ToString()); } // Write out the root operation ids writer.Write(new char[] { 'R', 'O', 'P', '\0' }); WriteValues(writer, state.GetRootOperationIds()); // Write out the set of operations var operations = state.GetOperations(); writer.Write(new char[] { 'O', 'P', 'S', '\0' }); writer.Write((uint)operations.Count); foreach (var operationValue in state.GetOperations()) { WriteOperationInfo(writer, operationValue.Value); } }
/** * No need to traverse --> graph is ready, just do some modifications: * remove ProductionOrderBoms, replace ProductionOrder by operationGraph, ... */ private DemandToProviderGraph CreateGraph3() { IDbTransactionData dbTransactionData = ZppConfiguration.CacheManager.GetDbTransactionData(); DemandToProviderGraph demandToProviderGraph = new DemandToProviderGraph(); // replace ProductionOrder by operationGraph foreach (var productionOrder in dbTransactionData.ProductionOrderGetAll()) { if (productionOrder.IsReadOnly() == false) { var productionOrderBomNode = new Node(productionOrder); if (demandToProviderGraph.Contains(productionOrderBomNode)) { OperationGraph operationGraph = new OperationGraph((ProductionOrder)productionOrder); INodes leafOfOperationGraph = operationGraph.GetLeafNodes(); demandToProviderGraph.ReplaceNodeByDirectedGraph(productionOrderBomNode, operationGraph); /*// remove all arrows from leaf, since material must be ready to the * // corresponding operation not to first operation * INodes successorsOfLeaf = * demandToProviderGraph.GetSuccessorNodes(leafOfOperationGraph.GetAny()); * foreach (var successor in successorsOfLeaf) * { * demandToProviderGraph.RemoveEdge(leafOfOperationGraph.GetAny(), successor); * }*/// --> somehow not neccessary } } } // connect every ProductionOrderBom successor to its operation foreach (var productionOrderBom in dbTransactionData.ProductionOrderBomGetAll()) { if (productionOrderBom.IsReadOnly() == false) { var productionOrderBomNode = new Node(productionOrderBom); if (demandToProviderGraph.Contains(productionOrderBomNode)) { ProductionOrderOperation productionOrderOperation = ((ProductionOrderBom)productionOrderBom).GetProductionOrderOperation(); INodes successorNodes = demandToProviderGraph.GetSuccessorNodes(productionOrderBom.GetId()); demandToProviderGraph.RemoveNode(productionOrderBomNode.GetId(), false); foreach (var successor in successorNodes) { demandToProviderGraph.AddEdge( new Edge(new Node(productionOrderOperation), successor)); } } } } return(demandToProviderGraph); }
/// <summary> /// Load the operation state from the provided directory /// </summary> public static bool TryLoadState( Path operationGraphFile, FileSystemState fileSystemState, out OperationGraph result) { // Verify the requested file exists if (!System.IO.File.Exists(operationGraphFile.ToString())) { Log.Info("Operation graph file does not exist"); result = new OperationGraph(); return(false); } // Open the file to read from using (var fileStream = System.IO.File.OpenRead(operationGraphFile.ToString())) using (var reader = new System.IO.BinaryReader(fileStream)) { // Read the contents of the build state file try { var loadedResult = OperationGraphReader.Deserialize(reader); // Map up the incoming file ids to the active file system state ids var activeFileIdMap = new Dictionary <FileId, FileId>(); for (var i = 0; i < loadedResult.GetReferencedFiles().Count; i++) { var fileReference = loadedResult.GetReferencedFiles()[i]; var activeFileId = fileSystemState.ToFileId(fileReference.Path); activeFileIdMap.Add(fileReference.FileId, activeFileId); // Update the referenced id fileReference.FileId = activeFileId; } // Update all of the operations foreach (var operationReference in loadedResult.GetOperations()) { var operation = operationReference.Value; UpdateFileIds(operation.DeclaredInput, activeFileIdMap); UpdateFileIds(operation.DeclaredOutput, activeFileIdMap); UpdateFileIds(operation.ObservedInput, activeFileIdMap); UpdateFileIds(operation.ObservedOutput, activeFileIdMap); } result = loadedResult; return(true); } catch { Log.Error("Failed to parse operation graph"); result = new OperationGraph(); return(false); } } }
private void BuildGraphColumn( FileSystemState fileSystemState, OperationGraph evaluateGraph, IList <IList <GraphNode> > activeGraph, IList <OperationId> activeIds, HashSet <OperationId> knownIds) { // Build up the total set of nodes in the next level var nextIds = new List <OperationId>(); foreach (var operationId in activeIds) { var operation = evaluateGraph.GetOperationInfo(operationId); foreach (var childId in operation.Children) { nextIds.Add(childId); } } // Find the depest level first if (nextIds.Count > 0) { BuildGraphColumn(fileSystemState, evaluateGraph, activeGraph, nextIds, knownIds); } // Build up all the nodes at this level that have not already been added var column = new List <GraphNode>(); foreach (var operationId in activeIds) { if (!knownIds.Contains(operationId)) { var operation = evaluateGraph.GetOperationInfo(operationId); var node = new GraphNode(operation.Title, operationId.value) { ChildNodes = operation.Children.Select(value => value.value).ToList(), }; knownIds.Add(operationId); column.Add(node); this.operationDetailsLookup.Add(operationId.value, new OperationDetailsViewModel(fileSystemState, operation)); } } // Add the new column at the start activeGraph.Insert(0, column); }
/// <summary> /// Save the operation state for the provided directory /// </summary> public static void SaveState( Path operationGraphFile, OperationGraph state, FileSystemState fileSystemState) { var targetFolder = operationGraphFile.GetParent(); // Update the operation graph referenced files var files = new HashSet <FileId>(); foreach (var operationReference in state.GetOperations()) { var operation = operationReference.Value; files.UnionWith(operation.DeclaredInput); files.UnionWith(operation.DeclaredOutput); files.UnionWith(operation.ReadAccess); files.UnionWith(operation.WriteAccess); files.UnionWith(operation.ObservedInput); files.UnionWith(operation.ObservedOutput); } var referencedFiles = new List <(FileId FileId, Path Path)>(); foreach (var fileId in files) { referencedFiles.Add((fileId, fileSystemState.GetFilePath(fileId))); } state.SetReferencedFiles(referencedFiles); // Ensure the target directories exists if (!System.IO.Directory.Exists(targetFolder.ToString())) { Log.Info("Create Directory: " + targetFolder.ToString()); System.IO.Directory.CreateDirectory(targetFolder.ToString()); } // Open the file to write to using (var fileStream = System.IO.File.Open(operationGraphFile.ToString(), System.IO.FileMode.Create, System.IO.FileAccess.Write)) using (var writer = new System.IO.BinaryWriter(fileStream)) { // Write the build state to the file stream OperationGraphWriter.Serialize(state, writer); } }
public void TestGraphIsComplete(string testConfigurationFileName) { InitThisTest(testConfigurationFileName); IDbTransactionData dbTransactionData = global::Zpp.ZppConfiguration.CacheManager.ReloadTransactionData(); IDirectedGraph <INode> operationGraph = new OperationGraph(new OrderOperationGraph()); IEnumerable <ProductionOrderOperation> productionOrderOperations = operationGraph.GetNodes().Select(x => (ProductionOrderOperation)x.GetNode().GetEntity()); foreach (var productionOrderOperation in dbTransactionData .ProductionOrderOperationGetAll()) { Assert.True(productionOrderOperations.Contains(productionOrderOperation), $"{productionOrderOperation} is missing."); } }
public void TestBackwardSchedulingTransitionTimeBetweenOperationsIsCorrect( string testConfigurationFileName) { InitThisTest(testConfigurationFileName); IDbTransactionData dbTransactionData = ZppConfiguration.CacheManager.ReloadTransactionData(); IDirectedGraph <INode> operationGraph = new OperationGraph(new OrderOperationGraph()); IStackSet <INode> innerLeafs = operationGraph.GetLeafNodes().ToStackSet(); IStackSet <INode> traversedNodes = new StackSet <INode>(); foreach (var leaf in innerLeafs) { INodes predecessorNodesRecursive = operationGraph.GetPredecessorNodesRecursive(leaf); IStackSet <ProductionOrderOperation> newPredecessorNodes = new StackSet <ProductionOrderOperation>( predecessorNodesRecursive.Select(x => (ProductionOrderOperation)x.GetEntity())); ProductionOrderOperation lastOperation = (ProductionOrderOperation)leaf.GetEntity(); ValidatePredecessorOperationsTransitionTimeIsCorrect(newPredecessorNodes, lastOperation, operationGraph, traversedNodes); traversedNodes.Push(leaf); } int expectedTraversedOperationCount = new Stack <ProductionOrderOperation>( dbTransactionData.ProductionOrderOperationGetAll()).Count(); int actualTraversedOperationCount = traversedNodes.Count(); Assert.True(actualTraversedOperationCount.Equals(expectedTraversedOperationCount), $"expectedTraversedOperationCount {expectedTraversedOperationCount} " + $"doesn't equal actualTraversedOperationCount {actualTraversedOperationCount}'"); }
public static async Task <RequestGraph> ToRequestGraphAsync(OperationGraph graph, IReadOnlyList <string> sources) { var maxSourceIndex = graph.Nodes.Max(x => x.Operation.SourceIndex); if (maxSourceIndex >= sources.Count) { throw new ArgumentException($"The max source index in the operation graph is {maxSourceIndex} so at least {maxSourceIndex + 1} sources are required."); } var operationToRequest = await RequestBuilder.BuildAsync(sources, graph.Nodes.Select(x => x.Operation)); // Initialize all of the request nodes. var requestNodes = new List <RequestNode>(); var operationNodeToRequestNode = new Dictionary <OperationNode, RequestNode>(); foreach (var operationNode in graph.Nodes) { var requestNode = new RequestNode( operationNode.HitIndex, operationToRequest[operationNode.Operation]); requestNodes.Add(requestNode); operationNodeToRequestNode.Add(operationNode, requestNode); } // Initialize dependencies. foreach (var operationNode in graph.Nodes) { var requestNode = operationNodeToRequestNode[operationNode]; foreach (var dependency in operationNode.Dependencies) { requestNode.Dependencies.Add(operationNodeToRequestNode[dependency]); } } return(new RequestGraph(requestNodes, sources.ToList())); }
private IList <IList <GraphNode> > BuildGraph(FileSystemState fileSystemState, OperationGraph evaluateGraph) { this.operationDetailsLookup.Clear(); var activeIds = evaluateGraph.GetRootOperationIds(); var activeGraph = new List <IList <GraphNode> >(); var knownIds = new HashSet <OperationId>(); BuildGraphColumn(fileSystemState, evaluateGraph, activeGraph, activeIds, knownIds); return(activeGraph); }
/// <summary> /// Execute the entire operation graph that is referenced by this build generate engine. /// </summary> public async Task GenerateAsync(Path soupTargetDirectory) { // Run all build operations in the correct order with incremental build checks Log.Diag("Build generate start"); // Load the parameters file var parametersFile = soupTargetDirectory + BuildConstants.GenerateParametersFileName; if (!ValueTableManager.TryLoadState(parametersFile, out var parametersState)) { Log.Error("Failed to load the parameter file: " + parametersFile.ToString()); throw new InvalidOperationException("Failed to load parameter file."); } // Load the read access file var readAccessFile = soupTargetDirectory + BuildConstants.GenerateReadAccessFileName; var readAccessList = new List <Path>(); if (!await PathListManager.TryLoadFileAsync(readAccessFile, readAccessList)) { Log.Error("Failed to load the read access file: " + readAccessFile.ToString()); throw new InvalidOperationException("Failed to load read access file."); } // Load the write access file var writeAccessFile = soupTargetDirectory + BuildConstants.GenerateWriteAccessFileName; var writeAccessList = new List <Path>(); if (!await PathListManager.TryLoadFileAsync(writeAccessFile, writeAccessList)) { Log.Error("Failed to load the write access file: " + writeAccessFile.ToString()); throw new InvalidOperationException("Failed to load write access file."); } // Get the required input state from the parameters var targetDirectory = new Path(parametersState["TargetDirectory"].AsString().ToString()); var packageDirectory = new Path(parametersState["PackageDirectory"].AsString().ToString()); // Load the recipe file var recipeFile = packageDirectory + BuildConstants.RecipeFileName; var(isSuccess, recipe) = await RecipeExtensions.TryLoadRecipeFromFileAsync(recipeFile); if (!isSuccess) { Log.Error("Failed to load the recipe: " + recipeFile.ToString()); throw new InvalidOperationException("Failed to load recipe."); } // Combine all the dependencies shared state var dependenciesSharedState = LoadDependenciesSharedState(parametersState); // Generate the set of build extension libraries var buildExtensionLibraries = GenerateBuildExtensionSet(recipe, dependenciesSharedState); // Start a new active state that is initialized to the recipe itself var activeState = new ValueTable(); // Initialize the Recipe Root Table var recipeState = recipe.Table; activeState.Add("Recipe", new Value(recipeState)); // Initialize the Parameters Root Table activeState.Add("Parameters", new Value(parametersState)); // Initialize the Dependencies Root Table activeState.Add("Dependencies", new Value(dependenciesSharedState)); // Keep the extension libraries open while running the build system // to ensure their memory is kept alive var evaluateGraph = new OperationGraph(); IValueTable sharedState = new ValueTable(); { // Create a new build system for the requested build var buildTaskManager = new BuildTaskManager(); // Run all build extension register callbacks foreach (var buildExtension in buildExtensionLibraries) { var library = LoadPlugin(buildExtension); FindAllCommands(library, buildTaskManager); } // Run the build var buildState = new BuildState( activeState, _fileSystemState, readAccessList, writeAccessList); buildTaskManager.Execute(buildState, soupTargetDirectory); // Grab the build results so the dependency libraries can be released asap evaluateGraph = buildState.BuildOperationGraph(); sharedState = buildState.SharedState; } // Save the operation graph so the evaluate phase can load it var evaluateGraphFile = soupTargetDirectory + BuildConstants.GenerateEvaluateOperationGraphFileName; OperationGraphManager.SaveState(evaluateGraphFile, evaluateGraph, _fileSystemState); // Save the shared state that is to be passed to the downstream builds var sharedStateFile = soupTargetDirectory + BuildConstants.GenerateSharedStateFileName; ValueTableManager.SaveState(sharedStateFile, sharedState); Log.Diag("Build generate end"); }