Skip to content

Latest commit

 

History

History
114 lines (97 loc) · 8.7 KB

contexts.md

File metadata and controls

114 lines (97 loc) · 8.7 KB

Contextual Singletons

The state of all operations performed on Mongo server processes (i.e., mongod and mongos) is tracked and managed by a global singleton called the ServiceContext. A ServiceContext maintains an arbitrary number of Client objects, which each represent a logical connection to the database over which operations can be performed. Each operation in turn is managed by a single OperationContext. A Client object can only perform a single logical operation at a time, and thus can only maintain a single OperationContext at a time. Note that all of these classes are heavily decorated (i.e., they inherit from Decorable), which makes them dynamically extensible.

A ServiceContext represents all of the state of a single Mongo server process, which may be either a mongod or a mongos. It creates and manages the previously mentioned Clients and OperationContexts, as well as a TransportLayer for performing network operations, a PeriodicRunner for running housekeeping tasks periodically, a StorageEngine for interacting with the actual database itself, and a set of time sources. In general, every Mongo server process has a single ServiceContext, known as the global ServiceContext. Typical uses of the global ServiceContext outside of server initialization and shutdown include looking up Client or OperationContext information for a particular thread or operation, or killing one or more running operations during, e.g., a primary replica step-down. The global ServiceContext is created during initialization of a Mongo server process and is only destroyed at shutdown, and is thus available for the entire duration of server operation. At shutdown, the global ServiceContext will kill all outstanding OperationContexts and Clients.

The ServiceContext associated with a given Client object can be fetched in a few ways; prefer using Client::getServiceContext() when possible. As of time of writing, every server process only maintains a single ServiceContext, but preferring Client::getServiceContext() or ServiceContext::getCurrentServiceContext() over ServiceContext::getGlobalServiceContext() will allow us to more easily maintain multiple ServiceContexts per server process if desired in the future.

Each logical connection to a Mongo service is managed by a Client object, where a logical connection may be a user or an internal process that needs to run a command or query on the database. Construction of a Client object is typically performed with a call to makeClient on the global ServiceContext, which can then be attached to any thread of execution, or with a call to Client::initThread which constructs a Client on the global ServiceContext and binds it to the current thread. All operations executed by the Client will take place on that Client’s associated thread serially over the network connection managed by the Session object that was passed into the Client’s constructor. If no Session is passed to the Client’s constructor, then the Client is assumed to operate on a local database and will perform no network operations. These Clients are sometimes referred to as “local clients”, and are often used when a Mongo service needs to query its own database.

A Client will typically execute multiple operations over the course of its lifetime, spawning an OperationContext for each. Because these operations are executed serially, each Client is associated with up to one OperationContext at any given time.

The Client lock

All Clients have an associated lock which protects their internal state including their currently associated OperationContext from concurrent access. Any mutation to a Client’s associated OperationContext (or other protected internal state) must take the Client lock before being performed, as an OperationContext can otherwise be killed and destroyed at any time. A Client thread may read its own internal state without taking the Client lock, but must take the Client lock when reading another Client thread's internal state. Only a Client's owning thread may write to its Client's internal state, and must take the lock when doing so. Clients implement the standard lockable interface (lock(), unlock(), and try_lock()) to support these operations. The semantics of the Client lock are summarized in the table below.

Internal state Client-owning thread Other threads
reads always allowed lock required
writes lock required never allowed

Client thread manipulation

Client::cc() may be used to get the Client object associated with the currently executing thread. Prefer passing Client objects as parameters over calls to Client::cc() when possible. A ThreadClient is an RAII-style class which may be used to construct and bind a Client to the current running thread and automatically unbind it once the ThreadClient goes out of scope. An AlternativeClientRegion is another RAII-style class which may be used to temporarily bind a Client object to the currently running thread (holding any currently bound Client in reserve), rebinding the current thread’s old Client to the current thread upon falling out of scope. ClientStrand functions similarly, but also provides an Executor interface for binding a Client to an arbitrary thread.

Each operation that executes on a Mongo server (e.g., a query or a command) is managed by its own OperationContext. An OperationContext shepherds an operation’s execution from its inception to either completion or cancellation. Cancellation may be triggered externally, such as from the controlling ServiceContext on a primary step-down, or from a user-issued killOp command; or internally, e.g., when an operation’s deadline has expired. Every OperationContext is associated with a single Client, which manages the logical connection to the database over which the operation will actually be executed. OperationContexts are also optionally associated with a Baton, which represents a thread of execution on which networking operations can be performed asynchronously.

Interruptibility

OperationContexts implement the Interruptible interface, which allows them to be killed by their associated Clients (or, by proxy, their owning ServiceContext). See this comment block for more details on when and how OperationContexts are interrupted.