Пример #1
0
        async Task <Sexp> EvaluateScriptInRserve(SexpList inputDataFrame, int reqHash, string rScript, RserveConnection rserveConn)
        {
            await semaphoreRserve.WaitAsync();

            try
            {
                if (inputDataFrame != null && inputDataFrame.Count > 0)
                {
                    rserveConn.Connection["q"] = inputDataFrame;
                }
                logger.Debug($"Evaluating R script, hashid ({reqHash}): {rScript}");

                var res = rserveConn.Connection.Eval(rScript);
                logger.Info($"Rserve result: {res.Count} rows, hashid ({reqHash})");
                if (res.Count == 0)
                {
                    HandleZeroRowsFromRserve(rserveConn);
                }

                return(res);
            }
            catch (Exception e)
            {
                HandleError(e, rserveConn);
                return(null);
            }
            finally
            {
                semaphoreRserve.Release();
            }
        }
Пример #2
0
        async Task <Sexp> EvaluateScriptInRserve(SexpList inputDataFrame, int reqHash, string rScript, RserveConnection rserveConn)
        {
            var stopwatch = new Stopwatch();

            stopwatch.Start();
            await rserveConn.semaphoreRserve.WaitAsync();

            stopwatch.Stop();
            logger.Trace($"Wait For Connection Took {stopwatch.ElapsedMilliseconds} ms, hashid ({reqHash})");
            try
            {
                if (inputDataFrame != null && inputDataFrame.Count > 0)
                {
                    rserveConn.Connection["q"] = inputDataFrame;
                }
                logger.Debug($"Evaluating R script, hashid ({reqHash}): {rScript}");

                var res = rserveConn.Connection.Eval(rScript);
                logger.Info($"Rserve result: {res.Count} rows, hashid ({reqHash})");
                if (res.Count == 0)
                {
                    HandleZeroRowsFromRserve(rserveConn);
                }

                return(res);
            }
            catch (Exception e)
            {
                HandleError(e, rserveConn);
                return(null);
            }
            finally
            {
                rserveConn.semaphoreRserve.Release();
            }
        }
Пример #3
0
        public override async Task EvaluateScript(IAsyncStreamReader <global::Qlik.Sse.BundledRows> requestStream, IServerStreamWriter <global::Qlik.Sse.BundledRows> responseStream, ServerCallContext context)
        {
            ScriptRequestHeader scriptHeader;
            CommonRequestHeader commonHeader;
            RserveConnection    rserveConn;
            int reqHash = requestStream.GetHashCode();

            if (!(capabilities.AllowScript))
            {
                throw new RpcException(new Status(StatusCode.PermissionDenied, $"Script evaluations disabled"));
            }

            try
            {
                rserveConn = connPool.GetConnection(rservePara);

                var header = GetHeader(context.RequestHeaders, "qlik-scriptrequestheader-bin");
                scriptHeader = ScriptRequestHeader.Parser.ParseFrom(header);

                var commonRequestHeader = GetHeader(context.RequestHeaders, "qlik-commonrequestheader-bin");
                commonHeader = CommonRequestHeader.Parser.ParseFrom(commonRequestHeader);

                logger.Info($"EvaluateScript called from client ({context.Peer}), hashid ({reqHash})");
                logger.Debug($"EvaluateScript header info: AppId ({commonHeader.AppId}), UserId ({commonHeader.UserId}), Cardinality ({commonHeader.Cardinality} rows)");
            }
            catch (Exception e)
            {
                logger.Error($"EvaluateScript with hashid ({reqHash}) failed: {e.Message}");
                throw new RpcException(new Status(StatusCode.DataLoss, e.Message));
            }

            try
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                var paramnames = $"EvaluateScript call with hashid({reqHash}) got Param names: ";

                foreach (var param in scriptHeader.Params)
                {
                    paramnames += $" {param.Name}";
                }
                logger.Info("{0}", paramnames);

                SexpList inputDataFrame = null;

                if (scriptHeader.Params != null && scriptHeader.Params.Count > 0)
                {
                    inputDataFrame = await AddInputData(scriptHeader.Params.ToArray(), requestStream);
                }

                var rResult = await EvaluateScriptInRserve(inputDataFrame, reqHash, scriptHeader.Script, rserveConn);

                // Disable caching (uncomment line below and comment next line if you do not want the results sent to Qlik to be cached in Qlik)
                //await GenerateResult(rResult, responseStream, context, cacheResultInQlik: false);
                await GenerateResult(rResult, responseStream, context);

                stopwatch.Stop();
                logger.Debug($"Took {stopwatch.ElapsedMilliseconds} ms, hashid ({reqHash})");
            }
            catch (Exception e)
            {
                throw new RpcException(new Status(StatusCode.InvalidArgument, $"{e.Message}"));
            }
            finally
            {
                //
            }
        }
