Пример #1
0
        /// <summary>
        /// Instantiate a Table by directly deserializing byte data from the given Deserializer.
        /// </summary>
        /// <param name="input">The Deserializer providing the data for the table.</param>
        internal TableBase(Deserializer input)
        {
            // Total byte length of the table data (ignored).
            int tableLength = input.ReadInt32();

            // Total byte length of the Table metadata.
            int tableMetadataLength = input.ReadInt32();

            // Status code (custom user-set value).
            this.Status = input.ReadSByte();
            // Column Count.
            this.ColumnCount = input.ReadInt16();

            // Initialize column-driven data store.
            ColumnType = new DBType[this.ColumnCount];
            Column = new object[this.ColumnCount];

            // Read column data types.
            for (short c = 0; c < this.ColumnCount; c++)
                ColumnType[c] = (DBType)input.ReadSByte();

            // Read column names.
            this.ColumnNameData = input.ReadRaw(tableMetadataLength - 3 - this.ColumnCount);

            // Row count.
            this.RowCount = input.ReadInt32();
        }
        /// <summary>
        /// Instantiate a Table by directly deserializing byte data from the given Deserializer.
        /// </summary>
        /// <param name="input">The Deserializer providing the data for the table.</param>
        internal SingleRowTable(Deserializer input)
            : base(input)
        {
            // Validate row count.
            if (this.RowCount > 1)
                throw new VoltInvalidDataException(Resources.InvalidRowCount, this.RowCount);
            else if (this.RowCount == 0)
                return;

            // Total byte length of the row (ignored).
            int rowLength = input.ReadInt32();

            // Read data and push in storage.
            for (short c = 0; c < this.ColumnCount; c++)
            {
                switch (ColumnType[c])
                {
                    case DBType.TINYINT:
                        Column.SetValue(input.ReadSByteN(), c);
                        break;
                    case DBType.SMALLINT:
                        Column.SetValue(input.ReadInt16N(), c);
                        break;
                    case DBType.INTEGER:
                        Column.SetValue(input.ReadInt32N(), c);
                        break;
                    case DBType.BIGINT:
                        Column.SetValue(input.ReadInt64N(), c);
                        break;
                    case DBType.FLOAT:
                        Column.SetValue(input.ReadDoubleN(), c);
                        break;
                    case DBType.DECIMAL:
                        Column.SetValue(input.ReadVoltDecimalN(), c);
                        break;
                    case DBType.TIMESTAMP:
                        Column.SetValue(input.ReadDateTimeN(), c);
                        break;
                    case DBType.VARBINARY:
                        Column.SetValue(input.ReadByteArray(), c);
                        break;
                    default:
                        Column.SetValue(input.ReadString(), c);
                        break;
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Parses the returned server message to read properties.
        /// </summary>
        /// <param name="input">The deserializer holding the data form the server message.</param>
        internal void ParseHeader(Deserializer input)
        {
            try
            {
                // Skip the client executionId: the caller (background network thread) already verified a match and
                // we recorded it at the start.
                input.Skip(8);

                // Check field map for status header parsing.
                this._HasFields = (HasFields)input.ReadByte();

                // Read the Status (and optional associated message).
                this.ServerStatus = (ResponseServerStatus)input.ReadSByte();
                if ((this._HasFields & HasFields.Status) == HasFields.Status)
                    this.ServerStatusString = input.ReadString();

                // Read the Application Status (and optional associated message).
                this.ServerApplicationStatus = input.ReadSByte();
                if ((this._HasFields & HasFields.ApplicationStatus) == HasFields.ApplicationStatus)
                    this.ServerApplicationStatusString = input.ReadString();

                // Track query duration (ms).
                this.ExecutionDuration = input.ReadInt32();

                // Skip exception data (currently not used and initialized to the same value as the Status string!).
                if ((this._HasFields & HasFields.Exception) == HasFields.Exception)
                    //this.ServerExceptionString = input.ReadString();
                    input.SkipString();

                // Figure out whether to move forward or kill over - note that we don't *really* kill over, but simply
                // report the Exception in the response's Exception field - the caller should validate that the
                // response is in good status before proceeding to read the results.
                switch (this.ServerStatus)
                {
                    case ResponseServerStatus.Success:
                        break;

                    case ResponseServerStatus.UserAbort:
                        this.Exception = new VoltAbortException(
                                                                 Resources.RequestAborted
                                                               , this.Status
                                                               , this.ServerStatusString
                                                               );
                        break;

                    case ResponseServerStatus.GracefulFailure:
                        this.Exception = new VoltRequestFailureException(
                                                                          Resources.RequestFailure
                                                                        , this.Status
                                                                        , this.ServerStatusString
                                                                        );
                        break;

                    case ResponseServerStatus.UnexpectedFailure:
                        this.Exception = new VoltCriticalRequestFailureException(
                                                                                  Resources.RequestFailure
                                                                                , this.Status
                                                                                , this.ServerStatusString
                                                                                );
                        break;

                    default:
                        this.Exception = new VoltCriticalRequestFailureException(
                                                                                  Resources.ServerFailure
                                                                                , this.Status
                                                                                , this.ServerStatusString
                                                                                );
                        break;
                }
            }
            catch (Exception x)
            {
                this.Exception = new VoltSerializationException(Resources.ResponseDeserializationFailure, x);
            }
        }
Пример #4
0
        /// <summary>
        /// Instantiate a Table by directly deserializing byte data from the given Deserializer.
        /// </summary>
        /// <param name="input">The Deserializer providing the data for the table.</param>
        internal Table(Deserializer input)
            : base(input)
        {
            // Allocate column-based data storage.
            for (short c = 0; c < this.ColumnCount; c++)
            {
                switch (ColumnType[c])
                {
                    case DBType.TINYINT:
                        Column[c] = new sbyte?[this.RowCount];
                        break;
                    case DBType.SMALLINT:
                        Column[c] = new short?[this.RowCount];
                        break;
                    case DBType.INTEGER:
                        Column[c] = new int?[this.RowCount];
                        break;
                    case DBType.BIGINT:
                        Column[c] = new long?[this.RowCount];
                        break;
                    case DBType.FLOAT:
                        Column[c] = new double?[this.RowCount];
                        break;
                    case DBType.DECIMAL:
                        Column[c] = new VoltDecimal?[this.RowCount];
                        break;
                    case DBType.TIMESTAMP:
                        Column[c] = new DateTime?[this.RowCount];
                        break;
                    case DBType.STRING:
                        Column[c] = new string[this.RowCount];
                        break;
                    case DBType.VARBINARY:
                        Column[c] = new byte[this.RowCount][];
                        break;
                    default:
                        throw new VoltUnsupportedTypeException(Resources.UnsupportedDBType, ColumnType[c]);
                }
            }

            // Get data and push to storage.
            for (int r = 0; r < this.RowCount; r++)
            {
                // Total byte length of the row (ignored).
                input.Skip(4);
                // Read data and push in storage.
                for (short c = 0; c < this.ColumnCount; c++)
                {
                    switch (ColumnType[c])
                    {
                        case DBType.TINYINT:
                            (Column[c] as sbyte?[])[r] = input.ReadSByteN();
                            break;
                        case DBType.SMALLINT:
                            (Column[c] as short?[])[r] = input.ReadInt16N();
                            break;
                        case DBType.INTEGER:
                            (Column[c] as int?[])[r] = input.ReadInt32N();
                            break;
                        case DBType.BIGINT:
                            (Column[c] as long?[])[r] = input.ReadInt64N();
                            break;
                        case DBType.FLOAT:
                            (Column[c] as double?[])[r] = input.ReadDoubleN();
                            break;
                        case DBType.DECIMAL:
                            (Column[c] as VoltDecimal?[])[r] = input.ReadVoltDecimalN();
                            break;
                        case DBType.TIMESTAMP:
                            (Column[c] as DateTime?[])[r] = input.ReadDateTimeN();
                            break;
                        case DBType.VARBINARY:
                            (Column[c] as byte[][])[r] = input.ReadByteArray();
                            break;
                        default:
                            (Column[c] as string[])[r] = input.ReadString();
                            break;
                    }
                }
            }

            // Attach the enumerable row collection.
            this._Rows = new RowCollection(this);
        }
        /// <summary>
        /// Returns a straight data array (boxed) of the requested data type from a single-column Table.
        /// </summary>
        /// <param name="input">The deserializer hoding the response data.</param>
        /// <param name="TResult">The desired output data type of the array elements.</param>
        /// <returns>A boxed array of elements of the requested data type.</returns>
        internal static object FromSingleColumn(Deserializer input, Type TResult)
        {
            // Skip table length, metadata length, status, get column count.
            short columnCount = input.Skip(9).ReadInt16();

            // Validate there is indeed only one column.
            if (columnCount != 1)
            {
                throw new VoltInvalidDataException(Resources.InvalidColumnCount, columnCount);
            }

            // Read column data type.
            DBType columnType = (DBType)input.ReadSByte();

            // Validate the data type matches the .NET casting request.
            if (VoltType.ToDBType(TResult) != columnType)
            {
                throw new VoltInvalidCastException(
                          Resources.InvalidCastException
                          , columnType.ToString()
                          , TResult.ToString()
                          );
            }

            // Skip column name, get Row count.
            int rowCount = input.SkipString().ReadInt32();

            // Load data.
            switch (VoltType.ToNetType(TResult))
            {
            case VoltType.NetType.Byte:
                byte[] dataByte = new byte[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataByte[r] = input.Skip(4).ReadByte();
                }
                return(dataByte);

            case VoltType.NetType.ByteN:
                byte?[] dataByteN = new byte?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataByteN[r] = input.Skip(4).ReadByteN();
                }
                return(dataByteN);

            case VoltType.NetType.SByte:
                sbyte[] dataSByte = new sbyte[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataSByte[r] = input.Skip(4).ReadSByte();
                }
                return(dataSByte);

            case VoltType.NetType.SByteN:
                sbyte?[] dataSByteN = new sbyte?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataSByteN[r] = input.Skip(4).ReadSByteN();
                }
                return(dataSByteN);

            case VoltType.NetType.Int16:
                short[] dataInt16 = new short[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataInt16[r] = input.Skip(4).ReadInt16();
                }
                return(dataInt16);

            case VoltType.NetType.Int16N:
                short?[] dataInt16N = new short?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataInt16N[r] = input.Skip(4).ReadInt16N();
                }
                return(dataInt16N);

            case VoltType.NetType.Int32:
                int[] dataInt32 = new int[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataInt32[r] = input.Skip(4).ReadInt32();
                }
                return(dataInt32);

            case VoltType.NetType.Int32N:
                int?[] dataInt32N = new int?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataInt32N[r] = input.Skip(4).ReadInt32N();
                }
                return(dataInt32N);

            case VoltType.NetType.Int64:
                long[] dataInt64 = new long[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataInt64[r] = input.Skip(4).ReadInt64();
                }
                return(dataInt64);

            case VoltType.NetType.Int64N:
                long?[] dataInt64N = new long?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataInt64N[r] = input.Skip(4).ReadInt64N();
                }
                return(dataInt64N);

            case VoltType.NetType.Double:
                double[] dataDouble = new double[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataDouble[r] = input.Skip(4).ReadDouble();
                }
                return(dataDouble);

            case VoltType.NetType.DoubleN:
                double?[] dataDoubleN = new double?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataDoubleN[r] = input.Skip(4).ReadDoubleN();
                }
                return(dataDoubleN);

            case VoltType.NetType.DateTime:
                DateTime[] dataDateTime = new DateTime[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataDateTime[r] = input.Skip(4).ReadDateTime();
                }
                return(dataDateTime);

            case VoltType.NetType.DateTimeN:
                DateTime?[] dataDateTimeN = new DateTime?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataDateTimeN[r] = input.Skip(4).ReadDateTimeN();
                }
                return(dataDateTimeN);

            case VoltType.NetType.String:
                string[] dataString = new string[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataString[r] = input.Skip(4).ReadString();
                }
                return(dataString);

            case VoltType.NetType.VoltDecimal:
                VoltDecimal[] dataVoltDecimal = new VoltDecimal[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataVoltDecimal[r] = input.Skip(4).ReadVoltDecimal();
                }
                return(dataVoltDecimal);

            case VoltType.NetType.VoltDecimalN:
                VoltDecimal?[] dataVoltDecimalN = new VoltDecimal?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataVoltDecimalN[r] = input.Skip(4).ReadVoltDecimalN();
                }
                return(dataVoltDecimalN);

            case VoltType.NetType.Decimal:
                Decimal[] dataDecimal = new Decimal[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataDecimal[r] = input.Skip(4).ReadDecimal();
                }
                return(dataDecimal);

            case VoltType.NetType.DecimalN:
                Decimal?[] dataDecimalN = new Decimal?[rowCount];
                for (int r = 0; r < rowCount; r++)
                {
                    dataDecimalN[r] = input.Skip(4).ReadDecimalN();
                }
                return(dataDecimalN);

            case VoltType.NetType.ByteArray:
                input.Skip(4);
                return(input.ReadByteArray());

            default:
                throw new VoltUnsupportedTypeException(Resources.UnsupportedParameterNETType, TResult.ToString());
            }
        }
