internal Topic SubscribeTopic(string key) { Topic topic; do { if (BeforeTopicCreated != null) { BeforeTopicCreated(key); } topic = Topics.GetOrAdd(key, _createTopic); if (BeforeTopicMarked != null) { BeforeTopicMarked(key, topic); } // Transition into the HasSubscriptions state as long as the topic is not dead InterlockedHelper.CompareExchangeOr(ref topic.State, TopicState.HasSubscriptions, TopicState.NoSubscriptions, TopicState.Dying); if (AfterTopicMarked != null) { AfterTopicMarked(key, topic, topic.State); } // If we were unable to transition into the HasSubscription state that means we're in the Dead state. // Loop around until we're able to create the topic new } while (topic.State != TopicState.HasSubscriptions); if (AfterTopicMarkedSuccessfully != null) { AfterTopicMarkedSuccessfully(key, topic); } return(topic); }
internal void GarbageCollectTopics() { if (Interlocked.CompareExchange(ref _gcRunning, GCState.Running, GCState.Idle) != GCState.Idle) { return; } int topicsWithNoSubs = 0; foreach (var pair in Topics) { if (pair.Value.IsExpired) { if (BeforeTopicGarbageCollected != null) { BeforeTopicGarbageCollected(pair.Key, pair.Value); } // Mark the topic as dead DestroyTopic(pair.Key, pair.Value); } else if (pair.Value.State == TopicState.NoSubscriptions) { // Keep track of the number of topics with no subscriptions topicsWithNoSubs++; } } int overflow = topicsWithNoSubs - _maxTopicsWithNoSubscriptions; if (overflow > 0) { // If we've overflowed the max the collect topics that don't have // subscribers var candidates = new List <KeyValuePair <string, Topic> >(); foreach (var pair in Topics) { if (pair.Value.State == TopicState.NoSubscriptions) { candidates.Add(pair); } } // We want to remove the overflow but oldest first candidates.Sort((leftPair, rightPair) => leftPair.Value.LastUsed.CompareTo(rightPair.Value.LastUsed)); // Clear up to the overflow and stay within bounds for (int i = 0; i < overflow && i < candidates.Count; i++) { var pair = candidates[i]; // We only want to kill the topic if it's in the NoSubscriptions or Dying state. if (InterlockedHelper.CompareExchangeOr(ref pair.Value.State, TopicState.Dead, TopicState.NoSubscriptions, TopicState.Dying)) { // Kill it DestroyTopicCore(pair.Key, pair.Value); } } } Interlocked.CompareExchange(ref _gcRunning, GCState.Idle, GCState.Running); }