Class UnsafeBuffer

  • All Implemented Interfaces:
    java.lang.Comparable<DirectBuffer>, AtomicBuffer, DirectBuffer, MutableDirectBuffer

    public class UnsafeBuffer
    extends AbstractMutableDirectBuffer
    implements AtomicBuffer
    Supports regular, byte ordered, and atomic (memory ordered) access to an underlying buffer. The buffer can be a byte[], one of the various ByteBuffer implementations, or an off Java heap memory address.

    ByteOrder of a wrapped buffer is not applied to the UnsafeBuffer. UnsafeBuffers are effectively stateless and can be used concurrently, the wrapping methods are an exception. To control ByteOrder use the appropriate method with the ByteOrder overload.

    Note: This class has a natural ordering that is inconsistent with equals. Types may be different but equal on buffer contents.

    Note: The wrap methods on this class are not thread safe. Concurrent access should only happen after a successful wrap.

    • Constructor Detail

      • UnsafeBuffer

        public UnsafeBuffer()
        Empty constructor for a reusable wrapper buffer.
      • UnsafeBuffer

        public UnsafeBuffer​(byte[] buffer)
        Attach a view to a byte[] for providing direct access.
        Parameters:
        buffer - to which the view is attached.
        See Also:
        wrap(byte[])
      • UnsafeBuffer

        public UnsafeBuffer​(byte[] buffer,
                            int offset,
                            int length)
        Attach a view to a byte[] for providing direct access.
        Parameters:
        buffer - to which the view is attached.
        offset - in bytes within the buffer to begin.
        length - in bytes of the buffer included in the view.
        See Also:
        wrap(byte[], int, int)
      • UnsafeBuffer

        public UnsafeBuffer​(java.nio.ByteBuffer buffer)
        Attach a view to a ByteBuffer for providing direct access, the ByteBuffer can be heap based or direct.
        Parameters:
        buffer - to which the view is attached.
      • UnsafeBuffer

        public UnsafeBuffer​(java.nio.ByteBuffer buffer,
                            int offset,
                            int length)
        Attach a view to a ByteBuffer for providing direct access, the ByteBuffer can be heap based or direct.
        Parameters:
        buffer - to which the view is attached.
        offset - in bytes within the buffer to begin.
        length - in bytes of the buffer included in the view.
      • UnsafeBuffer

        public UnsafeBuffer​(DirectBuffer buffer)
        Attach a view to an existing DirectBuffer.
        Parameters:
        buffer - to which the view is attached.
      • UnsafeBuffer

        public UnsafeBuffer​(DirectBuffer buffer,
                            int offset,
                            int length)
        Attach a view to an existing DirectBuffer.
        Parameters:
        buffer - to which the view is attached.
        offset - in bytes within the buffer to begin.
        length - in bytes of the buffer included in the view.
      • UnsafeBuffer

        public UnsafeBuffer​(long address,
                            int length)
        Attach a view to an off-heap memory region by address. This is useful for interacting with native libraries.
        Parameters:
        address - where the memory begins off-heap.
        length - of the buffer from the given address.
    • Method Detail

      • wrap

        public void wrap​(byte[] buffer)
        Attach a view to a byte[] for providing direct access.
        Specified by:
        wrap in interface DirectBuffer
        Parameters:
        buffer - to which the view is attached.
      • wrap

        public void wrap​(byte[] buffer,
                         int offset,
                         int length)
        Attach a view to a byte[] for providing direct access.
        Specified by:
        wrap in interface DirectBuffer
        Parameters:
        buffer - to which the view is attached.
        offset - in bytes at which the view begins.
        length - in bytes of the buffer included in the view.
      • wrap

        public void wrap​(java.nio.ByteBuffer buffer)
        Attach a view to a ByteBuffer for providing direct access, the ByteBuffer can be heap based or direct. The ByteBuffer.order() is not relevant for accessing the wrapped buffer.

        When using this method to wrap the view of the ByteBuffer the entire ByteBuffer gets wrapped between index 0 and capacity. If you want to just wrap the ByteBuffer between the position and the limit then you should use the DirectBuffer.wrap(ByteBuffer, int, int) method, eg:

        directBuffer.wrap(byteBuffer, byteBuffer.position(), byteBuffer.remaining());

        Specified by:
        wrap in interface DirectBuffer
        Parameters:
        buffer - to which the view is attached.
      • wrap

        public void wrap​(java.nio.ByteBuffer buffer,
                         int offset,
                         int length)
        Attach a view to a ByteBuffer for providing direct access.

        The ByteBuffer.order() is not relevant for accessing the wrapped buffer.

        Specified by:
        wrap in interface DirectBuffer
        Parameters:
        buffer - to which the view is attached.
        offset - in bytes at which the view begins.
        length - in bytes of the buffer included in the view.
      • wrap

        public void wrap​(DirectBuffer buffer,
                         int offset,
                         int length)
        Attach a view to a DirectBuffer for providing direct access.
        Specified by:
        wrap in interface DirectBuffer
        Parameters:
        buffer - to which the view is attached.
        offset - in bytes at which the view begins.
        length - in bytes of the buffer included in the view.
      • wrap

        public void wrap​(long address,
                         int length)
        Attach a view to an off-heap memory region by address.
        Specified by:
        wrap in interface DirectBuffer
        Parameters:
        address - where the memory begins off-heap.
        length - of the buffer from the given address.
      • byteBuffer

        public java.nio.ByteBuffer byteBuffer()
        Get the underlying ByteBuffer if one exists.

        NB: there may not be a one-to-one mapping between indices on this buffer and the underlying byte[], see DirectBuffer.wrapAdjustment().

        Specified by:
        byteBuffer in interface DirectBuffer
        Returns:
        the underlying ByteBuffer if one exists.
      • wrapAdjustment

        public int wrapAdjustment()
        Get the adjustment in indices between an index in this buffer and the wrapped object. The wrapped object might be a ByteBuffer or a byte[].

        You only need to use this adjustment if you plan to perform operations on the underlying byte array or byte buffer that rely on their indices.

        Specified by:
        wrapAdjustment in interface DirectBuffer
        Returns:
        the adjustment in indices between an index in this buffer and the wrapped object.
        See Also:
        DirectBuffer.byteArray(), DirectBuffer.byteBuffer()
      • isExpandable

        public boolean isExpandable()
        Is this buffer expandable to accommodate putting data into it beyond the current capacity?
        Specified by:
        isExpandable in interface MutableDirectBuffer
        Returns:
        true is the underlying storage can expand otherwise false.
      • verifyAlignment

        public void verifyAlignment()
        Verify that the underlying buffer is correctly aligned to prevent word tearing, other ordering issues and the JVM crashes. In particular this method verifies that the starting offset of the underlying buffer is properly aligned. However, the actual atomic call must ensure that the index is properly aligned, i.e. it must be aligned to the size of the operand. For example a call to any of the following methods AtomicBuffer.putIntRelease(int, int), AtomicBuffer.putIntVolatile(int, int), AtomicBuffer.addIntRelease(int, int) (int, int)}, AtomicBuffer.getIntVolatile(int), AtomicBuffer.getAndAddInt(int, int) or AtomicBuffer.getAndSetInt(int, int), must have the index aligned by four bytes (e.g. 0, 4, 8, 12, 60 etc.).

        Users are encouraged to call this method after constructing the AtomicBuffer instance in order to ensure that the underlying buffer supports atomic access to long values.

        Agrona provides an agent (org.agrona.agent.BufferAlignmentAgent) that checks the alignment of indexes for all operations at runtime. The agent throws an exception if the unaligned access is detected.

        Note: on some platforms unaligned atomic access can lead to the JVM crashes, e.g.:

         
         # Java VM: OpenJDK 64-Bit Server VM (25.352-b08 mixed mode bsd-aarch64 compressed oops)
         #
         # siginfo: si_signo: 10 (SIGBUS), si_code: 1 (BUS_ADRALN)
         
         
        Specified by:
        verifyAlignment in interface AtomicBuffer
        See Also:
        AtomicBuffer.ALIGNMENT
      • getLongVolatile

        public long getLongVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        getLongVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putLongVolatile

        public void putLongVolatile​(int index,
                                    long value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        putLongVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getLongAcquire

        public long getLongAcquire​(int index)
        Atomically get the value at a given index with acquire semantics.
        Specified by:
        getLongAcquire in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putLongOrdered

        public void putLongOrdered​(int index,
                                   long value)
        Atomically put a value to a given index with ordered store semantics.

        Instead of using this method, use AtomicBuffer.putLongRelease(int, long) instead. They are identical and the putLongRelease is the preferred version.

        Specified by:
        putLongOrdered in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • putLongRelease

        public void putLongRelease​(int index,
                                   long value)
        Atomically put a value to a given index with release semantics.
        Specified by:
        putLongRelease in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • addLongOrdered

        public long addLongOrdered​(int index,
                                   long increment)
        Atomically adds a value to a given index with ordered store semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Instead of using this method, use AtomicBuffer.addLongRelease(int, long) instead. They are identical but the addLongRelease is the preferred version.

        Specified by:
        addLongOrdered in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • addLongRelease

        public long addLongRelease​(int index,
                                   long increment)
        Atomically adds a value to a given index with ordered store semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Specified by:
        addLongRelease in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • putLongOpaque

        public void putLongOpaque​(int index,
                                  long value)
        Atomically put a value to a given index with opaque semantics.
        Specified by:
        putLongOpaque in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getLongOpaque

        public long getLongOpaque​(int index)
        Atomically get a value to a given index with opaque semantics.
        Specified by:
        getLongOpaque in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        Returns:
        the value for at a given index.
      • addLongOpaque

        public long addLongOpaque​(int index,
                                  long increment)
        Adds a value to a given index with opaque semantics. The read and write will be atomic, but the combination is not atomic. So don't use this method concurrently because you can run into lost updates due to a race-condition.
        Specified by:
        addLongOpaque in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • compareAndSetLong

        public boolean compareAndSetLong​(int index,
                                         long expectedValue,
                                         long updateValue)
        Atomic compare and set of a long given an expected value.

        This call has sequential-consistent semantics.

        Specified by:
        compareAndSetLong in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        set successful or not.
      • compareAndExchangeLong

        public long compareAndExchangeLong​(int index,
                                           long expectedValue,
                                           long updateValue)
        Atomic compare and exchange of a long given an expected value.

        This call has sequential-consistent semantics.

        Specified by:
        compareAndExchangeLong in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        the old value no matter if the expected value was found.
      • getAndSetLong

        public long getAndSetLong​(int index,
                                  long value)
        Atomically exchange a value at a location returning the previous contents.

        This call has sequential-consistent semantics.

        Specified by:
        getAndSetLong in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Returns:
        previous value at the index.
      • getAndAddLong

        public long getAndAddLong​(int index,
                                  long delta)
        Atomically add a delta to a value at a location returning the previous contents. To decrement a negative delta can be provided.

        This call has sequential-consistent semantics.

        Specified by:
        getAndAddLong in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        delta - to be added to the value at the index.
        Returns:
        previous value.
      • getIntVolatile

        public int getIntVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        getIntVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putIntVolatile

        public void putIntVolatile​(int index,
                                   int value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        putIntVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getIntAcquire

        public int getIntAcquire​(int index)
        Atomically get the value at a given index with acquire semantics.
        Specified by:
        getIntAcquire in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putIntOrdered

        public void putIntOrdered​(int index,
                                  int value)
        Atomically put a value to a given index with ordered semantics.

        Instead of using this method, use AtomicBuffer.putIntRelease(int, int) instead. They are identical but the putIntRelease is the preferred version.

        Specified by:
        putIntOrdered in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • putIntRelease

        public void putIntRelease​(int index,
                                  int value)
        Atomically put a value to a given index with release semantics.
        Specified by:
        putIntRelease in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • addIntOrdered

        public int addIntOrdered​(int index,
                                 int increment)
        Atomically add a value to a given index with ordered store semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Instead of using this method, use AtomicBuffer.addIntRelease(int, int) instead. They are identical but the addIntRelease is the preferred version.

        Specified by:
        addIntOrdered in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • addIntRelease

        public int addIntRelease​(int index,
                                 int increment)
        Atomically add a value to a given index with release semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Specified by:
        addIntRelease in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • putIntOpaque

        public void putIntOpaque​(int index,
                                 int value)
        Atomically put a value to a given index with opaque semantics.
        Specified by:
        putIntOpaque in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getIntOpaque

        public int getIntOpaque​(int index)
        Atomically get a value to a given index with opaque semantics.
        Specified by:
        getIntOpaque in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        Returns:
        the value for at a given index.
      • addIntOpaque

        public int addIntOpaque​(int index,
                                int increment)
        Adds a value to a given index with opaque semantics. The read and write will be atomic, but the combination is not atomic. So don't use this method concurrently because you can run into lost updates due to a race-condition.
        Specified by:
        addIntOpaque in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • compareAndSetInt

        public boolean compareAndSetInt​(int index,
                                        int expectedValue,
                                        int updateValue)
        Atomic compare and set of an int given an expected value.

        This call has sequential-consistent semantics.

        Specified by:
        compareAndSetInt in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        successful or not.
      • compareAndExchangeInt

        public int compareAndExchangeInt​(int index,
                                         int expectedValue,
                                         int updateValue)
        Atomic compare and exchange of a int given an expected value.

        This call has sequential-consistent semantics.

        Specified by:
        compareAndExchangeInt in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        the old value no matter if the expected value was found.
      • getAndSetInt

        public int getAndSetInt​(int index,
                                int value)
        Atomically exchange a value at a location returning the previous contents.

        This call has sequential-consistent semantics.

        Specified by:
        getAndSetInt in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Returns:
        previous value.
      • getAndAddInt

        public int getAndAddInt​(int index,
                                int delta)
        Atomically add a delta to a value at a location returning the previous contents. To decrement a negative delta can be provided.

        This call has sequential-consistent semantics.

        Specified by:
        getAndAddInt in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        delta - to be added to the value at the index.
        Returns:
        previous value.
      • getShortVolatile

        public short getShortVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        getShortVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putShortVolatile

        public void putShortVolatile​(int index,
                                     short value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        putShortVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getByteVolatile

        public byte getByteVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        getByteVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putByteVolatile

        public void putByteVolatile​(int index,
                                    byte value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        putByteVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getCharVolatile

        public char getCharVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        getCharVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putCharVolatile

        public void putCharVolatile​(int index,
                                    char value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Specified by:
        putCharVolatile in interface AtomicBuffer
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object
      • ensureCapacity

        protected final void ensureCapacity​(int index,
                                            int length)
        Description copied from class: AbstractMutableDirectBuffer
        A hook to ensure the underlying buffer has enough capacity for writing data into the buffer.
        Specified by:
        ensureCapacity in class AbstractMutableDirectBuffer
        Parameters:
        index - at which write occurs.
        length - in bytes.
      • boundsCheckWrap

        private static void boundsCheckWrap​(int offset,
                                            int length,
                                            int capacity)