@Override
    public boolean offer(final E e)
    {
        if (null == e)
        {
            throw new NullPointerException();
        }
        // offer can fail only when queue is full, otherwise it retries
        final int positionOnCycleMask = this.positionWithinCycleMask;
        final int cycleLengthLog2 = this.cycleLengthLog2;
        final int cycleLength = this.cycleLength;
        final int cycleIdBitShift = this.cycleIdBitShift;

        while (true)
        {
            final long activeCycleId = lvActiveCycleId(); // acquire activeCycleId
            final int activeCycleIndex = activeCycleIndex(activeCycleId);

            // this is a non-committed view of the producer position, but may be out of date when we XADD
            final long tempCycleClaim = lvProducerCycleClaim(activeCycleIndex);

            final int tempPositionWithinCycle = positionWithinCycle(tempCycleClaim, positionOnCycleMask);
            final long tempCycleId = producerClaimCycleId(tempCycleClaim, cycleIdBitShift);

            if (activeCycleId != tempCycleId || tempPositionWithinCycle > cycleLength)
            {
                // this covers the case of either being mid rotation or by some freak scheduling accident missing 2
                // rotations between activeCycleId load and lvProducerCycleClaim
                continue;
            }

            final long tempPosition = producerPosition(tempPositionWithinCycle, tempCycleId, cycleLengthLog2);

            // pre-checks are only valid for the temp values, so best effort...
            if (tempPosition >= lvProducerLimit())
            {
                if (isFull(tempPosition))
                {
                    return false;
                }
            }

            // try to claim on the active cycle (though the activeCycleIndex might be outdated)
            final long producerCycleClaim = getAndIncrementProducerCycleClaim(activeCycleIndex); // release producerCycleClaim[activeCycleIndex]

            final int positionWithinCycle = positionWithinCycle(producerCycleClaim, positionOnCycleMask);

            if (positionWithinCycle == positionOnCycleMask)
            {
                // This is an extreme rare case which requires very large numbers of getAndAdd operations to occur while
                // waiting for rotation, this is also mitigated by the full queue check above and the mid rotation guard
                // above it.
                throw new IllegalStateException(
                    "Too many over-claims: please enlarge the capacity or reduce the number of producers!\n" +
                        " positionWithinCycle=" + positionWithinCycle);
            }
            if (positionWithinCycle < cycleLength)
            {
                final long cycleId = producerClaimCycleId(producerCycleClaim, cycleIdBitShift);
                final boolean slowProducer = cycleId != activeCycleId;
                //it should fail with a slow producer
                if (!validateProducerClaim(
                    activeCycleIndex,
                    producerCycleClaim,
                    cycleId,
                    positionWithinCycle,
                    cycleLengthLog2, slowProducer))
                {
                    //the claim has been rollbacked and can be retried
                    continue;
                }
                soCycleElement(buffer, e, activeCycleIndex, positionWithinCycle, cycleLengthLog2);
                return true;
            }
            else if (positionWithinCycle == cycleLength)
            {
                final long cycleId = producerClaimCycleId(producerCycleClaim, cycleIdBitShift);
                rotateCycle(cycleId, cycleIdBitShift, maxCycleId);
            }
        }
    }
Note on terminology:
 - position/id: overall progress indicator, not an array index or offset at which to lookup/write.
 - index: for looking up within an array (including the inlined producerCycleClaim array)
 - offset: for pointer like access using Unsafe

The producer in this queue operates on cycleId and the producerCycleClaim array:
 - The cycleId grow monotonically, and the parity bit (cycleIndex) indicated which claim to use
 - The producerCycleClaim indicate position in a cycle as well as the originating cycleId. From a claim we can
   calculate the producer overall position as well as the position within a cycle.

The buffer is split into 2 cycles (matching cycleIndex 0 and 1), allowing the above indicators to control
producer progress on separate counters while maintaining the appearance of a contiguous buffer to the consumer.
jctools-experimental/src/main/java/org/jctools/queues/MpscRelaxedArrayQueue.java