- 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 flagThis class is not thread-safe.
- Author:
- AO Industries, Inc.
-
-
Field Summary
-
Fields inherited from class com.aoapps.persistence.AbstractPersistentBlockBuffer
pbuffer
-
-
Constructor Summary
Constructors Constructor Description DynamicPersistentBlockBuffer(PersistentBuffer pbuffer)
Creates a buffer.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description long
allocate(long minimumSize)
This will callAbstractPersistentBlockBuffer.barrier(boolean)
as necessary during block splitting.void
deallocate(long id)
Deallocates the block with the provided id.protected void
ensureCapacity(long capacity)
The capacity should always be enough because the capacity ensured here is constrained to a single block, and blocks are always allocated fully.protected long
getBlockAddress(long id)
Gets the address of the block in the underlying persistent buffer.long
getBlockSize(long id)
Gets the maximum amount of data that may be stored in the entry.Iterator<Long>
iterateBlockIds()
Iterates over the allocated block IDs in no specific order, with one exception: the first block allocated must be the first block iterated.-
Methods inherited from class com.aoapps.persistence.AbstractPersistentBlockBuffer
barrier, checkBounds, close, get, getInputStream, getInt, getLong, getOutputStream, getProtectionLevel, isClosed, put, putInt, putLong
-
-
-
-
Constructor Detail
-
DynamicPersistentBlockBuffer
public DynamicPersistentBlockBuffer(PersistentBuffer pbuffer) throws IOException
Creates a buffer.- Throws:
IOException
-
-
Method Detail
-
allocate
public long allocate(long minimumSize) throws IOException
This will callAbstractPersistentBlockBuffer.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 callPersistentBlockBuffer.barrier(boolean)
afterPersistentBlockBuffer.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 throwConcurrentModificationException
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 classAbstractPersistentBlockBuffer
- 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 classAbstractPersistentBlockBuffer
- Throws:
IOException
-
-