Exemple #1
0
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            ParamCheckUtility.ThrowIfNull(info, "info");

            info.AddValue(BrokerQueueItem.MessageVersionTag, SerializeMessageVersion(this.Message.Version));

            MemoryStream msgStream = null;

            try
            {
                msgStream = new MemoryStream();
                using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(msgStream))
                {
                    var msgStreamTemp = msgStream;
                    msgStream = null;
                    this.Message.WriteMessage(writer);
                    writer.Flush();
                    info.AddValue(BrokerQueueItem.MessageTag, msgStreamTemp.ToArray());
                }
            }
            finally
            {
                if (msgStream != null)
                {
                    msgStream.Dispose();
                }
            }

            BrokerQueueItem.SerializeObject(info, this.asyncState, BrokerQueueItem.AsyncStateTag);
            BrokerQueueItem.SerializeObject(info, this.persistGuid, BrokerQueueItem.PersistIdTag);
        }
Exemple #2
0
        private bool HandleResponseWithoutAsyncToken(BrokerQueue queue, BrokerQueueItem requestItem)
        {
            bool   isHandled        = false;
            Guid   persistId        = requestItem.PersistId;
            object asyncToken       = requestItem.PersistAsyncToken.AsyncToken;
            int    dispatcherNumber = requestItem.DispatchNumber;

            if (asyncToken != null && this.responsesWithoutAsyncTokenTable.Count > 0)
            {
                bool needPutResponse = false;
                DispatcherAsyncTokenItem asyncTokenItem = null;
                try
                {
                    lock (this.responsesWithoutAsyncTokenTable)
                    {
                        this.responsesWithoutAsyncTokenTable.TryGetValue(persistId, out asyncTokenItem);
                    }

                    if (asyncTokenItem != null)
                    {
                        lock (this.responsesWithoutAsyncTokenTable)
                        {
                            this.responsesWithoutAsyncTokenTable.Remove(persistId);
                        }

                        needPutResponse = true;

                        lock (this.requestsAsyncTokenTable)
                        {
                            this.requestsAsyncTokenTable.Remove(persistId);
                        }
                    }
                }
                catch (Exception e)
                {
                    if (needPutResponse)
                    {
                        BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PrefetchRequestCallback: fail to remove the async token from the table, Exception: {0}", e);
                    }
                    else
                    {
                        BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .PrefetchRequestCallback: can not get the response async token, Exception: {0}", e);
                    }
                }

                if (needPutResponse && dispatcherNumber == 0)
                {
                    asyncTokenItem.PersistAsyncToken.AsyncToken = asyncToken;
                    queue.PutResponseAsync(asyncTokenItem.Message, requestItem);
                    isHandled = true;
                }
            }
            return(isHandled);
        }
Exemple #3
0
        public void GetRequestAsync(BrokerQueueCallback requestCallback, object state)
        {
            ParamCheckUtility.ThrowIfNull(requestCallback, "requestCallback");
            bool isCallbackHandled = false;

            if (this.requestCacheQueue.Count > 0)
            {
                BrokerQueueItem request = null;

                if (!this.requestCacheQueue.TryDequeue(out request))
                {
                    BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .GetRequestAsync: All cached requests are dispatched.");
                }

                if (request != null)
                {
                    try
                    {
#if DEBUG
                        BrokerTracing.TraceVerbose("[BrokerQueueDispatcher] .GetRequestAsync: handle request callback from cache queue. request id={0}", GetMessageId(request));
#endif

                        this.RegisterReemit(request);

                        isCallbackHandled = true;
                        requestCallback(request, state);
                    }
                    catch (Exception e)
                    {
                        this.requestCacheQueue.Enqueue(request);

                        // request callback raise exception.
                        BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .GetRequestAsync: The request callback raise exception. Exception: {0}", e);
                    }
                }
            }

            if (this.requestCacheQueue.Count <= this.watermarkerForTriggerPrefetch)
            {
                BrokerTracing.TraceVerbose("[BrokerQueueDispatcher] .GetRequestAsync (perf): Trigger prefetch because the count of cached items is below threshold. state={0}", (int)state);
                this.TriggerPrefetch();
            }

            if (!isCallbackHandled)
            {
                this.requestCallbackQueue.Enqueue(new BrokerQueueCallbackItem(requestCallback, state));

                // in case the last request come in the cache queue right before the request callback enqueue.
                this.HandlePendingRequestCallback();
            }
        }
