Class UnsafeBuffer

java.lang.Object
org.agrona.AbstractMutableDirectBuffer
org.agrona.concurrent.UnsafeBuffer
All Implemented Interfaces:
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.

  • Field Details

  • Constructor Details

    • 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:
    • 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:
    • UnsafeBuffer

      public UnsafeBuffer(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(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 Details

    • 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(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(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)
      Attach a view to an existing DirectBuffer
      Specified by:
      wrap in interface DirectBuffer
      Parameters:
      buffer - to which the view is attached.
    • 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 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:
    • 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.putIntOrdered(int, int), AtomicBuffer.putIntVolatile(int, int), AtomicBuffer.addIntOrdered(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:
    • getLongVolatile

      public long getLongVolatile(int index)
      Get the value at a given index with volatile 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)
      Put a value to a given index with volatile semantics.
      Specified by:
      putLongVolatile in interface AtomicBuffer
      Parameters:
      index - in bytes for where to put.
      value - for at a given index.
    • putLongOrdered

      public void putLongOrdered(int index, long value)
      Put a value to a given index with ordered store semantics.
      Specified by:
      putLongOrdered 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)
      Add a value to a given index with ordered store semantics. Use a negative increment to decrement.
      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.
    • compareAndSetLong

      public boolean compareAndSetLong(int index, long expectedValue, long updateValue)
      Atomic compare and set of a long given an expected value.
      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.
    • getAndSetLong

      public long getAndSetLong(int index, long value)
      Atomically exchange a value at a location returning the previous contents.
      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.
      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)
      Get the value at a given index with volatile 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)
      Put a value to a given index with volatile semantics.
      Specified by:
      putIntVolatile in interface AtomicBuffer
      Parameters:
      index - in bytes for where to put.
      value - for at a given index.
    • putIntOrdered

      public void putIntOrdered(int index, int value)
      Put a value to a given index with ordered semantics.
      Specified by:
      putIntOrdered 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)
      Add a value to a given index with ordered store semantics. Use a negative increment to decrement.
      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.
    • compareAndSetInt

      public boolean compareAndSetInt(int index, int expectedValue, int updateValue)
      Atomic compare and set of an int given an expected value.
      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.
    • getAndSetInt

      public int getAndSetInt(int index, int value)
      Atomically exchange a value at a location returning the previous contents.
      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.
      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)
      Get the value at a given index with volatile 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)
      Put a value to a given index with volatile 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)
      Get the value at a given index with volatile 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)
      Put a value to a given index with volatile 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)
      Get the value at a given index with volatile 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)
      Put a value to a given index with volatile semantics.
      Specified by:
      putCharVolatile in interface AtomicBuffer
      Parameters:
      index - in bytes for where to put.
      value - for at a given index.
    • toString

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

      protected final void ensureCapacity(int index, int length)
      Specified by:
      ensureCapacity in class AbstractMutableDirectBuffer
    • boundsCheckWrap

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