Beispiel #1
0
        internal static bool TestConsumeMessage <T>(ISourceBlock <T> source)
        {
            bool consumed;

            source.ConsumeMessage(new DataflowMessageHeader(-99), new ActionBlock <T>(i => { }), out consumed);
            if (consumed)
            {
                Console.WriteLine("ConsumeMessage failed, didn't return messageConsumed==false for a unresrved msg");
                return(false);
            }

            // test consume the correct message with different target
            var mres           = new ManualResetEventSlim(false);
            var offeredMessage = default(DataflowMessageHeader);
            var target1        = new TransparentBlock <T>((msg) =>
            {
                offeredMessage = msg;
                mres.Set();
            }, false);

            source.LinkTo(target1);
            mres.Wait();

            if (!source.ReserveMessage(offeredMessage, target1))
            {
                Console.WriteLine("ReserveMessage failed, returned false");
                return(false);
            }

            //exclude writeOnce and broadCast because they don't respect reservation to the target
            if (!(source is WriteOnceBlock <T> || source is BroadcastBlock <T>))
            {
                //define another target
                var target2 = new TransparentBlock <T>(null);
                source.ConsumeMessage(offeredMessage, target2, out consumed);
                if (consumed)
                {
                    Console.WriteLine("ConsumeMessage failed, a different target succeeded to consume the message that it doesn't own");
                    return(false);
                }
            }

            //same target different msg
            source.ConsumeMessage(new DataflowMessageHeader(-99), target1, out consumed);
            if (consumed)
            {
                Console.WriteLine("ConsumeMessage failed, the target succeeded to consume a differnt msg");
                return(false);
            }

            //same target, same message
            source.ConsumeMessage(offeredMessage, target1, out consumed);
            if (!consumed)
            {
                Console.WriteLine("ConsumeMessage failed, the target failed to consume the reserved msg");
                return(false);
            }

            return(true);
        }
Beispiel #2
0
        internal static bool TestArgumentsExceptions <T>(ISourceBlock <T> source)
        {
            bool passed = true;

            var validMessageHeader                 = new DataflowMessageHeader(1);
            var invalidMessageHeader               = default(DataflowMessageHeader);
            ITargetBlock <T>    validTarget        = new BufferBlock <T>();
            ITargetBlock <T>    invalidTarget      = null;
            DataflowLinkOptions invalidLinkOptions = null;
            DataflowLinkOptions validLinkOptions   = new DataflowLinkOptions();
            bool consumed;

            Assert.Throws <ArgumentNullException>(() => source.ConsumeMessage(validMessageHeader, invalidTarget, out consumed));
            Assert.Throws <ArgumentException>(() => source.ConsumeMessage(invalidMessageHeader, validTarget, out consumed));
            Assert.Throws <ArgumentException>(() => source.ConsumeMessage(invalidMessageHeader, invalidTarget, out consumed));
            Assert.Throws <ArgumentNullException>(() => source.ReserveMessage(validMessageHeader, invalidTarget));
            Assert.Throws <ArgumentException>(() => source.ReserveMessage(invalidMessageHeader, validTarget));
            Assert.Throws <ArgumentException>(() => source.ReserveMessage(invalidMessageHeader, invalidTarget));
            Assert.Throws <ArgumentNullException>(() => source.ReleaseReservation(validMessageHeader, invalidTarget));
            Assert.Throws <ArgumentException>(() => source.ReleaseReservation(invalidMessageHeader, validTarget));
            Assert.Throws <ArgumentException>(() => source.ReleaseReservation(invalidMessageHeader, invalidTarget));
            Assert.Throws <ArgumentNullException>(() => source.LinkTo(invalidTarget));
            Assert.Throws <ArgumentNullException>(() => source.LinkTo(invalidTarget, validLinkOptions));
            Assert.Throws <ArgumentNullException>(() => source.LinkTo(validTarget, invalidLinkOptions));
            Assert.Throws <ArgumentNullException>(() => source.LinkTo(invalidTarget, invalidLinkOptions));

            return(passed);
        }