Exemple #4
0
        public object Clone()
        {
            var info    = new SerializationInfo(typeof(BrokerQueueItem), new FormatterConverter());
            var context = new StreamingContext();

            info.AddValue(BrokerQueueItem.MessageVersionTag, SerializeMessageVersion(this.Message.Version));
            MemoryStream msgStream = null;

            try
            {
                msgStream = new MemoryStream();
                using (XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(msgStream))
                {
                    var msgStreamTemp = msgStream;
                    msgStream = null;
                    var msg = this.MessageBuffer.CreateMessage();
                    msg.WriteMessage(writer);
                    writer.Flush();
                    info.AddValue(BrokerQueueItem.MessageTag, msgStreamTemp.ToArray());
                }
            }
            finally
            {
                if (msgStream != null)
                {
                    msgStream.Dispose();
                }
            }

            BrokerQueueItem.SerializeObject(info, this.asyncState, BrokerQueueItem.AsyncStateTag);
            BrokerQueueItem.SerializeObject(info, this.persistGuid, BrokerQueueItem.PersistIdTag);

            var item = new BrokerQueueItem(info, context);

            // Give it a new id.
            var newId = new UniqueId();

            item.Message.Headers.RemoveAll(Constant.MessageIdHeaderName, Constant.HpcHeaderNS);
            item.Message.Headers.Add(MessageHeader.CreateHeader(Constant.MessageIdHeaderName, Constant.HpcHeaderNS, newId));
            item.Message.Headers.MessageId = newId;
            item.CleanMessageBuffer();
            item.buffer = item.Message.CreateBufferedCopy(BrokerEntry.MaxMessageSize);

            item.asyncToken.AsyncToken = this.asyncToken.AsyncToken;
            item.asyncToken.Queue      = this.asyncToken.Queue;
            item.TryCount       = this.TryCount;
            item.DispatchNumber = this.DispatchNumber;
            item.ReemitToken    = this.ReemitToken;
            return(item);
        }
Exemple #5
0
 private void RegisterReemit(BrokerQueueItem request)
 {
     // Only re-emit when message can be resent.
     if (this.sharedData.Config.LoadBalancing.MessageResendLimit > 0)
     {
         request.RegisterReemit(
             TimeSpan.FromMilliseconds(this.sharedData.Config.LoadBalancing.MultiEmissionDelayTime),
             this.sharedData.Config.LoadBalancing.MessageResendLimit,
             clonedRequest =>
         {
             this.PutResponseAsync(null, clonedRequest, true);
             this.sharedData.Observer.RequestReemit();
         });
     }
 }
Exemple #6
0
        /// <summary>
        /// Initializes a new instance of the PersistMessage class for deserialization.
        /// </summary>
        /// <param name="info">the serializaion info.</param>
        /// <param name="context">the serialization context.</param>
        protected BrokerQueueItem(SerializationInfo info, StreamingContext context)
        {
            ParamCheckUtility.ThrowIfNull(info, "info");

            MessageVersion version = DeserializeMessageVersion(info.GetInt32(MessageVersionTag));

            using (XmlDictionaryReader reader = XmlDictionaryReader.CreateBinaryReader((byte[])info.GetValue(BrokerQueueItem.MessageTag, typeof(byte[])), BrokerEntry.ReaderQuotas))
            {
                using (Message messageTmp = Message.CreateMessage(reader, BrokerEntry.MaxMessageSize, version))
                {
                    this.buffer = messageTmp.CreateBufferedCopy(BrokerEntry.MaxMessageSize);
                }
            }

            int deserializeFlags = 0;

            foreach (SerializationEntry entry in info)
            {
                switch (entry.Name)
                {
                case BrokerQueueItem.AsyncStateTag:
                    this.asyncState   = BrokerQueueItem.DeserializeObject(entry);
                    deserializeFlags |= 1;
                    break;

                case BrokerQueueItem.PersistIdTag:
                    this.persistGuid  = (Guid)BrokerQueueItem.DeserializeObject(entry);
                    deserializeFlags |= 2;
                    break;
                }

                if (deserializeFlags == 3)
                {
                    break;
                }
            }

            this.context    = BrokerQueueItem.DummyRequestContextField;
            this.asyncToken = new BrokerQueueAsyncToken(this.persistGuid, this.asyncState, null, 0);
        }
