/// <summary>
        /// Cstor for InboundProtocolResponseValue
        /// Validate the payload for valid protocol response and store.
        /// </summary>
        /// <param name="inboundStreamMessage"></param>
        /// <param name="expectedType"></param>
        internal InboundProtocolResponseValue(InboundBaseStreamWireMessage inboundStreamMessage, StreamWireProtocolMessageKind expectedType)
        {
            Diagnostics.Assert(
                inboundStreamMessage.Kind == expectedType,
                "Unexpected StreamWireProtocolMessageKind in InboundBaseStreamWireMessage used to construct InboundProtocolResponseValue");
            Diagnostics.Assert(
                inboundStreamMessage.Payload != null,
                "null ProtocolResponseValue payload in InboundBaseStreamWireMessage used to construct InboundProtocolResponseValue");
            Diagnostics.Assert(
                inboundStreamMessage.Payload.Length == sizeof(int),
                "payload in InboundBaseStreamWireMessage used to construct InboundProtocolResponseValue contains more than ProtocolResponseValue");

            // Store appropriate decoded Protocol Response
            this.Response = (StreamWireProtocolResponse)BitConverter.ToInt32(inboundStreamMessage.Payload, 0);
        }
        internal InboundOpenStreamName(InboundBaseStreamWireMessage inboundBaseMessage)
        {
            Diagnostics.Assert(
                inboundBaseMessage.Kind == StreamWireProtocolMessageKind.OpenStream,
                "Wrong kind of InboundBaseStreamWireMessage used to construct InboundOpenStreamName");
            Diagnostics.Assert(
                inboundBaseMessage.Payload != null,
                "null streamName payload in InboundBaseStreamWireMessage used to construct InboundOpenStreamName");

            var encoder = new StringEncoder();
            var reader  = new BinaryReader(new MemoryStream(inboundBaseMessage.Payload));

            this.StreamName = new Uri(encoder.Decode(reader));
            Diagnostics.Assert(reader.PeekChar() == -1, "streamName payload in InboundBaseStreamWireMessage contains more than streamName");
        }
 internal InboundResetPartnerStreamsResponseValue(InboundBaseStreamWireMessage inboundStreamMessage)
     : base(inboundStreamMessage, StreamWireProtocolMessageKind.ResetPartnerStreamsResponse)
 {
 }
 internal InboundDeleteStreamResponseValue(InboundBaseStreamWireMessage inboundStreamMessage)
     : base(inboundStreamMessage, StreamWireProtocolMessageKind.DeleteStreamResponse)
 {
 }
