private static void soElement(AtomicReferenceArray<Object> buffer, int offset, Object e) { buffer.lazySet(offset, e); }
private static void soElement(AtomicReferenceArray<Object> buffer, int offset, Object e) { buffer.lazySet(offset, e); }
static <E> void soElement(AtomicReferenceArray buffer, int offset, Object value) { buffer.lazySet(offset, value); }
public static <E> void spElement(AtomicReferenceArray<E> buffer, int offset, E value) { buffer.lazySet(offset, value); // no weaker form available }
protected final void spElement(int offset, E value) { buffer.lazySet(offset, value); // no weaker form available }
public static <E> void soElement(AtomicReferenceArray<E> buffer, int offset, E value) { buffer.lazySet(offset, value); }
protected final void soElement(int offset, E value) { buffer.lazySet(offset, value); }
@SuppressWarnings({"unchecked", "cast", "rawtypes"}) public RingBuffer(E e) { buffer = new AtomicReferenceArray<>(SPACED_SIZE); buffer.lazySet(0, e); }
@Override public void onNext(T t) { long pi = producerIndex; int m = toFilter.length() - 1; int offset = (int)pi & m; toFilter.lazySet(offset, t); producerIndex = pi + 1; drain(); }
@Override public boolean offer(T e) { Objects.requireNonNull(e); long pi = producerIndex; AtomicReferenceArray<Object> a = producerArray; int m = mask; int offset = (int) (pi + 1) & m; if (a.get(offset) != null) { offset = (int) pi & m; AtomicReferenceArray<Object> b = new AtomicReferenceArray<>(m + 2); producerArray = b; b.lazySet(offset, e); a.lazySet(m + 1, b); a.lazySet(offset, NEXT); PRODUCER_INDEX.lazySet(this, pi + 1); } else { offset = (int) pi & m; a.lazySet(offset, e); PRODUCER_INDEX.lazySet(this, pi + 1); } return true; }
@SuppressWarnings("unchecked") @Override @Nullable public T poll() { long ci = consumerIndex; AtomicReferenceArray<Object> a = consumerArray; int m = mask; int offset = (int) ci & m; Object o = a.get(offset); if (o == null) { return null; } if (o == NEXT) { AtomicReferenceArray<Object> b = (AtomicReferenceArray<Object>) a.get(m + 1); a.lazySet(m + 1, null); o = b.get(offset); a = b; consumerArray = b; } a.lazySet(offset, null); CONSUMER_INDEX.lazySet(this, ci + 1); return (T) o; }
@Override public void drainTo(Consumer<E> consumer) { long head = readCounter; long tail = relaxedWriteCounter(); long size = (tail - head); if (size == 0) { return; } do { int index = (int) (head & SPACED_MASK); E e = buffer.get(index); if (e == null) { // not published yet break; } buffer.lazySet(index, null); consumer.accept(e); head += OFFSET; } while (head != tail); lazySetReadCounter(head); }
@Override public int offer(E e) { long head = readCounter; long tail = relaxedWriteCounter(); long size = (tail - head); if (size >= SPACED_SIZE) { return Buffer.FULL; } if (casWriteCounter(tail, tail + OFFSET)) { int index = (int) (tail & SPACED_MASK); buffer.lazySet(index, e); return Buffer.SUCCESS; } return Buffer.FAILED; }
@Override public E relaxedPoll() { final long consumerPosition = lvConsumerPosition(); final int offset = calcElementOffset(consumerPosition, this.mask); final AtomicReferenceArray<E> buffer = this.buffer; E e; if ((e = buffer.get(offset)) != null) { //can be used a memory_order_relaxed set here, because the consumer position write release the buffer value buffer.lazySet(offset, null); //consumer position allows the producers to move the claim limit (aka reduce backpressure) //hence can be set only after the buffer slot release soConsumerPosition(consumerPosition + 1); } return e; }
@Override public void onNext(T t) { if (t == null) { throw new NullPointerException("t == null"); } long pi = producerIndex.get(); queue.lazySet((int)pi & BUFFER_MASK, t); producerIndex.lazySet(pi + 1); drain(); }
@Override public E poll() { final long consumerPosition = lvConsumerPosition(); final int offset = calcElementOffset(consumerPosition, this.mask); final AtomicReferenceArray<E> buffer = this.buffer; E e; if ((e = buffer.get(offset)) != null) { //can be used a memory_order_relaxed set here, because the consumer position write release the buffer value buffer.lazySet(offset, null); //consumer position allows the producers to move the claim limit (aka reduce backpressure) //hence can be set only after the buffer slot release soConsumerPosition(consumerPosition + 1); return e; } else { return pollMaybeEmpty(buffer, offset, consumerPosition); } }
@Override public int drain(Consumer<E> c, int limit) { final long mask = this.mask; final AtomicReferenceArray<E> buffer = this.buffer; for (int i = 0; i < limit; i++) { final long consumerPosition = lvConsumerPosition(); final int offset = calcElementOffset(consumerPosition, mask); E e; if ((e = buffer.get(offset)) != null) { //can be used a memory_order_relaxed set here, because the consumer position write release the buffer value buffer.lazySet(offset, null); //consumer position allows the producers to move the claim limit (aka reduce backpressure) //hence can be set only after the buffer slot release soConsumerPosition(consumerPosition + 1); c.accept(e); } else { return i; } } return limit; }
@Override public void drain(Consumer<E> c, WaitStrategy w, ExitCondition exit) { final AtomicReferenceArray<E> buffer = this.buffer; final long mask = this.mask; long consumerPosition = lvConsumerPosition(); int counter = 0; while (exit.keepRunning()) { for (int i = 0; i < 4096; i++) { final int offset = calcElementOffset(consumerPosition, mask); final E e = buffer.get(offset);// LoadLoad if (null == e) { counter = w.idle(counter); continue; } consumerPosition++; counter = 0; //a plain store would be enough buffer.lazySet(offset, null); soConsumerPosition(consumerPosition); // ordered store -> atomic and ordered for size() c.accept(e); } } }
private E pollMaybeEmpty(AtomicReferenceArray<E> buffer, final int offset, final long consumerPosition) { final int activeCycleIndex = activeCycleIndex(lvActiveCycleId()); final long producerCycleClaim = AtomicLongArrayAccess.lvValue(this.producerCycleClaim, activeCycleIndex); final long producerPosition = producerPosition( cycleId(producerCycleClaim, this.cycleIdBitShift), positionOnCycle(producerCycleClaim, this.positionOnCycleMask), this.cycleLengthLog2); if (producerPosition == consumerPosition) { return null; } else { E e; while ((e = buffer.get(offset)) == null) { } //can be used a memory_order_relaxed set here, because the consumer position write release the buffer value buffer.lazySet(offset, null); //consumer position allows the producers to move the claim limit (aka reduce backpressure) //hence can be set only after the buffer slot release soConsumerPosition(consumerPosition + 1); return e; } }