public SnapshotWindowStreamable(IStreamable <TKey, TInput> source, IAggregate <TInput, TState, TOutput> aggregate)
            : base(source, source.Properties.Snapshot(aggregate))
        {
            Contract.Requires(source != null);

            this.Aggregate   = aggregate;
            this.sourceProps = source.Properties;

            if (this.sourceProps.IsStartEdgeOnly)
            {
                this.apt = AggregatePipeType.StartEdge;
            }
            else if (this.sourceProps.IsConstantDuration)
            {
                if (this.sourceProps.IsTumbling)
                {
                    this.apt = AggregatePipeType.Tumbling;
                }
                else if (this.sourceProps.ConstantDurationLength.HasValue && this.sourceProps.IsConstantHop && this.sourceProps.ConstantHopLength.HasValue)
                {
                    this.apt = AggregatePipeType.Hopping;
                }
                else
                {
                    this.apt = AggregatePipeType.Sliding;
                }
            }
            else
            {
                this.apt = AggregatePipeType.PriorityQueue;
            }

            Initialize();
        }
示例#2
0
 internal SnapshotWindowPlanNode(
     PlanNode previous,
     IQueryObject pipe,
     Type keyType,
     Type inputType,
     Type outputType,
     AggregatePipeType type,
     IAggregate <TInput, TState, TResult> aggregate,
     bool isGenerated, string errorMessages)
     : base(previous, pipe, keyType, outputType, inputType, isGenerated, errorMessages)
 {
     this.InternalAggregateType = type;
     this.Aggregate             = aggregate;
 }
        public static Tuple <Type, string> Generate <TKey, TInput, TState, TOutput>(SnapshotWindowStreamable <TKey, TInput, TState, TOutput> stream, AggregatePipeType pipeType)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(IStreamObserver <TKey, TInput>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            var             container = stream.Properties.QueryContainer;
            string          generatedClassName;
            string          expandedCode;
            List <Assembly> assemblyReferences;
            string          errorMessages = null;

            try
            {
                AggregateTemplate template;
                switch (pipeType)
                {
                case AggregatePipeType.StartEdge:
                    template = new SnapshotWindowStartEdgeTemplate();
                    break;

                case AggregatePipeType.PriorityQueue:
                    template = new SnapshotWindowPriorityQueueTemplate();
                    break;

                case AggregatePipeType.Tumbling:
                    template = new SnapshotWindowTumblingTemplate();
                    break;

                case AggregatePipeType.Sliding:
                    template = new SnapshotWindowSlidingTemplate();
                    break;

                case AggregatePipeType.Hopping:
                    template = new SnapshotWindowHoppingTemplate
                    {
                        hopsPerDuration = ((int)(stream.Source.Properties.ConstantDurationLength.Value / stream.Source.Properties.ConstantHopLength) + 1).ToString()
                    };
                    break;

                default:
                    Contract.Assert(false, "case meant to be exhaustive");
                    throw new InvalidOperationException("case meant to be exhaustive");
                }

                template.isUngrouped = (typeof(TKey) == typeof(Empty));
                var keyType    = template.keyType = typeof(TKey);
                var inputType  = template.inputType = typeof(TInput);
                var stateType  = template.stateType = typeof(TState);
                var outputType = template.outputType = typeof(TOutput);

                template.inputFields = new ColumnarRepresentation(inputType).AllFields;

                template.outputFields = new ColumnarRepresentation(outputType).AllFields;

                assemblyReferences = new List <Assembly>();

                #region Key Comparer
                IEqualityComparerExpression <TKey> keyComparer;
                keyComparer = stream.Properties.KeyEqualityComparer;
                var equalsExpression      = keyComparer.GetEqualsExpr();
                var getHashcodeExpression = keyComparer.GetGetHashCodeExpr();
                template.inlinedKeyComparerEquals =
                    (left, right) =>
                    string.Format("({0})", equalsExpression.Inline(left, right));
                template.inlinedKeyComparerGetHashCode =
                    (x) =>
                    string.Format("({0}/* inlined GetHashCode */)", getHashcodeExpression.Inline(x));
                if (keyType.IsAnonymousType())
                {
                    template.inlinedKeyComparerEquals =
                        (left, right) => string.Format("keyComparerEquals({0}, {1})", left, right);
                    template.inlinedKeyComparerGetHashCode =
                        (x) => string.Format("keyComparerGetHashCode({0})", x);
                }
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(equalsExpression));
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(getHashcodeExpression));
                #endregion

                #region Aggregate Functions
                var initialStateLambda = stream.Aggregate.InitialState();
                if (ConstantExpressionFinder.IsClosedExpression(initialStateLambda))
                {
                    template.initialState = initialStateLambda.Body.ExpressionToCSharp();
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(initialStateLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for Aggregate: couldn't inline the initial state lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledInitialState = true;
                        template.initialState            = "initialState()";
                    }
                }

                var accumulateLambda = stream.Aggregate.Accumulate();
                if (ConstantExpressionFinder.IsClosedExpression(accumulateLambda))
                {
                    var accTransformedLambda = Extensions.TransformFunction <TKey, TInput>(accumulateLambda, 2);
                    template.accumulate = (stateArg, longArg) => accTransformedLambda.Inline(stateArg, longArg);
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(accumulateLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for Aggregate: couldn't inline the accumulate lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledAccumulate = true;
                        template.accumulate            = (s1, s2) => string.Format("accumulate({0}, {1}, batch[i]);", s1, s2);
                    }
                }

                var deaccumulateLambda = stream.Aggregate.Deaccumulate();
                if (ConstantExpressionFinder.IsClosedExpression(deaccumulateLambda))
                {
                    var deaccumulateTransformedLambda = Extensions.TransformFunction <TKey, TInput>(deaccumulateLambda, 2);
                    template.deaccumulate = (stateArg, longArg) => deaccumulateTransformedLambda.Inline(stateArg, longArg);
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(deaccumulateLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for Aggregate: couldn't inline the deaccumulate lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledDeaccumulate = true;
                        template.deaccumulate            = (s1, s2) => string.Format("deaccumulate({0}, {1}, batch[i]);", s1, s2);
                    }
                }

                var differenceLambda = stream.Aggregate.Difference();
                if (ConstantExpressionFinder.IsClosedExpression(differenceLambda))
                {
                    template.difference = (stateArg1, stateArg2) => differenceLambda.Inline(stateArg1, stateArg2);
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(differenceLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        errorMessages = "Code Generation for Aggregate: couldn't inline the difference lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledDifference = true;
                        template.difference            = (s1, s2) => string.Format("difference({0}, {1});", s1, s2);
                    }
                }

                var computeResultLambda = stream.Aggregate.ComputeResult();
                if (ConstantExpressionFinder.IsClosedExpression(computeResultLambda))
                {
                    if (outputType.IsAnonymousType())
                    {
                        if (computeResultLambda.Body is NewExpression newExpression)
                        {
                            var outputBatchType = StreamMessageManager.GetStreamMessageType <TKey, TOutput>();
                            var foo             = Transform(newExpression, outputBatchType);
                            template.computeResult = (stateArg) => Expression.Lambda(foo, computeResultLambda.Parameters.ToArray()).Inline(stateArg);
                        }
                        else
                        {
                            template.computeResult = (stateArg) => computeResultLambda.Inline(stateArg);
                        }
                    }
                    else
                    {
                        template.computeResult = (stateArg) => computeResultLambda.Inline(stateArg);
                    }
                    assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(computeResultLambda));
                }
                else
                {
                    if (Config.CodegenOptions.SuperStrictColumnar || outputType.IsAnonymousType())
                    {
                        // second disjunct is because if we aren't inlining the computeResult function and
                        // the output type is anonymous, calling the compiled computeResult function returns
                        // a value of the anonymous type and since the generated operator represents the anonymous
                        // type as a generic parameter, it can't use the "field" (i.e., property) names to
                        // get the individual pieces to assign to each column of the output message.
                        errorMessages = "Code Generation for Aggregate: couldn't inline the compute result lambda!";
                        throw new InvalidOperationException(errorMessages);
                    }
                    else
                    {
                        template.useCompiledComputeResult = true;
                        template.computeResult            = (stateArg) => "computeResult(" + stateArg + ");";
                    }
                }
                #endregion

                generatedClassName = template.className = string.Format("Aggregate_{0}", sequenceNumber++);
                generatedClassName = generatedClassName.AddNumberOfNecessaryGenericArguments(keyType, inputType, stateType, outputType);

                template.staticCtor = Transformer.StaticCtor(template.className);
                expandedCode        = template.TransformText();

                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(typeof(TKey), typeof(TInput), typeof(TState), typeof(TOutput), typeof(FastDictionaryGenerator), typeof(SortedDictionary <,>)));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TInput>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TOutput>());
                assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TKey, TOutput>());
                if (container != null)
                {
                    assemblyReferences.AddRange(container.CollectedGeneratedTypes.Select(o => o.GetTypeInfo().Assembly));
                }

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                if (keyType.IsAnonymousType())
                {
                    if (errorMessages == null)
                    {
                        errorMessages = string.Empty;
                    }
                    errorMessages += "\nCodegen Warning: The key type for an aggregate is an anonymous type (or contains an anonymous type), preventing the inlining of the key equality and hashcode functions. This may lead to poor performance.\n";
                }
                var t = a.GetType(generatedClassName);
                if (t.GetTypeInfo().IsGenericType)
                {
                    var list = typeof(TKey).GetAnonymousTypes();
                    list.AddRange(typeof(TInput).GetAnonymousTypes());
                    list.AddRange(typeof(TState).GetAnonymousTypes());
                    list.AddRange(typeof(TOutput).GetAnonymousTypes());
                    t = t.MakeGenericType(list.ToArray());
                }
                return(Tuple.Create(t, errorMessages));
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }