java.lang.Object
net.i2p.sam.SAMHandlerPool

class SAMHandlerPoolextends Object
Shared NIO selector-based handler pool for SAM v3 control connections.

Replaces the thread-per-connection model for SAM v3 handlers with a single selector thread reading all handler sockets and dispatching complete command lines inline. Commands are processed serially per-connection in the order they arrive. PING/PONG keepalive and idle timeout are handled at the pool level so individual handlers do not consume threads while waiting for input.

  • Field Details

    • PONG_TIMEOUT

      private static final int PONG_TIMEOUT
      Time to wait for a pong before disconnecting.
      See Also:
    • FIRST_READ_TIMEOUT

      private static final int FIRST_READ_TIMEOUT
      Time allowed for the first command line.
      See Also:
    • IDLE_CHECK_INTERVAL

      private static final int IDLE_CHECK_INTERVAL
      Interval between idle connection checks.
      See Also:
    • _log

      private final Log _log
      Logger for the SAM handler pool.
    • _selector

      private final Selector _selector
      Selector watching the client connections.
    • _workers

      private final ThreadPoolExecutor _workers
      Pool running the command handlers.
    • _connectors

      private final ThreadPoolExecutor _connectors
      Pool running the session opens.
    • _teardowns

      private final ThreadPoolExecutor _teardowns
      Pool running the session closes.
    • _contexts

      private final Map<SocketChannel, SAMHandlerPool.ConnContext> _contexts
      Connection state, by channel.
    • _running

      private volatile boolean _running
      True while the pool is running.
    • _selectThread

      private I2PAppThread _selectThread
      The thread running the selector loop.
    • PING_PREFIX

      private static final String PING_PREFIX
      SAM ping command prefix.
      See Also:
    • PONG_PREFIX

      private static final String PONG_PREFIX
      SAM pong reply prefix.
      See Also:
    • CRLF

      private static final String CRLF
      SAM line terminator.
      See Also:
  • Constructor Details

    • SAMHandlerPool

      SAMHandlerPool()
      Create the pool.
  • Method Details

    • register

      void register(SAMv3Handler handler)
      Register a v3 handler with the pool. The pool will read commands from the handler's socket and dispatch them via processLine().
      Parameters:
      handler - non-null
    • queueTeardown

      static boolean queueTeardown(Executor pool, Runnable teardown)
      Hand a handler teardown to a pool that is allowed to block, instead of running it wherever the disconnect was noticed.

      stopHandling() runs SAMv3Handler.die(), which waits up to 10 seconds for a session's threads to exit. The selector thread is shared by every pooled connection, so running a teardown on it stalls all of them behind one slow client. Extracted so the hand-off itself is testable.

      Parameters:
      pool - the executor to hand the teardown to
      teardown - the teardown to run
      Returns:
      true if the pool accepted it; false if it was rejected, in which case the caller must still run the teardown somewhere
    • runTeardown

      void runTeardown(Runnable teardown)
      Run a handler teardown off the thread that noticed the disconnect, on the pool built for that work - not on the connector pool, whose four threads are what a user-facing STREAM CONNECT or FORWARD waits on.

      Falls back to running the teardown on the caller's thread only when the teardown pool has already shut down and there is nowhere left to hand it to. See queueTeardown(Executor, Runnable) for why the hand-off matters.

      Parameters:
      teardown - the teardown to run
    • unregister

      void unregister(SAMv3Handler handler)
      Remove a handler's socket from the pool. Called from stopHandling() or when the socket is stolen.
      Parameters:
      handler - non-null
    • start

      void start()
      Start the selector thread.
    • stop

      void stop()
      Stop the pool, interrupt selector, wait for workers.
    • getRegisteredCount

      int getRegisteredCount()
      Number of handlers currently registered (connected).
      Returns:
      the number of connected SAM handler contexts currently registered
    • getActiveCount

      int getActiveCount()
      Number of worker threads actively processing a command.
      Returns:
      the number of worker threads currently running a command
    • getPoolSize

      int getPoolSize()
      Current worker pool size (may include idle threads).
      Returns:
      the number of worker threads created, including those now idle
    • getQueueSize

      int getQueueSize()
      Number of commands waiting in the worker queue.
      Returns:
      the number of commands waiting in the worker's queue
    • getConnectors

      ThreadPoolExecutor getConnectors()
      Thread pool for blocking STREAM CONNECT operations. Fixed pool of 4 daemon threads with an unbounded work queue. Limits concurrent connects to prevent overwhelming the streaming layer while keeping pool workers unblocked. Excess CONNECTs queue up and are dispatched as connector threads become available.

      Handler teardowns do not run here - they have their own pool, because a teardown waits up to 10 seconds for a session's threads and would take a connect slot with it.

      Returns:
      the shared pool of four daemon threads that run blocking STREAM CONNECT operations
    • getTeardowns

      ThreadPoolExecutor getTeardowns()
      Thread pool that runs handler teardowns off the selector thread. Fixed pool of 2 daemon threads with an unbounded work queue, sized apart from the connector pool so a slow die() cannot stall new connections. runTeardown() hands its teardowns here, so this is the one place that pairing is stated.
      Returns:
      the pool teardowns are handed to