Пример #4
0
        public override async Task ExecuteFunction(IAsyncStreamReader <BundledRows> requestStream, IServerStreamWriter <BundledRows> responseStream, ServerCallContext context)
        {
            FunctionRequestHeader functionHeader;
            CommonRequestHeader   commonHeader;
            RserveConnection      rserveConn;
            int reqHash = requestStream.GetHashCode();

            Qlik.Sse.FunctionDefinition sseFunction;
            DefinedFunctions.Function   internalFunction;

            if (nrOfDefinedFunctions == 0)
            {
                throw new RpcException(new Status(StatusCode.Unimplemented, $"No functions defined"));
            }

            try
            {
                rserveConn = connPool.GetConnection(rservePara);

                var header = GetHeader(context.RequestHeaders, "qlik-functionrequestheader-bin");
                functionHeader = FunctionRequestHeader.Parser.ParseFrom(header);

                var commonRequestHeader = GetHeader(context.RequestHeaders, "qlik-commonrequestheader-bin");
                commonHeader = CommonRequestHeader.Parser.ParseFrom(commonRequestHeader);

                logger.Info($"ExecuteFunction: FunctionId ({functionHeader.FunctionId}), from client ({context.Peer}), hashid ({reqHash})");
                logger.Debug($"ExecuteFunction header info: AppId ({commonHeader.AppId}), UserId ({commonHeader.UserId}), Cardinality ({commonHeader.Cardinality} rows)");

                int funcIndex = definedFunctions.GetIndexOfFuncId(functionHeader.FunctionId);

                if (funcIndex < 0)
                {
                    throw new Exception($"FunctionId ({functionHeader.FunctionId}) is not a defined function");
                }
                sseFunction      = definedFunctions.sseFunctions[funcIndex];
                internalFunction = definedFunctions.funcDefs.functions[funcIndex];
            }
            catch (Exception e)
            {
                logger.Error($"ExecuteFunction with hashid ({reqHash}) failed: {e.Message}");
                throw new RpcException(new Status(StatusCode.DataLoss, e.Message));
            }

            try
            {
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                SexpList inputDataFrame = null;

                if (sseFunction.Params.Count > 0)
                {
                    inputDataFrame = await AddInputData(sseFunction.Params.ToArray(), requestStream);
                }

                var rResult = await EvaluateScriptInRserve(inputDataFrame, reqHash, internalFunction.FunctionRScript.Replace("\r", " "), rserveConn);

                await GenerateResult(rResult, responseStream, context, true, sseFunction.ReturnType, internalFunction.CacheResultInQlik);

                stopwatch.Stop();
                logger.Debug($"Took {stopwatch.ElapsedMilliseconds} ms, hashid ({reqHash})");
            }
            catch (Exception e)
            {
                throw new RpcException(new Status(StatusCode.InvalidArgument, $"{e.Message}"));
            }
            finally
            {
                //
            }
        }