Beispiel #5
0
        /// <summary>
        /// Handler for messages received on the session, will also deal with exceptions that occur when the session is closed or aborted
        /// </summary>
        /// <param name="receiveTask"></param>
        private void ReceiveContinuation(Task <IOperationData> receiveTask)
        {
            // Check for aborted session and other failures
            if (receiveTask.Exception != null)
            {
                var realException = receiveTask.Exception.InnerException;
                if (realException is InvalidOperationException || realException is OperationCanceledException)
                {
                    FabricEvents.Events.SessionReceiveFailure("SessionAborted@" + this.traceType, this.SessionId.ToString());
                }
                else
                {
                    Tracing.WriteExceptionAsError("InboundSessionDriver.ReceiveAsync.Failure", realException, "{0}", this.tracer);
                    Diagnostics.Assert(false, "{0} InboundSessionDriver.ReceiveAsync Unexpected Exception {1}", this.tracer, receiveTask.Exception.GetType());
                }
            }
            else
            {
                var wireMessage          = receiveTask.Result;
                var inboundStreamMessage = new InboundBaseStreamWireMessage(wireMessage);
                var kind = inboundStreamMessage.Kind;

                // Check if Stream Manager is available for updates.
                if (this.streamManager.NotWritable())
                {
                    // drop the message
                    FabricEvents.Events.WireMessageReceived(
                        "DroppedNotWritable@" + this.traceType + "@" + this.SessionId.ToString(),
                        inboundStreamMessage.StreamIdentity.ToString(),
                        inboundStreamMessage.MessageSequenceNumber,
                        kind.ToString());
                    return;
                }

                FabricEvents.Events.WireMessageReceived(
                    this.traceType + "@" + this.SessionId.ToString(),
                    inboundStreamMessage.StreamIdentity.ToString(),
                    inboundStreamMessage.MessageSequenceNumber,
                    kind.ToString());

                /*
                 * There are two basic approaches to dealing with messages here
                 * If the message is intended for a stream and the stream is not found it means we are in the middle of a restore process
                 * so we simply drop the message and build it into the protocol that it will be retried eventually
                 *
                 * If the message is intended for the stream manager to control restart or to drive stream lifecycle the stream manager
                 * will ensure it is in operating state and if not has a mechanism to wait for that state
                 */
                switch (kind)
                {
                case StreamWireProtocolMessageKind.ServiceData:
                    this.streamManager.MessageReceived(inboundStreamMessage)
                    .ContinueWith(antecedent => Task.Run(() => this.MessageReceivedContinuation(antecedent, inboundStreamMessage.StreamIdentity)));
                    break;

                case StreamWireProtocolMessageKind.SequenceAck:
                    this.streamManager.AckReceived(inboundStreamMessage)
                    .ContinueWith(antecedent => Task.Run(() => this.AckReceivedContinuation(antecedent, inboundStreamMessage.StreamIdentity)));
                    break;

                case StreamWireProtocolMessageKind.OpenStream:
                    this.streamManager.InboundStreamRequested(this.partnerKey, inboundStreamMessage)
                    .ContinueWith(this.InboundStreamRequestedContinuation);
                    break;

                case StreamWireProtocolMessageKind.CloseStream:
                    this.streamManager.MessageReceived(inboundStreamMessage)
                    .ContinueWith(antecedent => Task.Run(() => this.MessageReceivedContinuation(antecedent, inboundStreamMessage.StreamIdentity)));
                    break;

                case StreamWireProtocolMessageKind.OpenStreamResponse:
                    this.streamManager.CompleteOpenStreamProtocol(inboundStreamMessage)
                    .ContinueWith(this.CompleteOpenStreamProtocolContinuation);
                    break;

                case StreamWireProtocolMessageKind.CloseStreamResponse:
                    this.streamManager.CompleteCloseStreamProtocol(inboundStreamMessage)
                    .ContinueWith(this.CompleteCloseStreamProtocolContinuation);
                    break;

                case StreamWireProtocolMessageKind.ResetPartnerStreams:
                    // The StreamIdentity slot is actually carrying the Guid representing the era of the requester
                    this.streamManager.ResetPartnerStreamsAsync(inboundStreamMessage.StreamIdentity, this.partnerKey)
                    .ContinueWith(this.ResetPartnerStreamsAsyncContinuation);
                    break;

                case StreamWireProtocolMessageKind.ResetPartnerStreamsResponse:
                    var resetResponseValue = new InboundResetPartnerStreamsResponseValue(inboundStreamMessage);
                    Diagnostics.Assert(
                        resetResponseValue.Response == StreamWireProtocolResponse.ResetPartnerStreamsCompleted,
                        "{0} Unexpected reset partner streams response",
                        this.tracer);

                    // The StreamIdentity slot is actually carrying the Guid representing the era when the ResetPartnerStreams request was sent
                    // We will only process the respone if the request was sent in the current era
                    if (inboundStreamMessage.StreamIdentity == this.streamManager.Era)
                    {
                        this.streamManager.RestartPartnerStreamsAsync(this.partnerKey, this.streamManager.RuntimeResources.OutboundStreams, false)
                        .ContinueWith(this.RestartPartnerStreamsAsyncContinuation);
                    }
                    break;

                case StreamWireProtocolMessageKind.DeleteStream:
                    this.streamManager.DeleteInboundStreamRequested(this.partnerKey, inboundStreamMessage)
                    .ContinueWith(
                        antecedent => Task.Run(() => this.DeleteInboundStreamRequestedContinuation(antecedent, inboundStreamMessage.StreamIdentity)));
                    break;

                case StreamWireProtocolMessageKind.DeleteStreamResponse:
                    this.streamManager.CompleteDeleteStreamProtocol(inboundStreamMessage)
                    .ContinueWith(
                        antecedent => Task.Run(() => this.CompleteDeleteStreamProtocolContinuation(antecedent, inboundStreamMessage.StreamIdentity)));
                    break;

                default:
                    Diagnostics.Assert(
                        false,
                        "{0} Unknown message kind in InboundSessionDriver Kind-as-int: {1}",
                        this.tracer,
                        (int)inboundStreamMessage.Kind);
                    break;
                }

                // Restart the receive operation
                Diagnostics.Assert(this.inboundSession != null, "InboundSessionDriver.ReceiveContinuation.RestartReceive found null session");

                this.ReceiveOnSession();
            }
        }