Beispiel #3
0
        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock <TInput> source, Boolean consumeToAccept)
        {
            DataflowMessageStatus returnValue;

            lock (_m_incomingLock)
            {
                if (_m_alwaysAccept)
                {
                    bool consumed        = !consumeToAccept;
                    var  acceptedMessage = (source != null && consumeToAccept) ? source.ConsumeMessage(messageHeader, this, out consumed) : messageValue;
                    _m_messages.Enqueue(messageValue);
                    returnValue = DataflowMessageStatus.Accepted;
                }
                else
                {
                    returnValue = DataflowMessageStatus.Declined;
                }
            }
            if (_m_action != null)
            {
                _m_action(messageHeader);
            }

            return(returnValue);
        }
Beispiel #4
0
        public DataflowMessageStatus OfferMessage(
            DataflowMessageHeader messageHeader, TInput messageValue,
            ISourceBlock <TInput> source, bool consumeToAccept)
        {
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException("The messageHeader is not valid.",
                                            "messageHeader");
            }
            if (consumeToAccept && source == null)
            {
                throw new ArgumentException(
                          "consumeToAccept may only be true if provided with a non-null source.",
                          "consumeToAccept");
            }

            if (consumeToAccept)
            {
                if (!source.ReserveMessage(messageHeader, this))
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
                bool consummed;
                source.ConsumeMessage(messageHeader, this, out consummed);
                if (!consummed)
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
            }

            return(DataflowMessageStatus.Accepted);
        }
Beispiel #5
0
        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, ResourceEvent <TResource> resourceEvent, ISourceBlock <ResourceEvent <TResource> > source,
                                                  bool consumeToAccept)
        {
            if (_isCompleting)
            {
                return(DataflowMessageStatus.DecliningPermanently);
            }
            if (consumeToAccept)
            {
                resourceEvent = source.ConsumeMessage(messageHeader, this, out var consumed);
                if (!consumed)
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
            }

            if (resourceEvent.EventFlags.HasFlag(EventTypeFlags.ResetEmpty) ||
                resourceEvent.Value == null)
            {
                return(DataflowMessageStatus.Declined);
            }


            lock (_lock)
            {
                // decline any syncs if we're already queued up to process this resource
                if (resourceEvent.EventFlags.HasFlag(EventTypeFlags.Sync) && _items.ContainsKey(_keyFunc(resourceEvent.Value)))
                {
                    return(DataflowMessageStatus.Declined);
                }
                QueueActionLocked(resourceEvent);
            }

            return(DataflowMessageStatus.Accepted);
        }
        internal static void TestConsumeReserveReleaseArgumentsExceptions <T>(ISourceBlock <T> source)
        {
            DataflowMessageHeader validMessageHeader = new DataflowMessageHeader(1), invalidMessageHeader = default(DataflowMessageHeader);
            ITargetBlock <T>      validTarget = new BufferBlock <T>(), invalidTarget = null;
            bool consumed;

            Assert.Throws <ArgumentNullException>(() => source.ConsumeMessage(validMessageHeader, invalidTarget, out consumed));
            Assert.Throws <ArgumentException>(() => source.ConsumeMessage(invalidMessageHeader, validTarget, out consumed));
            Assert.Throws <ArgumentException>(() => source.ConsumeMessage(invalidMessageHeader, invalidTarget, out consumed));
            Assert.Throws <ArgumentNullException>(() => source.ReserveMessage(validMessageHeader, invalidTarget));
            Assert.Throws <ArgumentException>(() => source.ReserveMessage(invalidMessageHeader, validTarget));
            Assert.Throws <ArgumentException>(() => source.ReserveMessage(invalidMessageHeader, invalidTarget));
            Assert.Throws <ArgumentNullException>(() => source.ReleaseReservation(validMessageHeader, invalidTarget));
            Assert.Throws <ArgumentException>(() => source.ReleaseReservation(invalidMessageHeader, validTarget));
            Assert.Throws <ArgumentException>(() => source.ReleaseReservation(invalidMessageHeader, invalidTarget));
        }
