Class ExporterQueue
Bounded handoff queue between the profiler consumer thread and one exporter. Wraps a BlockingCollection<T> with explicit drop-newest semantics on full, and balances the batch refcount on drop so the pool doesn't leak.
public sealed class ExporterQueue : IDisposable
- Inheritance
-
ExporterQueue
- Implements
- Inherited Members
Remarks
Why BlockingCollection<T>? It's the BCL primitive that gives us a bounded queue plus the GetConsumingEnumerable(CancellationToken) blocking-iterator pattern that the exporter's dedicated thread runs:
foreach (var batch in queue.GetConsumingEnumerable(ct)) { exporter.ProcessBatch(batch); batch.Release(); }
No async/await, no thread-pool churn, just a sync exporter thread per exporter draining a bounded channel.
Drop-newest on full: if Typhon.Engine.ExporterQueue.TryEnqueue(Typhon.Engine.TraceRecordBatch) finds the queue at capacity, it drops the new batch (does not block the consumer thread) and increments DroppedBatches. Critically, it ALSO calls Typhon.Engine.TraceRecordBatch.Release on the dropped batch — without this, the batch's refcount would never reach zero and the pool would leak. With it, the refcount stays balanced no matter how many exporter queues drop a given batch on a given drain pass.
Why drop the newest, not the oldest? The newest batch hasn't started processing yet — dropping it costs nothing besides the loss of those events, while dropping the oldest would either require a complex rewind or invalidate work the exporter is in the middle of doing. Tracy's design philosophy: "prefer losing a sample to blocking the producer."
Constructors
ExporterQueue(int)
Create a queue bounded to boundedCapacity batches; excess enqueues drop-newest once full.
public ExporterQueue(int boundedCapacity)
Parameters
boundedCapacityintMaximum batches held before drop-newest engages. Must be ≥ 1.
Exceptions
- ArgumentOutOfRangeException
boundedCapacityis less than 1.
Properties
DroppedBatches
Total batches dropped due to a full queue. Read by diagnostics.
public long DroppedBatches { get; }
Property Value
Methods
Dispose()
Dispose the underlying BlockingCollection<T>. Call after the exporter thread has exited its consume loop.
public void Dispose()
GetConsumingEnumerable(CancellationToken)
Returns the blocking iterator that the exporter thread foreaches over. Yields each enqueued batch and exits when Typhon.Engine.ExporterQueue.CompleteAdding has been called and the queue is drained.
public IEnumerable<TraceRecordBatch> GetConsumingEnumerable(CancellationToken cancellationToken)
Parameters
cancellationTokenCancellationToken