Example #1
0
        private void PrefetchRequestCallback(BrokerQueueItem queueItem, object state)
        {
            try
            {
#if DEBUG
                BrokerTracing.TraceVerbose("[BrokerQueueDispatcher] .PrefetchRequestCallback: received one request. request id={0}", GetMessageId(queueItem));
#endif
                bool   isCached = false;
                bool   shouldDisposeQueueItem = false;
                Guid   persistId        = Guid.Empty;
                object asyncToken       = null;
                int    dispatcherNumber = 0;
                if (queueItem != null)
                {
                    dispatcherNumber = queueItem.DispatchNumber;
                    persistId        = queueItem.PersistId;
                    asyncToken       = queueItem.PersistAsyncToken.AsyncToken;
                    if (this.requestsAsyncTokenTable.Count > 0 && dispatcherNumber == 0)
                    {
                        // if the request is already in the cache or dispatched.
                        lock (this.requestsAsyncTokenTable)
                        {
                            if (this.requestsAsyncTokenTable.ContainsKey(persistId))
                            {
                                try
                                {
                                    DispatcherAsyncTokenItem asyncTokenItem = this.requestsAsyncTokenTable[persistId];
                                    if (asyncTokenItem.AsyncToken == null)
                                    {
                                        asyncTokenItem.AsyncToken = asyncToken;
                                    }

                                    // the duplicated request item is of no use after retrieving out its async token.  so we should dispose it if possible
                                    shouldDisposeQueueItem = true;
                                }
                                catch (Exception e)
                                {
                                    // the request in the table is removed by another thread.
                                    BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PrefetchRequestCallback: The request async token is removed from the table, Exception: {0}", e);
                                }

                                isCached = true;
                            }
                        }
                    }

                    if (!isCached)
                    {
                        bool needQueue = true;

                        // if there are pending requests callback, then dispatch the request through the pending requests callback.
                        if (this.requestCallbackQueue.Count > 0)
                        {
                            try
                            {
                                BrokerQueueCallbackItem requestCallback;
                                if (this.requestCallbackQueue.TryDequeue(out requestCallback))
                                {
                                    this.RegisterReemit(queueItem);

                                    requestCallback.Callback(queueItem, requestCallback.CallbackState);
                                    needQueue = false;
#if DEBUG
                                    BrokerTracing.TraceVerbose("[BrokerQueueDispatcher] .PrefetchRequestCallback: Invoked callback for request.");
#endif
                                }
                                else
                                {
                                    BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PrefetchRequestCallback: The requests callback queue is empty.");
                                }
                            }
                            catch (InvalidOperationException e)
                            {
                                // the request callback queue is drained by other threads.
                                BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PrefetchRequestCallback: The requests callback queue is empty, Exception: {0}", e);
                            }
                            catch (Exception e)
                            {
                                // request callback raise exception.
                                BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .PrefetchRequestCallback: The requests callback raise exception, Exception: {0}", e);
                            }
                        }

                        if (needQueue)
                        {
                            // if no pending requests callback, then append the request to the cache queue.
                            this.requestCacheQueue.Enqueue(queueItem);
                            if (this.requestCacheQueue.Count >= this.GetCacheContainerSize())
                            {
                                this.needPrefetch = false;
                            }
                            else
                            {
                                this.needPrefetch = true;
                            }
                        }
                    }
                }

                BrokerQueue brokerQueue = (BrokerQueue)state;

                // try to get the next request.
                if (this.needPrefetch)
                {
                    // hop to another thread to avoid recursive stack overflow for memory queue that will call the callback at the same thread.
                    ThreadPool.QueueUserWorkItem(this.GetRequestThreadProc, state);
                }
                else
                {
                    lock (this.waitBrokerQueuesForPeekRequests)
                    {
                        this.waitBrokerQueuesForPeekRequests.Add(brokerQueue);
                    }

                    if (this.requestCacheQueue.Count < this.sharedData.DispatcherCount + this.watermarkerForTriggerPrefetch)
                    {
                        this.TriggerPrefetch();
                    }
                }

                // drain the pending requests callback.
                this.HandlePendingRequestCallback();

                // check if the response already come back.
                if (!this.HandleResponseWithoutAsyncToken(brokerQueue, queueItem) && shouldDisposeQueueItem)
                {
                    // if its response is not back, and we've decided that the request queue item is of no use, dispose it.
                    queueItem.Dispose();
                }
            }
            catch (Exception e)
            {
                BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PrefetchRequestCallback: raised unknown exception: {0}", e);
            }
        }
