Beispiel #1
0
        /// <summary>
        ///     Temporarily disconnects the inbound message stream and drops
        ///     all the messages on the fly. Causes 'hiccuped' event to be generated in the peer.
        /// </summary>
        public void Hiccup()
        {
            // If termination is already under way do nothing.
            if (this.m_state != State.Active)
            {
                return;
            }

            // We'll drop the pointer to the in-pipe. From now on, the peer is
            // responsible for deallocating it.
            this.m_inboundPipe = null;

            // Create new in-pipe.
            this.m_inboundPipe = new YPipe <Msg>(Config.MessagePipeGranularity, "inpipe");
            this.m_inActive    = true;

            // Notify the peer about the hiccup.
            this.SendHiccup(this.m_peer, this.m_inboundPipe);
        }
Beispiel #2
0
        /// <summary>
        ///     Handles the delimiter read from the pipe.
        /// </summary>
        private void Delimit()
        {
            if (this.m_state == State.Active)
            {
                this.m_state = State.Delimited;
                return;
            }

            if (this.m_state == State.Pending)
            {
                this.m_outboundPipe = null;
                this.SendPipeTermAck(this.m_peer);
                this.m_state = State.Terminating;
                return;
            }

            // Delimiter in any other state is invalid.
            Debug.Assert(false);
        }
Beispiel #3
0
        public static Pipe[] PipePair([NotNull] ZObject[] parents, [NotNull] int[] highWaterMarks, [NotNull] int[] lowWaterMarks, [NotNull] bool[] delays)
        {
            // Creates two pipe objects. These objects are connected by two ypipes,
            // each to pass messages in one direction.

            YPipe <Msg> upipe1 = new YPipe <Msg>(Config.MessagePipeGranularity, "upipe1");
            YPipe <Msg> upipe2 = new YPipe <Msg>(Config.MessagePipeGranularity, "upipe2");

            Pipe[] pipes =
            {
                new Pipe(parents[0], upipe1, upipe2, highWaterMarks[1], highWaterMarks[0], lowWaterMarks[1], delays[0]),
                new Pipe(parents[1], upipe2, upipe1, highWaterMarks[0], highWaterMarks[1], lowWaterMarks[0], delays[1])
            };

            pipes[0].SetPeer(pipes[1]);
            pipes[1].SetPeer(pipes[0]);

            return(pipes);
        }
Beispiel #4
0
 /// <summary>
 ///     Create a new Pipe object with the given parent, and inbound and outbound YPipes.
 /// </summary>
 /// <remarks>
 ///     Constructor is private as pipe can only be created using <see cref="PipePair" /> method.
 /// </remarks>
 private Pipe(
     [NotNull] ZObject parent, [NotNull] YPipe <Msg> inboundPipe, [NotNull] YPipe <Msg> outboundPipe,
     int inHighWatermark, int outHighWatermark, int predefinedLowWatermark, bool delay)
     : base(parent)
 {
     this.m_parent                  = parent;
     this.m_inboundPipe             = inboundPipe;
     this.m_outboundPipe            = outboundPipe;
     this.m_inActive                = true;
     this.m_outActive               = true;
     this.m_highWatermark           = outHighWatermark;
     this.m_lowWatermark            = Pipe.ComputeLowWatermark(inHighWatermark, predefinedLowWatermark);
     this.m_numberOfMessagesRead    = 0;
     this.m_numberOfMessagesWritten = 0;
     this.m_peersMsgsRead           = 0;
     this.m_peer  = null;
     this.m_sink  = null;
     this.m_state = State.Active;
     this.m_delay = delay;
 }
Beispiel #5
0
        /// <summary>
        ///     This method is called to assign the specified pipe as a replacement for the outbound pipe that was being used.
        /// </summary>
        /// <param name="pipe">the pipe to use for writing</param>
        /// <remarks>
        ///     A "Hiccup" occurs when an outbound pipe experiences something like a transient disconnect or for whatever other
        ///     reason
        ///     is no longer available for writing to.
        /// </remarks>
        protected override void ProcessHiccup(object pipe)
        {
            // Destroy old out-pipe. Note that the read end of the pipe was already
            // migrated to this thread.
            Debug.Assert(this.m_outboundPipe != null);
            this.m_outboundPipe.Flush();
            Msg msg = new Msg();

            while (this.m_outboundPipe.TryRead(out msg))
            {
                msg.Close();
            }

            // Plug in the new out-pipe.
            Debug.Assert(pipe != null);
            this.m_outboundPipe = (YPipe <Msg>)pipe;
            this.m_outActive    = true;

            // If appropriate, notify the user about the hiccup.
            if (this.m_state == State.Active)
            {
                this.m_sink.Hiccuped(this);
            }
        }
Beispiel #6
0
        /// <summary>
        ///     Ask pipe to terminate. The termination will happen asynchronously
        ///     and user will be notified about actual deallocation by 'terminated'
        ///     event.
        /// </summary>
        /// <param name="delay">
        ///     if set to <c>true</c>, the pending messages will be processed
        ///     before actual shutdown.
        /// </param>
        public void Terminate(bool delay)
        {
            // Overload the value specified at pipe creation.
            this.m_delay = delay;

            // If terminate was already called, we can ignore the duplicate invocation.
            if (this.m_state == State.Terminated || this.m_state == State.DoubleTerminated)
            {
                return;
            }

            // If the pipe is in the phase of async termination, it's going to
            // closed anyway. No need to do anything special here.
            if (this.m_state == State.Terminating)
            {
                return;
            }

            if (this.m_state == State.Active)
            {
                // The simple sync termination case. Ask the peer to terminate and wait
                // for the ack.
                this.SendPipeTerm(this.m_peer);
                this.m_state = State.Terminated;
            }
            else if (this.m_state == State.Pending && !this.m_delay)
            {
                // There are still pending messages available, but the user calls
                // 'terminate'. We can act as if all the pending messages were read.
                this.m_outboundPipe = null;
                this.SendPipeTermAck(this.m_peer);
                this.m_state = State.Terminating;
            }
            else if (this.m_state == State.Pending)
            {
                // If there are pending messages still available, do nothing.
            }
            else if (this.m_state == State.Delimited)
            {
                // We've already got delimiter, but not term command yet. We can ignore
                // the delimiter and ack synchronously terminate as if we were in
                // active state.
                this.SendPipeTerm(this.m_peer);
                this.m_state = State.Terminated;
            }
            else
            {
                // There are no other states.
                Debug.Assert(false);
            }

            // Stop outbound flow of messages.
            this.m_outActive = false;

            if (this.m_outboundPipe != null)
            {
                // Drop any unfinished outbound messages.
                this.Rollback();

                // Write the delimiter into the pipe. Note that watermarks are not
                // checked; thus the delimiter can be written even when the pipe is full.

                Msg msg = new Msg();
                msg.InitDelimiter();
                this.m_outboundPipe.Write(ref msg, false);
                this.Flush();
            }
        }