public IAsyncResult BeginAdd(Message msg, ulong id, AsyncCallback cb, object state) { try { this.rwLock.EnterWriteLock(); this.PurgeExpired(); var cmsg = new CachedMessage(msg.SignalKey, msg.Value, msg.Created, id); if (this.messageIndex.Count + 1 < CapacityLimit) { // add and complete this.AddToCache(cmsg); return new CompletedAsyncResult(cb, state); } else { // move the 'Add' operation to pending until we've got room to // add the item and complete once the item has been dequeued // calling Complete on the AR var addAsyncResult = new AddAsyncResult(cb, state); this.pendingAdds.EnqueueAndDispatch(cmsg, addAsyncResult.Complete); return addAsyncResult; } } finally { this.rwLock.ExitWriteLock(); } }
void AddToCache(CachedMessage msg) { try { this.rwLock.EnterWriteLock(); this.messageIndex.Add(msg.Id, msg); } finally { this.rwLock.ExitWriteLock(); } // swap the pending gets queue so that we can drain the old // one and re-enqueue what we can't service right now var copiedPendingNotifications = Interlocked.Exchange(ref this.pendingNotifications, new InputQueue<NotificationRegistration>()); for (; ; ) { NotificationRegistration notificationRegistration; if (copiedPendingNotifications.Dequeue(TimeSpan.Zero, out notificationRegistration)) { if (!notificationRegistration.Cancelled) { if (notificationRegistration.EventKey.Equals(msg.SignalKey)) { SimpleIOThreadScheduler.ScheduleCallback( (pg) => ((NotificationRegistration)pg).Callback(), (e) => true, notificationRegistration); } else { this.pendingNotifications.EnqueueWithoutDispatch(notificationRegistration, null); } } } else { break; } } }