Пример #6
0
        /// <summary>
        /// Parses the returned server message to read properties.
        /// </summary>
        /// <param name="input">The deserializer holding the data form the server message.</param>
        internal void ParseHeader(Deserializer input)
        {
            try
            {
                // Skip the client executionId: the caller (background network thread) already verified a match and
                // we recorded it at the start.
                input.Skip(8);

                // Check field map for status header parsing.
                this._HasFields = (HasFields)input.ReadByte();

                // Read the Status (and optional associated message).
                this.ServerStatus = (ResponseServerStatus)input.ReadSByte();
                if ((this._HasFields & HasFields.Status) == HasFields.Status)
                {
                    this.ServerStatusString = input.ReadString();
                }

                // Read the Application Status (and optional associated message).
                this.ServerApplicationStatus = input.ReadSByte();
                if ((this._HasFields & HasFields.ApplicationStatus) == HasFields.ApplicationStatus)
                {
                    this.ServerApplicationStatusString = input.ReadString();
                }

                // Track query duration (ms).
                this.ExecutionDuration = input.ReadInt32();

                // Skip exception data (currently not used and initialized to the same value as the Status string!).
                if ((this._HasFields & HasFields.Exception) == HasFields.Exception)
                {
                    //this.ServerExceptionString = input.ReadString();
                    input.SkipString();
                }

                // Figure out whether to move forward or kill over - note that we don't *really* kill over, but simply
                // report the Exception in the response's Exception field - the caller should validate that the
                // response is in good status before proceeding to read the results.
                switch (this.ServerStatus)
                {
                case ResponseServerStatus.Success:
                    break;

                case ResponseServerStatus.UserAbort:
                    this.Exception = new VoltAbortException(
                        Resources.RequestAborted
                        , this.Status
                        , this.ServerStatusString
                        );
                    break;

                case ResponseServerStatus.GracefulFailure:
                    this.Exception = new VoltRequestFailureException(
                        Resources.RequestFailure
                        , this.Status
                        , this.ServerStatusString
                        );
                    break;

                case ResponseServerStatus.UnexpectedFailure:
                    this.Exception = new VoltCriticalRequestFailureException(
                        Resources.RequestFailure
                        , this.Status
                        , this.ServerStatusString
                        );
                    break;

                default:
                    this.Exception = new VoltCriticalRequestFailureException(
                        Resources.ServerFailure
                        , this.Status
                        , this.ServerStatusString
                        );
                    break;
                }
            }
            catch (Exception x)
            {
                this.Exception = new VoltSerializationException(Resources.ResponseDeserializationFailure, x);
            }
        }
        /// <summary>
        /// Returns a single value (strongly-type) of the requested data type from a single-row/single-column Table.
        /// </summary>
        /// <typeparam name="TResult">The desired output data type of the returned value.</typeparam>
        /// <param name="input">The deserializer hoding the response data.</param>
        /// <returns>The single cell contained in the table read.</returns>
        internal static TResult FromSingleValue <TResult>(Deserializer input)
        {
            // Skip basic metadata and get Column Count.
            short columnCount = input.Skip(9).ReadInt16();

            // Read column data type.
            DBType columnType = (DBType)input.ReadSByte();

            // Validate the data type matches the .NET casting request
            if (VoltType.ToDBType(typeof(TResult)) != columnType)
            {
                throw new VoltInvalidCastException(
                          Resources.InvalidCastException
                          , columnType.ToString()
                          , typeof(TResult).ToString()
                          );
            }

            // Skip column name and get Row count.
            int rowCount = input.SkipString().ReadInt32();

            // Validate there is indeed only one column and row.
            if ((columnCount != 1) || (rowCount != 1))
            {
                throw new VoltInvalidDataException(Resources.InvalidRowAndColumnCount, rowCount, columnCount);
            }

            // Load data (skip row length and load first value) - unfortunately, we do have to box this.
            switch (VoltType.ToNetType(typeof(TResult)))
            {
            case VoltType.NetType.Byte:
                return((TResult)(object)input.Skip(4).ReadByte());

            case VoltType.NetType.ByteN:
                return((TResult)(object)input.Skip(4).ReadByteN());

            case VoltType.NetType.SByte:
                return((TResult)(object)input.Skip(4).ReadSByte());

            case VoltType.NetType.SByteN:
                return((TResult)(object)input.Skip(4).ReadSByteN());

            case VoltType.NetType.Int16:
                return((TResult)(object)input.Skip(4).ReadInt16());

            case VoltType.NetType.Int16N:
                return((TResult)(object)input.Skip(4).ReadInt16N());

            case VoltType.NetType.Int32:
                return((TResult)(object)input.Skip(4).ReadInt32());

            case VoltType.NetType.Int32N:
                return((TResult)(object)input.Skip(4).ReadInt32N());

            case VoltType.NetType.Int64:
                return((TResult)(object)input.Skip(4).ReadInt64());

            case VoltType.NetType.Int64N:
                return((TResult)(object)input.Skip(4).ReadInt64N());

            case VoltType.NetType.Double:
                return((TResult)(object)input.Skip(4).ReadDouble());

            case VoltType.NetType.DoubleN:
                return((TResult)(object)input.Skip(4).ReadDoubleN());

            case VoltType.NetType.DateTime:
                return((TResult)(object)input.Skip(4).ReadDateTime());

            case VoltType.NetType.DateTimeN:
                return((TResult)(object)input.Skip(4).ReadDateTimeN());

            case VoltType.NetType.String:
                return((TResult)(object)input.Skip(4).ReadString());

            case VoltType.NetType.VoltDecimal:
                return((TResult)(object)input.Skip(4).ReadVoltDecimal());

            case VoltType.NetType.VoltDecimalN:
                return((TResult)(object)input.Skip(4).ReadVoltDecimalN());

            case VoltType.NetType.Decimal:
                return((TResult)(object)input.Skip(4).ReadDecimal());

            case VoltType.NetType.DecimalN:
                return((TResult)(object)input.Skip(4).ReadDecimalN());

            default:
                throw new VoltUnsupportedTypeException(
                          Resources.UnsupportedParameterNETType
                          , typeof(TResult).ToString()
                          );
            }
        }
        /// <summary>
        /// Open the connection.
        /// </summary>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Open()
        {
            // Synchronize access.
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (this.Status != ConnectionStatus.Closed)
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));

                // Set status to "connecting".
                this.Status = ConnectionStatus.Connecting;

                // Connect to the default endpoint (there should only be one anyways if this is a managed pool
                // connection, otherwise, you're on your own - this is a connection, not a Pool!).
                IPEndPoint endPoint = this.Settings.DefaultIPEndPoint;
                try
                {
                    // Create new socket stream and wrap a core protocol stream manager around it.
                    this.BaseStream = new VoltProtocolStream(endPoint, this.Settings.ConnectionTimeout);

                    // Now send login message.
                    using (Serializer serializer = new Serializer())
                    {
                        var msg = serializer
                                  .Write(this.Settings.ServiceType.ToString().ToLowerInvariant())
                                  .Write(this.Settings.UserID)
                                  .WriteRaw(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(this.Settings.Password)))
                                  .GetBytes();
                        this.BaseStream.WriteMessage(msg.Array, msg.Offset, msg.Count);
                    }

                    // Receive and process login response message.
                    var deserializer = new Deserializer(this.BaseStream.ReadMessage());
                    LoginResponseStatus status = (LoginResponseStatus)deserializer.ReadSByte();
                    if (status != LoginResponseStatus.Connected)
                    {
                        // Re-package server response in an appropriate exception.
                        switch (status)
                        {
                            case LoginResponseStatus.ConnectionHandshakeTimeout:
                                throw new VoltConnectionException(
                                                                   Resources.LRS_ConnectionHandshakeTimeout
                                                                 , endPoint
                                                                 , status
                                                                 );

                            case LoginResponseStatus.CorruptedHandshake:
                                throw new VoltConnectionException(
                                                                   Resources.LRS_CorruptedHandshake
                                                                 , endPoint
                                                                 , status
                                                                 );

                            case LoginResponseStatus.InvalidCredentials:
                                throw new VoltPermissionException(
                                                                   Resources.LRS_InvalidCredentials
                                                                 , endPoint
                                                                 , status
                                                                 );

                            case LoginResponseStatus.ServerTooBusy:
                                throw new VoltConnectionException(
                                                                   Resources.LRS_ServerTooBusy
                                                                 , endPoint
                                                                 , status
                                                                 );

                            default:
                                throw new VoltConnectionException(Resources.LRS_Unknown, endPoint, status);
                        }
                    }
                    // Parse the rest of the response the get core cluster information.
                    try
                    {
                        this.ServerHostId = deserializer.ReadInt32();
                        this.ConnectionId = deserializer.ReadInt64();
                        this.ClusterStartTimeStamp = deserializer.ReadDateTimeFromMilliseconds();
                        this.LeaderIPEndPoint = new IPEndPoint(
                                                                new IPAddress(deserializer.ReadRaw(4))
                                                              , endPoint.Port
                                                              );
                        this.BuildString = deserializer.ReadString();
                    }
                    catch (Exception x)
                    {
                        throw new VoltConnectionException(Resources.LR_FailedParsingResponse, x, endPoint);
                    }

                    // Now that we are successfully connected, set the socket timeout to infinite (we are constantly
                    // listening for new messages).
                    this.BaseStream.ResetTimeout(Timeout.Infinite);

                    // Create background threads.
                    this.BackgroundNetworkThread = new Thread(this.BackgroundNetworkThreadRun)
                                                    {
                                                        IsBackground = true,
                                                        Priority = ThreadPriority.AboveNormal
                                                    };
                    this.BackgroundTimeoutThread = new Thread(this.BackgroundTimeoutThreadRun)
                                                    {
                                                        IsBackground = true
                                                    };

                    // Starting background processing threads.
                    this.BackgroundNetworkThread.Start();
                    this.BackgroundTimeoutThread.Start();

                    // Start Callback executor
                    this.CallbackExecutor.Start();

                    // Ensure terminal exception is reset
                    this.TerminalException = null;

                    // Connection is now ready.
                    this.Status = ConnectionStatus.Connected;

                    // Initialize statistics as needed.
                    if (this.Settings.StatisticsEnabled)
                    {
                        this.Stats = new Dictionary<string, Statistics>(StringComparer.OrdinalIgnoreCase);
                        // For lifetime statistics, keep track of previous connection cycles, if any.
                        if (this.LifetimeStats != null)
                        {
                            if (this.PastLifetimeStats != null)
                                this.PastLifetimeStats.SummarizeWith(this.LifetimeStats);
                            else
                                this.PastLifetimeStats = this.LifetimeStats;
                        }
                        this.LifetimeStats = new Statistics();
                    }

                    // Trace as needed
                    if (this.Settings.TraceEnabled)
                        VoltTrace.TraceEvent(
                                              TraceEventType.Information
                                            , VoltTraceEventType.ConnectionOpened
                                            , Resources.TraceConnectionOpened
                                            , this.ServerHostId
                                            , this.ConnectionId
                                            , endPoint
                                            , this.LeaderIPEndPoint
                                            , this.ClusterStartTimeStamp
                                            , this.BuildString
                                            );
                }
                catch (Exception x)
                {
                    try
                    {
                        // In case of failure, terminate everything immediately (will correct status).
                        this.Terminate();
                    }
                    catch { }
                    // Re-throw exception, wrapping if needed.
                    if (x is VoltException)
                        throw new VoltConnectionException(Resources.ConnectionFailure, x, endPoint);
                    else
                        throw x;
                }
            }
            return this;
        }
