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 <cstdint> 34 35 #include "mongo/base/string_data.h" 36 #include "mongo/client/connection_string.h" 37 #include "mongo/client/index_spec.h" 38 #include "mongo/client/mongo_uri.h" 39 #include "mongo/client/query.h" 40 #include "mongo/client/read_preference.h" 41 #include "mongo/db/dbmessage.h" 42 #include "mongo/db/jsobj.h" 43 #include "mongo/db/write_concern_options.h" 44 #include "mongo/platform/atomic_word.h" 45 #include "mongo/rpc/metadata.h" 46 #include "mongo/rpc/protocol.h" 47 #include "mongo/rpc/unique_message.h" 48 #include "mongo/stdx/functional.h" 49 #include "mongo/transport/message_compressor_manager.h" 50 #include "mongo/util/mongoutils/str.h" 51 #include "mongo/util/net/abstract_message_port.h" 52 #include "mongo/util/net/message.h" 53 #include "mongo/util/net/op_msg.h" 54 55 namespace mongo { 56 57 namespace executor { 58 struct RemoteCommandResponse; 59 } 60 61 class DBClientCursor; 62 class DBClientCursorBatchIterator; 63 64 /** 65 * Represents a full query description, including all options required for the query to be passed on 66 * to other hosts 67 */ 68 class QuerySpec { 69 std::string _ns; 70 int _ntoskip; 71 int _ntoreturn; 72 int _options; 73 BSONObj _query; 74 BSONObj _fields; 75 Query _queryObj; 76 77 public: QuerySpec(const std::string & ns,const BSONObj & query,const BSONObj & fields,int ntoskip,int ntoreturn,int options)78 QuerySpec(const std::string& ns, 79 const BSONObj& query, 80 const BSONObj& fields, 81 int ntoskip, 82 int ntoreturn, 83 int options) 84 : _ns(ns), 85 _ntoskip(ntoskip), 86 _ntoreturn(ntoreturn), 87 _options(options), 88 _query(query.getOwned()), 89 _fields(fields.getOwned()), 90 _queryObj(_query) {} 91 QuerySpec()92 QuerySpec() {} 93 isEmpty()94 bool isEmpty() const { 95 return _ns.size() == 0; 96 } 97 isExplain()98 bool isExplain() const { 99 return _queryObj.isExplain(); 100 } filter()101 BSONObj filter() const { 102 return _queryObj.getFilter(); 103 } 104 hint()105 BSONObj hint() const { 106 return _queryObj.getHint(); 107 } sort()108 BSONObj sort() const { 109 return _queryObj.getSort(); 110 } query()111 BSONObj query() const { 112 return _query; 113 } fields()114 BSONObj fields() const { 115 return _fields; 116 } fieldsData()117 BSONObj* fieldsData() { 118 return &_fields; 119 } 120 121 // don't love this, but needed downstrem fieldsPtr()122 const BSONObj* fieldsPtr() const { 123 return &_fields; 124 } 125 ns()126 std::string ns() const { 127 return _ns; 128 } ntoskip()129 int ntoskip() const { 130 return _ntoskip; 131 } ntoreturn()132 int ntoreturn() const { 133 return _ntoreturn; 134 } options()135 int options() const { 136 return _options; 137 } 138 setFields(BSONObj & o)139 void setFields(BSONObj& o) { 140 _fields = o.getOwned(); 141 } 142 toString()143 std::string toString() const { 144 return str::stream() << "QSpec " 145 << BSON("ns" << _ns << "n2skip" << _ntoskip << "n2return" << _ntoreturn 146 << "options" 147 << _options 148 << "query" 149 << _query 150 << "fields" 151 << _fields); 152 } 153 }; 154 155 156 /** Typically one uses the QUERY(...) macro to construct a Query object. 157 Example: QUERY( "age" << 33 << "school" << "UCLA" ) 158 */ 159 #define QUERY(x) ::mongo::Query(BSON(x)) 160 161 // Useful utilities for namespaces 162 /** @return the database name portion of an ns std::string */ 163 std::string nsGetDB(const std::string& ns); 164 165 /** @return the collection name portion of an ns std::string */ 166 std::string nsGetCollection(const std::string& ns); 167 168 /** 169 abstract class that implements the core db operations 170 */ 171 class DBClientBase { 172 MONGO_DISALLOW_COPYING(DBClientBase); 173 174 public: DBClientBase()175 DBClientBase() 176 : _logLevel(logger::LogSeverity::Log()), 177 _connectionId(ConnectionIdSequence.fetchAndAdd(1)), 178 _cachedAvailableOptions((enum QueryOptions)0), 179 _haveCachedAvailableOptions(false) {} 180 ~DBClientBase()181 virtual ~DBClientBase() {} 182 183 /** 184 @return a single object that matches the query. if none do, then the object is empty 185 @throws AssertionException 186 */ 187 virtual BSONObj findOne(const std::string& ns, 188 const Query& query, 189 const BSONObj* fieldsToReturn = 0, 190 int queryOptions = 0); 191 192 /** query N objects from the database into an array. makes sense mostly when you want a small 193 * number of results. if a huge number, use query() and iterate the cursor. 194 */ 195 void findN(std::vector<BSONObj>& out, 196 const std::string& ns, 197 Query query, 198 int nToReturn, 199 int nToSkip = 0, 200 const BSONObj* fieldsToReturn = 0, 201 int queryOptions = 0); 202 203 /** 204 * @return a pair with a single object that matches the filter within the collection specified 205 * by the UUID and the namespace of that collection on the queried node. 206 * 207 * If the command fails, an assertion error is thrown. Otherwise, if no document matches 208 * the query, an empty BSONObj is returned. 209 * @throws AssertionException 210 */ 211 virtual std::pair<BSONObj, NamespaceString> findOneByUUID(const std::string& db, 212 UUID uuid, 213 const BSONObj& filter); 214 215 virtual std::string getServerAddress() const = 0; 216 217 /** helper function. run a simple command where the command expression is simply 218 { command : 1 } 219 @param info -- where to put result object. may be null if caller doesn't need that info 220 @param command -- command name 221 @return true if the command returned "ok". 222 */ 223 bool simpleCommand(const std::string& dbname, BSONObj* info, const std::string& command); 224 225 rpc::ProtocolSet getClientRPCProtocols() const; 226 rpc::ProtocolSet getServerRPCProtocols() const; 227 228 void setClientRPCProtocols(rpc::ProtocolSet clientProtocols); 229 230 /** 231 * actualServer is set to the actual server where they call went if there was a choice (for 232 * example SlaveOk). 233 */ 234 virtual bool call(Message& toSend, 235 Message& response, 236 bool assertOk = true, 237 std::string* actualServer = nullptr) = 0; 238 239 virtual void say(Message& toSend, 240 bool isRetry = false, 241 std::string* actualServer = nullptr) = 0; 242 243 /* used by QueryOption_Exhaust. To use that your subclass must implement this. */ recv(Message & m,int lastRequestId)244 virtual bool recv(Message& m, int lastRequestId) { 245 verify(false); 246 return false; 247 } 248 249 // In general, for lazy queries, we'll need to say, recv, then checkResponse 250 virtual void checkResponse(const std::vector<BSONObj>& batch, 251 bool networkError, 252 bool* retry = nullptr, 253 std::string* targetHost = nullptr) { 254 if (retry) 255 *retry = false; 256 if (targetHost) 257 *targetHost = ""; 258 } 259 260 virtual bool lazySupported() const = 0; 261 262 /** 263 * Sets a RequestMetadataWriter on this connection. 264 * 265 * TODO: support multiple metadata writers. 266 */ 267 virtual void setRequestMetadataWriter(rpc::RequestMetadataWriter writer); 268 269 /** 270 * Gets the RequestMetadataWriter that is set on this connection. This may 271 * be an uninitialized stdx::function, so it should be checked for validity 272 * with operator bool() first. 273 */ 274 const rpc::RequestMetadataWriter& getRequestMetadataWriter(); 275 276 /** 277 * Sets a ReplyMetadataReader on this connection. 278 * 279 * TODO: support multiple metadata readers. 280 */ 281 virtual void setReplyMetadataReader(rpc::ReplyMetadataReader reader); 282 283 /** 284 * Gets the ReplyMetadataReader that is set on this connection. This may 285 * be an uninitialized stdx::function, so it should be checked for validity 286 * with operator bool() first. 287 */ 288 const rpc::ReplyMetadataReader& getReplyMetadataReader(); 289 290 /** 291 * Runs the specified command request. 292 */ 293 virtual std::pair<rpc::UniqueReply, DBClientBase*> runCommandWithTarget(OpMsgRequest request); 294 295 /** 296 * This shared_ptr overload is used to possibly return a shared_ptr to the replica set member 297 * that the command was dispatched to. It's needed if the caller needs a lifetime for that 298 * connection that extends beyond the lifetime, or subsequent calls, against the top level 299 * client. 300 * 301 * It has this slightly insane api because: 302 * + we don't want to thread enable_shared_from_this pervasively through the dbclient tree 303 * + we use this from places we don't want to know about dbclient_rs (and so don't know if we'll 304 * get our own ptr back). 305 * + the only caller who needs this is the shell (because other callers have more control over 306 * lifetime). 307 */ 308 virtual std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>> runCommandWithTarget( 309 OpMsgRequest request, std::shared_ptr<DBClientBase> me); 310 311 /** 312 * Runs the specified command request. This thin wrapper just unwraps the reply and ignores the 313 * target connection from the above runCommandWithTarget(). 314 */ runCommand(OpMsgRequest request)315 rpc::UniqueReply runCommand(OpMsgRequest request) { 316 return runCommandWithTarget(std::move(request)).first; 317 } 318 319 /** 320 * Runs the specified command request in fire-and-forget mode and returns the connection that 321 * the command was actually sent on. If the connection doesn't support OP_MSG, the request will 322 * be run as a normal two-way command and the reply will be ignored after parsing. 323 */ 324 virtual DBClientBase* runFireAndForgetCommand(OpMsgRequest request); 325 326 /** Run a database command. Database commands are represented as BSON objects. Common database 327 commands have prebuilt helper functions -- see below. If a helper is not available you can 328 directly call runCommand. 329 330 @param dbname database name. Use "admin" for global administrative commands. 331 @param cmd the command object to execute. For example, { ismaster : 1 } 332 @param info the result object the database returns. Typically has { ok : ..., errmsg : ... } 333 fields set. 334 @param options see enum QueryOptions - normally not needed to run a command 335 @param auth if set, the BSONObj representation will be appended to the command object sent 336 337 @return true if the command returned "ok". 338 */ 339 bool runCommand(const std::string& dbname, BSONObj cmd, BSONObj& info, int options = 0); 340 341 /* 342 * This wraps up the runCommand function avove, but returns the DBClient that actually ran 343 * the command. When called against a replica set, this will return the specific 344 * replica set member the command ran against. 345 * 346 * This is used in the shell so that cursors can send getMore through the correct connection. 347 */ 348 std::tuple<bool, DBClientBase*> runCommandWithTarget(const std::string& dbname, 349 BSONObj cmd, 350 BSONObj& info, 351 int options = 0); 352 353 /** 354 * See the opMsg overload comment for why this function takes a shared_ptr ostensibly to this. 355 */ 356 std::tuple<bool, std::shared_ptr<DBClientBase>> runCommandWithTarget( 357 const std::string& dbname, 358 BSONObj cmd, 359 BSONObj& info, 360 std::shared_ptr<DBClientBase> me, 361 int options = 0); 362 363 /** 364 * Authenticates to another cluster member using appropriate authentication data. 365 * Uses getInternalUserAuthParams() to retrive authentication parameters. 366 * @return true if the authentication was succesful 367 */ 368 bool authenticateInternalUser(); 369 370 /** 371 * Authenticate a user. 372 * 373 * The "params" BSONObj should be initialized with some of the fields below. Which fields 374 * are required depends on the mechanism, which is mandatory. 375 * 376 * "mechanism": The std::string name of the sasl mechanism to use. Mandatory. 377 * "user": The std::string name of the user to authenticate. Mandatory. 378 * "db": The database target of the auth command, which identifies the location 379 * of the credential information for the user. May be "$external" if 380 * credential information is stored outside of the mongo cluster. Mandatory. 381 * "pwd": The password data. 382 * "digestPassword": Boolean, set to true if the "pwd" is undigested (default). 383 * "serviceName": The GSSAPI service name to use. Defaults to "mongodb". 384 * "serviceHostname": The GSSAPI hostname to use. Defaults to the name of the remote 385 * host. 386 * 387 * Other fields in "params" are silently ignored. 388 * 389 * Returns normally on success, and throws on error. Throws a DBException with getCode() == 390 * ErrorCodes::AuthenticationFailed if authentication is rejected. All other exceptions are 391 * tantamount to authentication failure, but may also indicate more serious problems. 392 */ 393 void auth(const BSONObj& params); 394 395 /** Authorize access to a particular database. 396 Authentication is separate for each database on the server -- you may authenticate for any 397 number of databases on a single connection. 398 The "admin" database is special and once authenticated provides access to all databases on 399 the server. 400 @param digestPassword if password is plain text, set this to true. otherwise assumed 401 to be pre-digested 402 @param[out] authLevel level of authentication for the given user 403 @return true if successful 404 */ 405 bool auth(const std::string& dbname, 406 const std::string& username, 407 const std::string& pwd, 408 std::string& errmsg, 409 bool digestPassword = true); 410 411 /** 412 * Logs out the connection for the given database. 413 * 414 * @param dbname the database to logout from. 415 * @param info the result object for the logout command (provided for backwards 416 * compatibility with mongo shell) 417 */ 418 virtual void logout(const std::string& dbname, BSONObj& info); 419 420 /** count number of objects in collection ns that match the query criteria specified 421 throws UserAssertion if database returns an error 422 */ 423 virtual unsigned long long count(const std::string& ns, 424 const BSONObj& query = BSONObj(), 425 int options = 0, 426 int limit = 0, 427 int skip = 0); 428 429 static std::string createPasswordDigest(const std::string& username, 430 const std::string& clearTextPassword); 431 432 /** returns true in isMaster parm if this db is the current master 433 of a replica pair. 434 435 pass in info for more details e.g.: 436 { "ismaster" : 1.0 , "msg" : "not paired" , "ok" : 1.0 } 437 438 returns true if command invoked successfully. 439 */ 440 virtual bool isMaster(bool& isMaster, BSONObj* info = 0); 441 442 /** 443 Create a new collection in the database. Normally, collection creation is automatic. You 444 would use this function if you wish to specify special options on creation. 445 446 If the collection already exists, no action occurs. 447 448 @param ns fully qualified collection name 449 @param size desired initial extent size for the collection. 450 Must be <= 1000000000 for normal collections. 451 For fixed size (capped) collections, this size is the total/max size of the 452 collection. 453 @param capped if true, this is a fixed size collection (where old data rolls out). 454 @param max maximum number of objects if capped (optional). 455 456 returns true if successful. 457 */ 458 bool createCollection(const std::string& ns, 459 long long size = 0, 460 bool capped = false, 461 int max = 0, 462 BSONObj* info = 0); 463 464 /** Get error result from the last write operation (insert/update/delete) on this connection. 465 db doesn't change the command's behavior - it is just for auth checks. 466 @return error message text, or empty std::string if no error. 467 */ 468 std::string getLastError( 469 const std::string& db, bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); 470 /** 471 * Same as the form of getLastError that takes a dbname, but just uses the admin DB. 472 */ 473 std::string getLastError(bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); 474 475 /** Get error result from the last write operation (insert/update/delete) on this connection. 476 db doesn't change the command's behavior - it is just for auth checks. 477 @return full error object. 478 479 If "w" is -1, wait for propagation to majority of nodes. 480 If "wtimeout" is 0, the operation will block indefinitely if needed. 481 */ 482 virtual BSONObj getLastErrorDetailed( 483 const std::string& db, bool fsync = false, bool j = false, int w = 0, int wtimeout = 0); 484 /** 485 * Same as the form of getLastErrorDetailed that takes a dbname, but just uses the admin DB. 486 */ 487 virtual BSONObj getLastErrorDetailed(bool fsync = false, 488 bool j = false, 489 int w = 0, 490 int wtimeout = 0); 491 492 /** Can be called with the returned value from getLastErrorDetailed to extract an error string. 493 If all you need is the string, just call getLastError() instead. 494 */ 495 static std::string getLastErrorString(const BSONObj& res); 496 497 /** Return the last error which has occurred, even if not the very last operation. 498 499 @return { err : <error message>, nPrev : <how_many_ops_back_occurred>, ok : 1 } 500 501 result.err will be null if no error has occurred. 502 */ 503 BSONObj getPrevError(); 504 505 /** Delete the specified collection. 506 * @param info An optional output parameter that receives the result object the database 507 * returns from the drop command. May be null if the caller doesn't need that info. 508 */ 509 virtual bool dropCollection(const std::string& ns, 510 const WriteConcernOptions& writeConcern = WriteConcernOptions(), 511 BSONObj* info = nullptr) { 512 std::string db = nsGetDB(ns); 513 std::string coll = nsGetCollection(ns); 514 uassert(10011, "no collection name", coll.size()); 515 516 BSONObj temp; 517 if (info == nullptr) { 518 info = &temp; 519 } 520 521 bool res = runCommand( 522 db.c_str(), BSON("drop" << coll << "writeConcern" << writeConcern.toBSON()), *info); 523 return res; 524 } 525 526 /** Copy database from one server or name to another server or name. 527 528 Generally, you should dropDatabase() first as otherwise the copied information will MERGE 529 into whatever data is already present in this database. 530 531 For security reasons this function only works when you are authorized to access the "admin" 532 db. However, if you have access to said db, you can copy any database from one place to 533 another. 534 TODO: this needs enhancement to be more flexible in terms of security. 535 536 This method provides a way to "rename" a database by copying it to a new db name and 537 location. The copy is "repaired" and compacted. 538 539 fromdb database name from which to copy. 540 todb database name to copy to. 541 fromhost hostname of the database (and optionally, ":port") from which to 542 copy the data. copies from self if "". 543 544 returns true if successful 545 */ 546 bool copyDatabase(const std::string& fromdb, 547 const std::string& todb, 548 const std::string& fromhost = "", 549 BSONObj* info = 0); 550 551 /** Run javascript code on the database server. 552 dbname database SavedContext in which the code runs. The javascript variable 'db' will be 553 assigned to this database when the function is invoked. 554 jscode source code for a javascript function. 555 info the command object which contains any information on the invocation result 556 including the return value and other information. If an error occurs running the 557 jscode, error information will be in info. (try "log() << info.toString()") 558 retValue return value from the jscode function. 559 args args to pass to the jscode function. when invoked, the 'args' variable will be 560 defined for use by the jscode. 561 562 returns true if runs ok. 563 564 See testDbEval() in dbclient.cpp for an example of usage. 565 */ 566 bool eval(const std::string& dbname, 567 const std::string& jscode, 568 BSONObj& info, 569 BSONElement& retValue, 570 BSONObj* args = 0); 571 572 /** validate a collection, checking for errors and reporting back statistics. 573 this operation is slow and blocking. 574 */ 575 bool validate(const std::string& ns, bool scandata = true) { 576 BSONObj cmd = BSON("validate" << nsGetCollection(ns) << "scandata" << scandata); 577 BSONObj info; 578 return runCommand(nsGetDB(ns).c_str(), cmd, info); 579 } 580 581 /* The following helpers are simply more convenient forms of eval() for certain common cases */ 582 583 /* invocation with no return value of interest -- with or without one simple parameter */ 584 bool eval(const std::string& dbname, const std::string& jscode); 585 template <class T> eval(const std::string & dbname,const std::string & jscode,T parm1)586 bool eval(const std::string& dbname, const std::string& jscode, T parm1) { 587 BSONObj info; 588 BSONElement retValue; 589 BSONObjBuilder b; 590 b.append("0", parm1); 591 BSONObj args = b.done(); 592 return eval(dbname, jscode, info, retValue, &args); 593 } 594 595 /** eval invocation with one parm to server and one numeric field (either int or double) 596 * returned */ 597 template <class T, class NumType> eval(const std::string & dbname,const std::string & jscode,T parm1,NumType & ret)598 bool eval(const std::string& dbname, const std::string& jscode, T parm1, NumType& ret) { 599 BSONObj info; 600 BSONElement retValue; 601 BSONObjBuilder b; 602 b.append("0", parm1); 603 BSONObj args = b.done(); 604 if (!eval(dbname, jscode, info, retValue, &args)) 605 return false; 606 ret = (NumType)retValue.number(); 607 return true; 608 } 609 610 /** 611 * { name : "<short collection name>", 612 * options : { } 613 * } 614 */ 615 std::list<BSONObj> getCollectionInfos(const std::string& db, const BSONObj& filter = BSONObj()); 616 617 bool exists(const std::string& ns); 618 619 /** Create an index on the collection 'ns' as described by the given keys. If you wish 620 * to specify options, see the more flexible overload of 'createIndex' which takes an 621 * IndexSpec object. Failure to construct the index is reported by throwing a 622 * AssertionException. 623 * 624 * @param ns Namespace on which to create the index 625 * @param keys Document describing keys and index types. You must provide at least one 626 * field and its direction. 627 */ createIndex(StringData ns,const BSONObj & keys)628 void createIndex(StringData ns, const BSONObj& keys) { 629 return createIndex(ns, IndexSpec().addKeys(keys)); 630 } 631 632 /** Create an index on the collection 'ns' as described by the given 633 * descriptor. Failure to construct the index is reported by throwing a 634 * AssertionException. 635 * 636 * @param ns Namespace on which to create the index 637 * @param descriptor Configuration object describing the index to create. The 638 * descriptor must describe at least one key and index type. 639 */ 640 virtual void createIndex(StringData ns, const IndexSpec& descriptor); 641 642 virtual std::list<BSONObj> getIndexSpecs(const std::string& ns, int options = 0); 643 644 virtual void dropIndex(const std::string& ns, BSONObj keys); 645 virtual void dropIndex(const std::string& ns, const std::string& indexName); 646 647 /** 648 drops all indexes for the collection 649 */ 650 virtual void dropIndexes(const std::string& ns); 651 652 virtual void reIndex(const std::string& ns); 653 654 static std::string genIndexName(const BSONObj& keys); 655 656 /** Erase / drop an entire database */ 657 virtual bool dropDatabase(const std::string& dbname, 658 const WriteConcernOptions& writeConcern = WriteConcernOptions(), 659 BSONObj* info = nullptr) { 660 BSONObj o; 661 if (info == nullptr) 662 info = &o; 663 return runCommand( 664 dbname, BSON("dropDatabase" << 1 << "writeConcern" << writeConcern.toBSON()), *info); 665 } 666 667 virtual std::string toString() const = 0; 668 669 /** 670 * Run a pseudo-command such as sys.inprog/currentOp, sys.killop/killOp 671 * or sys.unlock/fsyncUnlock 672 * 673 * The real command will be tried first, and if the remote server does not 674 * implement the command, it will fall back to the pseudoCommand. 675 * 676 * The cmdArgs parameter should NOT include {<commandName>: 1}. 677 * 678 * TODO: remove after MongoDB 3.2 is released and replace all callers with 679 * a call to plain runCommand 680 */ 681 virtual bool runPseudoCommand(StringData db, 682 StringData realCommandName, 683 StringData pseudoCommandCol, 684 const BSONObj& cmdArgs, 685 BSONObj& info, 686 int options = 0); 687 688 /** 689 * Reconnect if needed and allowed. 690 */ checkConnection()691 virtual void checkConnection() {} 692 693 static const uint64_t INVALID_SOCK_CREATION_TIME; 694 getConnectionId()695 long long getConnectionId() const { 696 return _connectionId; 697 } 698 699 virtual int getMinWireVersion() = 0; 700 virtual int getMaxWireVersion() = 0; 701 702 /** send a query to the database. 703 @param ns namespace to query, format is <dbname>.<collectname>[.<collectname>]* 704 @param query query to perform on the collection. this is a BSONObj (binary JSON) 705 You may format as 706 { query: { ... }, orderby: { ... } } 707 to specify a sort order. 708 @param nToReturn n to return (i.e., limit). 0 = unlimited 709 @param nToSkip start with the nth item 710 @param fieldsToReturn optional template of which fields to select. if unspecified, 711 returns all fields 712 @param queryOptions see options enum at top of this file 713 714 @return cursor. 0 if error (connection failure) 715 @throws AssertionException 716 */ 717 virtual std::unique_ptr<DBClientCursor> query(const std::string& ns, 718 Query query, 719 int nToReturn = 0, 720 int nToSkip = 0, 721 const BSONObj* fieldsToReturn = 0, 722 int queryOptions = 0, 723 int batchSize = 0); 724 725 726 /** Uses QueryOption_Exhaust, when available. 727 728 Exhaust mode sends back all data queries as fast as possible, with no back-and-forth for 729 OP_GETMORE. If you are certain you will exhaust the query, it could be useful. 730 731 Use the DBClientCursorBatchIterator version, below, if you want to do items in large 732 blocks, perhaps to avoid granular locking and such. 733 */ 734 virtual unsigned long long query(stdx::function<void(const BSONObj&)> f, 735 const std::string& ns, 736 Query query, 737 const BSONObj* fieldsToReturn = 0, 738 int queryOptions = 0); 739 740 virtual unsigned long long query(stdx::function<void(DBClientCursorBatchIterator&)> f, 741 const std::string& ns, 742 Query query, 743 const BSONObj* fieldsToReturn = 0, 744 int queryOptions = 0); 745 746 747 /** don't use this - called automatically by DBClientCursor for you 748 @param cursorId id of cursor to retrieve 749 @return an handle to a previously allocated cursor 750 @throws AssertionException 751 */ 752 virtual std::unique_ptr<DBClientCursor> getMore(const std::string& ns, 753 long long cursorId, 754 int nToReturn = 0, 755 int options = 0); 756 757 /** 758 insert an object into the database 759 */ 760 virtual void insert(const std::string& ns, BSONObj obj, int flags = 0); 761 762 /** 763 insert a vector of objects into the database 764 */ 765 virtual void insert(const std::string& ns, const std::vector<BSONObj>& v, int flags = 0); 766 767 /** 768 updates objects matching query 769 */ 770 virtual void update( 771 const std::string& ns, Query query, BSONObj obj, bool upsert = false, bool multi = false); 772 773 virtual void update(const std::string& ns, Query query, BSONObj obj, int flags); 774 775 virtual void remove(const std::string& ns, Query query, int flags = 0); 776 777 virtual bool isFailed() const = 0; 778 779 /** 780 * if not checked recently, checks whether the underlying socket/sockets are still valid 781 */ 782 virtual bool isStillConnected() = 0; 783 784 virtual void killCursor(const NamespaceString& ns, long long cursorID); 785 786 virtual ConnectionString::ConnectionType type() const = 0; 787 788 virtual double getSoTimeout() const = 0; 789 getSockCreationMicroSec()790 virtual uint64_t getSockCreationMicroSec() const { 791 return INVALID_SOCK_CREATION_TIME; 792 } 793 reset()794 virtual void reset() {} 795 796 virtual bool isReplicaSetMember() const = 0; 797 798 virtual bool isMongos() const = 0; 799 800 /** 801 * Parses command replies and runs them through the metadata reader. 802 * This is virtual and non-const to allow subclasses to act on failures. 803 */ 804 virtual rpc::UniqueReply parseCommandReplyMessage(const std::string& host, 805 const Message& replyMsg); 806 807 protected: 808 /** if the result of a command is ok*/ 809 bool isOk(const BSONObj&); 810 811 /** if the element contains a not master error */ 812 bool isNotMasterErrorString(const BSONElement& e); 813 814 BSONObj _countCmd( 815 const std::string& ns, const BSONObj& query, int options, int limit, int skip); 816 817 /** 818 * Look up the options available on this client. Caches the answer from 819 * _lookupAvailableOptions(), below. 820 */ 821 QueryOptions availableOptions(); 822 823 virtual QueryOptions _lookupAvailableOptions(); 824 825 virtual void _auth(const BSONObj& params); 826 827 // should be set by subclasses during connection. 828 void _setServerRPCProtocols(rpc::ProtocolSet serverProtocols); 829 830 /** controls how chatty the client is about network errors & such. See log.h */ 831 const logger::LogSeverity _logLevel; 832 833 static AtomicInt64 ConnectionIdSequence; 834 long long _connectionId; // unique connection id for this connection 835 836 private: 837 /** 838 * The rpc protocols this client supports. 839 * 840 */ 841 rpc::ProtocolSet _clientRPCProtocols{rpc::supports::kAll}; 842 843 /** 844 * The rpc protocol the remote server(s) support. We support 'opQueryOnly' by default unless 845 * we detect support for OP_COMMAND at connection time. 846 */ 847 rpc::ProtocolSet _serverRPCProtocols{rpc::supports::kOpQueryOnly}; 848 849 rpc::RequestMetadataWriter _metadataWriter; 850 rpc::ReplyMetadataReader _metadataReader; 851 852 enum QueryOptions _cachedAvailableOptions; 853 bool _haveCachedAvailableOptions; 854 }; // DBClientBase 855 856 /** 857 A basic connection to the database. 858 This is the main entry point for talking to a simple Mongo setup 859 */ 860 class DBClientConnection : public DBClientBase { 861 public: 862 using DBClientBase::query; 863 864 /** 865 * A hook used to validate the reply of an 'isMaster' command during connection. If the hook 866 * returns a non-OK Status, the DBClientConnection object will disconnect from the remote 867 * server. This function must not throw - it can only indicate failure by returning a non-OK 868 * status. 869 */ 870 using HandshakeValidationHook = 871 stdx::function<Status(const executor::RemoteCommandResponse& isMasterReply)>; 872 873 /** 874 @param _autoReconnect if true, automatically reconnect on a connection failure 875 @param timeout tcp timeout in seconds - this is for read/write, not connect. 876 Connect timeout is fixed, but short, at 5 seconds. 877 */ 878 DBClientConnection(bool _autoReconnect = false, 879 double so_timeout = 0, 880 MongoURI uri = {}, 881 const HandshakeValidationHook& hook = HandshakeValidationHook()); 882 ~DBClientConnection()883 virtual ~DBClientConnection() { 884 _numConnections.fetchAndAdd(-1); 885 } 886 887 /** 888 * Connect to a Mongo database server. 889 * 890 * If autoReconnect is true, you can try to use the DBClientConnection even when 891 * false was returned -- it will try to connect again. 892 * 893 * @param server server to connect to. 894 * @param errmsg any relevant error message will appended to the string 895 * @return false if fails to connect. 896 */ 897 virtual bool connect(const HostAndPort& server, 898 StringData applicationName, 899 std::string& errmsg); 900 901 /** 902 * Semantically equivalent to the previous connect method, but returns a Status 903 * instead of taking an errmsg out parameter. Also allows optional validation of the reply to 904 * the 'isMaster' command executed during connection. 905 * 906 * @param server The server to connect to. 907 * @param a hook to validate the 'isMaster' reply received during connection. If the hook 908 * fails, the connection will be terminated and a non-OK status will be returned. 909 */ 910 Status connect(const HostAndPort& server, StringData applicationName); 911 912 /** 913 * This version of connect does not run 'isMaster' after creating a TCP connection to the 914 * remote host. This method should be used only when calling 'isMaster' would create a deadlock, 915 * such as in 'isSelf'. 916 * 917 * @param server The server to connect to. 918 */ 919 Status connectSocketOnly(const HostAndPort& server); 920 921 /** Connect to a Mongo database server. Exception throwing version. 922 Throws a AssertionException if cannot connect. 923 924 If autoReconnect is true, you can try to use the DBClientConnection even when 925 false was returned -- it will try to connect again. 926 927 @param serverHostname host to connect to. can include port number ( 127.0.0.1 , 928 127.0.0.1:5555 ) 929 */ 930 931 /** 932 * Logs out the connection for the given database. 933 * 934 * @param dbname the database to logout from. 935 * @param info the result object for the logout command (provided for backwards 936 * compatibility with mongo shell) 937 */ 938 virtual void logout(const std::string& dbname, BSONObj& info); 939 940 virtual std::unique_ptr<DBClientCursor> query(const std::string& ns, 941 Query query = Query(), 942 int nToReturn = 0, 943 int nToSkip = 0, 944 const BSONObj* fieldsToReturn = 0, 945 int queryOptions = 0, 946 int batchSize = 0) { 947 checkConnection(); 948 return DBClientBase::query( 949 ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions, batchSize); 950 } 951 952 virtual unsigned long long query(stdx::function<void(DBClientCursorBatchIterator&)> f, 953 const std::string& ns, 954 Query query, 955 const BSONObj* fieldsToReturn, 956 int queryOptions); 957 958 using DBClientBase::runCommandWithTarget; 959 std::pair<rpc::UniqueReply, DBClientBase*> runCommandWithTarget(OpMsgRequest request) override; 960 std::pair<rpc::UniqueReply, std::shared_ptr<DBClientBase>> runCommandWithTarget( 961 OpMsgRequest request, std::shared_ptr<DBClientBase> me) override; 962 963 rpc::UniqueReply parseCommandReplyMessage(const std::string& host, 964 const Message& replyMsg) override; 965 966 /** 967 @return true if this connection is currently in a failed state. When autoreconnect is on, 968 a connection will transition back to an ok state after reconnecting. 969 */ isFailed()970 bool isFailed() const { 971 return _failed; 972 } 973 isStillConnected()974 bool isStillConnected() { 975 return _port ? _port->isStillConnected() : true; 976 } 977 setWireVersions(int minWireVersion,int maxWireVersion)978 void setWireVersions(int minWireVersion, int maxWireVersion) { 979 _minWireVersion = minWireVersion; 980 _maxWireVersion = maxWireVersion; 981 } 982 getMinWireVersion()983 int getMinWireVersion() final { 984 return _minWireVersion; 985 } 986 getMaxWireVersion()987 int getMaxWireVersion() final { 988 return _maxWireVersion; 989 } 990 port()991 AbstractMessagingPort& port() { 992 verify(_port); 993 return *_port; 994 } 995 toString()996 std::string toString() const { 997 std::stringstream ss; 998 ss << _serverAddress; 999 if (!_resolvedAddress.empty()) 1000 ss << " (" << _resolvedAddress << ")"; 1001 if (_failed) 1002 ss << " failed"; 1003 return ss.str(); 1004 } 1005 getServerAddress()1006 std::string getServerAddress() const { 1007 return _serverAddress.toString(); 1008 } getServerHostAndPort()1009 const HostAndPort& getServerHostAndPort() const { 1010 return _serverAddress; 1011 } 1012 1013 virtual void say(Message& toSend, bool isRetry = false, std::string* actualServer = 0); 1014 virtual bool recv(Message& m, int lastRequestId); 1015 virtual void checkResponse(const std::vector<BSONObj>& batch, 1016 bool networkError, 1017 bool* retry = NULL, 1018 std::string* host = NULL); 1019 virtual bool call(Message& toSend, Message& response, bool assertOk, std::string* actualServer); type()1020 virtual ConnectionString::ConnectionType type() const { 1021 return ConnectionString::MASTER; 1022 } 1023 void setSoTimeout(double timeout); getSoTimeout()1024 double getSoTimeout() const { 1025 return _so_timeout; 1026 } 1027 lazySupported()1028 virtual bool lazySupported() const { 1029 return true; 1030 } 1031 getNumConnections()1032 static int getNumConnections() { 1033 return _numConnections.load(); 1034 } 1035 1036 /** 1037 * Set the name of the replica set that this connection is associated to. 1038 * Note: There is no validation on replSetName. 1039 */ 1040 void setParentReplSetName(const std::string& replSetName); 1041 1042 uint64_t getSockCreationMicroSec() const; 1043 getCompressorManager()1044 MessageCompressorManager& getCompressorManager() { 1045 return _compressorManager; 1046 } 1047 1048 // throws SocketException if in failed state and not reconnecting or if waiting to reconnect checkConnection()1049 void checkConnection() override { 1050 if (_failed) 1051 _checkConnection(); 1052 } 1053 isReplicaSetMember()1054 bool isReplicaSetMember() const override { 1055 return _isReplicaSetMember; 1056 } 1057 isMongos()1058 bool isMongos() const override { 1059 return _isMongos; 1060 } 1061 1062 protected: 1063 int _minWireVersion{0}; 1064 int _maxWireVersion{0}; 1065 bool _isReplicaSetMember = false; 1066 bool _isMongos = false; 1067 1068 virtual void _auth(const BSONObj& params); 1069 1070 std::unique_ptr<AbstractMessagingPort> _port; 1071 1072 bool _failed; 1073 const bool autoReconnect; 1074 Backoff autoReconnectBackoff; 1075 1076 HostAndPort _serverAddress; 1077 std::string _resolvedAddress; 1078 std::string _applicationName; 1079 1080 void _checkConnection(); 1081 1082 std::map<std::string, BSONObj> authCache; 1083 double _so_timeout; 1084 1085 static AtomicInt32 _numConnections; 1086 1087 private: 1088 /** 1089 * Inspects the contents of 'replyBody' and informs the replica set monitor that the host 'this' 1090 * is connected with is no longer the primary if a "not master" error message or error code was 1091 * returned. 1092 */ 1093 void handleNotMasterResponse(const BSONObj& replyBody, StringData errorMsgFieldName); 1094 1095 // Contains the string for the replica set name of the host this is connected to. 1096 // Should be empty if this connection is not pointing to a replica set member. 1097 std::string _parentReplSetName; 1098 1099 // Hook ran on every call to connect() 1100 HandshakeValidationHook _hook; 1101 1102 MessageCompressorManager _compressorManager; 1103 1104 MongoURI _uri; 1105 }; 1106 1107 BSONElement getErrField(const BSONObj& result); 1108 bool hasErrField(const BSONObj& result); 1109 1110 inline std::ostream& operator<<(std::ostream& s, const Query& q) { 1111 return s << q.toString(); 1112 } 1113 1114 } // namespace mongo 1115 1116 #include "mongo/client/dbclientcursor.h" 1117