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); }
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); }
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(); } }
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); }
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(); }); } }
/// <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); }
/// <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);
/// <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);
/// <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); }
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); } } } } }
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); } }
/// <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()); }
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); } }