Пример #9
0
        /// <summary>
        /// Parse the response header (deferred to the based class) and the result Payload.
        /// </summary>
        /// <param name="message">The byte buffer of the binary response data from the server.</param>
        internal override void ParseResponse(byte[] message)
        {
            var input = new Deserializer(message);

            // Parse header information first, deferring to base class
            this.ParseHeader(input);

            // Return immediately if header parsing failed
            if (this.ServerStatus != ResponseServerStatus.Success)
            {
                return;
            }

            // Parse the result
            try
            {
                // Unfortunately this is ugly: have to dynamically check the type to figure out which path to take
                // - no generic implementation can seamlessly deal with T, T[] and T[][]
                Type type = typeof(TResult);

                // Array type - either of:
                //  - Table[] an array of generic Tables
                //  - SingleRowTable[] an array of generic single-row Tables
                //  - T[][] an array of generic single-column Tables
                //  - T[] a single single-column Table
                if (type.IsArray)
                {
                    // Get sub-type within the array
                    Type elementType = type.GetElementType();

                    // We have a Table Array
                    if (elementType == typeof(Table))
                    {
                        this._Result = (TResult)(object)input.ReadTableArray();
                    }

                    // We have a SingleRowTable aArray
                    else if (elementType == typeof(SingleRowTable))
                    {
                        this._Result = (TResult)(object)input.ReadSingleRowTableArray();
                    }

                    // We have an array of single-column tables
                    else if (elementType.IsArray)
                    {
                        short count  = input.ReadInt16();
                        Array result = Array.CreateInstance(elementType, count);
                        for (short i = 0; i < count; i++)
                        {
                            result.SetValue(Table.FromSingleColumn(input, elementType.GetElementType()), i);
                        }
                        this._Result = (TResult)(object)result;
                    }

                    // We have a single single-column table
                    else
                    {
                        short count = input.ReadInt16();
                        if (count != 1)
                        {
                            throw new VoltInvalidDataException(Resources.InvalidResultsetSize, count);
                        }
                        if (elementType == typeof(byte))
                        {
                            elementType = typeof(byte[]);
                        }
                        this._Result = (TResult)Table.FromSingleColumn(input, elementType);
                    }
                }
                // Base type - either of:
                //  - Table
                //  - SingleRowTable
                //  - T
                else
                {
                    if (type == typeof(Null))
                    {
                        this._Result = (TResult)(object)new Null();
                    }
                    else
                    {
                        // Read count: there should be only 1 data set for those calls
                        short count = input.ReadInt16();
                        if (count != 1)
                        {
                            throw new VoltInvalidDataException(Resources.InvalidResultsetSize, count);
                        }

                        // A single Table
                        if (type == typeof(Table))
                        {
                            this._Result = (TResult)(object)new Table(input);
                        }

                        // A single single-row Table
                        else if (type == typeof(SingleRowTable))
                        {
                            this._Result = (TResult)(object)new SingleRowTable(input);
                        }

                        // A single value
                        else
                        {
                            this._Result = (TResult)Table.FromSingleValue <TResult>(input);
                        }
                    }
                }
            }
            catch (Exception x)
            {
                this.Exception = new VoltSerializationException(Resources.ResponseDeserializationFailure, x);
            }
        }
