Beispiel #1
0
        public SelectManyKeyPipeWithStartEdge(SelectManyStreamable <TKey, TSource, TResult> stream, IStreamObserver <TKey, TResult> observer)
            : base(stream, observer)
        {
            this.selector     = (Expression <Func <long, TKey, TSource, IEnumerable <TResult> > >)stream.Selector;
            this.selectorFunc = this.selector.Compile();
            this.pool         = MemoryManager.GetMemoryPool <TKey, TResult>(stream.Properties.IsColumnar);
            this.pool.Get(out this.batch);
            this.batch.Allocate();

            this.iter          = 0;
            this.errorMessages = stream.ErrorMessages;
        }
Beispiel #2
0
        public static Tuple <Type, string> Generate <TKey, TPayload, TResult>(SelectManyStreamable <TKey, TPayload, TResult> stream)
        {
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(UnaryPipe <TKey, TPayload, TResult>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string generatedClassName;
            string expandedCode;
            string errorMessages = null;

            try
            {
                generatedClassName = $"SelectMany_{sequenceNumber++}";
                var keyType     = typeof(TKey);
                var payloadType = typeof(TPayload);
                var resultType  = typeof(TResult);
                var template    = new SelectManyTemplate(generatedClassName, keyType, payloadType, resultType);

                var tm  = new TypeMapper(keyType, payloadType, resultType);
                var gps = tm.GenericTypeVariables(keyType, payloadType, resultType);
                template.genericParameters            = gps.BracketedCommaSeparatedString();
                template.numberOfGenericParameters    = gps.Count();
                template.TKeyTResultGenericParameters = tm.GenericTypeVariables(keyType, resultType).BracketedCommaSeparatedString();
                template.MemoryPoolGenericParameters  = $"<{template.TKey}, {template.TResult}>";
                if (resultType == typeof(int) || resultType == typeof(long) || resultType == typeof(string))
                {
                    template.MemoryPoolGenericParameters = string.Empty;
                }

                var payloadParameterIndex = 0;
                if (stream.HasKey && stream.HasStartEdge)
                {
                    payloadParameterIndex = 2;
                }
                else if (stream.HasKey || stream.HasStartEdge)
                {
                    payloadParameterIndex = 1;
                }

                var selector         = stream.Selector;
                var payloadParameter = selector.Parameters.ElementAt(payloadParameterIndex);

                template.PARAMETER = payloadParameter.Name;

                template.resultPayloadRepresentation = new ColumnarRepresentation(resultType);
                template.resultFields = template.resultPayloadRepresentation.AllFields;

                if (template.numberOfGenericParameters > 0)
                {
                    generatedClassName = generatedClassName + "`" + template.numberOfGenericParameters.ToString(CultureInfo.InvariantCulture);
                }

                expandedCode = string.Empty;

                Expression transformedSelector = selector;

                // No substitutions are made for the start edge parameter or key parameter. Both just remain in the
                // body of the result selector and are set as local variables in the generated code.

                var keyParameterIndex = stream.HasStartEdge ? 1 : 0;

                var tuple = OptimizeSelectMany(selector.Body);
                if (tuple != null)
                {
                    template.enumerableRepeatSelector = true;
                    var resultSelector         = stream.Selector;
                    var sourceMessageType      = StreamMessageManager.GetStreamMessageType <TKey, TPayload>();
                    var pseudoLambdaParameters = new ParameterExpression[stream.HasKey ? 2 : 1];
                    var pseudoLambdaIndex      = 0;
                    if (stream.HasKey)
                    {
                        pseudoLambdaParameters[pseudoLambdaIndex++] = selector.Parameters[keyParameterIndex];
                    }
                    pseudoLambdaParameters[pseudoLambdaIndex] = payloadParameter;
                    var pseudoLambda = Expression.Lambda(tuple.Item1, pseudoLambdaParameters);

                    var parameterSubstitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >
                    {
                        Tuple.Create(payloadParameter, new SelectParameterInformation()
                        {
                            BatchName = "batch", BatchType = sourceMessageType, IndexVariableName = "i", parameterRepresentation = new ColumnarRepresentation(payloadType)
                        })
                    };
                    var projectionResult = SelectTransformer.Transform(pseudoLambda, parameterSubstitutions, template.resultPayloadRepresentation, true, stream.HasStartEdge);
                    template.computedFields = projectionResult.ComputedFields;
                    template.useEnumerator  = false;
                    var loopCounter   = tuple.Item2;
                    var newParameters = new ParameterExpression[stream.HasKey ? 2 : 1];
                    newParameters[0] = payloadParameter;
                    if (stream.HasKey)
                    {
                        newParameters[1] = selector.Parameters[keyParameterIndex];
                    }

                    var loopCounterLambda      = Expression.Lambda(loopCounter, payloadParameter);
                    var transformedLoopCounter = Extensions.TransformFunction <TKey, TPayload>(loopCounterLambda, 0);
                    template.loopCounter = transformedLoopCounter.Body.ExpressionToCSharp();

                    // REVIEW: Alternative: use Inline to replace occurrences of the key parameter
                    // with "batch.key.col[i]".
                    if (stream.HasKey)
                    {
                        template.keyParameterName = selector.Parameters[keyParameterIndex].Name;
                    }
                }
                else
                {
                    transformedSelector = Extensions.TransformFunction <TKey, TPayload>(stream.Selector, payloadParameterIndex).Body;

                    if (transformedSelector == null)
                    {
                        template.useEnumerator = true;
                        template.transformedSelectorAsSource = stream.Selector.ExpressionToCSharp();
                    }
                    else
                    {
                        var tuple2 = OptimizeSelectMany(transformedSelector);
                        if (tuple2 != null)
                        {
                            template.useEnumerator = false;
                            template.loopCounter   = tuple2.Item2.ExpressionToCSharp();
                            template.transformedSelectorAsSource = tuple2.Item1.ExpressionToCSharp();
                        }
                        else
                        {
                            template.useEnumerator = true;
                            template.transformedSelectorAsSource = transformedSelector.ExpressionToCSharp();
                        }
                    }
                }

                template.StartEdgeParameterName = stream.HasStartEdge ? selector.Parameters.ElementAt(0).Name : null;
                template.hasKey = stream.HasKey;
                expandedCode    = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeof(TKey), typeof(TPayload), typeof(TResult));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TPayload>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TResult>());
                assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TKey, TResult>());
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(stream.Selector));

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var t = a.GetType(generatedClassName);
                t = t.InstantiateAsNecessary(typeof(TKey), typeof(TPayload), typeof(TResult));
                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));
            }
        }