public void Schedule(Subscription subscription) { if (subscription.SetQueued()) { lock (_queue) { _queue.Enqueue(subscription); Monitor.Pulse(_queue); AddWorker(); } } }
public void RemoveSubscription(Subscription subscription) { lock (Subscriptions) { if (_subs.Remove(subscription.Identity)) { Subscriptions.Remove(subscription); } } }
public void AddSubscription(Subscription subscription) { lock (Subscriptions) { if (_subs.Add(subscription.Identity)) { Subscriptions.Add(subscription); } } }
private void RemoveEvent(Subscription subscription, string eventKey) { Topic topic; if (_topics.TryGetValue(eventKey, out topic)) { topic.RemoveSubscription(subscription); subscription.RemoveCursor(eventKey); } }
/// <summary> /// /// </summary> /// <param name="subscriber"></param> /// <param name="cursor"></param> /// <param name="callback"></param> /// <returns></returns> public IDisposable Subscribe(ISubscriber subscriber, string cursor, Func<MessageResult, Task<bool>> callback, int messageBufferSize) { IEnumerable<Cursor> cursors = null; if (cursor == null) { cursors = from key in subscriber.EventKeys select new Cursor { Key = key, Id = GetMessageId(key) }; } else { cursors = Cursor.GetCursors(cursor); } var subscription = new Subscription(subscriber.Identity, cursors, callback, messageBufferSize, _counters); var topics = new HashSet<Topic>(); foreach (var key in subscriber.EventKeys) { Topic topic = _topics.GetOrAdd(key, _ => new Topic()); // Set the subscription for this topic subscription.SetCursorTopic(key, topic); // Add it to the list of topics topics.Add(topic); } foreach (var topic in topics) { topic.AddSubscription(subscription); } if (!String.IsNullOrEmpty(cursor)) { // Update all of the cursors so we're within the range foreach (var pair in subscription.Cursors) { Topic topic; if (_topics.TryGetValue(pair.Key, out topic) && pair.Id > topic.Store.GetMessageCount()) { subscription.UpdateCursor(pair.Key, 0); } } } Action<string, string> eventAdded = (eventKey, eventCursor) => { Topic topic = _topics.GetOrAdd(eventKey, _ => new Topic()); // Get the cursor for this event key ulong id = eventCursor == null ? 0 : UInt64.Parse(eventCursor); // Add or update the cursor (in case it already exists) subscription.AddOrUpdateCursor(eventKey, id, topic); // Add it to the list of subs topic.AddSubscription(subscription); }; Action<string> eventRemoved = eventKey => RemoveEvent(subscription, eventKey); subscriber.EventAdded += eventAdded; subscriber.EventRemoved += eventRemoved; // If there's a cursor then schedule work for this subscription if (!String.IsNullOrEmpty(cursor)) { _engine.Schedule(subscription); } return new DisposableAction(() => { // This will stop work from continuting to happen subscription.Dispose(); subscriber.EventAdded -= eventAdded; subscriber.EventRemoved -= eventRemoved; string currentCursor = Cursor.MakeCursor(subscription.Cursors); foreach (var eventKey in subscriber.EventKeys) { RemoveEvent(subscription, eventKey); } subscription.Invoke(new MessageResult(currentCursor)); }); }
private void PumpImplAsync(Task workTask, Subscription subscription, TaskCompletionSource<object> taskCompletionSource) { // Async path workTask.ContinueWith(task => { subscription.UnsetQueued(); _busyWorkersCounter.SafeSetRaw(Interlocked.Decrement(ref _busyWorkers)); Debug.Assert(_busyWorkers >= 0, "The number of busy workers has somehow gone negative"); if (task.IsFaulted) { taskCompletionSource.TrySetException(task.Exception); } else { PumpImpl(taskCompletionSource); } }); }