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.
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionprivate static classPer-connection context tracked by the pool.private static classThread factory for worker threads with sequential numbering.private classNIO selector loop.Field Summary
FieldsModifier and TypeFieldDescriptionprivate final ThreadPoolExecutorPool running the session opens.private final Map<SocketChannel, SAMHandlerPool.ConnContext> Connection state, by channel.private final LogLogger for the SAM handler pool.private booleanTrue while the pool is running.private final SelectorSelector watching the client connections.private I2PAppThreadThe thread running the selector loop.private final ThreadPoolExecutorPool running the session closes.private final ThreadPoolExecutorPool running the command handlers.private static final StringSAM line terminator.private static final intTime allowed for the first command line.private static final intInterval between idle connection checks.private static final StringSAM ping command prefix.private static final StringSAM pong reply prefix.private static final intTime to wait for a pong before disconnecting.Constructor Summary
ConstructorsMethod Summary
Modifier and TypeMethodDescription(package private) intNumber of worker threads actively processing a command.(package private) ThreadPoolExecutorThread pool for blocking STREAM CONNECT operations.(package private) intCurrent worker pool size (may include idle threads).(package private) intNumber of commands waiting in the worker queue.(package private) intNumber of handlers currently registered (connected).(package private) ThreadPoolExecutorThread pool that runs handler teardowns off the selector thread.(package private) static booleanqueueTeardown(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.(package private) voidregister(SAMv3Handler handler) Register a v3 handler with the pool.(package private) voidrunTeardown(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.(package private) voidstart()Start the selector thread.(package private) voidstop()Stop the pool, interrupt selector, wait for workers.(package private) voidunregister(SAMv3Handler handler) Remove a handler's socket from the pool.
Field Details
PONG_TIMEOUT
private static final int PONG_TIMEOUTTime to wait for a pong before disconnecting.- See Also:
FIRST_READ_TIMEOUT
private static final int FIRST_READ_TIMEOUTTime allowed for the first command line.- See Also:
IDLE_CHECK_INTERVAL
private static final int IDLE_CHECK_INTERVALInterval between idle connection checks.- See Also:
_log
Logger for the SAM handler pool._selector
Selector watching the client connections._workers
Pool running the command handlers._connectors
Pool running the session opens._teardowns
Pool running the session closes._contexts
Connection state, by channel._running
private volatile boolean _runningTrue while the pool is running._selectThread
The thread running the selector loop.PING_PREFIX
PONG_PREFIX
CRLF
Constructor Details
SAMHandlerPool
SAMHandlerPool()Create the pool.
Method Details
register
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
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 toteardown- 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
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
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