private E removeElement(final E[] buffer, long index, final long mask) { final long offset = calcElementOffset(index, mask); // load plain, element happens before it's index becomes visible final E e = lpElement(buffer, offset); // store ordered, make sure nulling out is visible. Producer is waiting for this value. soElement(buffer, offset, null); return e; }
@Override public E relaxedPoll() { final E[] buffer = this.buffer; final long cIndex = lpConsumerIndex(); final long offset = calcElementOffset(cIndex); // If we can't see the next available element we can't poll E e = lvElement(buffer, offset); // LoadLoad if (null == e) { return null; } spElement(buffer, offset, null); soConsumerIndex(cIndex + 1); // StoreStore return e; }
/** * Write a reference to the given position * @param offset index into the reference array * @param reference */ protected void writeReference(long offset, Object reference) { assert referenceMessageSize != 0 : "References are not in use"; // Is there a way to compute the element offset once and just // arithmetic? UnsafeRefArrayAccess.spElement(references, UnsafeRefArrayAccess.calcElementOffset(offset), reference); }
/** * Read a reference at the given position * @param offset index into the reference array * @return */ protected Object readReference(long offset) { assert referenceMessageSize != 0 : "References are not in use"; // Is there a way to compute the element offset once and just // arithmetic? return UnsafeRefArrayAccess.lpElement(references, UnsafeRefArrayAccess.calcElementOffset(offset)); }
private Object spinWaitForElement(E[] buffer, long offset) { Object e; do { e = lvElement(buffer, offset); } while (e == null); return e; }
final void writeToQueue(final E[] buffer, final E e, final long index, final long offset) { soElement(buffer, offset, e);// StoreStore soProducerIndex(index + 1);// this ensures atomic write of long on 32bit platforms }
@Override public E relaxedPeek() { long currConsumerIndex = lvConsumerIndex(); return lpElement(buffer, calcElementOffset(currConsumerIndex)); }
@Override public E poll() { // local load of field to avoid repeated loads after volatile reads final long[] lSequenceBuffer = sequenceBuffer; long consumerIndex = lvConsumerIndex();// LoadLoad final long seqOffset = calcSequenceOffset(consumerIndex); final long seq = lvSequence(lSequenceBuffer, seqOffset);// LoadLoad final long delta = seq - (consumerIndex + 1); if (delta < 0) { // queue is empty return null; } // on 64bit(no compressed oops) JVM this is the same as seqOffset final long offset = calcElementOffset(consumerIndex); final E e = UnsafeRefArrayAccess.lpElement(buffer, offset); UnsafeRefArrayAccess.spElement(buffer, offset, null); // Move sequence ahead by capacity, preparing it for next offer // (seeing this value from a consumer will lead to retry 2) soSequence(lSequenceBuffer, seqOffset, consumerIndex + mask + 1);// StoreStore soConsumerIndex(consumerIndex+1); return e; }
private void soCycleElement(E[] buffer, E e, int activeCycleIndex, int positionWithinCycle, int cycleLengthLog2) { final int indexInBuffer = calcElementIndexInBuffer(positionWithinCycle, activeCycleIndex, cycleLengthLog2); final long offset = UnsafeRefArrayAccess.calcElementOffset(indexInBuffer); soElement(buffer, offset, e); }
private void signalConsumerProgress(long consumerPosition, E[] buffer, long offset) { spElement(buffer, offset, null); soConsumerPosition(consumerPosition + 1); }
private E spinForElement(final E[] buffer, long offset) { E e; do { e = lvElement(buffer, offset); } while (e == null); return e; }
protected final void soNext(E[] curr, E[] next) { long offset = nextArrayOffset(curr); soElement(curr, offset, next); }
@Override public E peek() { return UnsafeRefArrayAccess.lpElement(buffer, calcElementOffset(lvConsumerIndex())); }
UnsafeRefArrayAccess.spElement(buffer, elementOffset, e);
private boolean addSlowPath(E[] buffer, long mask, E newVal, int hash) { final int limit = (int) (hash + mask); for (int i = hash + 1; i <= limit; i++) { final long offset = calcElementOffset(i, mask); final E currVal = lpElement(buffer, offset); if (currVal == null) { size++; soElement(buffer, offset, newVal); return true; } else if (newVal.equals(currVal)) { return false; } } return false; }
@Override public boolean relaxedOffer(E e) { if (null == e) { throw new NullPointerException("Null is not a valid element"); } final E[] buffer = this.buffer; final long mask = this.mask; final long producerIndex = lpProducerIndex(); final long offset = calcElementOffset(producerIndex, mask); if (null != lvElement(buffer, offset)) { return false; } spElement(buffer, offset, e); // single producer, so store ordered is valid. It is also required to correctly publish the element // and for the consumers to pick up the tail value. soProducerIndex(producerIndex + 1); return true; }
private E newBufferPeek(E[] nextBuffer, long index) { final long offset = newBufferAndOffset(nextBuffer, index); final E n = lvElement(nextBuffer, offset);// LoadLoad if (null == n) { throw new IllegalStateException("new buffer must have at least one element"); } return n; }