bool UpdateProperty(BufferedReceiveMessageProperty property, ReceiveContext receiveContext, int channelKey, string bookmarkName, BufferedReceiveState state) { // If there's data already there make sure the state is allowed if (property.UserState == null) { property.UserState = new PropertyData() { ReceiveContext = receiveContext, ChannelKey = channelKey, BookmarkName = bookmarkName, State = state }; } else { PropertyData data = (PropertyData)property.UserState; // We should not buffer twice at the same state if (data.State == state) { return(false); } data.State = state; } return(true); }
public bool BufferReceive(OperationContext operationContext, ReceiveContext receiveContext, string bookmarkName, BufferedReceiveState state, bool retry) { bool flag = false; BufferedReceiveMessageProperty property = null; if (BufferedReceiveMessageProperty.TryGet(operationContext.IncomingMessageProperties, out property)) { CorrelationMessageProperty property = null; if (!CorrelationMessageProperty.TryGet(operationContext.IncomingMessageProperties, out property)) { return(flag); } EventHandler handler = null; InstanceKey instanceKey = property.CorrelationKey; int channelKey = operationContext.Channel.GetHashCode(); if (!this.throttle.Acquire(channelKey)) { return(flag); } try { if (!this.UpdateProperty(property, receiveContext, channelKey, bookmarkName, state)) { return(flag); } if (handler == null) { handler = delegate(object sender, EventArgs e) { lock (this.thisLock) { if (this.bufferedProperties.ContainsKey(instanceKey) && this.bufferedProperties[instanceKey].Remove(property)) { try { property.RequestContext.DelayClose(false); property.RequestContext.Abort(); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } } this.throttle.Release(channelKey); } } }; } receiveContext.Faulted += handler; lock (this.thisLock) { if (receiveContext.State != ReceiveContextState.Received) { return(flag); } bool flag2 = false; if (retry) { property.RequestContext.DelayClose(true); property.RegisterForReplay(operationContext); property.ReplayRequest(); property.Notification.NotifyInvokeReceived(property.RequestContext.InnerRequestContext); flag2 = true; } else { ReadOnlyCollection <BookmarkInfo> bookmarksForInstance = this.host.DurableInstanceManager.PersistenceProviderDirectory.GetBookmarksForInstance(instanceKey); if (bookmarksForInstance != null) { for (int i = 0; i < bookmarksForInstance.Count; i++) { BookmarkInfo info = bookmarksForInstance[i]; if (info.BookmarkName == bookmarkName) { property.RequestContext.DelayClose(true); property.RegisterForReplay(operationContext); property.ReplayRequest(); property.Notification.NotifyInvokeReceived(property.RequestContext.InnerRequestContext); flag2 = true; break; } } } } if (!flag2) { List <BufferedReceiveMessageProperty> list; if (!this.bufferedProperties.TryGetValue(instanceKey, out list)) { list = new List <BufferedReceiveMessageProperty>(); this.bufferedProperties.Add(instanceKey, list); } property.RequestContext.DelayClose(true); property.RegisterForReplay(operationContext); list.Add(property); } else { this.throttle.Release(channelKey); } return(true); } } finally { if (!flag) { this.throttle.Release(channelKey); } } } return(flag); }
public bool BufferReceive(OperationContext operationContext, ReceiveContext receiveContext, string bookmarkName, BufferedReceiveState state, bool retry) { Fx.Assert(receiveContext != null, "ReceiveContext must be present in order to perform buffering"); bool success = false; BufferedReceiveMessageProperty property = null; if (BufferedReceiveMessageProperty.TryGet(operationContext.IncomingMessageProperties, out property)) { CorrelationMessageProperty correlation = null; if (CorrelationMessageProperty.TryGet(operationContext.IncomingMessageProperties, out correlation)) { InstanceKey instanceKey = correlation.CorrelationKey; int channelKey = operationContext.Channel.GetHashCode(); if (this.throttle.Acquire(channelKey)) { try { // Tag the property with identifying data to be used during later processing if (UpdateProperty(property, receiveContext, channelKey, bookmarkName, state)) { // Cleanup if we are notified the ReceiveContext faulted underneath us receiveContext.Faulted += delegate(object sender, EventArgs e) { lock (this.thisLock) { if (this.bufferedProperties.ContainsKey(instanceKey)) { if (this.bufferedProperties[instanceKey].Remove(property)) { try { property.RequestContext.DelayClose(false); property.RequestContext.Abort(); } catch (Exception exception) { if (Fx.IsFatal(exception)) { throw; } // ---- these exceptions as we are already on the error path } this.throttle.Release(channelKey); } } } }; // Actual Buffering lock (this.thisLock) { // Optimistic state check in case we just raced with the receiveContext // faulting. If the receiveContext still faults after the state check, the above // cleanup routine will handle things correctly. In both cases, a double-release // of the throttle is protected. if (receiveContext.State == ReceiveContextState.Received) { bool found = false; // if the exception indicates retry-able (such as RetryException), // we will simply retry. This happens when racing with abort and // WF informing the client to retry (BufferedReceiveManager is a // client in this case). if (retry) { property.RequestContext.DelayClose(true); property.RegisterForReplay(operationContext); property.ReplayRequest(); property.Notification.NotifyInvokeReceived(property.RequestContext.InnerRequestContext); found = true; } else { ReadOnlyCollection <BookmarkInfo> bookmarks = this.host.DurableInstanceManager.PersistenceProviderDirectory.GetBookmarksForInstance(instanceKey); // Retry in case match the existing bookmark if (bookmarks != null) { for (int i = 0; i < bookmarks.Count; ++i) { BookmarkInfo bookmark = bookmarks[i]; if (bookmark.BookmarkName == bookmarkName) { // Found it so retry... property.RequestContext.DelayClose(true); property.RegisterForReplay(operationContext); property.ReplayRequest(); property.Notification.NotifyInvokeReceived(property.RequestContext.InnerRequestContext); found = true; break; } } } } if (!found) { List <BufferedReceiveMessageProperty> properties; if (!this.bufferedProperties.TryGetValue(instanceKey, out properties)) { properties = new List <BufferedReceiveMessageProperty>(); this.bufferedProperties.Add(instanceKey, properties); } property.RequestContext.DelayClose(true); property.RegisterForReplay(operationContext); properties.Add(property); } else { this.throttle.Release(channelKey); } success = true; } } } } finally { if (!success) { this.throttle.Release(channelKey); } } } } } return(success); }
private bool UpdateProperty(BufferedReceiveMessageProperty property, ReceiveContext receiveContext, int channelKey, string bookmarkName, BufferedReceiveState state) { if (property.UserState == null) { PropertyData data = new PropertyData { ReceiveContext = receiveContext, ChannelKey = channelKey, BookmarkName = bookmarkName, State = state }; property.UserState = data; } else { PropertyData userState = (PropertyData)property.UserState; if (userState.State == state) { return(false); } userState.State = state; } return(true); }