Beispiel #7
0
        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock <T> source,
                                                  bool consumeToAccept)
        {
            if (!IsOpen)
            {
                return(DataflowMessageStatus.Declined);
            }

            if (consumeToAccept)
            {
                bool messageConsumed;

                source.ConsumeMessage(messageHeader, this, out messageConsumed);
                if (!messageConsumed)
                {
                    return(DataflowMessageStatus.Declined);
                }
            }

            toPropergate = messageValue;
            foreach (ITargetBlock <T> target in this.links)
            {
                target.OfferMessage(messageHeader, messageValue, this, true);
            }

            return(DataflowMessageStatus.Accepted);
        }
Beispiel #8
0
        /// <summary>
        /// Consumes the message (request by other targets).
        /// </summary>
        /// <param name="messageHeader">The message header.</param>
        /// <param name="target">The target.</param>
        /// <param name="messageConsumed">if set to <c>true</c> [message consumed].</param>
        /// <returns></returns>
        public T ConsumeMessage(
            DataflowMessageHeader messageHeader,
            ITargetBlock <T> target,
            out bool messageConsumed)
        {
            T result = Source.ConsumeMessage(messageHeader, target, out messageConsumed);

            BlockInfo.PoolRequestCounters.Increment(messageConsumed);

            #region BlockInfo.PoolRequest.Add(...)

            var hookTarget = target as ITargetHook <T>;
            if (!(target is LinkHook <T>)) // optimization, in this case the like hook will handle the message
            {
                string targetName = string.Empty;
                if (hookTarget != null)
                {
                    targetName = hookTarget.BlockInfo.Name;
                }

                var msg = new ConsumeTrace(messageHeader.Id, messageConsumed, BlockInfo.Name, targetName, result);
                BlockInfo.PoolRequest.Add(msg);
            }

            #endregion // BlockInfo.PoolRequest.Add(...)

            BlockInfo.Refresh();

            return(result);
        }
        /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
        DataflowMessageStatus ITargetBlock <T> .OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock <T> source, Boolean consumeToAccept)
        {
            // Validate arguments
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException(SR.Argument_InvalidMessageHeader, "messageHeader");
            }
            if (source == null && consumeToAccept)
            {
                throw new ArgumentException(SR.Argument_CantConsumeFromANullSource, "consumeToAccept");
            }
            Contract.EndContractBlock();

            bool thisThreadReservedCompletion = false;

            lock (ValueLock)
            {
                // If we are declining messages, bail
                if (_decliningPermanently)
                {
                    return(DataflowMessageStatus.DecliningPermanently);
                }

                // Consume the message from the source if necessary. We do this while holding ValueLock to prevent multiple concurrent
                // offers from all succeeding.
                if (consumeToAccept)
                {
                    bool consumed;
                    messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
                    if (!consumed)
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                }

                // Update the header and the value
                _header = Common.SingleMessageHeader;
                _value  = messageValue;

                // We got what we needed. Start declining permanently.
                _decliningPermanently = true;

                // Reserve Completion
                if (!_completionReserved)
                {
                    thisThreadReservedCompletion = _completionReserved = true;
                }
            }

            // Since this call to OfferMessage succeeded (and only one can ever), complete the block
            // (but asynchronously so as not to block the Post call while offering to
            // targets, running synchronous continuations off of the completion task, etc.)
            if (thisThreadReservedCompletion)
            {
                CompleteBlockAsync(exceptions: null);
            }
            return(DataflowMessageStatus.Accepted);
        }