Пример #5
0
        /// <summary>
        /// Decode a Qap1-encoded Sexp
        /// </summary>
        /// <param name="data">The byte stream in which the Sexp is encoded</param>
        /// <param name="start">At which index of data does the Sexp begin?</param>
        /// <returns>The decoded Sexp.</returns>
        private static Sexp DecodeSexp( byte[] data , ref long start )
        {
            // pull sexp type
            byte xt = data[ start ];

            // calculate length of payload
            var lengthBuf = new byte[ 8 ];
            Array.Copy( data , start + 1 , lengthBuf , 0 , 3 );
            start += 4;
            if ( ( xt & XtLarge ) == XtLarge )
            {
                Array.Copy( data , start , lengthBuf , 3 , 4 );
                start += 4;
                xt -= XtLarge;
            }
            var length = ( long )BitConverter.ToUInt64( lengthBuf , 0 );

            // has attributes?  process first
            SexpTaggedList attrs = null;
            if ( ( xt & XtHasAttr ) == XtHasAttr )
            {
                xt -= XtHasAttr;
                long oldstart = start;
                attrs = ( SexpTaggedList )DecodeSexp( data , ref start );
                length -= start - oldstart;
            }

            long end = start + length;
            Sexp result;

            switch ( xt )
            {
                case XtNull:
                    {
                        if ( length != 0 )
                        {
                            throw new RserveException( "Attempting to decode an SexpNull, but it is followed by data when it shouldn't be." );
                        }
                        result = new SexpNull();
                    }
                    break;
                case XtSymName:
                    {
                        // keep all characters up to the first null
                        var symnNamBuf = new byte[ length ];
                        Array.Copy( data , start , symnNamBuf , 0 , length );
                        string res = Encoding.UTF8.GetString( symnNamBuf );
                        result = new SexpSymname( res.Split( '\x00' )[ 0 ] );
                    }
                    break;
                case XtArrayInt:
                    {
                        var res = new int[ length / 4 ];
                        var intBuf = new byte[ 4 ];
                        for ( long i = 0 ; i < length ; i += 4 )
                        {
                            Array.Copy( data , start + i , intBuf , 0 , 4 );
                            res[ i / 4 ] = BitConverter.ToInt32( intBuf , 0 );
                        }

                        // is date or just an integer?
                        if ( ( attrs != null ) && ( attrs.ContainsKey( "class" ) && attrs[ "class" ].AsStrings.Contains( "Date" ) ) )
                        {
                            result = new SexpArrayDate( res );
                        }
                        else
                        {
                            result = new SexpArrayInt( res );
                        }
                    }
                    break;
                case XtArrayBool:
                    {
                        if ( length < 4 )
                        {
                            throw new RserveException( "Decoding an SexpArrayBool where data doesn't seem to contain a data length field." );
                        }
                        var boolLengthBuf = new byte[ 4 ];
                        Array.Copy( data , start , boolLengthBuf , 0 , 4 );
                        var datalength = BitConverter.ToInt32( boolLengthBuf , 0 );
                        if ( datalength > length - 4 )
                        {
                            throw new RserveException( "Decoding an SexpArrayBool where transmitted data field too short for number of entries." );
                        }

                        var res = new bool?[ datalength ];
                        for ( int i = 0 ; i < datalength ; i++ )
                        {
                            // R logical is false if 0, true if 1, and NA if 2
                            switch ( data[ start + i + 4 ] )
                            {
                                case 0:
                                    res[ i ] = false;
                                    break;
                                case 1:
                                    res[ i ] = true;
                                    break;
                                case 2:
                                    res[ i ] = null;
                                    break;
                                default:
                                    throw new RserveException( "Decoding an SexpArrayBool and found an element in the array that is not an R bool: " + data[ start + i + 4 ] );
                            }
                        }

                        result = new SexpArrayBool( res );
                    }
                    break;
                case XtArrayDouble:
                    {
                        var res = new double[ length / 8 ];
                        var doubleBuf = new byte[ 8 ];
                        for ( long i = 0 ; i < length ; i += 8 )
                        {
                            Array.Copy( data , start + i , doubleBuf , 0 , 8 );
                            res[ i / 8 ] = BitConverter.ToDouble( doubleBuf , 0 );
                        }

                        // is date or just a double?
                        if ( ( attrs != null ) && ( attrs.ContainsKey( "class" ) && attrs[ "class" ].AsStrings.Contains( "Date" ) ) )
                        {
                            result = new SexpArrayDate( res.Select( Convert.ToInt32 ) );
                        }
                        else
                        {
                            result = new SexpArrayDouble( res );
                        }
                    }
                    break;
                case XtArrayString:
                    {
                        var res = new List<string>();
                        long i = 0;
                        for ( long j = 0 ; j < length ; j++ )
                        {
                            if ( data[ start + j ] != 0 )
                            {
                                continue;
                            }

                            if ( ( j == i + 1 ) && ( data[ start + i ] == 255 ) )
                            {
                                res.Add( null );
                            }
                            else
                            {
                                if ( data[ start + i ] == 255 )
                                {
                                    i++;
                                }

                                var stringBuf = new byte[ j - i ];
                                Array.Copy( data , start + i , stringBuf , 0 , j - i );
                                res.Add( Encoding.UTF8.GetString( stringBuf ) );
                            }
                            i = j + 1;
                        }

                        result = new SexpArrayString( res );
                    }
                    break;
                case XtListNoTag:
                case XtLangNoTag:
                case XtVector:
                    result = new SexpList();
                    while ( start < end )
                    {
                        result.Add( DecodeSexp( data , ref start ) );
                    }
                    break;
                case XtLangTag:
                case XtListTag:
                    result = new SexpTaggedList();
                    while ( start < end )
                    {
                        Sexp val = DecodeSexp( data , ref start );
                        Sexp key = DecodeSexp( data , ref start );
                        result.Add( key.IsNull ? String.Empty : key.AsString , val );
                    }

                    break;
                case XtRaw:
                    {
                        var d = new byte[ length ];
                        Array.Copy( data , start , d , 0 , length );
                        result = new SexpQap1Raw( xt , d );
                    }
                    break;
                default:
                    throw new RserveException( "Cannot decode an Sexp because the type is not recognized: " + xt );
            }

            if ( start > end )
            {
                throw new RserveException( "When decoding an Sexp, more data consumed than provided." );
            }

            start = end;
            if ( attrs != null )
            {
                foreach ( var a in attrs.AsSexpDictionary )
                {
                    result.Attributes.Add( a.Key , a.Value );
                }
            }

            return result;
        }