Exemple #7
0
 /// <summary>
 /// Acknowledge if a response has been sent back to client successfully or not
 /// </summary>
 /// <param name="response">response item</param>
 /// <param name="success">if the response item has been sent back to client successfully or not</param>
 public abstract void AckResponse(BrokerQueueItem response, bool success);
Exemple #8
0
 /// <summary>
 /// Put the response into the storage, and delete corresponding request from the storage.
 /// the async result will return void.byt GetResult will throw exception if the response is not persisted into the persistence.
 /// </summary>
 /// <param name="responseMsg">the response message</param>
 /// <param name="requestItem">corresponding request item</param>
 public abstract void PutResponseAsync(Message responseMsg, BrokerQueueItem requestItem);
Exemple #9
0
 /// <summary>
 /// Put the response into the storage, and delete corresponding request from the storage.
 /// the async result will return void.byt GetResult will throw exception if the response is not persisted into the persistence.
 /// </summary>
 /// <param name="responseMsg">the response message</param>
 /// <param name="requestItem">corresponding request item</param>
 /// <remarks>
 /// This method here is only visible from the interface as it is included mainly
 /// for testability. All callers of this method should have an instance of IBrokerQueueFactory
 /// instead of any special implementation.
 /// </remarks>
 void IBrokerQueueFactory.PutResponseAsync(Message responseMsg, BrokerQueueItem requestItem)
 {
     this.Dispatcher.PutResponseAsync(responseMsg, requestItem);
 }
Exemple #10
0
        private void HandlePendingRequestCallback()
        {
            while (this.requestCacheQueue.Count > 0 && this.requestCallbackQueue.Count > 0)
            {
                BrokerQueueItem request = null;
                try
                {
                    if (!this.requestCacheQueue.TryDequeue(out request))
                    {
                        BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .HandlePendingRequestCallback: All cached requests are dispatched.");
                    }
                }
                catch (InvalidOperationException e)
                {
                    // the queue is drained by others thread.
                    BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .HandlePendingRequestCallback: All cached requests are dispatched. Exception: {0}", e);
                }

                if (request != null)
                {
                    BrokerQueueCallbackItem requestCallback = null;
                    try
                    {
                        if (!this.requestCallbackQueue.TryDequeue(out requestCallback))
                        {
                            requestCallback = null;

                            // the requests callback queue is drained by other threads.
                            this.requestCacheQueue.Enqueue(request);

                            BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .HandlePendingRequestCallback: No available pending request callbacks in the queue.");
                        }
                    }
                    catch (InvalidOperationException e)
                    {
                        // the requests callback queue is drained by other threads.
                        this.requestCacheQueue.Enqueue(request);

                        BrokerTracing.TraceInfo("[BrokerQueueDispatcher] .HandlePendingRequestCallback: No available pending request callbacks in the queue. Exception: {0}", e);
                    }

                    if (requestCallback != null)
                    {
                        try
                        {
#if DEBUG
                            BrokerTracing.TraceVerbose("[BrokerQueueDispatcher] .HandlePendingRequestCallback: invoke callback. request id={0}", GetMessageId(request));
#endif

                            this.RegisterReemit(request);

                            requestCallback.Callback(request, requestCallback.CallbackState);
                        }
                        catch (Exception e)
                        {
                            // the get request callback raise exception.
                            this.requestCacheQueue.Enqueue(request);

                            BrokerTracing.TraceWarning("[BrokerQueueDispatcher] .HandlePendingRequestCallback: The request callback raise exception. Exception: {0}", e);
                        }
                    }
                }
            }
        }
Exemple #11
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);
            }
        }
Exemple #12
0
        /// <summary>
        /// Retrieve message id from a BrokerQueueItem instance
        /// </summary>
        /// <param name="messageItem">the BrokerQueueItem instance</param>
        /// <returns>message id of the message represented by the BrokerQueueItem instance</returns>
        private static string GetMessageId(BrokerQueueItem messageItem)
        {
            UniqueId messageId = SoaHelper.GetMessageId(messageItem.Message);

            return(messageId == null ? string.Empty : messageId.ToString());
        }
Exemple #13
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);
            }
        }