Class DynamicPersistentBlockBuffer

java.lang.Object
com.aoapps.persistence.AbstractPersistentBlockBuffer
com.aoapps.persistence.DynamicPersistentBlockBuffer
All Implemented Interfaces:
PersistentBlockBuffer, Closeable, AutoCloseable

public class DynamicPersistentBlockBuffer extends AbstractPersistentBlockBuffer

Treats a PersistentBuffer as a set of allocatable blocks. Each block is stored in a 2^n area of the buffer, where the usable space is 2^n-1 (the first byte of that area of the buffer indicates the block size and allocated status).

Free space maps are generated upon instantiation. This means that startup costs can be fairly high. This class is designed for long-lifetime situations.

Blocks that are allocated take no space in memory, while blocks that are deallocated consume space. Adjacent blocks are automatically merged into a larger free block of twice the size. Blocks are also split into smaller blocks before allocating additional space.

Fragmentation may occur in the file over time, but is minimized by the use of per-block size free space maps along with block merging and splitting. There is currently no compaction tool.

Each entry has a one-byte header: bits 0-5: maxBits (0-63) the power of two of the size of this block (max data size is (2^maxBits)-1). bit 6: reserved, should be 0 bit 7: allocated flag

This class is not thread-safe.

Author:
AO Industries, Inc.
  • Constructor Details

  • Method Details

    • allocate

      public long allocate(long minimumSize) throws IOException
      This will call AbstractPersistentBlockBuffer.barrier(boolean) as necessary during block splitting.
      Throws:
      IOException
    • deallocate

      public void deallocate(long id) throws IOException, IllegalStateException
      Description copied from interface: PersistentBlockBuffer

      Deallocates the block with the provided id. The ids of other blocks will not be altered. The space may later be reallocated with the same, or possibly different id. The space may also be reclaimed.

      barrier does not need to be called after a deallocation, but if not called previously deallocated blocks may reappear after a system failure. It is up to higher-level data structures to detect this. In no event, however, will failing to call PersistentBlockBuffer.barrier(boolean) after PersistentBlockBuffer.deallocate(long) cause corruption beyond that just described.

      Throws:
      IllegalStateException - if the block is not allocated.
      IOException
    • iterateBlockIds

      public Iterator<Long> iterateBlockIds() throws IOException
      Description copied from interface: PersistentBlockBuffer

      Iterates over the allocated block IDs in no specific order, with one exception: the first block allocated must be the first block iterated. This block may contain critical higher-level data structure meta data. If all blocks are deallocated, then the first one added has this same requirement.

      The Iterator.remove() method may be used from the iterator in order to deallocate a block. The block allocation should not be modified during the iteration through any means other than the iterator itself. An attempt will be made to throw ConcurrentModificationException in this case, but this is only intended to catch bugs.

      Throws:
      IOException
    • getBlockSize

      public long getBlockSize(long id) throws IOException
      Gets the maximum amount of data that may be stored in the entry. This is the underlying power-of-two block size minus one. May only check the block size of allocated blocks (not necessarily enforced, it is up to the caller to ensure this).
      Throws:
      IOException
    • getBlockAddress

      protected long getBlockAddress(long id) throws IOException
      Description copied from class: AbstractPersistentBlockBuffer
      Gets the address of the block in the underlying persistent buffer. This should only be called for allocated blocks, implementations should check this with assertions.
      Specified by:
      getBlockAddress in class AbstractPersistentBlockBuffer
      Throws:
      IOException
    • ensureCapacity

      protected void ensureCapacity(long capacity) throws IOException
      The capacity should always be enough because the capacity ensured here is constrained to a single block, and blocks are always allocated fully. This merely asserts this fact.
      Specified by:
      ensureCapacity in class AbstractPersistentBlockBuffer
      Throws:
      IOException