1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <boost/optional.hpp> 34 35 #include "mongo/bson/bsonobj.h" 36 #include "mongo/client/connection_string.h" 37 #include "mongo/client/read_preference.h" 38 #include "mongo/db/namespace_string.h" 39 #include "mongo/db/repl/optime.h" 40 #include "mongo/db/repl/read_concern_args.h" 41 #include "mongo/executor/remote_command_response.h" 42 #include "mongo/s/shard_id.h" 43 44 namespace mongo { 45 46 class BatchedCommandRequest; 47 class BatchedCommandResponse; 48 class OperationContext; 49 class RemoteCommandTargeter; 50 51 /** 52 * Presents an interface for talking to shards, regardless of whether that shard is remote or is 53 * the current (local) shard. 54 */ 55 class Shard { 56 public: 57 struct CommandResponse { CommandResponseCommandResponse58 CommandResponse(boost::optional<HostAndPort> hostAndPort, 59 BSONObj response, 60 BSONObj metadata, 61 Status commandStatus, 62 Status writeConcernStatus) 63 : hostAndPort(std::move(hostAndPort)), 64 response(std::move(response)), 65 metadata(std::move(metadata)), 66 commandStatus(std::move(commandStatus)), 67 writeConcernStatus(std::move(writeConcernStatus)) {} 68 69 /** 70 * Takes the response from running a batch write command and writes the appropriate response 71 * into batchResponse, while also returning the Status of the operation. 72 */ 73 static Status processBatchWriteResponse(StatusWith<CommandResponse> response, 74 BatchedCommandResponse* batchResponse); 75 76 boost::optional<HostAndPort> hostAndPort; 77 BSONObj response; 78 BSONObj metadata; 79 Status commandStatus; 80 Status writeConcernStatus; 81 }; 82 83 struct QueryResponse { 84 std::vector<BSONObj> docs; 85 repl::OpTime opTime; 86 }; 87 88 enum class RetryPolicy { 89 kIdempotent, 90 kNotIdempotent, 91 kNoRetry, 92 }; 93 94 virtual ~Shard() = default; 95 getId()96 const ShardId& getId() const { 97 return _id; 98 } 99 100 /** 101 * Returns true if this shard object represents the config server. 102 */ 103 bool isConfig() const; 104 105 /** 106 * Returns the current connection string for the shard. 107 */ 108 virtual const ConnectionString getConnString() const = 0; 109 110 /** 111 * Returns the connection string that was used to create the Shard from the ShardFactory. The 112 * current connection string may be different. 113 * NOTE: Chances are this isn't the method you want. When in doubt, prefer to use 114 * getConnString() instead. 115 */ 116 virtual const ConnectionString originalConnString() const = 0; 117 118 /** 119 * Returns the RemoteCommandTargeter for the hosts in this shard. 120 * 121 * This is only valid to call on ShardRemote instances. 122 */ 123 virtual std::shared_ptr<RemoteCommandTargeter> getTargeter() const = 0; 124 125 /** 126 * Notifies the RemoteCommandTargeter owned by the shard of a particular mode of failure for 127 * the specified host. 128 * 129 * This is only valid to call on ShardRemote instances. 130 */ 131 virtual void updateReplSetMonitor(const HostAndPort& remoteHost, 132 const Status& remoteCommandStatus) = 0; 133 134 /** 135 * Returns a string description of this shard entry. 136 */ 137 virtual std::string toString() const = 0; 138 139 /** 140 * Returns whether a server operation which failed with the given error code should be retried 141 * (i.e. is safe to retry and has the potential to succeed next time). The 'options' argument 142 * describes whether the operation that generated the given code was idempotent, which affects 143 * which codes are safe to retry on. 144 */ 145 virtual bool isRetriableError(ErrorCodes::Error code, RetryPolicy options) = 0; 146 147 /** 148 * Runs the specified command returns the BSON command response plus parsed out Status of this 149 * response and write concern error (if present). Retries failed operations according to the 150 * given "retryPolicy". Retries indefinitely until/unless a non-retriable error is encountered, 151 * the maxTimeMs on the OperationContext expires, or the operation is interrupted. 152 */ 153 StatusWith<CommandResponse> runCommand(OperationContext* opCtx, 154 const ReadPreferenceSetting& readPref, 155 const std::string& dbName, 156 const BSONObj& cmdObj, 157 RetryPolicy retryPolicy); 158 159 /** 160 * Same as the other variant of runCommand, but allows the operation timeout to be overriden. 161 * Runs for the lesser of the remaining time on the operation context or the specified maxTimeMS 162 * override. 163 */ 164 StatusWith<CommandResponse> runCommand(OperationContext* opCtx, 165 const ReadPreferenceSetting& readPref, 166 const std::string& dbName, 167 const BSONObj& cmdObj, 168 Milliseconds maxTimeMSOverride, 169 RetryPolicy retryPolicy); 170 171 /** 172 * Same as runCommand, but will only retry failed operations up to 3 times, regardless of 173 * the retryPolicy or the remaining maxTimeMs. 174 * Wherever possible this method should be avoided in favor of runCommand. 175 */ 176 StatusWith<CommandResponse> runCommandWithFixedRetryAttempts( 177 OperationContext* opCtx, 178 const ReadPreferenceSetting& readPref, 179 const std::string& dbName, 180 const BSONObj& cmdObj, 181 RetryPolicy retryPolicy); 182 183 /** 184 * Same as runCommand, but will only retry failed operations up to 3 times, regardless of 185 * the retryPolicy or the remaining maxTimeMs. 186 * Wherever possible this method should be avoided in favor of runCommand. 187 */ 188 StatusWith<CommandResponse> runCommandWithFixedRetryAttempts( 189 OperationContext* opCtx, 190 const ReadPreferenceSetting& readPref, 191 const std::string& dbName, 192 const BSONObj& cmdObj, 193 Milliseconds maxTimeMSOverride, 194 RetryPolicy retryPolicy); 195 196 /** 197 * Runs a write command against a shard. This is separate from runCommand, because write 198 * commands return errors in a different format than regular commands do, so checking for 199 * retriable errors must be done differently. 200 */ 201 BatchedCommandResponse runBatchWriteCommand(OperationContext* opCtx, 202 const Milliseconds maxTimeMS, 203 const BatchedCommandRequest& batchRequest, 204 RetryPolicy retryPolicy); 205 206 /** 207 * Warning: This method exhausts the cursor and pulls all data into memory. 208 * Do not use other than for very small (i.e., admin or metadata) collections. 209 * Performs retries if the query fails in accordance with the kIdempotent RetryPolicy. 210 * 211 * ShardRemote instances expect "readConcernLevel" to always be kMajorityReadConcern, whereas 212 * ShardLocal instances expect either kLocalReadConcern or kMajorityReadConcern. 213 */ 214 StatusWith<QueryResponse> exhaustiveFindOnConfig(OperationContext* opCtx, 215 const ReadPreferenceSetting& readPref, 216 const repl::ReadConcernLevel& readConcernLevel, 217 const NamespaceString& nss, 218 const BSONObj& query, 219 const BSONObj& sort, 220 const boost::optional<long long> limit); 221 /** 222 * Builds an index on a config server collection. 223 * Creates the collection if it doesn't yet exist. Does not error if the index already exists, 224 * so long as the options are the same. 225 * NOTE: Currently only supported for LocalShard. 226 */ 227 virtual Status createIndexOnConfig(OperationContext* opCtx, 228 const NamespaceString& ns, 229 const BSONObj& keys, 230 bool unique) = 0; 231 232 // This timeout will be used by default in operations against the config server, unless 233 // explicitly overridden 234 static const Milliseconds kDefaultConfigCommandTimeout; 235 236 /** 237 * Returns false if the error is a retriable error and/or causes a replset monitor update. These 238 * errors, if from a remote call, should not be further propagated back to another server 239 * because that server will interpret them as orignating on this server rather than the one this 240 * server called. 241 */ 242 static bool shouldErrorBePropagated(ErrorCodes::Error code); 243 244 protected: 245 Shard(const ShardId& id); 246 247 private: 248 /** 249 * Runs the specified command against the shard backed by this object with a timeout set to the 250 * minimum of maxTimeMSOverride or the timeout of the OperationContext. 251 * 252 * The return value exposes RemoteShard's host for calls to updateReplSetMonitor. 253 * 254 * NOTE: LocalShard implementation will not return a valid host and so should be ignored. 255 */ 256 virtual StatusWith<CommandResponse> _runCommand(OperationContext* opCtx, 257 const ReadPreferenceSetting& readPref, 258 const std::string& dbname, 259 Milliseconds maxTimeMSOverride, 260 const BSONObj& cmdObj) = 0; 261 262 virtual StatusWith<QueryResponse> _exhaustiveFindOnConfig( 263 OperationContext* opCtx, 264 const ReadPreferenceSetting& readPref, 265 const repl::ReadConcernLevel& readConcernLevel, 266 const NamespaceString& nss, 267 const BSONObj& query, 268 const BSONObj& sort, 269 boost::optional<long long> limit) = 0; 270 271 /** 272 * Identifier of the shard as obtained from the configuration data (i.e. shard0000). 273 */ 274 const ShardId _id; 275 }; 276 277 } // namespace mongo 278