Beispiel #10
0
        static void SourceBlockTestInternal <T>(ISourceBlock <T> block)
        {
            var target = new BufferBlock <T> ();

            bool consumed;

            // invalid header
            AssertEx.Throws <ArgumentException> (
                () =>
                block.ConsumeMessage(new DataflowMessageHeader(), target, out consumed));

            // header that wasn't sent by the block doesn't throw
            block.ConsumeMessage(new DataflowMessageHeader(1), target, out consumed);

            AssertEx.Throws <ArgumentNullException> (
                () =>
                block.ConsumeMessage(new DataflowMessageHeader(1), null, out consumed));


            AssertEx.Throws <ArgumentException> (
                () =>
                block.ReserveMessage(new DataflowMessageHeader(), target));

            // header that wasn't sent by the block doesn't throw
            block.ReserveMessage(new DataflowMessageHeader(1), target);

            AssertEx.Throws <ArgumentNullException> (
                () =>
                block.ReserveMessage(new DataflowMessageHeader(1), null));

            AssertEx.Throws <ArgumentException> (
                () =>
                block.ReleaseReservation(new DataflowMessageHeader(), target));

            AssertEx.Throws <ArgumentNullException>(() => block.LinkTo(null, new DataflowLinkOptions()));

            AssertEx.Throws <ArgumentNullException>(() => block.LinkTo(target, null));
        }
        private async void Consume(ISourceBlock <int> source, DataflowMessageHeader messageHeader)
        {
            await Task.Delay(3000);

            bool succeed;
            int  i = source.ConsumeMessage(messageHeader, this, out succeed);

            lock (Program._sync)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine("\tConsumed: {0}: Id = {1}, succeed = {2}", _name, messageHeader.Id, succeed);
                Console.ResetColor();
            }
        }
        internal static async Task TestReserveAndConsume <T>(
            ISourceBlock <T> block, bool reservationIsTargetSpecific = true)
        {
            bool consumed;

            block.ConsumeMessage(new DataflowMessageHeader(-99), new ActionBlock <T>(i => { }), out consumed);
            Assert.False(consumed);

            var tcs            = new TaskCompletionSource <bool>();
            var offeredMessage = default(DataflowMessageHeader);
            var target         = new DelegatePropagator <T, T>
            {
                OfferMessageDelegate = (messageHeader, value, source, consumeToAccept) =>
                {
                    offeredMessage = messageHeader;
                    tcs.TrySetResult(true);
                    return(DataflowMessageStatus.Postponed);
                }
            };

            block.LinkTo(target);
            await tcs.Task;

            Assert.True(block.ReserveMessage(offeredMessage, target));             // reserve the message

            if (reservationIsTargetSpecific)
            {
                block.ConsumeMessage(offeredMessage, new ActionBlock <T>(delegate { }), out consumed);                // different target tries to consume
                Assert.False(consumed);
            }

            block.ConsumeMessage(new DataflowMessageHeader(-99), target, out consumed);             // right target, wrong message
            Assert.False(consumed);

            block.ConsumeMessage(offeredMessage, target, out consumed);             // right target, right message
            Assert.True(consumed);
        }
Beispiel #13
0
        /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock <T> source, bool consumeToAccept)
        {
            // Validate arguments
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
            }
            if (source == null && consumeToAccept)
            {
                throw new ArgumentException(SR.Argument_CantConsumeFromANullSource, nameof(consumeToAccept));
            }
            Contract.EndContractBlock();

            lock (_sharedResources._incomingLock)
            {
                // If we've already stopped accepting messages, decline permanently
                if (_decliningPermanently ||
                    _sharedResources._decliningPermanently)
                {
                    return(DataflowMessageStatus.DecliningPermanently);
                }

                // Consume the message from the source if necessary, and store the message
                if (consumeToAccept)
                {
                    Debug.Assert(source != null, "We must have thrown if source == null && consumeToAccept == true.");

                    bool consumed;
                    messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
                    if (!consumed)
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                }
                _messages.Add(messageValue);

                // If this message makes a batch, notify the shared resources that a batch has been completed
                if (--_sharedResources._remainingItemsInBatch == 0)
                {
                    _sharedResources._batchSizeReachedAction();
                }

                return(DataflowMessageStatus.Accepted);
            }
        }
