/// <summary> /// When an entry is archived, we need to attempt scavenging to cleanup the list /// </summary> public void OnEntryArchived(QueueEntry entry) { var next = head.Next; var newNext = head.GetNextValidEntry(); if (next == newNext) { // the head of the queue has not been archived, hence the archival must have been mid queue. // so update unscavengedEntry if entry is further back in the queue than the current unscavengedEntry value var currentUnscavengedEntry = unscavengedEntry; while (currentUnscavengedEntry == null || currentUnscavengedEntry.CompareTo(entry) < 0) { Interlocked.CompareExchange(ref unscavengedEntry, entry, currentUnscavengedEntry); currentUnscavengedEntry = unscavengedEntry; } // only going to scavenge() after N entries have been scavenged if (Interlocked.Increment(ref scavenges) > 10) { Interlocked.Exchange(ref scavenges, 0); Scavenge(); } } else { // the head has been scavenged var currentUnscavengedEntry = unscavengedEntry; if (currentUnscavengedEntry != null && (next == null || currentUnscavengedEntry.CompareTo(next) < 0)) { Interlocked.CompareExchange(ref unscavengedEntry, null, currentUnscavengedEntry); currentUnscavengedEntry = unscavengedEntry; } } }
public void TryDelivery(QueueEntry head) { // TODO: check link credit to determine if we can deliver if (!HasCreditToDeliver()) { return; } lock (syncRoot) { var next = head.GetNextValidEntry(); while (next != null) { if (next.IsAvailable) { // TODO: FILTER out entries we don't care about if (queue.TryAcquire(next, this)) { break; // if not acquired, we'll try again with the next one } } // loop until we get an available entry to deliver // or null next = next.GetNextValidEntry(); } if (next == null) { return; // nothing to deliver } if (next != null) { // message acquired and ready to be delivered OnMessageAquired(next); } } }