Example #2
0
        public void PutResponseAsync(Message responseMsg, BrokerQueueItem requestItem, bool ignoreAsyncToken = false)
        {
            try
            {
                // Null means the request has been put back.
                if (responseMsg != null && this.sharedData.Config.LoadBalancing.MessageResendLimit > 0)
                {
                    if (!requestItem.ReemitToken.Finish())
                    {
                        TraceUtils.TraceWarning(
                            "BrokerQueueDispatcher",
                            "PutResponseAsync",
                            "Drop the response {0} since no multi emission callback registered",
                            Utility.GetMessageIdFromMessage(requestItem.Message));

                        return;
                    }
                }

                BrokerQueueAsyncToken asyncToken = requestItem.PersistAsyncToken;
                if (asyncToken.AsyncToken != null || ignoreAsyncToken || responseMsg == null)
                {
                    asyncToken.Queue.PutResponseAsync(responseMsg, requestItem);
                    return;
                }

                DispatcherAsyncTokenItem asyncTokenItem = null;
                lock (this.requestsAsyncTokenTable)
                {
                    this.requestsAsyncTokenTable.TryGetValue(asyncToken.PersistId, out asyncTokenItem);
                }

                if (asyncTokenItem != null)
                {
                    bool hasGetAsyncToken = false;
                    try
                    {
                        if (asyncTokenItem != null)
                        {
                            if (asyncTokenItem.AsyncToken != null)
                            {
                                asyncToken.AsyncToken = asyncTokenItem.AsyncToken;
                                hasGetAsyncToken      = true;

                                lock (this.requestsAsyncTokenTable)
                                {
                                    this.requestsAsyncTokenTable.Remove(asyncToken.PersistId);
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        if (hasGetAsyncToken)
                        {
                            BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .PutResponseAsync: remove the async token from the table raised the exception, {0}", e);
                        }
                        else
                        {
                            // maybe there are duplicate responses, and the request in the async token table is removed by the previous request.
                            BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .PutResponseAsync: try to get the async token from the table raised the exception, {0}", e);
                        }
                    }

                    if (hasGetAsyncToken)
                    {
                        asyncToken.Queue.PutResponseAsync(responseMsg, requestItem);
                    }
                    else
                    {
                        BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PutResponseAsync: Failed to get async token.");

                        lock (this.responsesWithoutAsyncTokenTable)
                        {
                            this.responsesWithoutAsyncTokenTable.Add(asyncToken.PersistId, new DispatcherAsyncTokenItem(responseMsg, asyncToken));
                        }

                        if (asyncTokenItem.AsyncToken != null)
                        {
                            bool needPutToTheQueue = false;
                            try
                            {
                                lock (this.responsesWithoutAsyncTokenTable)
                                {
                                    this.responsesWithoutAsyncTokenTable.Remove(asyncToken.PersistId);
                                }

                                needPutToTheQueue = true;

                                lock (this.requestsAsyncTokenTable)
                                {
                                    this.requestsAsyncTokenTable.Remove(asyncToken.PersistId);
                                }
                            }
                            catch (Exception e)
                            {
                                if (needPutToTheQueue)
                                {
                                    BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PutResponseAsync: remove the request async token from the table failed, the exception: {0}", e);
                                }
                                else
                                {
                                    // in case the reponse message is persisted by another thread.
                                    BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PutResponseAsync: remove the response from the responses without async table fail, the exception: {0}", e);
                                }
                            }

                            if (needPutToTheQueue)
                            {
                                asyncToken.AsyncToken = asyncTokenItem.AsyncToken;
                                asyncToken.Queue.PutResponseAsync(responseMsg, requestItem);
                            }
                            else
                            {
                                BrokerTracing.TraceWarning(
                                    "[BrokerQueueDispatcher] .PutResponseAsync: Don't put response back because needPutToTheQueue=false. AsyncToken.PersistId={0}, requestItem id: {1}, response id:{2}",
                                    asyncToken.PersistId,
                                    requestItem?.Message?.Headers?.MessageId,
                                    responseMsg?.Headers?.MessageId);
                            }
                        }
                        else
                        {
                            // the request item is processed and its response is returned, but its async token is unknown yet.  At this point, as corresponding DispatcherAsyncToken item is
                            // already put into responsesWithoutAsyncTokenTable, the request item itself is of no use now. so dispose it.
                            BrokerTracing.TraceInfo(
                                "[BrokerQueueDispatcher] .PutResponseAsync: Dispose requestItem id: {0}, response id:{1}",
                                requestItem?.Message?.Headers?.MessageId,
                                responseMsg?.Headers?.MessageId);

                            requestItem.Dispose();
                        }
                    }
                }
                else
                {
                    BrokerTracing.TraceError("[BrokerQueueDispatcher] .PutResponseAsync: can not find the async token.");
                }
            }
            catch (Exception e)
            {
                BrokerTracing.TraceError("[BrokerQueueDispatcher] .PutResponseAsync: unkown exception, {0}", e);
            }
        }