Beispiel #14
0
        /// <summary>Implements the slow path for OfferMessage.</summary>
        /// <param name="messageHeader">The message header for the offered value.</param>
        /// <param name="messageValue">The offered value.</param>
        /// <param name="source">The source offering the message. This may be null.</param>
        /// <param name="consumeToAccept">true if we need to call back to the source to consume the message; otherwise, false if we can simply accept it directly.</param>
        /// <returns>The status of the message.</returns>
        private DataflowMessageStatus OfferMessage_Slow(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock <TInput> source, bool consumeToAccept)
        {
            // If we're declining permanently, let the caller know.
            if (_decliningPermanently)
            {
                return(DataflowMessageStatus.DecliningPermanently);
            }

            // If the message header is invalid, throw.
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException(SR.Argument_InvalidMessageHeader, "messageHeader");
            }

            // If the caller has requested we consume the message using ConsumeMessage, do so.
            if (consumeToAccept)
            {
                if (source == null)
                {
                    throw new ArgumentException(SR.Argument_CantConsumeFromANullSource, "consumeToAccept");
                }
                bool consumed;
                messageValue = source.ConsumeMessage(messageHeader, _owningTarget, out consumed);
                if (!consumed)
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
            }

            // See the "fast path" comments in Post
            _messages.Enqueue(messageValue);
#if NET_4_0_ABOVE
            Interlocked.MemoryBarrier();        // ensure the read of _activeConsumer doesn't move up before the writes in Enqueue
#else
            Thread.MemoryBarrier();             // ensure the read of _activeConsumer doesn't move up before the writes in Enqueue
#endif
            if (_activeConsumer == null)
            {
                ScheduleConsumerIfNecessary(isReplica: false);
            }
            return(DataflowMessageStatus.Accepted);
        }
Beispiel #15
0
        public DataflowMessageStatus OfferMessage(ITargetBlock <TInput> target,
                                                  DataflowMessageHeader messageHeader,
                                                  TInput messageValue,
                                                  ISourceBlock <TInput> source,
                                                  bool consumeToAccept)
        {
            if (!messageHeader.IsValid)
            {
                return(DataflowMessageStatus.Declined);
            }
            if (messageQueue.IsAddingCompleted)
            {
                return(DataflowMessageStatus.DecliningPermanently);
            }

            if (consumeToAccept)
            {
                bool consummed;
                if (!source.ReserveMessage(messageHeader, target))
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
                messageValue = source.ConsumeMessage(messageHeader, target, out consummed);
                if (!consummed)
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
            }

            try {
                messageQueue.Add(messageValue);
            } catch (InvalidOperationException) {
                // This is triggered either if the underlying collection didn't accept the item
                // or if the messageQueue has been marked complete, either way it corresponds to a false
                return(DataflowMessageStatus.DecliningPermanently);
            }
            EnsureProcessing();

            VerifyCompleteness();

            return(DataflowMessageStatus.Accepted);
        }
Beispiel #16
0
        public DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader,
                                                  TOutput messageValue,
                                                  ISourceBlock <TOutput> source,
                                                  bool consumeToAccept)
        {
            if (!messageHeader.IsValid)
            {
                return(DataflowMessageStatus.Declined);
            }

            if (consumeToAccept)
            {
                bool consummed;
                if (!source.ReserveMessage(messageHeader, this))
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
                messageValue = source.ConsumeMessage(messageHeader, this, out consummed);
                if (!consummed)
                {
                    return(DataflowMessageStatus.NotAvailable);
                }
            }

            ReceivedValue = messageValue;
            completion.TrySetResult(messageValue);
            Thread.MemoryBarrier();
            waitHandle.Set();

            /* We do the unlinking here so that we don't get called twice
             */
            if (linkBridge != null)
            {
                linkBridge.Dispose();
                linkBridge = null;
            }

            return(DataflowMessageStatus.Accepted);
        }
Beispiel #17
0
        public DataflowMessageStatus OfferMessage(
            DataflowMessageHeader messageHeader, T messageValue, ISourceBlock <T> source, bool consumeToAccept)
        {
            if (!IsOpen)
            {
                return(DataflowMessageStatus.Declined);
            }

            if (consumeToAccept)
            {
                source.ConsumeMessage(messageHeader, this, out var messageConsumed);
                if (!messageConsumed)
                {
                    return(DataflowMessageStatus.Declined);
                }
            }

            _toPropergate = messageValue;
            _links.ForEach(target => target.OfferMessage(messageHeader, messageValue, this, true));

            return(DataflowMessageStatus.Accepted);
        }
