private static QueryPlanNode BuildPlanNode( int numStreams, int streamNo, string[] streamNames, QueryGraph queryGraph, OuterInnerDirectionalGraph outerInnerGraph, OuterJoinDesc[] outerJoinDescList, InnerJoinGraph innerJoinGraph, QueryPlanIndex[] indexSpecs, EventType[] typesPerStream, bool[] ishistorical, DependencyGraph dependencyGraph, HistoricalStreamIndexList[] historicalStreamIndexLists, ExprEvaluatorContext exprEvaluatorContext, TableMetadata[] tablesPerStream) { // For each stream build an array of substreams, considering required streams (inner joins) first // The order is relevant therefore preserving order via a LinkedHashMap. var substreamsPerStream = new LinkedHashMap <int, int[]>(); var requiredPerStream = new bool[numStreams]; // Recursive populating the required (outer) and optional (inner) relationships // of this stream and the substream ISet <int> completedStreams = new HashSet <int>(); // keep track of tree path as only those stream events are always available to historical streams var streamCallStack = new Stack <int>(); streamCallStack.Push(streamNo); // For all inner-joins, the algorithm is slightly different if (innerJoinGraph.IsAllInnerJoin) { requiredPerStream.Fill(true); RecursiveBuildInnerJoin(streamNo, streamCallStack, queryGraph, completedStreams, substreamsPerStream, dependencyGraph); // compute a best chain to see if all streams are handled and add the remaining var bestChain = NStreamQueryPlanBuilder.ComputeBestPath(streamNo, queryGraph, dependencyGraph); AddNotYetNavigated(streamNo, numStreams, substreamsPerStream, bestChain); } else { RecursiveBuild(streamNo, streamCallStack, queryGraph, outerInnerGraph, innerJoinGraph, completedStreams, substreamsPerStream, requiredPerStream, dependencyGraph); } // verify the substreamsPerStream, all streams must exists and be linked VerifyJoinedPerStream(streamNo, substreamsPerStream); // build list of instructions for lookup var lookupInstructions = BuildLookupInstructions(streamNo, substreamsPerStream, requiredPerStream, streamNames, queryGraph, indexSpecs, typesPerStream, outerJoinDescList, ishistorical, historicalStreamIndexLists, exprEvaluatorContext, tablesPerStream); // build strategy tree for putting the result back together var assemblyTopNodeFactory = AssemblyStrategyTreeBuilder.Build(streamNo, substreamsPerStream, requiredPerStream); var assemblyInstructionFactories = BaseAssemblyNodeFactory.GetDescendentNodesBottomUp(assemblyTopNodeFactory); return(new LookupInstructionQueryPlanNode(streamNo, streamNames[streamNo], numStreams, requiredPerStream, lookupInstructions, assemblyInstructionFactories)); }
public void TestComputeBestPath() { NStreamQueryPlanBuilder.BestChainResult bestChain = NStreamQueryPlanBuilder.ComputeBestPath( 0, _queryGraph, _dependencyGraph); Assert.AreEqual(3, bestChain.Depth); Assert.IsTrue(Collections.AreEqual(bestChain.Chain, new int[] { 2, 4, 3, 1 })); bestChain = NStreamQueryPlanBuilder.ComputeBestPath(3, _queryGraph, _dependencyGraph); Assert.AreEqual(4, bestChain.Depth); Assert.IsTrue(Collections.AreEqual(bestChain.Chain, new int[] { 4, 2, 0, 1 })); // try a stream that is not connected in any way _queryGraph = new QueryGraph(6, null, false); bestChain = NStreamQueryPlanBuilder.ComputeBestPath(5, _queryGraph, _dependencyGraph); Log.Debug(".testComputeBestPath bestChain=" + bestChain); Assert.AreEqual(0, bestChain.Depth); Assert.IsTrue(Collections.AreEqual(bestChain.Chain, new int[] { 0, 1, 2, 3, 4 })); }