diff options
author | Benety Goh <benety@mongodb.com> | 2018-10-25 13:37:44 -0400 |
---|---|---|
committer | Benety Goh <benety@mongodb.com> | 2018-10-25 13:37:44 -0400 |
commit | 7d8df4c73934ef757e4007743ab6b69e3e80b7c2 (patch) | |
tree | c2711ed6a864b24c7c4c0de1b8c5347a87388244 /src/mongo/db/query/plan_executor.h | |
parent | b9db97a9ec5644c00db39a02813e82daa814b692 (diff) | |
download | mongo-7d8df4c73934ef757e4007743ab6b69e3e80b7c2.tar.gz |
SERVER-37589 split PlanExecutor into interface and implementation
Diffstat (limited to 'src/mongo/db/query/plan_executor.h')
-rw-r--r-- | src/mongo/db/query/plan_executor.h | 235 |
1 files changed, 58 insertions, 177 deletions
diff --git a/src/mongo/db/query/plan_executor.h b/src/mongo/db/query/plan_executor.h index b789a0cf338..9c97d30903d 100644 --- a/src/mongo/db/query/plan_executor.h +++ b/src/mongo/db/query/plan_executor.h @@ -31,7 +31,6 @@ #pragma once #include <boost/optional.hpp> -#include <queue> #include "mongo/base/status.h" #include "mongo/db/catalog/util/partitioned.h" @@ -138,6 +137,13 @@ public: }; /** + * RegistrationToken is the type of key used to register this PlanExecutor with the + * CursorManager. + */ + using RegistrationToken = + boost::optional<Partitioned<stdx::unordered_set<PlanExecutor*>>::PartitionId>; + + /** * This class will ensure a PlanExecutor is disposed before it is deleted. */ class Deleter { @@ -146,9 +152,10 @@ public: * Constructs an empty deleter. Useful for creating a * unique_ptr<PlanExecutor, PlanExecutor::Deleter> without populating it. */ - Deleter() {} + Deleter() = default; - Deleter(OperationContext* opCtx, const Collection* collection); + inline Deleter(OperationContext* opCtx, CursorManager* cursorManager) + : _opCtx(opCtx), _cursorManager(cursorManager) {} /** * If an owner of a std::unique_ptr<PlanExecutor, PlanExecutor::Deleter> wants to assume @@ -164,7 +171,19 @@ public: * been registered with the CursorManager, will deregister it. If 'execPtr' is a yielding * PlanExecutor, callers must hold a lock on the collection in at least MODE_IS. */ - void operator()(PlanExecutor* execPtr); + inline void operator()(PlanExecutor* execPtr) { + try { + // It is illegal to invoke operator() on a default constructed Deleter. + invariant(_opCtx); + if (!_dismissed) { + execPtr->dispose(_opCtx, _cursorManager); + } + delete execPtr; + } catch (...) { + std::terminate(); + } + } + private: OperationContext* _opCtx = nullptr; @@ -238,6 +257,13 @@ public: const Collection* collection, YieldPolicy yieldPolicy); + /** + * A PlanExecutor must be disposed before destruction. In most cases, this will happen + * automatically through a PlanExecutor::Deleter or a ClientCursor. + */ + PlanExecutor() = default; + virtual ~PlanExecutor() = default; + // // Accessors // @@ -245,38 +271,27 @@ public: /** * Get the working set used by this executor, without transferring ownership. */ - WorkingSet* getWorkingSet() const; + virtual WorkingSet* getWorkingSet() const = 0; /** * Get the stage tree wrapped by this executor, without transferring ownership. */ - PlanStage* getRootStage() const; + virtual PlanStage* getRootStage() const = 0; /** * Get the query that this executor is executing, without transferring ownership. */ - CanonicalQuery* getCanonicalQuery() const; + virtual CanonicalQuery* getCanonicalQuery() const = 0; /** * Return the NS that the query is running over. */ - const NamespaceString& nss() const { - return _nss; - } + virtual const NamespaceString& nss() const = 0; /** * Return the OperationContext that the plan is currently executing within. */ - OperationContext* getOpCtx() const; - - /** - * Generates a tree of stats objects with a separate lifetime from the execution - * stage tree wrapped by this PlanExecutor. - * - * This may be called without holding any locks. It also may be called on a PlanExecutor that - * has been killed or has produced an error. - */ - std::unique_ptr<PlanStageStats> getStats() const; + virtual OperationContext* getOpCtx() const = 0; // // Methods that just pass down to the PlanStage tree. @@ -288,7 +303,7 @@ public: * While in the "saved" state, it is only legal to call restoreState, * detachFromOperationContext, or the destructor. */ - void saveState(); + virtual void saveState() = 0; /** * Restores the state saved by a saveState() call. @@ -304,7 +319,7 @@ public: * this scenario, locks will have been released, and will not be held when control returns to * the caller. */ - Status restoreState(); + virtual Status restoreState() = 0; /** * Detaches from the OperationContext and releases any storage-engine state. @@ -313,7 +328,7 @@ public: * only legal to call reattachToOperationContext or the destructor. It is not legal to call * detachFromOperationContext() while already in the detached state. */ - void detachFromOperationContext(); + virtual void detachFromOperationContext() = 0; /** * Reattaches to the OperationContext and reacquires any storage-engine state. @@ -321,7 +336,7 @@ public: * It is only legal to call this in the "detached" state. On return, the cursor is left in a * "saved" state, so callers must still call restoreState to use this object. */ - void reattachToOperationContext(OperationContext* opCtx); + virtual void reattachToOperationContext(OperationContext* opCtx) = 0; /** * Same as restoreState but without the logic to retry if a WriteConflictException is @@ -329,7 +344,7 @@ public: * * This is only public for PlanYieldPolicy. DO NOT CALL ANYWHERE ELSE. */ - Status restoreStateWithoutRetrying(); + virtual Status restoreStateWithoutRetrying() = 0; // // Running Support @@ -344,9 +359,9 @@ public: * * If a YIELD_AUTO policy is set, then this method may yield. */ - ExecState getNextSnapshotted(Snapshotted<BSONObj>* objOut, RecordId* dlOut); + virtual ExecState getNextSnapshotted(Snapshotted<BSONObj>* objOut, RecordId* dlOut) = 0; - ExecState getNext(BSONObj* objOut, RecordId* dlOut); + virtual ExecState getNext(BSONObj* objOut, RecordId* dlOut) = 0; /** * Returns 'true' if the plan is done producing results (or writing), 'false' otherwise. @@ -354,7 +369,7 @@ public: * Tailable cursors are a possible exception to this: they may have further results even if * isEOF() returns true. */ - bool isEOF(); + virtual bool isEOF() = 0; /** * Execute the plan to completion, throwing out the results. Used when you want to work the @@ -366,7 +381,7 @@ public: * error occurs, it is illegal to subsequently access the collection, since it may have been * dropped. */ - Status executePlan(); + virtual Status executePlan() = 0; // // Concurrency-related methods. @@ -380,7 +395,7 @@ public: * method is called multiple times, only the first 'killStatus' will be retained. It is an error * to call this method with Status::OK. */ - void markAsKilled(Status killStatus); + virtual void markAsKilled(Status killStatus) = 0; /** * Cleans up any state associated with this PlanExecutor. Must be called before deleting this @@ -395,7 +410,7 @@ public: * is the owner's responsibility to call dispose() with a valid OperationContext before * deleting the PlanExecutor. */ - void dispose(OperationContext* opCtx, CursorManager* cursorManager); + virtual void dispose(OperationContext* opCtx, CursorManager* cursorManager) = 0; /** * Helper method to aid in displaying an ExecState for debug or other recreational purposes. @@ -414,173 +429,39 @@ public: * If used in combination with getNextSnapshotted(), then the SnapshotId associated with * 'obj' will be null when 'obj' is dequeued. */ - void enqueue(const BSONObj& obj); + virtual void enqueue(const BSONObj& obj) = 0; /** * Helper method which returns a set of BSONObj, where each represents a sort order of our * output. */ - BSONObjSet getOutputSorts() const; + virtual BSONObjSet getOutputSorts() const = 0; /** * Communicate to this PlanExecutor that it is no longer registered with the CursorManager as a * 'non-cached PlanExecutor'. */ - void unsetRegistered() { - _registrationToken.reset(); - } - - boost::optional<Partitioned<stdx::unordered_set<PlanExecutor*>>::PartitionId> - getRegistrationToken() const& { - return _registrationToken; - } + virtual void unsetRegistered() = 0; + virtual RegistrationToken getRegistrationToken() const& = 0; void getRegistrationToken() && = delete; + virtual void setRegistrationToken(RegistrationToken token) & = 0; - void setRegistrationToken( - Partitioned<stdx::unordered_set<PlanExecutor*>>::PartitionId token) & { - invariant(!_registrationToken); - _registrationToken = token; - } - - bool isMarkedAsKilled() const { - return !_killStatus.isOK(); - } - - Status getKillStatus() { - invariant(isMarkedAsKilled()); - return _killStatus; - } + virtual bool isMarkedAsKilled() const = 0; + virtual Status getKillStatus() = 0; - bool isDisposed() const { - return _currentState == kDisposed; - } - - bool isDetached() const { - return _currentState == kDetached; - } + virtual bool isDisposed() const = 0; + virtual bool isDetached() const = 0; /** * If the last oplog timestamp is being tracked for this PlanExecutor, return it. * Otherwise return a null timestamp. */ - Timestamp getLatestOplogTimestamp(); - -private: - /** - * Returns true if the PlanExecutor should listen for inserts, which is when a getMore is called - * on a tailable and awaitData cursor that still has time left and hasn't been interrupted. - */ - bool shouldListenForInserts(); - - /** - * Returns true if the PlanExecutor should wait for data to be inserted, which is when a getMore - * is called on a tailable and awaitData cursor on a capped collection. Returns false if an EOF - * should be returned immediately. - */ - bool shouldWaitForInserts(); - - /** - * Gets the CappedInsertNotifier for a capped collection. Returns nullptr if this plan executor - * is not capable of yielding based on a notifier. - */ - std::shared_ptr<CappedInsertNotifier> getCappedInsertNotifier(); - - /** - * Yields locks and waits for inserts to the collection. Returns ADVANCED if there has been an - * insertion and there may be new results. Returns DEAD if the PlanExecutor was killed during a - * yield. This method is only to be used for tailable and awaitData cursors, so rather than - * returning DEAD if the operation has exceeded its time limit, we return IS_EOF to preserve - * this PlanExecutor for future use. - * - * If an error is encountered and 'errorObj' is provided, it is populated with an object - * describing the error. - */ - ExecState waitForInserts(CappedInsertNotifierData* notifierData, - Snapshotted<BSONObj>* errorObj); - - ExecState getNextImpl(Snapshotted<BSONObj>* objOut, RecordId* dlOut); + virtual Timestamp getLatestOplogTimestamp() = 0; /** - * New PlanExecutor instances are created with the static make() methods above. + * Turns a BSONObj representing an error status produced by getNext() into a Status. */ - PlanExecutor(OperationContext* opCtx, - std::unique_ptr<WorkingSet> ws, - std::unique_ptr<PlanStage> rt, - std::unique_ptr<QuerySolution> qs, - std::unique_ptr<CanonicalQuery> cq, - const Collection* collection, - NamespaceString nss, - YieldPolicy yieldPolicy); - - /** - * A PlanExecutor must be disposed before destruction. In most cases, this will happen - * automatically through a PlanExecutor::Deleter or a ClientCursor. - */ - ~PlanExecutor(); - - /** - * Public factory methods delegate to this private factory to do their work. - */ - static StatusWith<std::unique_ptr<PlanExecutor, PlanExecutor::Deleter>> make( - OperationContext* opCtx, - std::unique_ptr<WorkingSet> ws, - std::unique_ptr<PlanStage> rt, - std::unique_ptr<QuerySolution> qs, - std::unique_ptr<CanonicalQuery> cq, - const Collection* collection, - NamespaceString nss, - YieldPolicy yieldPolicy); - - /** - * Clients of PlanExecutor expect that on receiving a new instance from one of the make() - * factory methods, plan selection has already been completed. In order to enforce this - * property, this function is called to do plan selection prior to returning the new - * PlanExecutor. - * - * If the tree contains plan selection stages, such as MultiPlanStage or SubplanStage, - * this calls into their underlying plan selection facilities. Otherwise, does nothing. - * - * If a YIELD_AUTO policy is set then locks are yielded during plan selection. - * - * Returns a non-OK status if query planning fails. In particular, this function returns - * ErrorCodes::QueryPlanKilled if plan execution cannot proceed due to a concurrent write or - * catalog operation. - */ - Status pickBestPlan(const Collection* collection); - - // The OperationContext that we're executing within. This can be updated if necessary by using - // detachFromOperationContext() and reattachToOperationContext(). - OperationContext* _opCtx; - - std::unique_ptr<CanonicalQuery> _cq; - std::unique_ptr<WorkingSet> _workingSet; - std::unique_ptr<QuerySolution> _qs; - std::unique_ptr<PlanStage> _root; - - // If _killStatus has a non-OK value, then we have been killed and the value represents the - // reason for the kill. - Status _killStatus = Status::OK(); - - // What namespace are we operating over? - NamespaceString _nss; - - // This is used to handle automatic yielding when allowed by the YieldPolicy. Never NULL. - // TODO make this a non-pointer member. This requires some header shuffling so that this - // file includes plan_yield_policy.h rather than the other way around. - const std::unique_ptr<PlanYieldPolicy> _yieldPolicy; - - // A stash of results generated by this plan that the user of the PlanExecutor didn't want - // to consume yet. We empty the queue before retrieving further results from the plan - // stages. - std::queue<BSONObj> _stash; - - enum { kUsable, kSaved, kDetached, kDisposed } _currentState = kUsable; - - // Set if this PlanExecutor is registered with the CursorManager. - boost::optional<Partitioned<stdx::unordered_set<PlanExecutor*>>::PartitionId> - _registrationToken; - - bool _everDetachedFromOperationContext = false; + virtual Status getMemberObjectStatus(const BSONObj& memberObj) const = 0; }; } // namespace mongo |