Beispiel #18
0
            public DataflowMessageStatus OfferMessage(
                DataflowMessageHeader messageHeader, TSource messageValue,
                ISourceBlock <TSource> source, bool consumeToAccept)
            {
                if (consumeToAccept)
                {
                    if (!source.ReserveMessage(messageHeader, this))
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                    bool consumed;
                    messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
                    if (!consumed)
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                }

                observer.OnNext(messageValue);

                return(DataflowMessageStatus.Accepted);
            }
Beispiel #19
0
            public DataflowMessageStatus OfferMessage(
                DataflowMessageHeader messageHeader, TMessage messageValue,
                ISourceBlock <TMessage> source, bool consumeToAccept)
            {
                if (!chooserBlock.canAccept)
                {
                    return(DataflowMessageStatus.DecliningPermanently);
                }

                bool lockTaken = false;

                try {
                    chooserBlock.messageLock.Enter(ref lockTaken);
                    if (!chooserBlock.canAccept)
                    {
                        return(DataflowMessageStatus.DecliningPermanently);
                    }

                    if (consumeToAccept)
                    {
                        bool consummed;
                        messageValue = source.ConsumeMessage(messageHeader, this, out consummed);
                        if (!consummed)
                        {
                            return(DataflowMessageStatus.NotAvailable);
                        }
                    }

                    chooserBlock.canAccept = false;
                } finally {
                    if (lockTaken)
                    {
                        chooserBlock.messageLock.Exit();
                    }
                }

                chooserBlock.MessageArrived(index, action, messageValue);
                return(DataflowMessageStatus.Accepted);
            }
Beispiel #20
0
        public DataflowMessageStatus OfferMessage(
            DataflowMessageHeader messageHeader, TOutput messageValue,
            ISourceBlock <TOutput> source, bool consumeToAccept)
        {
            if (!messageHeader.IsValid)
            {
                return(DataflowMessageStatus.Declined);
            }

            if (completion.Task.Status != TaskStatus.WaitingForActivation)
            {
                return(DataflowMessageStatus.DecliningPermanently);
            }

            lock (completion) {
                if (completion.Task.Status != TaskStatus.WaitingForActivation)
                {
                    return(DataflowMessageStatus.DecliningPermanently);
                }

                if (consumeToAccept)
                {
                    bool consummed;
                    if (!source.ReserveMessage(messageHeader, this))
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                    messageValue = source.ConsumeMessage(messageHeader, this, out consummed);
                    if (!consummed)
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                }

                completion.TrySetResult(messageValue);
            }
            CompletionSet();
            return(DataflowMessageStatus.Accepted);
        }
Beispiel #21
0
        /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
        internal DataflowMessageStatus OfferMessage(DataflowMessageHeader messageHeader, TInput messageValue, ISourceBlock <TInput> source, bool consumeToAccept)
        {
            // Validate arguments
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
            }
            if (source == null && consumeToAccept)
            {
                throw new ArgumentException(SR.Argument_CantConsumeFromANullSource, nameof(consumeToAccept));
            }

            lock (IncomingLock)
            {
                // If we shouldn't be accepting more messages, don't.
                if (_decliningPermanently)
                {
                    CompleteBlockIfPossible();
                    return(DataflowMessageStatus.DecliningPermanently);
                }

                // We can directly accept the message if:
                //      1) we are not bounding, OR
                //      2) we are bounding AND there is room available AND there are no postponed messages AND no messages are currently being transfered to the input queue.
                // (If there were any postponed messages, we would need to postpone so that ordering would be maintained.)
                // (Unlike all other blocks, TargetCore can accept messages while processing, because
                // input message IDs are properly assigned and the correct order is preserved.)
                if (_boundingState == null ||
                    (_boundingState.OutstandingTransfers == 0 && _boundingState.CountIsLessThanBound && _boundingState.PostponedMessages.Count == 0))
                {
                    // Consume the message from the source if necessary
                    if (consumeToAccept)
                    {
                        Debug.Assert(source != null, "We must have thrown if source == null && consumeToAccept == true.");

                        bool consumed;
                        messageValue = source.ConsumeMessage(messageHeader, _owningTarget, out consumed);
                        if (!consumed)
                        {
                            return(DataflowMessageStatus.NotAvailable);
                        }
                    }

                    // Assign a message ID - strictly sequential, no gaps.
                    // Once consumed, enqueue the message with its ID and kick off asynchronous processing.
                    long messageId = _nextAvailableInputMessageId.Value++;
                    Debug.Assert(messageId != Common.INVALID_REORDERING_ID, "The assigned message ID is invalid.");
                    if (_boundingState != null)
                    {
                        _boundingState.CurrentCount += 1;                         // track this new item against our bound
                    }
                    _messages.Enqueue(new KeyValuePair <TInput, long>(messageValue, messageId));
                    ProcessAsyncIfNecessary();
                    return(DataflowMessageStatus.Accepted);
                }
                // Otherwise, we try to postpone if a source was provided
                else if (source != null)
                {
                    Debug.Assert(_boundingState != null && _boundingState.PostponedMessages != null,
                                 "PostponedMessages must have been initialized during construction in non-greedy mode.");

                    // Store the message's info and kick off asynchronous processing
                    _boundingState.PostponedMessages.Push(source, messageHeader);
                    ProcessAsyncIfNecessary();
                    return(DataflowMessageStatus.Postponed);
                }
                // We can't do anything else about this message
                return(DataflowMessageStatus.Declined);
            }
        }