Пример #10
0
        /// <summary>
        /// Instantiate a Table by directly deserializing byte data from the given Deserializer.
        /// </summary>
        /// <param name="input">The Deserializer providing the data for the table.</param>
        internal Table(Deserializer input)
            : base(input)
        {
            // Allocate column-based data storage.
            for (short c = 0; c < this.ColumnCount; c++)
            {
                switch (ColumnType[c])
                {
                case DBType.TINYINT:
                    Column[c] = new sbyte?[this.RowCount];
                    break;

                case DBType.SMALLINT:
                    Column[c] = new short?[this.RowCount];
                    break;

                case DBType.INTEGER:
                    Column[c] = new int?[this.RowCount];
                    break;

                case DBType.BIGINT:
                    Column[c] = new long?[this.RowCount];
                    break;

                case DBType.FLOAT:
                    Column[c] = new double?[this.RowCount];
                    break;

                case DBType.DECIMAL:
                    Column[c] = new VoltDecimal?[this.RowCount];
                    break;

                case DBType.TIMESTAMP:
                    Column[c] = new DateTime?[this.RowCount];
                    break;

                case DBType.STRING:
                    Column[c] = new string[this.RowCount];
                    break;

                case DBType.VARBINARY:
                    Column[c] = new byte[this.RowCount][];
                    break;

                default:
                    throw new VoltUnsupportedTypeException(Resources.UnsupportedDBType, ColumnType[c]);
                }
            }

            // Get data and push to storage.
            for (int r = 0; r < this.RowCount; r++)
            {
                // Total byte length of the row (ignored).
                input.Skip(4);
                // Read data and push in storage.
                for (short c = 0; c < this.ColumnCount; c++)
                {
                    switch (ColumnType[c])
                    {
                    case DBType.TINYINT:
                        (Column[c] as sbyte?[])[r] = input.ReadSByteN();
                        break;

                    case DBType.SMALLINT:
                        (Column[c] as short?[])[r] = input.ReadInt16N();
                        break;

                    case DBType.INTEGER:
                        (Column[c] as int?[])[r] = input.ReadInt32N();
                        break;

                    case DBType.BIGINT:
                        (Column[c] as long?[])[r] = input.ReadInt64N();
                        break;

                    case DBType.FLOAT:
                        (Column[c] as double?[])[r] = input.ReadDoubleN();
                        break;

                    case DBType.DECIMAL:
                        (Column[c] as VoltDecimal?[])[r] = input.ReadVoltDecimalN();
                        break;

                    case DBType.TIMESTAMP:
                        (Column[c] as DateTime?[])[r] = input.ReadDateTimeN();
                        break;

                    case DBType.VARBINARY:
                        (Column[c] as byte[][])[r] = input.ReadByteArray();
                        break;

                    default:
                        (Column[c] as string[])[r] = input.ReadString();
                        break;
                    }
                }
            }

            // Attach the enumerable row collection.
            this._Rows = new RowCollection(this);
        }
