/* ---- many producers ---- */ public override void Produce(T t) { if (_size == 0) { return; } long produceNumber = _produceCount.AndIncrement; int offset = ( int )(produceNumber & _mask); VolatileRef <T> volatileRef = _data[offset]; if (AssertPreviousCompleted(produceNumber, volatileRef)) { volatileRef.Ref = t; volatileRef.ProduceNumber = produceNumber; } else { // If we don't manage to wait for the previous produce to complete even after // all the yields in `assertPreviousCompleted`, we drop `t` to avoid causing // a problem in db operation. We increment dropEvents to so the RecentBuffer // consumer can detect that there has been a drop. _dropEvents.incrementAndGet(); } }
public override void Foreach(System.Action <T> consumer) { if (_size == 0) { return; } long snapshotProduce = _produceCount.get(); long snapshotConsume = Math.Max(_consumeCount.get(), snapshotProduce - _size); for (long i = snapshotConsume; i < snapshotProduce; i++) { int offset = ( int )(i & _mask); VolatileRef <T> volatileRef = _data[offset]; if (volatileRef.ProduceNumber < i) { return; } consumer(volatileRef.Ref); } }
public RingRecentBuffer(int size) { if (size > 0) { Preconditions.requirePowerOfTwo(size); } this._size = size; _mask = size - 1; //noinspection unchecked _data = new VolatileRef[size]; for (int i = 0; i < size; i++) { _data[i] = new VolatileRef <T>(); _data[i].produceNumber = i - size; } _produceCount = new AtomicLong(0); _consumeCount = new AtomicLong(0); _dropEvents = new AtomicLong(0); }
private bool AssertPreviousCompleted(long produceNumber, VolatileRef <T> volatileRef) { int attempts = 100; long prevProduceNumber = volatileRef.ProduceNumber; while (prevProduceNumber != produceNumber - _size && attempts > 0) { // Coming in here is expected to be very rare, because it means that producers have // circled around the ring buffer, and the producer `size` elements ago hasn't finished // writing to the buffer. We yield and hope the previous produce is done when we get back. try { Thread.Sleep(0, 1000); } catch (InterruptedException) { // continue } prevProduceNumber = volatileRef.ProduceNumber; attempts--; } return(attempts > 0); }