Beispiel #22
0
        /// <include file='XmlDocs/CommonXmlDocComments.xml' path='CommonXmlDocComments/Targets/Member[@name="OfferMessage"]/*' />
        DataflowMessageStatus ITargetBlock <T> .OfferMessage(DataflowMessageHeader messageHeader, T messageValue, ISourceBlock <T> source, Boolean consumeToAccept)
        {
            // Validate arguments
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException(SR.Argument_InvalidMessageHeader, nameof(messageHeader));
            }
            if (source == null && consumeToAccept)
            {
                throw new ArgumentException(SR.Argument_CantConsumeFromANullSource, nameof(consumeToAccept));
            }
            Contract.EndContractBlock();

            lock (IncomingLock)
            {
                // If we've already stopped accepting messages, decline permanently
                if (_targetDecliningPermanently)
                {
                    CompleteTargetIfPossible();
                    return(DataflowMessageStatus.DecliningPermanently);
                }

                // We can directly accept the message if:
                //      1) we are not bounding, OR
                //      2) we are bounding AND there is room available AND there are no postponed messages AND we are not currently processing.
                // (If there were any postponed messages, we would need to postpone so that ordering would be maintained.)
                // (We should also postpone if we are currently processing, because there may be a race between consuming postponed messages and
                // accepting new ones directly into the queue.)
                if (_boundingState == null
                    ||
                    (_boundingState.CountIsLessThanBound && _boundingState.PostponedMessages.Count == 0 && _boundingState.TaskForInputProcessing == null))
                {
                    // Consume the message from the source if necessary
                    if (consumeToAccept)
                    {
                        Debug.Assert(source != null, "We must have thrown if source == null && consumeToAccept == true.");

                        bool consumed;
                        messageValue = source.ConsumeMessage(messageHeader, this, out consumed);
                        if (!consumed)
                        {
                            return(DataflowMessageStatus.NotAvailable);
                        }
                    }

                    // Once consumed, pass it to the source
                    _source.AddMessage(messageValue);
                    if (_boundingState != null)
                    {
                        _boundingState.CurrentCount++;
                    }

                    return(DataflowMessageStatus.Accepted);
                }
                // Otherwise, we try to postpone if a source was provided
                else if (source != null)
                {
                    Debug.Assert(_boundingState != null && _boundingState.PostponedMessages != null,
                                 "PostponedMessages must have been initialized during construction in bounding mode.");

                    _boundingState.PostponedMessages.Push(source, messageHeader);
                    return(DataflowMessageStatus.Postponed);
                }
                // We can't do anything else about this message
                return(DataflowMessageStatus.Declined);
            }
        }
Beispiel #23
0
 public Ping ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock <Ping> target, out bool messageConsumed)
 {
     return(_source.ConsumeMessage(messageHeader, target, out messageConsumed));
 }
