Architecture

Parallelism at two levels — across tasks via the connection pool, within transfers via chunk pipelining on a single SMB session.

Connection pool

HybridSMB runs up to four SMB operations in parallel through SmbConnectionPool(4). Each slot is one smb2_context — its own TCP socket and full session:

session flow
TCP → NEGOTIATE → SESSION SETUP → TREE CONNECT

Tasks call requestContext(mode), hold a slot for the operator's lifetime, then release via PoolContextHandle. One operator per slot (mutex on the context). Work on different slots runs concurrently.

Slot assignment

slot 0
interactive only
slot 1
general
slot 2
general
slot 3
general
SlotAcceptsTypical work
slot[0] Interactive only listDirectory, getPathInfo, rename, move
slot[1..3] Any mode Download, upload, copy, delete; grows on demand
Slot 0 is UI insurance. Interactive ops never queue behind bulk metadata work. When slot 0 is busy, interactive work overflows to slots 1–3.

Acquire modes

ModeOperators
Interactive getPathInfo, shallow listDirectory, moveItem, renameItem, createDirectory, getSecurityDescriptor, listShares
Metadata downloadFile, uploadFile, copyItem, duplicateItem, deleteItem, recursive listDirectory

FIFO queue per mode.

Pool vs SMB3 multichannel

The server sees each active slot as a separate client connection — multiple full sessions to the same host/share, not channels bound to one session.

This poolSMB3 multichannel
SessionsOne per slotOne across channels
Server viewN connections1 client, N channels
Slot 0 reserved for UIYes
Requires server multichannel capNoYes

libsmb2 does not implement SMB3 multichannel. Each smb2_context maps to one file descriptor, so the pool uses independent contexts instead.

Chunk pipeline

Cross-task parallelism is the pool. Within a single transfer, SmbFileIO pipelines up to eight SMB2 READ/WRITE requests on the same smb2_context (kMaxInFlight).

Same connection, same session — credit-based pipelining, separate from slot assignment.

Diagnostics

pool-debug.ts
const info = smb.getPoolInfo();
const id = smb.subscribePoolInfo((snap) => console.log(snap));
smb.unsubscribePoolInfo(id);

PoolSlotInfo fields: index, interactiveOnly, state, isConnected, shareName, taskId, kind.

ObservationLikely cause
Same index turning over quicklyTasks queuing on one slot
Slots 1–3 all Assigned, metadata pendingPool full
Interactive kind on slot 1–3Slot 0 was busy

See example/components/PoolDebugPanel.js for a live debug UI.