private void LogEvents() { var eventsToDrain = events.Count; while (eventsToDrain > 0) { var eventsDrained = events.Drain(temporaryBuffer, 0, temporaryBuffer.Length); if (eventsDrained == 0) { break; } eventsToDrain -= eventsDrained; try { eventsWriter.WriteEvents(temporaryBuffer, eventsDrained); } catch { Interlocked.Add(ref eventsLost, eventsDrained); throw; } } var currentEventsLost = EventsLost; if (currentEventsLost > eventsLostSinceLastIteration) { temporaryBuffer[0] = CreateOverflowEvent(currentEventsLost - eventsLostSinceLastIteration); eventsWriter.WriteEvents(temporaryBuffer, 1); eventsLostSinceLastIteration = currentEventsLost; } }
public void Should_not_have_race_between_Add_and_Drain_that_turns_queue_wait_task_to_inconsistent_state() { for (var j = 0; j < 10; ++j) { var queue = new ConcurrentBoundedQueue <object>(100); var o = new object(); var addTask = Task.Run( () => { for (var i = 0; i < 1000000; i++) { if (!queue.TryAdd(o)) { i--; } } }); var drainTask = Task.Run( () => { var arr = new object[1000]; while (true) { var drained = queue.Drain(arr, 0, arr.Length); if (drained == 0 && addTask.IsCompleted) { return; } } }); Task.WhenAll(drainTask, addTask).GetAwaiter().GetResult(); if (queue.WaitForNewItemsAsync().IsCompleted&& queue.Count == 0) { Assert.Fail("Queue is broken: TryWaitForNewItemsAsync is completed, but queue is empty."); } } }
public void Drain_should_return_empty_array_when_queue_is_empty() { queue.Drain(drainResult, 0, drainResult.Length); drainResult.Should().Equal(Enumerable.Repeat((string)null, Capacity)); }
public async Task <bool> WritePendingEventsAsync( IEventsWriterProvider writerProvider, ConcurrentBoundedQueue <LogEventInfo> queue, LogEventInfo[] buffer, AtomicLong eventsLostCurrently, AtomicLong eventsLostSinceLastIteration, CancellationToken cancellation) { var eventsToDrain = queue.Count; if (eventsToDrain == 0) { return(true); } var writer = await writerProvider.ObtainWriterAsync(cancellation).ConfigureAwait(false); if (writer == null) { return(false); } while (eventsToDrain > 0) { var eventsDrained = queue.Drain(buffer, 0, buffer.Length); if (eventsDrained == 0) { break; } eventsToDrain -= eventsDrained; try { writer.WriteEvents(buffer, eventsDrained); } catch (Exception error) { eventsLostCurrently.Add(eventsDrained); SafeConsole.ReportError("Failure in writing log events to a file:", error); break; } finally { Array.Clear(buffer, 0, eventsDrained); } } var lostEventsAfterWriting = eventsLostCurrently.Value; if (lostEventsAfterWriting > eventsLostSinceLastIteration) { buffer[0] = CreateOverflowEvent(queue, lostEventsAfterWriting - eventsLostSinceLastIteration); try { writer.WriteEvents(buffer, 1); } catch { // ignored } eventsLostSinceLastIteration.Value = lostEventsAfterWriting; return(false); } return(true); }
public void All_successfully_added_items_should_be_eventually_consumed(int capacity, int writersCount) { var addedItemsCount = 0; var drainedItemsCount = 0; var queue = new ConcurrentBoundedQueue <object>(capacity); var cancellation = new CancellationTokenSource(); var cancellationToken = cancellation.Token; var trigger = new CountdownEvent(writersCount + 1); var writers = Enumerable.Range(0, writersCount) .Select( _ => Task.Run( () => { trigger.Signal(); trigger.Wait(); while (!cancellationToken.IsCancellationRequested) { var item = new object(); if (queue.TryAdd(item)) { Interlocked.Increment(ref addedItemsCount); } } })) .ToArray(); var reader = Task.Run( async() => { trigger.Signal(); trigger.Wait(); var buffer = new object[10]; while (!cancellation.IsCancellationRequested || writers.Any(w => !w.IsCompleted) || queue.Count > 0) { if (!await queue.TryWaitForNewItemsAsync(100.Milliseconds()).ConfigureAwait(false)) { if (writers.Any(w => !w.IsCompleted)) { throw new Exception("Wait seems to be stuck."); } } var count = queue.Drain(buffer, 0, buffer.Length); drainedItemsCount += count; } }); Thread.Sleep(10.Seconds()); cancellation.Cancel(); Task.WaitAll(writers); reader.Wait(); Console.WriteLine($"added: {addedItemsCount}, drained: {drainedItemsCount}"); queue.Count.Should().Be(0); drainedItemsCount.Should().Be(addedItemsCount); }