Пример #11
0
        /// <summary>
        /// Open the connection.
        /// </summary>
        /// <returns>A reference to the current connection instance for action chaining.</returns>
        public override VoltConnection Open()
        {
            // Synchronize access.
            lock (this.SyncRoot)
            {
                // Validate connection status.
                if (this.Status != ConnectionStatus.Closed)
                {
                    throw new InvalidOperationException(string.Format(Resources.InvalidConnectionStatus, this.Status));
                }

                // Set status to "connecting".
                this.Status = ConnectionStatus.Connecting;

                // Connect to the default endpoint (there should only be one anyways if this is a managed pool
                // connection, otherwise, you're on your own - this is a connection, not a Pool!).
                IPEndPoint endPoint = this.Settings.DefaultIPEndPoint;
                try
                {
                    // Create new socket stream and wrap a core protocol stream manager around it.
                    this.BaseStream = new VoltProtocolStream(endPoint, this.Settings.ConnectionTimeout);

                    // Now send login message.
                    using (Serializer serializer = new Serializer())
                    {
                        var msg = serializer
                                  .Write(this.Settings.ServiceType.ToString().ToLowerInvariant())
                                  .Write(this.Settings.UserID)
                                  .WriteRaw(SHA1.Create().ComputeHash(Encoding.UTF8.GetBytes(this.Settings.Password)))
                                  .GetBytes();
                        this.BaseStream.WriteMessage(msg.Array, msg.Offset, msg.Count);
                    }

                    // Receive and process login response message.
                    var deserializer           = new Deserializer(this.BaseStream.ReadMessage());
                    LoginResponseStatus status = (LoginResponseStatus)deserializer.ReadSByte();
                    if (status != LoginResponseStatus.Connected)
                    {
                        // Re-package server response in an appropriate exception.
                        switch (status)
                        {
                        case LoginResponseStatus.ConnectionHandshakeTimeout:
                            throw new VoltConnectionException(
                                      Resources.LRS_ConnectionHandshakeTimeout
                                      , endPoint
                                      , status
                                      );

                        case LoginResponseStatus.CorruptedHandshake:
                            throw new VoltConnectionException(
                                      Resources.LRS_CorruptedHandshake
                                      , endPoint
                                      , status
                                      );

                        case LoginResponseStatus.InvalidCredentials:
                            throw new VoltPermissionException(
                                      Resources.LRS_InvalidCredentials
                                      , endPoint
                                      , status
                                      );

                        case LoginResponseStatus.ServerTooBusy:
                            throw new VoltConnectionException(
                                      Resources.LRS_ServerTooBusy
                                      , endPoint
                                      , status
                                      );

                        default:
                            throw new VoltConnectionException(Resources.LRS_Unknown, endPoint, status);
                        }
                    }
                    // Parse the rest of the response the get core cluster information.
                    try
                    {
                        this.ServerHostId          = deserializer.ReadInt32();
                        this.ConnectionId          = deserializer.ReadInt64();
                        this.ClusterStartTimeStamp = deserializer.ReadDateTimeFromMilliseconds();
                        this.LeaderIPEndPoint      = new IPEndPoint(
                            new IPAddress(deserializer.ReadRaw(4))
                            , endPoint.Port
                            );
                        this.BuildString = deserializer.ReadString();
                    }
                    catch (Exception x)
                    {
                        throw new VoltConnectionException(Resources.LR_FailedParsingResponse, x, endPoint);
                    }

                    // Now that we are successfully connected, set the socket timeout to infinite (we are constantly
                    // listening for new messages).
                    this.BaseStream.ResetTimeout(Timeout.Infinite);

                    // Create background threads.
                    this.BackgroundNetworkThread = new Thread(this.BackgroundNetworkThreadRun)
                    {
                        IsBackground = true,
                        Priority     = ThreadPriority.AboveNormal
                    };
                    this.BackgroundTimeoutThread = new Thread(this.BackgroundTimeoutThreadRun)
                    {
                        IsBackground = true
                    };

                    // Starting background processing threads.
                    this.BackgroundNetworkThread.Start();
                    this.BackgroundTimeoutThread.Start();

                    // Start Callback executor
                    this.CallbackExecutor.Start();

                    // Ensure terminal exception is reset
                    this.TerminalException = null;

                    // Connection is now ready.
                    this.Status = ConnectionStatus.Connected;

                    // Initialize statistics as needed.
                    if (this.Settings.StatisticsEnabled)
                    {
                        this.Stats = new Dictionary <string, Statistics>(StringComparer.OrdinalIgnoreCase);
                        // For lifetime statistics, keep track of previous connection cycles, if any.
                        if (this.LifetimeStats != null)
                        {
                            if (this.PastLifetimeStats != null)
                            {
                                this.PastLifetimeStats.SummarizeWith(this.LifetimeStats);
                            }
                            else
                            {
                                this.PastLifetimeStats = this.LifetimeStats;
                            }
                        }
                        this.LifetimeStats = new Statistics();
                    }

                    // Trace as needed
                    if (this.Settings.TraceEnabled)
                    {
                        VoltTrace.TraceEvent(
                            TraceEventType.Information
                            , VoltTraceEventType.ConnectionOpened
                            , Resources.TraceConnectionOpened
                            , this.ServerHostId
                            , this.ConnectionId
                            , endPoint
                            , this.LeaderIPEndPoint
                            , this.ClusterStartTimeStamp
                            , this.BuildString
                            );
                    }
                }
                catch (Exception x)
                {
                    try
                    {
                        // In case of failure, terminate everything immediately (will correct status).
                        this.Terminate();
                    }
                    catch { }
                    // Re-throw exception, wrapping if needed.
                    if (x is VoltException)
                    {
                        throw new VoltConnectionException(Resources.ConnectionFailure, x, endPoint);
                    }
                    else
                    {
                        throw x;
                    }
                }
            }
            return(this);
        }