Class TimedBufferPool

java.lang.Object
express.mvp.myra.transport.buffer.TimedBufferPool
All Implemented Interfaces:
AutoCloseable

public class TimedBufferPool extends Object implements AutoCloseable
Buffer pool wrapper providing timeout-based acquisition and metrics tracking.

This class wraps a LockFreeBufferPool to add blocking acquisition with timeouts, efficient waiting using condition variables, and comprehensive metrics tracking.

Acquisition Modes

Efficient Waiting

Unlike busy-spin approaches, this implementation uses a Condition variable for efficient waiting. Threads waiting for buffers are parked and only woken when:

  • A buffer is released back to the pool
  • The timeout expires
  • The thread is interrupted

Metrics

The pool tracks acquisition statistics including:

  • Total, successful, and failed acquisition counts
  • Average and maximum wait times
  • Current availability

Use metrics() to retrieve a snapshot of current metrics.

Usage Example

try (TimedBufferPool pool = new TimedBufferPool(256, 65536)) {
    // Non-blocking acquisition
    BufferRef buf = pool.tryAcquire();
    if (buf != null) {
        try {
            // Use buffer...
        } finally {
            buf.release(); // Standard release via BufferRef
        }
    }

    // Blocking acquisition with timeout
    BufferRef buf2 = pool.acquireWithTimeout(Duration.ofMillis(100));
    if (buf2 != null) {
        try {
            // Use buffer...
        } finally {
            buf2.release(); // Standard release via BufferRef
        }
    } else {
        // Handle timeout
    }
}

Thread Safety

All methods are thread-safe. The underlying lock-free pool handles concurrent acquisitions efficiently, while a lightweight lock is used only for condition variable signaling during waits.

Release Signaling

To enable efficient waiting, call signalRelease() after releasing a buffer back to the pool via BufferRef.release(). Alternatively, use the releaseAndSignal(BufferRef) convenience method which does both.

See Also:
  • Constructor Details

    • TimedBufferPool

      public TimedBufferPool(int count, int bufferSize)
      Creates a new timed buffer pool with the specified capacity.

      This constructor creates a new underlying LockFreeBufferPool.

      Parameters:
      count - the number of buffers (must be a power of 2)
      bufferSize - the size of each buffer in bytes
      Throws:
      IllegalArgumentException - if count is not a power of 2
    • TimedBufferPool

      public TimedBufferPool(LockFreeBufferPool delegate)
      Creates a new timed buffer pool wrapping an existing pool.

      The wrapped pool will not be closed when this TimedBufferPool is closed.

      Parameters:
      delegate - the underlying buffer pool to wrap
  • Method Details

    • tryAcquire

      public BufferRef tryAcquire()
      Attempts to acquire a buffer without blocking.

      This method returns immediately, either with a buffer or null if none are available. Equivalent to calling the underlying pool's acquire method directly.

      Returns:
      a BufferRef with refCount=1, or null if pool is empty
    • acquireWithTimeout

      public BufferRef acquireWithTimeout(Duration timeout) throws InterruptedException
      Acquires a buffer, blocking up to the specified timeout if none are available.

      This method first attempts a non-blocking acquisition. If unsuccessful, it waits using a condition variable (not busy-spin) for up to the specified duration.

      Wait time is tracked for metrics. On success, the wait time is recorded; on timeout, it's counted as a failed acquisition.

      Parameters:
      timeout - the maximum time to wait for a buffer
      Returns:
      a BufferRef with refCount=1, or null if timeout expired
      Throws:
      InterruptedException - if the current thread is interrupted while waiting
      NullPointerException - if timeout is null
    • awaitAvailable

      public boolean awaitAvailable(Duration timeout) throws InterruptedException
      Waits for a buffer to become available without acquiring it.

      This is useful for scenarios where you want to check availability before committing to an acquisition, or for implementing custom retry logic.

      Note: Between this method returning true and a subsequent acquisition attempt, another thread may acquire the available buffer.

      Parameters:
      timeout - the maximum time to wait
      Returns:
      true if a buffer is available, false if timeout expired
      Throws:
      InterruptedException - if the current thread is interrupted while waiting
      NullPointerException - if timeout is null
    • releaseAndSignal

      public void releaseAndSignal(BufferRef buf)
      Releases a buffer and signals waiting threads.

      This is a convenience method that combines BufferRef.release() with signalRelease(). Use this when you want waiters to be notified.

      Important: Only call this if the buffer's refCount will drop to 0, otherwise use BufferRef.release() directly.

      Parameters:
      buf - the buffer to release
      Throws:
      NullPointerException - if buf is null
    • signalRelease

      public void signalRelease()
      Signals waiting threads that a buffer may be available.

      Call this method after releasing a buffer back to the pool (when refCount reaches 0) to wake up threads waiting in acquireWithTimeout(Duration) or awaitAvailable(Duration).

      It is safe to call this method even if no buffer was actually released; waiters will simply re-check availability and continue waiting if necessary.

    • metrics

      public BufferPoolMetrics metrics()
      Returns a snapshot of current pool metrics.

      The returned metrics are a point-in-time snapshot. The values may be slightly inconsistent if concurrent operations are in progress, but this is acceptable for monitoring purposes.

      Returns:
      current metrics snapshot
    • resetMetrics

      public void resetMetrics()
      Resets all metrics counters to zero.

      This is useful for periodic metric collection windows or testing.

    • capacity

      public int capacity()
      Returns the total capacity of the pool.
      Returns:
      the number of buffers in the pool
    • available

      public int available()
      Returns the number of currently available buffers.
      Returns:
      the available buffer count
    • delegate

      public LockFreeBufferPool delegate()
      Returns the underlying lock-free buffer pool.

      Direct access to the delegate is provided for advanced use cases where the lock-free acquire/release is preferred over timed acquisition.

      Returns:
      the underlying buffer pool
    • close

      public void close()
      Closes the pool and releases all resources.

      If this pool was created with a count and bufferSize (owns the delegate), the underlying pool is closed. If wrapping an existing pool, it remains open.

      After closing, any waiting threads will be interrupted.

      Specified by:
      close in interface AutoCloseable