Exemplo n.º 1
0
        /// <summary>
        /// Instantiate a new instance of MSMQMessageFetcher class.
        /// </summary>
        /// <param name="messageQueue">target MSMQ queue</param>
        /// <param name="messageCount">number of messages in queue</param>
        /// <param name="messageFormatter">message formatter for deserializing MSMQ message</param>
        /// <param name="prefetchCacheCapacity">prefetch cache capacity</param>
        /// <param name="maxOutstandingFetchCount">maximun number of outstanding BeginPeek operations</param>
        public MSMQMessageFetcher(MessageQueue messageQueue, long messageCount, IMessageFormatter messageFormatter, int prefetchCacheCapacity, int maxOutstandingFetchCount)
        {
            this.msmqQueueField           = messageQueue;
            this.msmqMessageCount         = messageCount;
            this.messageFormatter         = messageFormatter;
            this.prefetchCacheCapacity    = prefetchCacheCapacity;
            this.maxOutstandingFetchCount = maxOutstandingFetchCount;
            this.prefetchCredit           = this.prefetchCacheCapacity;

            this.messagePeekCursorField   = new RefCountedCursor(this.msmqQueueField.CreateCursor());
            this.messagePeekActionField   = PeekAction.Current;
            this.msmqQueueField.Disposed += this.OnQueueDisposed;

            this.prefetchTimer.AutoReset = false;
            this.prefetchTimer.Interval  = 500;
            this.prefetchTimer.Elapsed  += (sender, args) =>
            {
                Debug.WriteLine("[MSMQMessageFetcher] .prefetchTimer raised.");
                this.PeekMessage();
                if (!this.isDisposedField)
                {
                    this.prefetchTimer.Enabled = true;
                }
            };
            this.prefetchTimer.Enabled = true;

            BrokerTracing.TraceVerbose("[MSMQMessageFetcher] .Create new instance: prefetchCacheCapacity={0}, maxOutstandingFetchCount={1}", this.prefetchCacheCapacity, this.maxOutstandingFetchCount);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Dispose this MSMQMessageFetcher instance.
        /// </summary>
        public void SafeDispose()
        {
            BrokerTracing.TraceVerbose("[MSMQMessageFetcher] .SafeDispose.");

            //
            // SafeDispose:
            // 1. mark this instance as disposed
            // 2. wait for all outstanding BeginPeek operations back, and then dispose the cursor.
            //
            if (!this.isDisposedField)
            {
                this.isDisposedField = true;
                // dispose prefetched messages
                this.lockPrefetchCache.EnterWriteLock();
                try
                {
                    if (this.prefetchCache != null)
                    {
                        // below line of code is put inside of prefetchCache lock scope just to ensure it's executed only once
                        this.msmqQueueField.Disposed -= this.OnQueueDisposed;

                        if (!this.prefetchCache.IsEmpty)
                        {
                            BrokerTracing.TraceWarning("[MSMQMessageFetcher] .SafeDispose: PrefetchCache is not empty when disposing.");
                        }

                        foreach (MessageResult result in this.prefetchCache)
                        {
                            if (result.Message != null)
                            {
                                result.Message.Dispose();
                            }
                        }

                        this.prefetchCache = null;
                    }
                }
                finally
                {
                    this.lockPrefetchCache.ExitWriteLock();
                }

                this.rwlockMessagePeekCursorField.EnterWriteLock();
                try
                {
                    if (this.messagePeekCursorField != null)
                    {
                        this.messagePeekCursorField.Release();
                        this.messagePeekCursorField = null;
                    }
                }
                finally
                {
                    this.rwlockMessagePeekCursorField.ExitWriteLock();
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Callback function invoked on BeginPeek completion.
        /// </summary>
        /// <param name="ar"></param>
        private void PeekMessageComplete(IAsyncResult ar)
        {
            BrokerTracing.TraceVerbose("[MSMQMessageFetcher] .PeekMessageComplete: Peek message complete.");

            Exception exception = null;

            System.Messaging.Message message         = null;
            bool             needRetry               = false;
            RefCountedCursor storedMessagePeekCursor = ar.AsyncState as RefCountedCursor;

            this.rwlockMessagePeekCursorField.EnterReadLock();
            try
            {
                try
                {
                    //
                    // Check if target queue is disposed. If so, don't call EndPeek.  However, the check doesn't guarantee
                    // that msmqQueueField is valid when EndPeek is invoked on it. So ObjectDisposedException shall be handled.
                    //
                    if (this.isQueueDisposed)
                    {
                        BrokerTracing.TraceWarning("[MSMQMessageFetcher]) .PeekMessageComplete: target queue is disposed");
                        return;
                    }

                    message = this.msmqQueueField.EndPeek(ar);
                    Interlocked.Increment(ref this.peekCursorPosition);
                }
                catch (MessageQueueException e)
                {
                    if (this.isDisposedField)
                    {
                        this.RevertFetchCount();
                        return;
                    }

                    needRetry = MessageQueueHelper.HandleAsyncCallbackError(
                        e,
                        ref this.messagePeekActionField,
                        "[MSMQMessageFetcher] .PeekMessageComplete: EndPeek message failed, outstandingPeekCount:{0}, messageCount={1}",
                        this.outstandingFetchCount,
                        this.msmqMessageCount);

                    if (!needRetry)
                    {
                        BrokerTracing.TraceError(
                            "[MSMQMessageFetcher] .PeekMessageComplete: end peek message failed, outstandingPeekCount:{0}, messageCount:{1} Exception:{2}",
                            this.outstandingFetchCount,
                            this.msmqMessageCount,
                            e);
                        exception = e;
                    }
                }
                catch (Exception e)
                {
                    if (this.isDisposedField)
                    {
                        this.RevertFetchCount();
                        return;
                    }

                    BrokerTracing.TraceError("[MSMQMessageFetcher] .PeekMessageComplete: end peek message failed, Exception:{0}", e.ToString());
                    exception = e;
                }
                finally
                {
                    storedMessagePeekCursor.Release();
                }
            }
            finally
            {
                this.rwlockMessagePeekCursorField.ExitReadLock();
            }

            if (needRetry)
            {
                Interlocked.Increment(ref this.pendingFetchCount);
                return;
            }

            if (message == null && exception == null)
            {
                BrokerTracing.TraceWarning("[MSMQMessageFetcher] .PeekMessageComplete: EndPeek return null.");
            }

            if (message != null)
            {
                // if the message is one of the partial messages
                if (message.AppSpecific > 0 && !string.IsNullOrEmpty(message.Label))
                {
                    try
                    {
                        BrokerTracing.TraceVerbose(
                            "[MSMQMessageFetcher] .PeekMessageComplete: peek partial message with AppSpecific {0} and Label {1}.", message.AppSpecific, message.Label);
                        string[] labels    = message.Label.Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);
                        string   groupId   = labels[0];
                        int      msgNumber = int.Parse(labels[1]);
                        ConcurrentDictionary <int, Message> messages = this.partialMessages.GetOrAdd(groupId, (k) => new ConcurrentDictionary <int, Message>());
                        if (!messages.TryAdd(msgNumber, message))
                        {
                            BrokerTracing.TraceError(
                                "[MSMQMessageFetcher] .PeekMessageComplete: try add one of the composed messages failed. Message Label {0}.", message.Label);
                        }

                        // check if all partial messages are peeked and cached
                        if (this.partialMessageCounters.AddOrUpdate(groupId, 1, (k, v) => v + 1) == message.AppSpecific)
                        {
                            BrokerTracing.TraceVerbose(
                                "[MSMQMessageFetcher] .PeekMessageComplete: all partial messages are peeked and cached for group {0}.", groupId);
                            Message msg = new Message();
                            msg.BodyType = message.BodyType;
                            byte[]      buffer    = new byte[Constant.MSMQChunkSize];
                            List <long> lookUpIds = new List <long>(message.AppSpecific);
                            for (int i = 1; i <= message.AppSpecific; i++)
                            {
                                Message m     = messages[i];
                                int     count = m.BodyStream.Read(buffer, 0, Constant.MSMQChunkSize);
                                msg.BodyStream.Write(buffer, 0, count);
                                lookUpIds.Add(m.LookupId);
                            }
                            msg.BodyStream.Position = 0;
                            BrokerQueueItem brokerQueueItem = null;

                            // Deserialize message to BrokerQueueItem
                            try
                            {
                                brokerQueueItem = (BrokerQueueItem)this.messageFormatter.Read(msg);
                                brokerQueueItem.PersistAsyncToken.AsyncToken = lookUpIds.ToArray();
                            }
                            catch (Exception e)
                            {
                                BrokerTracing.TraceError(
                                    "[MSMQMessageFetcher] .PeekMessageComplete: deserialize message failed for composed messages with groupId {0}, Exception:{1}", groupId,
                                    e);
                                exception = e;
                            }

                            messages.Clear();
                            if (!this.partialMessages.TryRemove(groupId, out messages))
                            {
                                BrokerTracing.TraceWarning(
                                    "[MSMQMessageFetcher] .PeekMessageComplete: try to remove partial messages with groupId {0} from cahce failed.", groupId);
                            }
                            int messageCount;
                            if (!this.partialMessageCounters.TryRemove(groupId, out messageCount))
                            {
                                BrokerTracing.TraceWarning(
                                    "[MSMQMessageFetcher] .PeekMessageComplete: try to remove partial message counters with groupId {0} from cahce failed.", groupId);
                            }

                            this.HandleMessageResult(new MessageResult(brokerQueueItem, exception));
                        }
                        else
                        {
                            Interlocked.Increment(ref this.pendingFetchCount);
                        }
                    }
                    catch (Exception ex)
                    {
                        BrokerTracing.TraceError(
                            "[MSMQMessageFetcher] .PeekMessageComplete: peek composed message failed, Exception:{0}", ex);
                    }
                }
                else
                {
                    BrokerQueueItem brokerQueueItem = null;

                    // Deserialize message to BrokerQueueItem
                    try
                    {
                        brokerQueueItem = (BrokerQueueItem)this.messageFormatter.Read(message);
                        brokerQueueItem.PersistAsyncToken.AsyncToken = new long[1] {
                            message.LookupId
                        };
                    }
                    catch (Exception e)
                    {
                        BrokerTracing.TraceError(
                            "[MSMQMessageFetcher] .PeekMessageComplete: deserialize message failed, Exception:{0}",
                            e.ToString());
                        exception = e;
                    }

                    this.HandleMessageResult(new MessageResult(brokerQueueItem, exception));
                }
            }
        }