void NetworkInterfaceMock::startCommand(const TaskExecutor::CallbackHandle& cbHandle, const RemoteCommandRequest& request, const RemoteCommandCompletionFn& onFinish) { stdx::lock_guard<stdx::mutex> lk(_mutex); invariant(!_inShutdown); const Date_t now = _now_inlock(); NetworkOperationIterator insertBefore = _unscheduled.begin(); while ((insertBefore != _unscheduled.end()) && (insertBefore->getNextConsiderationDate() <= now)) { ++insertBefore; } _unscheduled.insert(insertBefore, NetworkOperation(cbHandle, request, now, onFinish)); }
Status NetworkInterfaceMock::startCommand(const CallbackHandle& cbHandle, RemoteCommandRequest& request, const RemoteCommandCompletionFn& onFinish) { if (inShutdown()) { return {ErrorCodes::ShutdownInProgress, "NetworkInterfaceMock shutdown in progress"}; } stdx::lock_guard<stdx::mutex> lk(_mutex); const Date_t now = _now_inlock(); auto op = NetworkOperation(cbHandle, request, now, onFinish); // If we don't have a hook, or we have already 'connected' to this host, enqueue the op. if (!_hook || _connections.count(request.target)) { _enqueueOperation_inlock(std::move(op)); } else { _connectThenEnqueueOperation_inlock(request.target, std::move(op)); } return Status::OK(); }
void NetworkInterfaceMock::_connectThenEnqueueOperation_inlock(const HostAndPort& target, NetworkOperation&& op) { invariant(_hook); // if there is no hook, we shouldn't even hit this codepath invariant(!_connections.count(target)); auto handshakeReplyIter = _handshakeReplies.find(target); auto handshakeReply = (handshakeReplyIter != std::end(_handshakeReplies)) ? handshakeReplyIter->second : RemoteCommandResponse(BSONObj(), BSONObj(), Milliseconds(0)); auto valid = _hook->validateHost(target, handshakeReply); if (!valid.isOK()) { op.setResponse(_now_inlock(), valid); op.finishResponse(); return; } auto swHookPostconnectCommand = _hook->makeRequest(target); if (!swHookPostconnectCommand.isOK()) { op.setResponse(_now_inlock(), swHookPostconnectCommand.getStatus()); op.finishResponse(); return; } boost::optional<RemoteCommandRequest> hookPostconnectCommand = std::move(swHookPostconnectCommand.getValue()); if (!hookPostconnectCommand) { // If we don't have a post connect command, enqueue the actual command. _enqueueOperation_inlock(std::move(op)); _connections.emplace(op.getRequest().target); return; } // The completion handler for the postconnect command schedules the original command. auto postconnectCompletionHandler = [this, op](ResponseStatus rs) mutable { stdx::lock_guard<stdx::mutex> lk(_mutex); if (!rs.isOK()) { op.setResponse(_now_inlock(), rs); op.finishResponse(); return; } auto handleStatus = _hook->handleReply(op.getRequest().target, std::move(rs)); if (!handleStatus.isOK()) { op.setResponse(_now_inlock(), handleStatus); op.finishResponse(); return; } _enqueueOperation_inlock(std::move(op)); _connections.emplace(op.getRequest().target); }; auto postconnectOp = NetworkOperation(op.getCallbackHandle(), std::move(*hookPostconnectCommand), _now_inlock(), std::move(postconnectCompletionHandler)); _enqueueOperation_inlock(std::move(postconnectOp)); }