Class HugeAtomicByteArray

  • All Implemented Interfaces:
    HugeCursorSupport<byte[]>

    public abstract class HugeAtomicByteArray
    extends java.lang.Object
    implements HugeCursorSupport<byte[]>
    A long-indexable array of atomic bytes that can contain more than 2 bn. elements.

    It is implemented by paging of smaller byte-arrays (byte[][]) to support approx. 32k bn. elements. If the the provided size is small enough, an optimized view of a single byte[] might be used.

    • The array is of a fixed size and cannot grow or shrink dynamically.
    • The array is not optimized for sparseness and has a large memory overhead if the values written to it are very sparse.
    • The array does not support default values and returns the same default for unset values that a regular byte[] does (0).
    • It only supports a minimal subset of the atomic operations that AtomicLongArray provides.

    Basic Usage

     
     AllocationTracker allocationTracker = ...;
     long arraySize = 42L;
     HugeAtomicByteArray array = HugeAtomicByteArray.newArray(arraySize, allocationTracker);
     array.set(13L, (byte)37);
     byte value = array.get(13L);
     // value = (byte)37;
     
     
    Implementation is similar to the AtomicLongArray (but for bytes), based on sun.misc.Unsafe https://hg.openjdk.java.net/jdk/jdk13/file/9e0c80381e32/jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicLongArray.java
    • Method Summary

      All Methods Static Methods Instance Methods Abstract Methods Concrete Methods 
      Modifier and Type Method Description
      abstract byte compareAndExchange​(long index, byte expect, byte update)
      Atomically sets the element at position index to the given updated value if the current value, referred to as the witness value, == the expected value.
      abstract boolean compareAndSet​(long index, byte expect, byte update)
      Atomically sets the element at position index to the given updated value if the current value == the expected value.
      abstract byte get​(long index)  
      abstract byte getAndAdd​(long index, byte delta)
      Atomically adds the given delta to the value at the given index.
      static long memoryEstimation​(long size)  
      static HugeAtomicByteArray newArray​(long size)
      Creates a new array of the given size.
      abstract HugeCursor<byte[]> newCursor()
      Returns a new HugeCursor for this array.
      abstract long release()
      Destroys the data, allowing the underlying storage arrays to be collected as garbage.
      abstract void set​(long index, byte value)
      Sets the byte value at the given index to the given value.
      abstract void setAll​(byte value)
      Set all entries in the array to the given value.
      abstract long size()
      Returns the length of this array.
      abstract long sizeOf()  
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
    • Constructor Detail

      • HugeAtomicByteArray

        public HugeAtomicByteArray()
    • Method Detail

      • get

        public abstract byte get​(long index)
        Returns:
        the byte value at the given index
        Throws:
        java.lang.ArrayIndexOutOfBoundsException - if the index is not within size()
      • getAndAdd

        public abstract byte getAndAdd​(long index,
                                       byte delta)
        Atomically adds the given delta to the value at the given index.
        Parameters:
        index - the index
        delta - the value to add
        Returns:
        the previous value at index
      • set

        public abstract void set​(long index,
                                 byte value)
        Sets the byte value at the given index to the given value.
        Throws:
        java.lang.ArrayIndexOutOfBoundsException - if the index is not within size()
      • compareAndSet

        public abstract boolean compareAndSet​(long index,
                                              byte expect,
                                              byte update)
        Atomically sets the element at position index to the given updated value if the current value == the expected value.
        Parameters:
        index - the index
        expect - the expected value
        update - the new value
        Returns:
        true if successful. False return indicates that the actual value was not equal to the expected value.
      • compareAndExchange

        public abstract byte compareAndExchange​(long index,
                                                byte expect,
                                                byte update)
        Atomically sets the element at position index to the given updated value if the current value, referred to as the witness value, == the expected value. This operation works as if implemented as
             if (this.compareAndSet(index, expect, update)) {
                 return expect;
             } else {
                 return this.get(index);
             }
         
        The actual implementation is done with a single atomic operation so that the returned witness value is the value that was failing the update, not one that needs be read again after the failed update. This allows one to write CAS-loops in a different way, which removes one volatile read per loop iteration
             var oldValue = this.get(index);
             while (true) {
                 var newValue = updateFunction(oldValue);
                 var witnessValue = this.compareAndExchange(index, oldValue, newValue);
                 if (witnessValue == oldValue) {
                     // update successful
                     break;
                 }
                 // update unsuccessful set, loop and try again.
                 // Here we already have the updated witness value and don't need to issue
                 // a new read
                 oldValue = witnessValue;
             }
         
        Parameters:
        index - the index
        expect - the expected value
        update - the new value
        Returns:
        the result that is the witness value, which will be the same as the expected value if successful or the new current value if unsuccessful.
      • size

        public abstract long size()
        Returns the length of this array.

        If the size is greater than zero, the highest supported index is size() - 1

        The behavior is identical to calling array.length on primitive arrays.

        Specified by:
        size in interface HugeCursorSupport<byte[]>
      • sizeOf

        public abstract long sizeOf()
        Returns:
        the amount of memory used by the instance of this array, in bytes. This should be the same as returned from release() without actually releasing the array.
      • setAll

        public abstract void setAll​(byte value)
        Set all entries in the array to the given value. This method is not atomic!
      • release

        public abstract long release()
        Destroys the data, allowing the underlying storage arrays to be collected as garbage. The array is unusable after calling this method and will throw NullPointerExceptions on virtually every method invocation.

        Note that the data might not immediately collectible if there are still cursors alive that reference this array. You have to HugeCursor.close() every cursor instance as well.

        Returns:
        the amount of memory freed, in bytes.
      • newArray

        public static HugeAtomicByteArray newArray​(long size)
        Creates a new array of the given size.
      • memoryEstimation

        public static long memoryEstimation​(long size)