Beispiel #6
0
        // Hides the base SetResult method which we need to override
        // This method is called when the message is actually delivered to a ReceiveAsync call
        // The update to the CloseMessageSequenceNumber property of Inbound is transactional
        internal async Task SetResult(InboundBaseStreamWireMessage message)
        {
            var closeSeqNumber = this.stream.CloseMessageSequenceNumber;

            if (message.Kind == StreamWireProtocolMessageKind.CloseStream)
            {
                // The close message can be a repeat in recovery cases, but the close sequence number must be unique
                // It is also possible that the transaction surrounding this ReceiveAsync will abort and the message
                // will not in fact be consumed -- and will be received again, but the close sequence number must be unique
                Diagnostics.Assert(
                    closeSeqNumber == StreamConstants.InitialValueOfLastSequenceNumberInStream || closeSeqNumber == message.MessageSequenceNumber,
                    "{0} TraceId::{1} encountered multiple close sequence number values {2} and {3}",
                    this.stream.Tracer,
                    this.traceId,
                    closeSeqNumber,
                    message.MessageSequenceNumber);

                try
                {
                    // this method is idempotent; the close sequence number for a stream is invariant
                    await this.stream.SetCloseMessageSequenceNumber(message.MessageSequenceNumber, this.transactionContext);

                    await this.stream.CloseInboundStream(this.transactionContext);
                }
                catch (Exception e)
                {
                    if (e is FabricObjectClosedException)
                    {
                        FabricEvents.Events.DataMessageDelivery(
                            string.Format(CultureInfo.InvariantCulture, "ObjectClosed@{0}{1}", this.traceId, this.stream.TraceType),
                            this.stream.StreamIdentity.ToString(),
                            message.MessageSequenceNumber,
                            this.transactionContext.Id.ToString());

                        this.TrySetException(e);
                        return;
                    }
                    if (e is FabricNotPrimaryException)
                    {
                        FabricEvents.Events.DataMessageDelivery(
                            string.Format(CultureInfo.InvariantCulture, "NotPrimary@{0}{1}", this.traceId, this.stream.TraceType),
                            this.stream.StreamIdentity.ToString(),
                            message.MessageSequenceNumber,
                            this.transactionContext.Id.ToString());

                        this.TrySetException(e);
                        return;
                    }
                    if (e is FabricNotReadableException)
                    {
                        FabricEvents.Events.DataMessageDelivery(
                            string.Format(CultureInfo.InvariantCulture, "NotReadable@{0}{1}", this.traceId, this.stream.TraceType),
                            this.stream.StreamIdentity.ToString(),
                            message.MessageSequenceNumber,
                            this.transactionContext.Id.ToString());

                        this.TrySetException(e);
                        return;
                    }

                    Tracing.WriteExceptionAsError(
                        "DataMessageDelivery.Failure",
                        e,
                        "Partition::Replica {0} TraceId: {1} MessageNumber: {2} TransactionId: {3}",
                        this.stream.TraceType,
                        this.traceId,
                        message.MessageSequenceNumber,
                        this.transactionContext.Id);
                    Diagnostics.Assert(
                        false,
                        "Unexpected Exception In {0} TraceId: {1} MessageNumber: {2} TransactionId: {3}",
                        this.stream.TraceType,
                        this.traceId,
                        message.MessageSequenceNumber,
                        this.transactionContext.Id);
                }
            }
            else
            {
                Diagnostics.Assert(
                    closeSeqNumber == StreamConstants.InitialValueOfLastSequenceNumberInStream || closeSeqNumber > message.MessageSequenceNumber,
                    "{0} received payload message with sequence number {1} which is greater than the close sequence number {2}",
                    this.stream.Tracer,
                    message.MessageSequenceNumber,
                    closeSeqNumber);
            }

            var setResultSuccess = this.TrySetResult(message);

            if (setResultSuccess)
            {
                FabricEvents.Events.DataMessageDelivery(
                    "Success::" + this.traceId + "@" + this.stream.TraceType,
                    this.stream.StreamIdentity.ToString(),
                    message.MessageSequenceNumber,
                    this.transactionContext.Id.ToString());
            }
            else
            {
                FabricEvents.Events.DataMessageDelivery(
                    "Failure::" + this.traceId + "@" + this.stream.TraceType,
                    this.stream.StreamIdentity.ToString(),
                    message.MessageSequenceNumber,
                    this.transactionContext.Id.ToString());
            }
        }