/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.f1x.io.disruptor; import com.lmax.disruptor.*; import org.f1x.util.ByteRingReader; public final class ByteRing { private final int bufferSize; private final byte [] entries; private final int indexMask; private final SingleProducerSequencer sequencer; /** * Create a new single producer ByteRing with the specified wait strategy. * * @see SingleProducerSequencer * @param bufferSize number of elements to create within the ring buffer. * @param waitStrategy used to determine how to wait for new elements to become available. * @throws IllegalArgumentException if bufferSize is less than 1 and not a power of 2 */ public ByteRing (int bufferSize, WaitStrategy waitStrategy) { sequencer = new SingleProducerSequencer(bufferSize, waitStrategy); this.bufferSize = bufferSize; this.entries = new byte[bufferSize]; this.indexMask = bufferSize - 1; } /** * Claim the next n bytes in sequence for publishing. Producer will have to use a little care and some math. * <pre> * int n = 10; * long hi = ring.next(n); * long lo = hi - (n - 1); * for (long sequence = lo; sequence <= hi; sequence++) { * // Do work. * } * ring.publish(lo, hi); * </pre> * * @param n the number of sequences to claim * @return the highest claimed sequence value */ public long next(int n) { return sequencer.next(n); } /** Translates sequence number to ring buffer offset */ public final int index(long sequence) { return (int) sequence & indexMask; } /** * Publish byte sequence. * * @param hi last sequence number to publish */ public void publish(long hi) { sequencer.publish(hi); } /** * Get the current cursor value for the ring buffer. The cursor value is * the last value that was published, or the highest available sequence * that can be consumed. */ public final long getCursor() { return sequencer.getCursor(); } /** * Create a new SequenceBarrier to be used by an EventProcessor to track which messages * are available to be read from the ring buffer given a list of sequences to track. * * @see SequenceBarrier * @param sequencesToTrack Optional dependency * @return A sequence barrier that will track the specified sequences. */ public SequenceBarrier newBarrier(Sequence... sequencesToTrack) { return sequencer.newBarrier(sequencesToTrack); } public void addGatingSequences(Sequence... gatingSequences) { sequencer.addGatingSequences(gatingSequences); } /** Writes single byte specified by value parameter and advances offset */ int write (int offset, int value) { assert offset >=0 && offset < bufferSize; entries[offset++] = (byte) (0xFF & value); if (offset == bufferSize) offset = 0; return offset; } /** Store given INT32 number in Big-Endian notation (Used to store message length) */ public void writeInt (long sequence, int value) { assert sequence >= 0; int offset = index(sequence); offset = write (offset, value >>> 24); offset = write (offset, value >>> 16); offset = write (offset, value >>> 8); write (offset, value); } /** Read INT32 number stored in Big-Endian notation (Used to read message length) */ int readInt (long sequence) { assert sequence >= 0; int offset = index(sequence); int result = (0xFF & entries[offset++]); if (offset == bufferSize) offset = 0; result = (result << 8) + (0xFF & entries[offset++]); if (offset == bufferSize) offset = 0; result = (result << 8) + (0xFF & entries[offset++]); if (offset == bufferSize) offset = 0; result = (result << 8) + (0xFF & entries[offset]); return result; } int processBlock(long current, int messageSize, RingBufferBlockProcessor processor) { return processor.process(entries, index(current), messageSize, bufferSize); } public int write(long current, byte [] src, int srcPos, int length) { final int index = index(current); final int wrappedSize = index + length - bufferSize; if (wrappedSize <= 0) { System.arraycopy(src, srcPos, entries, index, length); } else { assert wrappedSize < length; final int numberOfBytesToWrite = length - wrappedSize; System.arraycopy(src, srcPos, entries, index, numberOfBytesToWrite); System.arraycopy(src, srcPos + numberOfBytesToWrite, entries, 0, wrappedSize); } return length; } // /** // * Read data into the given byte array starting from given offset up to // * // * @param offset offset in the byte array // * @param length number of bytes to read // * @return number of bytes actually written // */ // public int callProducer(ByteProducer byteProducer, int offset, int length) { // if (offset + length <= bufferSize) { // return byteProducer.write(entries, offset, length); // } else { // int wrappedSize = offset + length - bufferSize; // assert wrappedSize > 0; // assert wrappedSize < length; // final int numberOfBytesToWrite = length - wrappedSize; // int result = byteProducer.write(entries, offset, numberOfBytesToWrite); // if (result == numberOfBytesToWrite) // result += byteProducer.write(entries, 0, wrappedSize); // return result; // } // } ByteRingReader createByteRingReader() { return new ByteRingReader(entries); } public int getCapacity() { return bufferSize; } }