Open-Source Wikis

/

MongoDB

/

Systems

/

Executors, futures, and batons

mongodb/mongo

Executors, futures, and batons

Asynchronous work in MongoDB is built on a small set of primitives: Future<T>, Promise<T>, TaskExecutor, Baton, and the connection pool. They are used to express I/O, parallel fan-out (AsyncRequestsSender), and most background work in the server.

Futures and promises

src/mongo/util/future.h defines:

  • Future<T> — read end of an async result. Continuations attached with .then(), .onError(), .onCompletion() run on whichever executor completes the future, or on the executor passed to .thenRunOn(e).
  • Promise<T> — write end. Setting setValue/setError resolves the future.
  • SemiFuture<T> — like Future, but with no implicit executor. Continuations must be explicit about where they run. Used for inter-component boundaries.
  • SharedSemiFuture<T> — multi-consumer variant.

The full design rationale is in docs/futures_and_promises.md. The MongoDB types do not match std::future — they are non-blocking, support continuation chaining, and are zero-allocation in the common case.

SemiFuture<BSONObj> findDoc(OperationContext* opCtx);

findDoc(opCtx)
    .thenRunOn(executor)
    .then([](BSONObj doc) {
        // do something with doc on `executor`
        return processDoc(doc);
    })
    .onError([](Status s) {
        return Status(ErrorCodes::InternalError, "lookup failed: " + s.reason());
    });

Task executors

src/mongo/executor/ defines:

Type Role
TaskExecutor Abstract base. Schedules work, runs network ops via a NetworkInterface.
ThreadPoolTaskExecutor The default impl. Backed by a ThreadPool and a NetworkInterface.
NetworkInterfaceASIO / NetworkInterfaceTL ASIO-based outbound network drivers used by the executor.
ConnectionPool Pools outbound TCP/TLS connections to other servers, reused across operations.
RemoteCommandRequest / RemoteCommandResponse The unit of an outbound command sent through a TaskExecutor.
PinnedConnectionTaskExecutor A wrapper that pins all work to a single connection. Used for some sharding fan-outs.

Each major subsystem allocates its own executor instances (or shares a pool). Examples:

  • Sharding has the TaskExecutorPool (src/mongo/s/sharding_task_executor_pool*) — a fan-out of executors used by mongos and shards.
  • Replication uses dedicated executors for the syncer (src/mongo/db/repl/) and the rollback machinery.
  • Background services schedule on the global PeriodicRunner (src/mongo/util/periodic_runner.h).

Batons

A baton is a lightweight, single-thread-bound work queue. It lets a thread "drop into" a wait, run scheduled continuations on its own context while waiting, and resume once the wait completes. The design is in docs/baton.md. Batons are owned by OperationContext and used heavily in the transport layer to keep request handling on the originating thread.

opCtx->getBaton()->schedule([] (Status s) {
    // runs on the opCtx's owning thread
});

Periodic runner

src/mongo/util/periodic_runner.h is a process-wide registry of "periodic jobs" — closures invoked on a timer. The TTL monitor, FTDC collector, and many cluster-parameter refreshers are scheduled here.

Thread pools

src/mongo/util/concurrency/thread_pool.h implements a generic thread pool. The ThreadPoolTaskExecutor adapts it to the TaskExecutor interface. Pool sizes are tunable via server parameters such as taskExecutorPoolSize.

Connection pool

The egress connection pool (src/mongo/executor/connection_pool*) maintains warm connections to other servers. It's controlled by:

  • ConnectionPool::Options — min/max pool size, refresh interval, host timeout.
  • The shardingTaskExecutorPoolMaxSize, shardingTaskExecutorPoolMaxConnecting, and similar server parameters.

Error handling

  • A continuation that throws turns the result into an error future automatically.
  • Network errors propagate as Status codes from the ErrorCodes::NetworkTimeout / HostUnreachable family.
  • The OperationContext carries cancellation; opCtx->getCancellationToken() can be passed into futures so they cancel when the operation is killed.

Key source files

File Purpose
src/mongo/util/future.h / future_impl.h The Future/Promise family.
src/mongo/util/baton.h / default_baton.cpp Single-thread work queues.
src/mongo/executor/task_executor.h Abstract TaskExecutor.
src/mongo/executor/thread_pool_task_executor.cpp The default thread-pool-backed executor.
src/mongo/executor/network_interface_tl.cpp The transport-layer-backed network interface.
src/mongo/executor/connection_pool.cpp Egress connection pool.
src/mongo/util/periodic_runner.h Timer-driven periodic work.
src/mongo/util/concurrency/thread_pool.h Generic thread pool.

Integration points

Entry points for modification

Most code that needs to do work asynchronously should use an existing executor. Adding a new pool is rare; a new periodic job is a one-line registration with PeriodicRunner. When debugging starvation or stalls, check the connection pool stats from connPoolStats and the taskExecutorPool section of serverStatus.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Executors, futures, and batons – MongoDB wiki | Factory