summaryrefslogtreecommitdiff
path: root/src/mongo/executor/network_interface_mock.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/executor/network_interface_mock.h')
-rw-r--r--src/mongo/executor/network_interface_mock.h549
1 files changed, 277 insertions, 272 deletions
diff --git a/src/mongo/executor/network_interface_mock.h b/src/mongo/executor/network_interface_mock.h
index ff16f8eff6a..910566aa375 100644
--- a/src/mongo/executor/network_interface_mock.h
+++ b/src/mongo/executor/network_interface_mock.h
@@ -39,286 +39,291 @@
namespace mongo {
namespace executor {
+/**
+ * Mock network implementation for use in unit tests.
+ *
+ * To use, construct a new instance on the heap, and keep a pointer to it. Pass
+ * the pointer to the instance into the TaskExecutor constructor, transferring
+ * ownership. Start the executor's run() method in a separate thread, schedule the
+ * work you want to test into the executor, then while the test is still going, iterate
+ * through the ready network requests, servicing them and advancing time as needed.
+ *
+ * The mock has a fully virtualized notion of time and the the network. When the
+ * executor under test schedules a network operation, the startCommand
+ * method of this class adds an entry to the _unscheduled queue for immediate consideration.
+ * The test driver loop, when it examines the request, may schedule a response, ask the
+ * interface to redeliver the request at a later virtual time, or to swallow the virtual
+ * request until the end of the simulation. The test driver loop can also instruct the
+ * interface to run forward through virtual time until there are operations ready to
+ * consider, via runUntil.
+ *
+ * The thread acting as the "network" and the executor run thread are highly synchronized
+ * by this code, allowing for deterministic control of operation interleaving.
+ */
+class NetworkInterfaceMock : public NetworkInterface {
+public:
+ class NetworkOperation;
+ typedef stdx::list<NetworkOperation> NetworkOperationList;
+ typedef NetworkOperationList::iterator NetworkOperationIterator;
+
+ NetworkInterfaceMock();
+ virtual ~NetworkInterfaceMock();
+ virtual std::string getDiagnosticString();
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // NetworkInterface methods
+ //
+ ////////////////////////////////////////////////////////////////////////////////
+
+ virtual void startup();
+ virtual void shutdown();
+ virtual void waitForWork();
+ virtual void waitForWorkUntil(Date_t when);
+ virtual void signalWorkAvailable();
+ virtual Date_t now();
+ virtual void startCommand(const TaskExecutor::CallbackHandle& cbHandle,
+ const RemoteCommandRequest& request,
+ const RemoteCommandCompletionFn& onFinish);
+ virtual void cancelCommand(const TaskExecutor::CallbackHandle& cbHandle);
+
+
+ ////////////////////////////////////////////////////////////////////////////////
+ //
+ // Methods for simulating network operations and the passage of time.
+ //
+ // Methods in this section are to be called by the thread currently simulating
+ // the network.
+ //
+ ////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Causes the currently running (non-executor) thread to assume the mantle of the network
+ * simulation thread.
+ *
+ * Call this before calling any of the other methods in this section.
+ */
+ void enterNetwork();
+
+ /**
+ * Causes the currently running thread to drop the mantle of "network simulation thread".
+ *
+ * Call this before calling any methods that might block waiting for the
+ * executor thread.
+ */
+ void exitNetwork();
+
+ /**
+ * Returns true if there are unscheduled network requests to be processed.
+ */
+ bool hasReadyRequests();
+
+ /**
+ * Gets the next unscheduled request to process, blocking until one is available.
+ *
+ * Will not return until the executor thread is blocked in waitForWorkUntil or waitForWork.
+ */
+ NetworkOperationIterator getNextReadyRequest();
+
+ /**
+ * Schedules "response" in response to "noi" at virtual time "when".
+ */
+ void scheduleResponse(NetworkOperationIterator noi,
+ Date_t when,
+ const TaskExecutor::ResponseStatus& response);
+
+ /**
+ * Swallows "noi", causing the network interface to not respond to it until
+ * shutdown() is called.
+ */
+ void blackHole(NetworkOperationIterator noi);
+
+ /**
+ * Defers decision making on "noi" until virtual time "dontAskUntil". Use
+ * this when getNextReadyRequest() returns a request you want to deal with
+ * after looking at other requests.
+ */
+ void requeueAt(NetworkOperationIterator noi, Date_t dontAskUntil);
+
/**
- * Mock network implementation for use in unit tests.
+ * Runs the simulator forward until now() == until or hasReadyRequests() is true.
*
- * To use, construct a new instance on the heap, and keep a pointer to it. Pass
- * the pointer to the instance into the TaskExecutor constructor, transferring
- * ownership. Start the executor's run() method in a separate thread, schedule the
- * work you want to test into the executor, then while the test is still going, iterate
- * through the ready network requests, servicing them and advancing time as needed.
+ * Will not return until the executor thread is blocked in waitForWorkUntil or waitForWork.
+ */
+ void runUntil(Date_t until);
+
+ /**
+ * Processes all ready, scheduled network operations.
*
- * The mock has a fully virtualized notion of time and the the network. When the
- * executor under test schedules a network operation, the startCommand
- * method of this class adds an entry to the _unscheduled queue for immediate consideration.
- * The test driver loop, when it examines the request, may schedule a response, ask the
- * interface to redeliver the request at a later virtual time, or to swallow the virtual
- * request until the end of the simulation. The test driver loop can also instruct the
- * interface to run forward through virtual time until there are operations ready to
- * consider, via runUntil.
+ * Will not return until the executor thread is blocked in waitForWorkUntil or waitForWork.
+ */
+ void runReadyNetworkOperations();
+
+private:
+ /**
+ * Type used to identify which thread (network mock or executor) is currently executing.
*
- * The thread acting as the "network" and the executor run thread are highly synchronized
- * by this code, allowing for deterministic control of operation interleaving.
+ * Values are used in a bitmask, as well.
+ */
+ enum ThreadType { kNoThread = 0, kExecutorThread = 1, kNetworkThread = 2 };
+
+ /**
+ * Returns the current virtualized time.
+ */
+ Date_t _now_inlock() const {
+ return _now;
+ }
+
+ /**
+ * Implementation of waitForWork*.
+ */
+ void _waitForWork_inlock(stdx::unique_lock<stdx::mutex>* lk);
+
+ /**
+ * Returns true if there are ready requests for the network thread to service.
+ */
+ bool _hasReadyRequests_inlock();
+
+ /**
+ * Returns true if the network thread could run right now.
+ */
+ bool _isNetworkThreadRunnable_inlock();
+
+ /**
+ * Returns true if the executor thread could run right now.
+ */
+ bool _isExecutorThreadRunnable_inlock();
+
+ /**
+ * Runs all ready network operations, called while holding "lk". May drop and
+ * reaquire "lk" several times, but will not return until the executor has blocked
+ * in waitFor*.
+ */
+ void _runReadyNetworkOperations_inlock(stdx::unique_lock<stdx::mutex>* lk);
+
+ // Mutex that synchronizes access to mutable data in this class and its subclasses.
+ // Fields guarded by the mutex are labled (M), below, and those that are read-only
+ // in multi-threaded execution, and so unsynchronized, are labeled (R).
+ stdx::mutex _mutex;
+
+ // Condition signaled to indicate that the network processing thread should wake up.
+ stdx::condition_variable _shouldWakeNetworkCondition; // (M)
+
+ // Condition signaled to indicate that the executor run thread should wake up.
+ stdx::condition_variable _shouldWakeExecutorCondition; // (M)
+
+ // Bitmask indicating which threads are runnable.
+ int _waitingToRunMask; // (M)
+
+ // Indicator of which thread, if any, is currently running.
+ ThreadType _currentlyRunning; // (M)
+
+ // The current time reported by this instance of NetworkInterfaceMock.
+ Date_t _now; // (M)
+
+ // Set to true by "startUp()"
+ bool _hasStarted; // (M)
+
+ // Set to true by "shutDown()".
+ bool _inShutdown; // (M)
+
+ // Next date that the executor expects to wake up at (due to a scheduleWorkAt() call).
+ Date_t _executorNextWakeupDate; // (M)
+
+ // List of network operations whose responses haven't been scheduled or blackholed. This is
+ // where network requests are first queued. It is sorted by
+ // NetworkOperation::_nextConsiderationDate, which is set to now() when startCommand() is
+ // called, and adjusted by requeueAt().
+ NetworkOperationList _unscheduled; // (M)
+
+ // List of network operations that have been returned by getNextReadyRequest() but not
+ // yet scheudled, black-holed or requeued.
+ NetworkOperationList _processing; // (M)
+
+ // List of network operations whose responses have been scheduled but not delivered, sorted
+ // by NetworkOperation::_responseDate. These operations will have their responses delivered
+ // when now() == getResponseDate().
+ NetworkOperationList _scheduled; // (M)
+
+ // List of network operations that will not be responded to until shutdown() is called.
+ NetworkOperationList _blackHoled; // (M)
+};
+
+/**
+ * Representation of an in-progress network operation.
+ */
+class NetworkInterfaceMock::NetworkOperation {
+public:
+ NetworkOperation();
+ NetworkOperation(const TaskExecutor::CallbackHandle& cbHandle,
+ const RemoteCommandRequest& theRequest,
+ Date_t theRequestDate,
+ const RemoteCommandCompletionFn& onFinish);
+ ~NetworkOperation();
+
+ /**
+ * Adjusts the stored virtual time at which this entry will be subject to consideration
+ * by the test harness.
+ */
+ void setNextConsiderationDate(Date_t nextConsiderationDate);
+
+ /**
+ * Sets the response and thet virtual time at which it will be delivered.
+ */
+ void setResponse(Date_t responseDate, const TaskExecutor::ResponseStatus& response);
+
+ /**
+ * Predicate that returns true if cbHandle equals the executor's handle for this network
+ * operation. Used for searching lists of NetworkOperations.
+ */
+ bool isForCallback(const TaskExecutor::CallbackHandle& cbHandle) const {
+ return cbHandle == _cbHandle;
+ }
+
+ /**
+ * Gets the request that initiated this operation.
+ */
+ const RemoteCommandRequest& getRequest() const {
+ return _request;
+ }
+
+ /**
+ * Gets the virtual time at which the operation was started.
+ */
+ Date_t getRequestDate() const {
+ return _requestDate;
+ }
+
+ /**
+ * Gets the virtual time at which the test harness should next consider what to do
+ * with this request.
+ */
+ Date_t getNextConsiderationDate() const {
+ return _nextConsiderationDate;
+ }
+
+ /**
+ * After setResponse() has been called, returns the virtual time at which
+ * the response should be delivered.
*/
- class NetworkInterfaceMock : public NetworkInterface {
- public:
- class NetworkOperation;
- typedef stdx::list<NetworkOperation> NetworkOperationList;
- typedef NetworkOperationList::iterator NetworkOperationIterator;
-
- NetworkInterfaceMock();
- virtual ~NetworkInterfaceMock();
- virtual std::string getDiagnosticString();
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // NetworkInterface methods
- //
- ////////////////////////////////////////////////////////////////////////////////
-
- virtual void startup();
- virtual void shutdown();
- virtual void waitForWork();
- virtual void waitForWorkUntil(Date_t when);
- virtual void signalWorkAvailable();
- virtual Date_t now();
- virtual void startCommand(const TaskExecutor::CallbackHandle& cbHandle,
- const RemoteCommandRequest& request,
- const RemoteCommandCompletionFn& onFinish);
- virtual void cancelCommand(const TaskExecutor::CallbackHandle& cbHandle);
-
-
- ////////////////////////////////////////////////////////////////////////////////
- //
- // Methods for simulating network operations and the passage of time.
- //
- // Methods in this section are to be called by the thread currently simulating
- // the network.
- //
- ////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Causes the currently running (non-executor) thread to assume the mantle of the network
- * simulation thread.
- *
- * Call this before calling any of the other methods in this section.
- */
- void enterNetwork();
-
- /**
- * Causes the currently running thread to drop the mantle of "network simulation thread".
- *
- * Call this before calling any methods that might block waiting for the
- * executor thread.
- */
- void exitNetwork();
-
- /**
- * Returns true if there are unscheduled network requests to be processed.
- */
- bool hasReadyRequests();
-
- /**
- * Gets the next unscheduled request to process, blocking until one is available.
- *
- * Will not return until the executor thread is blocked in waitForWorkUntil or waitForWork.
- */
- NetworkOperationIterator getNextReadyRequest();
-
- /**
- * Schedules "response" in response to "noi" at virtual time "when".
- */
- void scheduleResponse(
- NetworkOperationIterator noi,
- Date_t when,
- const TaskExecutor::ResponseStatus& response);
-
- /**
- * Swallows "noi", causing the network interface to not respond to it until
- * shutdown() is called.
- */
- void blackHole(NetworkOperationIterator noi);
-
- /**
- * Defers decision making on "noi" until virtual time "dontAskUntil". Use
- * this when getNextReadyRequest() returns a request you want to deal with
- * after looking at other requests.
- */
- void requeueAt(NetworkOperationIterator noi, Date_t dontAskUntil);
-
- /**
- * Runs the simulator forward until now() == until or hasReadyRequests() is true.
- *
- * Will not return until the executor thread is blocked in waitForWorkUntil or waitForWork.
- */
- void runUntil(Date_t until);
-
- /**
- * Processes all ready, scheduled network operations.
- *
- * Will not return until the executor thread is blocked in waitForWorkUntil or waitForWork.
- */
- void runReadyNetworkOperations();
-
- private:
- /**
- * Type used to identify which thread (network mock or executor) is currently executing.
- *
- * Values are used in a bitmask, as well.
- */
- enum ThreadType {
- kNoThread = 0,
- kExecutorThread = 1,
- kNetworkThread = 2
- };
-
- /**
- * Returns the current virtualized time.
- */
- Date_t _now_inlock() const { return _now; }
-
- /**
- * Implementation of waitForWork*.
- */
- void _waitForWork_inlock(stdx::unique_lock<stdx::mutex>* lk);
-
- /**
- * Returns true if there are ready requests for the network thread to service.
- */
- bool _hasReadyRequests_inlock();
-
- /**
- * Returns true if the network thread could run right now.
- */
- bool _isNetworkThreadRunnable_inlock();
-
- /**
- * Returns true if the executor thread could run right now.
- */
- bool _isExecutorThreadRunnable_inlock();
-
- /**
- * Runs all ready network operations, called while holding "lk". May drop and
- * reaquire "lk" several times, but will not return until the executor has blocked
- * in waitFor*.
- */
- void _runReadyNetworkOperations_inlock(stdx::unique_lock<stdx::mutex>* lk);
-
- // Mutex that synchronizes access to mutable data in this class and its subclasses.
- // Fields guarded by the mutex are labled (M), below, and those that are read-only
- // in multi-threaded execution, and so unsynchronized, are labeled (R).
- stdx::mutex _mutex;
-
- // Condition signaled to indicate that the network processing thread should wake up.
- stdx::condition_variable _shouldWakeNetworkCondition; // (M)
-
- // Condition signaled to indicate that the executor run thread should wake up.
- stdx::condition_variable _shouldWakeExecutorCondition; // (M)
-
- // Bitmask indicating which threads are runnable.
- int _waitingToRunMask; // (M)
-
- // Indicator of which thread, if any, is currently running.
- ThreadType _currentlyRunning; // (M)
-
- // The current time reported by this instance of NetworkInterfaceMock.
- Date_t _now; // (M)
-
- // Set to true by "startUp()"
- bool _hasStarted; // (M)
-
- // Set to true by "shutDown()".
- bool _inShutdown; // (M)
-
- // Next date that the executor expects to wake up at (due to a scheduleWorkAt() call).
- Date_t _executorNextWakeupDate; // (M)
-
- // List of network operations whose responses haven't been scheduled or blackholed. This is
- // where network requests are first queued. It is sorted by
- // NetworkOperation::_nextConsiderationDate, which is set to now() when startCommand() is
- // called, and adjusted by requeueAt().
- NetworkOperationList _unscheduled; // (M)
-
- // List of network operations that have been returned by getNextReadyRequest() but not
- // yet scheudled, black-holed or requeued.
- NetworkOperationList _processing; // (M)
-
- // List of network operations whose responses have been scheduled but not delivered, sorted
- // by NetworkOperation::_responseDate. These operations will have their responses delivered
- // when now() == getResponseDate().
- NetworkOperationList _scheduled; // (M)
-
- // List of network operations that will not be responded to until shutdown() is called.
- NetworkOperationList _blackHoled; // (M)
- };
+ Date_t getResponseDate() const {
+ return _responseDate;
+ }
/**
- * Representation of an in-progress network operation.
+ * Delivers the response, by invoking the onFinish callback passed into the constructor.
*/
- class NetworkInterfaceMock::NetworkOperation {
- public:
- NetworkOperation();
- NetworkOperation(const TaskExecutor::CallbackHandle& cbHandle,
- const RemoteCommandRequest& theRequest,
- Date_t theRequestDate,
- const RemoteCommandCompletionFn& onFinish);
- ~NetworkOperation();
-
- /**
- * Adjusts the stored virtual time at which this entry will be subject to consideration
- * by the test harness.
- */
- void setNextConsiderationDate(Date_t nextConsiderationDate);
-
- /**
- * Sets the response and thet virtual time at which it will be delivered.
- */
- void setResponse(Date_t responseDate, const TaskExecutor::ResponseStatus& response);
-
- /**
- * Predicate that returns true if cbHandle equals the executor's handle for this network
- * operation. Used for searching lists of NetworkOperations.
- */
- bool isForCallback(const TaskExecutor::CallbackHandle& cbHandle) const {
- return cbHandle == _cbHandle;
- }
-
- /**
- * Gets the request that initiated this operation.
- */
- const RemoteCommandRequest& getRequest() const { return _request; }
-
- /**
- * Gets the virtual time at which the operation was started.
- */
- Date_t getRequestDate() const { return _requestDate; }
-
- /**
- * Gets the virtual time at which the test harness should next consider what to do
- * with this request.
- */
- Date_t getNextConsiderationDate() const { return _nextConsiderationDate; }
-
- /**
- * After setResponse() has been called, returns the virtual time at which
- * the response should be delivered.
- */
- Date_t getResponseDate() const { return _responseDate; }
-
- /**
- * Delivers the response, by invoking the onFinish callback passed into the constructor.
- */
- void finishResponse();
-
- private:
- Date_t _requestDate;
- Date_t _nextConsiderationDate;
- Date_t _responseDate;
- TaskExecutor::CallbackHandle _cbHandle;
- RemoteCommandRequest _request;
- TaskExecutor::ResponseStatus _response;
- RemoteCommandCompletionFn _onFinish;
- };
+ void finishResponse();
+
+private:
+ Date_t _requestDate;
+ Date_t _nextConsiderationDate;
+ Date_t _responseDate;
+ TaskExecutor::CallbackHandle _cbHandle;
+ RemoteCommandRequest _request;
+ TaskExecutor::ResponseStatus _response;
+ RemoteCommandCompletionFn _onFinish;
+};
} // namespace executor
} // namespace mongo