Beispiel #24
0
 public TTarget ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock <TTarget> target, out bool messageConsumed) =>
 _output.ConsumeMessage(messageHeader, target, out messageConsumed);
Beispiel #25
0
 public T ConsumeMessage(DataflowMessageHeader messageHeader,
                         ITargetBlock <T> target, out bool messageConsumed)
 {
     return(actualSource.ConsumeMessage(messageHeader, predicateBlock,
                                        out messageConsumed));
 }
Beispiel #26
0
        public DataflowMessageStatus OfferMessage(
            DataflowMessageHeader messageHeader, TInput messageValue,
            ISourceBlock <TInput> source, bool consumeToAccept)
        {
            if (!messageHeader.IsValid)
            {
                throw new ArgumentException("The messageHeader is not valid.",
                                            "messageHeader");
            }
            if (consumeToAccept && source == null)
            {
                throw new ArgumentException(
                          "consumeToAccept may only be true if provided with a non-null source.",
                          "consumeToAccept");
            }

            if (MessageQueue.IsAddingCompleted || !CompHelper.CanRun)
            {
                return(DataflowMessageStatus.DecliningPermanently);
            }

            var full = options.BoundedCapacity != -1 &&
                       Thread.VolatileRead(ref itemCount) >= options.BoundedCapacity;

            if (!greedy || full)
            {
                if (source == null)
                {
                    return(DataflowMessageStatus.Declined);
                }

                postponedMessages [source] = messageHeader;

                // necessary to avoid race condition
                DecreaseCount(0);

                if (!greedy && !full)
                {
                    EnsureProcessing(true);
                }

                return(DataflowMessageStatus.Postponed);
            }

            // in this case, we need to use locking to make sure
            // we don't consume when we can't accept
            if (consumeToAccept && canAccept != null)
            {
                bool lockTaken = false;
                try {
                    consumingLock.Enter(ref lockTaken);
                    if (!canAcceptFromBefore && !canAccept())
                    {
                        return(DataflowMessageStatus.DecliningPermanently);
                    }

                    bool consummed;
                    messageValue = source.ConsumeMessage(messageHeader, Target, out consummed);
                    if (!consummed)
                    {
                        canAcceptFromBefore = true;
                        return(DataflowMessageStatus.NotAvailable);
                    }

                    canAcceptFromBefore = false;
                } finally {
                    if (lockTaken)
                    {
                        consumingLock.Exit();
                    }
                }
            }
            else
            {
                if (consumeToAccept)
                {
                    bool consummed;
                    messageValue = source.ConsumeMessage(messageHeader, Target, out consummed);
                    if (!consummed)
                    {
                        return(DataflowMessageStatus.NotAvailable);
                    }
                }

                if (canAccept != null && !canAccept())
                {
                    return(DataflowMessageStatus.DecliningPermanently);
                }
            }

            try {
                MessageQueue.Add(messageValue);
            } catch (InvalidOperationException) {
                // This is triggered either if the underlying collection didn't accept the item
                // or if the messageQueue has been marked complete, either way it corresponds to a false
                return(DataflowMessageStatus.DecliningPermanently);
            }

            IncreaseCount();

            EnsureProcessing(true);

            VerifyCompleteness();

            return(DataflowMessageStatus.Accepted);
        }
 public ISegment <IGeofencingSample> ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock <ISegment <IGeofencingSample> > target, out bool messageConsumed) => _source.ConsumeMessage(messageHeader, target, out messageConsumed);
Beispiel #28
0
 public T[] ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock <T[]> targets, out bool messageConsumed)
 {
     return(_batchBlock.ConsumeMessage(messageHeader, targets, out messageConsumed));
 }
Beispiel #29
0
 TSplit ISourceBlock <TSplit> .ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock <TSplit> target, out bool messageConsumed)
 {
     return(orderCapturer.ConsumeMessage(messageHeader, target, out messageConsumed));
 }
Beispiel #30
0
 public TOutput ConsumeMessage(DataflowMessageHeader messageHeader, ITargetBlock <TOutput> target, out bool messageConsumed)
 {
     return(source.ConsumeMessage(messageHeader, target, out messageConsumed));
 }