Class RegisteredBufferPoolImpl
- All Implemented Interfaces:
RegisteredBufferPool, AutoCloseable
This implementation manages a fixed set of off-heap memory regions that can be pre-registered with the I/O backend (e.g., io_uring's registered buffers). Registration eliminates per-operation kernel address validation, providing approximately 1.7x throughput improvement.
Memory Layout
The pool allocates a single contiguous memory block, then slices it into individual buffers. This design provides several benefits:
- TLB efficiency: Contiguous memory uses fewer TLB entries
- Huge page support: Large pools automatically use 2MB huge pages
- Simpler registration: Single memory region for kernel registration
- Cache locality: Sequential buffers are cache-line adjacent
Page Alignment
Buffer sizes are aligned to 4KB page boundaries. This ensures:
- Each buffer starts on a page boundary
- DMA transfers work correctly for registered buffers
- No false sharing between adjacent buffers
Thread Safety
This implementation uses an ArrayBlockingQueue for buffer management, providing
thread-safe acquire/release with blocking semantics. The queue is lock-based but contention is
typically low as I/O operations take much longer than queue operations.
Sizing Recommendations
| Use Case | Buffer Count | Buffer Size |
|---|---|---|
| Client (low concurrency) | 64-128 | 8-16 KB |
| Server (moderate load) | 256-512 | 16-32 KB |
| High-throughput server | 1024-4096 | 32-64 KB |
- See Also:
-
Constructor Summary
ConstructorsConstructorDescriptionRegisteredBufferPoolImpl(int numBuffers, int bufferSize) Creates a new buffer pool with the specified number of buffers and size. -
Method Summary
Modifier and TypeMethodDescriptionacquire()Acquires a buffer from the pool, blocking if necessary.intReturns the number of buffers currently available for acquisition.intcapacity()Returns the total number of buffers in the pool.voidclose()Closes the pool and releases all underlying resources.Returns the array of all buffers for backend registration.getBufferSegment(RegisteredBuffer buffer) Returns the raw memory segment backing a buffer.intinUse()Returns the number of buffers currently in use.voidrelease(RegisteredBuffer buffer) Releases a buffer back to the pool for reuse.Attempts to acquire a buffer without blocking.
-
Constructor Details
-
RegisteredBufferPoolImpl
public RegisteredBufferPoolImpl(int numBuffers, int bufferSize) Creates a new buffer pool with the specified number of buffers and size.The actual buffer size may be larger than requested due to page alignment. For example, requesting 5000-byte buffers will allocate 8192 bytes per buffer (rounded up to 2 pages).
Memory Calculation
Total memory =
numBuffers × alignedBufferSize, where:alignedBufferSize = ((bufferSize + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE
- Parameters:
numBuffers- the number of buffers in the pool (must be positive)bufferSize- the requested size of each buffer in bytes (must be positive)- Throws:
IllegalArgumentException- if numBuffers or bufferSize is not positiveOutOfMemoryError- if unable to allocate the required memory
-
-
Method Details
-
acquire
Description copied from interface:RegisteredBufferPoolAcquires a buffer from the pool, blocking if necessary.If no buffers are currently available, this method blocks until one is released by another thread. The returned buffer has been cleared (position=0, limit=capacity).
- Specified by:
acquirein interfaceRegisteredBufferPool- Returns:
- a registered buffer ready for use
-
tryAcquire
Description copied from interface:RegisteredBufferPoolAttempts to acquire a buffer without blocking.Returns immediately with a buffer if one is available, or
nullif all buffers are in use. This is useful for non-blocking I/O patterns.- Specified by:
tryAcquirein interfaceRegisteredBufferPool- Returns:
- a registered buffer, or
nullif none available
-
release
Description copied from interface:RegisteredBufferPoolReleases a buffer back to the pool for reuse.The buffer is automatically cleared (position reset, limit set to capacity) before being made available for the next acquire. This method is also called automatically when
RegisteredBuffer.close()is invoked.This method is idempotent; releasing an already-released buffer has no effect.
- Specified by:
releasein interfaceRegisteredBufferPool- Parameters:
buffer- the buffer to release; must have been acquired from this pool
-
capacity
public int capacity()Description copied from interface:RegisteredBufferPoolReturns the total number of buffers in the pool.This is the fixed capacity set at pool creation time.
- Specified by:
capacityin interfaceRegisteredBufferPool- Returns:
- the total buffer count
-
available
public int available()Description copied from interface:RegisteredBufferPoolReturns the number of buffers currently available for acquisition.Note: This value may change immediately after the call returns due to concurrent acquire/release operations.
- Specified by:
availablein interfaceRegisteredBufferPool- Returns:
- the current available buffer count
-
inUse
public int inUse()Description copied from interface:RegisteredBufferPoolReturns the number of buffers currently in use.This equals
capacity() - available(). Note: This value may change immediately after the call returns.- Specified by:
inUsein interfaceRegisteredBufferPool- Returns:
- the current in-use buffer count
-
getAllBuffers
Returns the array of all buffers for backend registration.This method is called by the I/O backend during initialization to register all buffers with the kernel. For io_uring, this triggers
LibUring.registerBuffers(MemorySegment, MemorySegment, int).Note: The returned array should not be modified.
- Returns:
- array of all buffers in the pool (length equals
capacity())
-
getBufferSegment
Returns the raw memory segment backing a buffer.This method is used by the I/O backend to access the underlying memory for registration and I/O operations.
- Parameters:
buffer- the buffer to get the segment from- Returns:
- the memory segment backing the buffer
-
close
public void close()Description copied from interface:RegisteredBufferPoolCloses the pool and releases all underlying resources.After closing:
- All buffers become invalid (accessing them is undefined behavior)
RegisteredBufferPool.acquire()andRegisteredBufferPool.tryAcquire()will throw- The underlying memory is freed
This method blocks until all buffers can be reclaimed. Ensure all I/O operations using buffers from this pool have completed before closing.
- Specified by:
closein interfaceAutoCloseable- Specified by:
closein interfaceRegisteredBufferPool
-