4.8 KiB
Server-Internal Baton Pattern
Batons are lightweight job queues in mongod and mongos processes that allow recording the intent
to execute a task (e.g., polling on a network socket) and deferring its execution to a later time.
Batons, often by reusing Client threads and through the Waitable interface, move the execution
of scheduled tasks out of the line, potentially hiding the execution cost from the critical path. A
total of four baton classes are available today:
Baton Basics
All baton implementations extend Baton. They are tightly associated with an OperationContext and
its Client thread. An OperationContext that belongs to a ServiceContext with a
TransportLayer uses an AsioNetworkingBaton, else a DefaultBaton. The baton is accessed through
the OperationContext with a call to OperationContext::getBaton().
Each baton implementation exposes an interface to allow scheduling tasks on the baton, to demand the awakening of the baton on client socket disconnect, and to create a SubBaton. A SubBaton, for any of the baton types, is essentially a handle to a local object that proxies scheduling requests to its underlying baton until it is detached (e.g., through destruction of its handle).
Additionally, a NetworkingBaton enables consumers of a transport layer to execute I/O themselves, rather than delegating it to other threads. They are special batons that are able to poll network sockets, which is not feasible through other baton types. This is essential for minimizing context switches and improving the readability of stack traces.
A baton runs automatically when blocking on its associated OperationContext with a call to
OperationContext::waitForConditionOrInterrupt(). Many different apis that take in or use an
Interruptible will eventually call into this method (e.g. Future::get(...),
OperationContext::sleepUntil(...), etc.).
DefaultBaton
DefaultBaton is the most basic baton implementation. This baton provides the platform to execute
tasks while a client thread awaits an event or a timeout, essentially paving the way towards
utilizing idle cycles of client threads for useful work. Tasks can be scheduled on this baton
through its associated OperationContext and using OperationContext::getBaton()::schedule(...).
Note that because Baton extends an OutOfLineExecutor, it can be used as the executor to run work
on an ExecutorFuture.
AsioNetworkingBaton
The AsioNetworkingBaton can schedule and run tasks similarly to the DefaultBaton, but it also
implements the NetworkingBaton interface to provide a networking reactor. It can register sessions
to monitor and will utilize poll(2) and eventfd(2) to wait until I/O can be performed on the
socket or until interrupted.
This baton is primarily used for egress networking where it gets scheduled to send off a command after a connection is made (see the relevant code here). This means that the AsioNetworkingBaton will normally perform socket I/O without needing to poll. It only registers a session for polling if another read or write is needed on the socket (e.g. registering a session during socket read).
In order for an egress session to use the baton, it must be specified as an argument to
TaskExecutor::scheduleRemoteCommand(...).
Note that this baton is only available for Linux.
Example
For an example of scheduling a task on the OperationContext baton, see here.
Considerations
Since any task scheduled on a baton is intended for out-of-line execution, it must be non-blocking and preferably short-lived to ensure forward progress.