summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaria van Keulen <maria@mongodb.com>2017-07-28 16:01:00 -0400
committerMaria van Keulen <maria@mongodb.com>2017-08-30 11:25:24 -0400
commit49708981947fbd44c0b8afa8c24b9c586c25091d (patch)
tree5d8cb68b670172d408425a10caf7b34aa728ed11
parent03055999749ed577af14d5d9cc969f616b4c3196 (diff)
downloadmongo-49708981947fbd44c0b8afa8c24b9c586c25091d.tar.gz
SERVER-29839 Protect from mid-command renames in parseNsOrUUID
-rw-r--r--src/mongo/db/catalog/SConscript1
-rw-r--r--src/mongo/db/catalog/database_test.cpp23
-rw-r--r--src/mongo/db/commands/find_cmd.cpp17
-rw-r--r--src/mongo/db/commands/list_indexes.cpp3
-rw-r--r--src/mongo/db/commands/parallel_collection_scan.cpp3
-rw-r--r--src/mongo/db/concurrency/d_concurrency.cpp22
-rw-r--r--src/mongo/db/concurrency/d_concurrency.h21
-rw-r--r--src/mongo/db/db_raii.cpp42
-rw-r--r--src/mongo/db/db_raii.h24
-rw-r--r--src/mongo/db/query/SConscript1
-rw-r--r--src/mongo/db/query/canonical_query.cpp2
-rw-r--r--src/mongo/db/query/query_request.cpp32
-rw-r--r--src/mongo/db/query/query_request.h23
-rw-r--r--src/mongo/s/balancer_configuration_test.cpp2
-rw-r--r--src/mongo/s/catalog/sharding_catalog_test.cpp24
-rw-r--r--src/mongo/s/cluster_identity_loader_test.cpp2
-rw-r--r--src/mongo/s/sharding_test_fixture.cpp2
17 files changed, 201 insertions, 43 deletions
diff --git a/src/mongo/db/catalog/SConscript b/src/mongo/db/catalog/SConscript
index 5f1f5b2704e..9479faf9f4c 100644
--- a/src/mongo/db/catalog/SConscript
+++ b/src/mongo/db/catalog/SConscript
@@ -125,6 +125,7 @@ env.CppUnitTest(
LIBDEPS=[
'database',
'index_create',
+ '$BUILD_DIR/mongo/db/concurrency/lock_manager',
'$BUILD_DIR/mongo/db/db_raii',
'$BUILD_DIR/mongo/db/namespace_string',
'$BUILD_DIR/mongo/db/op_observer_d',
diff --git a/src/mongo/db/catalog/database_test.cpp b/src/mongo/db/catalog/database_test.cpp
index 4ba521f6b65..35c1127bb64 100644
--- a/src/mongo/db/catalog/database_test.cpp
+++ b/src/mongo/db/catalog/database_test.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/catalog/index_create.h"
#include "mongo/db/catalog/uuid_catalog.h"
#include "mongo/db/client.h"
+#include "mongo/db/concurrency/d_concurrency.h"
#include "mongo/db/concurrency/write_conflict_exception.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/jsobj.h"
@@ -537,4 +538,26 @@ TEST_F(
db->makeUniqueCollectionNamespace(_opCtx.get(), model));
});
}
+
+TEST_F(DatabaseTest, DBLockCanBePassedToAutoGetDb) {
+ NamespaceString nss("test", "coll");
+ Lock::DBLock lock(_opCtx.get(), nss.db(), MODE_X);
+ {
+ AutoGetDb db(_opCtx.get(), nss.db(), std::move(lock));
+ ASSERT(_opCtx.get()->lockState()->isDbLockedForMode(nss.db(), MODE_X));
+ }
+ // The moved lock should go out of scope here, so the database should no longer be locked.
+ ASSERT_FALSE(_opCtx.get()->lockState()->isDbLockedForMode(nss.db(), MODE_X));
+}
+
+TEST_F(DatabaseTest, DBLockCanBePassedToAutoGetCollectionOrViewForReadCommand) {
+ NamespaceString nss("test", "coll");
+ Lock::DBLock lock(_opCtx.get(), nss.db(), MODE_X);
+ {
+ AutoGetCollectionOrViewForReadCommand coll(_opCtx.get(), nss, std::move(lock));
+ ASSERT(_opCtx.get()->lockState()->isDbLockedForMode(nss.db(), MODE_X));
+ }
+ // The moved lock should go out of scope here, so the database should no longer be locked.
+ ASSERT_FALSE(_opCtx.get()->lockState()->isDbLockedForMode(nss.db(), MODE_X));
+}
} // namespace
diff --git a/src/mongo/db/commands/find_cmd.cpp b/src/mongo/db/commands/find_cmd.cpp
index fe1d0940ff9..cbe0ce20d55 100644
--- a/src/mongo/db/commands/find_cmd.cpp
+++ b/src/mongo/db/commands/find_cmd.cpp
@@ -40,6 +40,7 @@
#include "mongo/db/clientcursor.h"
#include "mongo/db/commands.h"
#include "mongo/db/commands/run_aggregate.h"
+#include "mongo/db/concurrency/d_concurrency.h"
#include "mongo/db/db_raii.h"
#include "mongo/db/exec/working_set_common.h"
#include "mongo/db/matcher/extensions_callback_real.h"
@@ -228,14 +229,14 @@ public:
const std::string& dbname,
const BSONObj& cmdObj,
BSONObjBuilder& result) override {
- const NamespaceString nss(parseNsOrUUID(opCtx, dbname, cmdObj));
-
// Although it is a command, a find command gets counted as a query.
globalOpCounters.gotQuery();
// Parse the command BSON to a QueryRequest.
const bool isExplain = false;
- auto qrStatus = QueryRequest::makeFromFindCommand(nss, cmdObj, isExplain);
+ // Pass parseNs to makeFromFindCommand in case cmdObj does not have a UUID.
+ auto qrStatus = QueryRequest::makeFromFindCommand(
+ NamespaceString(parseNs(dbname, cmdObj)), cmdObj, isExplain);
if (!qrStatus.isOK()) {
return appendCommandStatus(result, qrStatus.getStatus());
}
@@ -252,6 +253,12 @@ public:
}
}
+ // Acquire locks. If the query is on a view, we release our locks and convert the query
+ // request into an aggregation command.
+ Lock::DBLock dbSLock(opCtx, dbname, MODE_IS);
+ const NamespaceString nss(parseNsOrUUID(opCtx, dbname, cmdObj));
+ qr->refreshNSS(opCtx);
+
// Fill out curop information.
//
// We pass negative values for 'ntoreturn' and 'ntoskip' to indicate that these values
@@ -276,9 +283,7 @@ public:
}
std::unique_ptr<CanonicalQuery> cq = std::move(statusWithCQ.getValue());
- // Acquire locks. If the query is on a view, we release our locks and convert the query
- // request into an aggregation command.
- AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss);
+ AutoGetCollectionOrViewForReadCommand ctx(opCtx, nss, std::move(dbSLock));
Collection* collection = ctx.getCollection();
if (ctx.getView()) {
// Relinquish locks. The aggregation command will re-acquire them.
diff --git a/src/mongo/db/commands/list_indexes.cpp b/src/mongo/db/commands/list_indexes.cpp
index a050e9adfff..74b75cfeffa 100644
--- a/src/mongo/db/commands/list_indexes.cpp
+++ b/src/mongo/db/commands/list_indexes.cpp
@@ -120,6 +120,7 @@ public:
const string& dbname,
const BSONObj& cmdObj,
BSONObjBuilder& result) {
+ Lock::DBLock dbSLock(opCtx, dbname, MODE_IS);
const NamespaceString ns(parseNsOrUUID(opCtx, dbname, cmdObj));
const long long defaultBatchSize = std::numeric_limits<long long>::max();
long long batchSize;
@@ -129,7 +130,7 @@ public:
return appendCommandStatus(result, parseCursorStatus);
}
- AutoGetCollectionForReadCommand autoColl(opCtx, ns);
+ AutoGetCollectionForReadCommand autoColl(opCtx, ns, std::move(dbSLock));
if (!autoColl.getDb()) {
return appendCommandStatus(
result,
diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp
index 5fbe37b1132..6b84996369c 100644
--- a/src/mongo/db/commands/parallel_collection_scan.cpp
+++ b/src/mongo/db/commands/parallel_collection_scan.cpp
@@ -89,9 +89,10 @@ public:
const string& dbname,
const BSONObj& cmdObj,
BSONObjBuilder& result) {
+ Lock::DBLock dbSLock(opCtx, dbname, MODE_IS);
const NamespaceString ns(parseNsOrUUID(opCtx, dbname, cmdObj));
- AutoGetCollectionForReadCommand ctx(opCtx, ns);
+ AutoGetCollectionForReadCommand ctx(opCtx, ns, std::move(dbSLock));
Collection* collection = ctx.getCollection();
if (!collection)
diff --git a/src/mongo/db/concurrency/d_concurrency.cpp b/src/mongo/db/concurrency/d_concurrency.cpp
index 42e7bb96d7f..d5d9fe1684c 100644
--- a/src/mongo/db/concurrency/d_concurrency.cpp
+++ b/src/mongo/db/concurrency/d_concurrency.cpp
@@ -152,6 +152,15 @@ Lock::GlobalLock::GlobalLock(OperationContext* opCtx,
_enqueue(lockMode, timeoutMs);
}
+Lock::GlobalLock::GlobalLock(GlobalLock&& otherLock)
+ : _opCtx(otherLock._opCtx),
+ _result(otherLock._result),
+ _pbwm(std::move(otherLock._pbwm)),
+ _isOutermostLock(otherLock._isOutermostLock) {
+ // Mark as moved so the destructor doesn't invalidate the newly-constructed lock.
+ otherLock._result = LOCK_INVALID;
+}
+
void Lock::GlobalLock::_enqueue(LockMode lockMode, unsigned timeoutMs) {
if (_opCtx->lockState()->shouldConflictWithSecondaryBatchApplication()) {
_pbwm.lock(MODE_IS);
@@ -200,8 +209,19 @@ Lock::DBLock::DBLock(OperationContext* opCtx, StringData db, LockMode mode)
invariant(LOCK_OK == _opCtx->lockState()->lock(_id, _mode));
}
+Lock::DBLock::DBLock(DBLock&& otherLock)
+ : _id(otherLock._id),
+ _opCtx(otherLock._opCtx),
+ _mode(otherLock._mode),
+ _globalLock(std::move(otherLock._globalLock)) {
+ // Mark as moved so the destructor doesn't invalidate the newly-constructed lock.
+ otherLock._mode = MODE_NONE;
+}
+
Lock::DBLock::~DBLock() {
- _opCtx->lockState()->unlock(_id);
+ if (_mode != MODE_NONE) {
+ _opCtx->lockState()->unlock(_id);
+ }
}
void Lock::DBLock::relockWithMode(LockMode newMode) {
diff --git a/src/mongo/db/concurrency/d_concurrency.h b/src/mongo/db/concurrency/d_concurrency.h
index 479dc84fb2a..44be439d539 100644
--- a/src/mongo/db/concurrency/d_concurrency.h
+++ b/src/mongo/db/concurrency/d_concurrency.h
@@ -83,8 +83,17 @@ public:
lock(mode);
}
+ ResourceLock(ResourceLock&& otherLock)
+ : _rid(otherLock._rid), _locker(otherLock._locker), _result(otherLock._result) {
+ // Mark as moved so the destructor doesn't invalidate the newly-
+ // constructed lock.
+ otherLock._result = LOCK_INVALID;
+ }
+
~ResourceLock() {
- unlock();
+ if (isLocked()) {
+ unlock();
+ }
}
void lock(LockMode mode);
@@ -174,6 +183,7 @@ public:
class EnqueueOnly {};
GlobalLock(OperationContext* opCtx, LockMode lockMode, unsigned timeoutMs);
+ GlobalLock(GlobalLock&&);
/**
* Enqueues lock but does not block on lock acquisition.
@@ -188,10 +198,12 @@ public:
EnqueueOnly enqueueOnly);
~GlobalLock() {
- if (isLocked() && _isOutermostLock) {
- _opCtx->recoveryUnit()->abandonSnapshot();
+ if (_result != LOCK_INVALID) {
+ if (isLocked() && _isOutermostLock) {
+ _opCtx->recoveryUnit()->abandonSnapshot();
+ }
+ _unlock();
}
- _unlock();
}
/**
@@ -268,6 +280,7 @@ public:
class DBLock {
public:
DBLock(OperationContext* opCtx, StringData db, LockMode mode);
+ DBLock(DBLock&&);
~DBLock();
/**
diff --git a/src/mongo/db/db_raii.cpp b/src/mongo/db/db_raii.cpp
index bff855fcc5b..018a2591ed3 100644
--- a/src/mongo/db/db_raii.cpp
+++ b/src/mongo/db/db_raii.cpp
@@ -49,13 +49,23 @@ MONGO_FP_DECLARE(setAutoGetCollectionWait);
AutoGetDb::AutoGetDb(OperationContext* opCtx, StringData ns, LockMode mode)
: _dbLock(opCtx, ns, mode), _db(dbHolder().get(opCtx, ns)) {}
+AutoGetDb::AutoGetDb(OperationContext* opCtx, StringData ns, Lock::DBLock lock)
+ : _dbLock(std::move(lock)), _db(dbHolder().get(opCtx, ns)) {}
+
AutoGetCollection::AutoGetCollection(OperationContext* opCtx,
const NamespaceString& nss,
LockMode modeDB,
LockMode modeColl,
ViewMode viewMode)
+ : AutoGetCollection(opCtx, nss, modeColl, viewMode, Lock::DBLock(opCtx, nss.db(), modeDB)) {}
+
+AutoGetCollection::AutoGetCollection(OperationContext* opCtx,
+ const NamespaceString& nss,
+ LockMode modeColl,
+ ViewMode viewMode,
+ Lock::DBLock lock)
: _viewMode(viewMode),
- _autoDb(opCtx, nss.db(), modeDB),
+ _autoDb(opCtx, nss.db(), std::move(lock)),
_collLock(opCtx->lockState(), nss.ns(), modeColl),
_coll(_autoDb.getDb() ? _autoDb.getDb()->getCollection(opCtx, nss) : nullptr) {
Database* db = _autoDb.getDb();
@@ -132,6 +142,15 @@ AutoGetCollectionForRead::AutoGetCollectionForRead(OperationContext* opCtx,
_ensureMajorityCommittedSnapshotIsValid(nss, opCtx);
}
+AutoGetCollectionForRead::AutoGetCollectionForRead(OperationContext* opCtx,
+ const NamespaceString& nss,
+ AutoGetCollection::ViewMode viewMode,
+ Lock::DBLock lock) {
+ _autoColl.emplace(opCtx, nss, MODE_IS, viewMode, std::move(lock));
+
+ // Note: this can yield.
+ _ensureMajorityCommittedSnapshotIsValid(nss, opCtx);
+}
void AutoGetCollectionForRead::_ensureMajorityCommittedSnapshotIsValid(const NamespaceString& nss,
OperationContext* opCtx) {
while (true) {
@@ -169,9 +188,11 @@ void AutoGetCollectionForRead::_ensureMajorityCommittedSnapshotIsValid(const Nam
}
AutoGetCollectionForReadCommand::AutoGetCollectionForReadCommand(
- OperationContext* opCtx, const NamespaceString& nss, AutoGetCollection::ViewMode viewMode) {
-
- _autoCollForRead.emplace(opCtx, nss, viewMode);
+ OperationContext* opCtx,
+ const NamespaceString& nss,
+ AutoGetCollection::ViewMode viewMode,
+ Lock::DBLock lock) {
+ _autoCollForRead.emplace(opCtx, nss, viewMode, std::move(lock));
const int doNotChangeProfilingLevel = 0;
_statsTracker.emplace(opCtx,
nss,
@@ -185,6 +206,11 @@ AutoGetCollectionForReadCommand::AutoGetCollectionForReadCommand(
css->checkShardVersionOrThrow(opCtx);
}
+AutoGetCollectionForReadCommand::AutoGetCollectionForReadCommand(
+ OperationContext* opCtx, const NamespaceString& nss, AutoGetCollection::ViewMode viewMode)
+ : AutoGetCollectionForReadCommand(
+ opCtx, nss, viewMode, Lock::DBLock(opCtx, nss.db(), MODE_IS)) {}
+
AutoGetCollectionOrViewForReadCommand::AutoGetCollectionOrViewForReadCommand(
OperationContext* opCtx, const NamespaceString& nss)
: AutoGetCollectionForReadCommand(opCtx, nss, AutoGetCollection::ViewMode::kViewsPermitted),
@@ -192,6 +218,14 @@ AutoGetCollectionOrViewForReadCommand::AutoGetCollectionOrViewForReadCommand(
? _autoCollForRead->getDb()->getViewCatalog()->lookup(opCtx, nss.ns())
: nullptr) {}
+AutoGetCollectionOrViewForReadCommand::AutoGetCollectionOrViewForReadCommand(
+ OperationContext* opCtx, const NamespaceString& nss, Lock::DBLock lock)
+ : AutoGetCollectionForReadCommand(
+ opCtx, nss, AutoGetCollection::ViewMode::kViewsPermitted, std::move(lock)),
+ _view(_autoCollForRead->getDb() && !getCollection()
+ ? _autoCollForRead->getDb()->getViewCatalog()->lookup(opCtx, nss.ns())
+ : nullptr) {}
+
void AutoGetCollectionOrViewForReadCommand::releaseLocksForView() noexcept {
invariant(_view);
_view = nullptr;
diff --git a/src/mongo/db/db_raii.h b/src/mongo/db/db_raii.h
index 641b64e7988..7ff6b8f1a1d 100644
--- a/src/mongo/db/db_raii.h
+++ b/src/mongo/db/db_raii.h
@@ -58,6 +58,7 @@ class AutoGetDb {
public:
AutoGetDb(OperationContext* opCtx, StringData ns, LockMode mode);
+ AutoGetDb(OperationContext* opCtx, StringData ns, Lock::DBLock lock);
Database* getDb() const {
return _db;
@@ -94,6 +95,11 @@ public:
LockMode modeColl)
: AutoGetCollection(opCtx, nss, modeDB, modeColl, ViewMode::kViewsForbidden) {}
+ AutoGetCollection(OperationContext* opCtx,
+ const NamespaceString& nss,
+ LockMode modeColl,
+ ViewMode viewMode,
+ Lock::DBLock lock);
/**
* This constructor is intended for internal use and should not be used outside this file.
* AutoGetCollectionForReadCommand and AutoGetCollectionOrViewForReadCommand use 'viewMode' to
@@ -272,6 +278,10 @@ public:
const NamespaceString& nss,
AutoGetCollection::ViewMode viewMode);
+ AutoGetCollectionForRead(OperationContext* opCtx,
+ const NamespaceString& nss,
+ AutoGetCollection::ViewMode viewMode,
+ Lock::DBLock lock);
Database* getDb() const {
return _autoColl->getDb();
}
@@ -309,6 +319,12 @@ public:
: AutoGetCollectionForReadCommand(
opCtx, nss, AutoGetCollection::ViewMode::kViewsForbidden) {}
+ AutoGetCollectionForReadCommand(OperationContext* opCtx,
+ const NamespaceString& nss,
+ Lock::DBLock lock)
+ : AutoGetCollectionForReadCommand(
+ opCtx, nss, AutoGetCollection::ViewMode::kViewsForbidden, std::move(lock)) {}
+
Database* getDb() const {
return _autoCollForRead->getDb();
}
@@ -322,6 +338,11 @@ protected:
const NamespaceString& nss,
AutoGetCollection::ViewMode viewMode);
+ AutoGetCollectionForReadCommand(OperationContext* opCtx,
+ const NamespaceString& nss,
+ AutoGetCollection::ViewMode viewMode,
+ Lock::DBLock lock);
+
// '_autoCollForRead' may need to be reset by AutoGetCollectionOrViewForReadCommand, so needs to
// be a boost::optional.
boost::optional<AutoGetCollectionForRead> _autoCollForRead;
@@ -343,6 +364,9 @@ class AutoGetCollectionOrViewForReadCommand final : public AutoGetCollectionForR
public:
AutoGetCollectionOrViewForReadCommand(OperationContext* opCtx, const NamespaceString& nss);
+ AutoGetCollectionOrViewForReadCommand(OperationContext* opCtx,
+ const NamespaceString& nss,
+ Lock::DBLock lock);
ViewDefinition* getView() const {
return _view.get();
diff --git a/src/mongo/db/query/SConscript b/src/mongo/db/query/SConscript
index 367b285f454..c57bd8f3016 100644
--- a/src/mongo/db/query/SConscript
+++ b/src/mongo/db/query/SConscript
@@ -246,6 +246,7 @@ env.Library(
LIBDEPS=[
"$BUILD_DIR/mongo/base",
"$BUILD_DIR/mongo/db/repl/read_concern_args",
+ "$BUILD_DIR/mongo/db/catalog/uuid_catalog"
],
)
diff --git a/src/mongo/db/query/canonical_query.cpp b/src/mongo/db/query/canonical_query.cpp
index 17d18c6b798..1df80364b65 100644
--- a/src/mongo/db/query/canonical_query.cpp
+++ b/src/mongo/db/query/canonical_query.cpp
@@ -536,7 +536,7 @@ Status CanonicalQuery::isValid(MatchExpression* root, const QueryRequest& parsed
std::string CanonicalQuery::toString() const {
str::stream ss;
- ss << "ns=" << _qr->ns();
+ ss << "ns=" << _qr->nss().ns();
if (_qr->getBatchSize()) {
ss << " batchSize=" << *_qr->getBatchSize();
diff --git a/src/mongo/db/query/query_request.cpp b/src/mongo/db/query/query_request.cpp
index 6e4d0745b2a..00a8915c1c4 100644
--- a/src/mongo/db/query/query_request.cpp
+++ b/src/mongo/db/query/query_request.cpp
@@ -34,6 +34,7 @@
#include "mongo/base/status_with.h"
#include "mongo/bson/simple_bsonobj_comparator.h"
#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/catalog/uuid_catalog.h"
#include "mongo/db/commands.h"
#include "mongo/db/dbmessage.h"
#include "mongo/db/namespace_string.h"
@@ -110,12 +111,21 @@ const char QueryRequest::kFindCommandName[] = "find";
const char QueryRequest::kShardVersionField[] = "shardVersion";
QueryRequest::QueryRequest(NamespaceString nss) : _nss(std::move(nss)) {}
+QueryRequest::QueryRequest(CollectionUUID uuid) : _uuid(std::move(uuid)) {}
+
+void QueryRequest::refreshNSS(OperationContext* opCtx) {
+ UUIDCatalog& catalog = UUIDCatalog::get(opCtx);
+ if (_uuid) {
+ invariant(catalog.lookupCollectionByUUID(_uuid.get()));
+ _nss = catalog.lookupNSSByUUID(_uuid.get());
+ }
+ invariant(!_nss.isEmpty());
+}
// static
-StatusWith<unique_ptr<QueryRequest>> QueryRequest::makeFromFindCommand(NamespaceString nss,
- const BSONObj& cmdObj,
- bool isExplain) {
- auto qr = stdx::make_unique<QueryRequest>(nss);
+StatusWith<unique_ptr<QueryRequest>> QueryRequest::parseFromFindCommand(unique_ptr<QueryRequest> qr,
+ const BSONObj& cmdObj,
+ bool isExplain) {
qr->_explain = isExplain;
// Parse the command BSON by looping through one element at a time.
@@ -385,6 +395,20 @@ StatusWith<unique_ptr<QueryRequest>> QueryRequest::makeFromFindCommand(Namespace
return std::move(qr);
}
+StatusWith<unique_ptr<QueryRequest>> QueryRequest::makeFromFindCommand(NamespaceString nss,
+ const BSONObj& cmdObj,
+ bool isExplain) {
+ BSONElement first = cmdObj.firstElement();
+ if (first.type() == BinData && first.binDataType() == BinDataType::newUUID) {
+ auto uuid = uassertStatusOK(UUID::parse(first));
+ auto qr = stdx::make_unique<QueryRequest>(uuid);
+ return parseFromFindCommand(std::move(qr), cmdObj, isExplain);
+ } else {
+ auto qr = stdx::make_unique<QueryRequest>(nss);
+ return parseFromFindCommand(std::move(qr), cmdObj, isExplain);
+ }
+}
+
BSONObj QueryRequest::asFindCommand() const {
BSONObjBuilder bob;
asFindCommand(&bob);
diff --git a/src/mongo/db/query/query_request.h b/src/mongo/db/query/query_request.h
index 620e50d8804..fa0f269b4b5 100644
--- a/src/mongo/db/query/query_request.h
+++ b/src/mongo/db/query/query_request.h
@@ -31,8 +31,10 @@
#include <boost/optional.hpp>
#include <string>
+#include "mongo/db/catalog/collection_options.h"
#include "mongo/db/jsobj.h"
#include "mongo/db/namespace_string.h"
+#include "mongo/db/operation_context.h"
namespace mongo {
@@ -52,6 +54,8 @@ public:
QueryRequest(NamespaceString nss);
+ QueryRequest(CollectionUUID uuid);
+
/**
* Returns a non-OK status if any property of the QR has a bad value (e.g. a negative skip
* value) or if there is a bad combination of options (e.g. awaitData is illegal without
@@ -61,7 +65,8 @@ public:
/**
* Parses a find command object, 'cmdObj'. Caller must indicate whether or not this lite
- * parsed query is an explained query or not via 'isExplain'.
+ * parsed query is an explained query or not via 'isExplain'. Accepts a NSS with which
+ * to initialize the QueryRequest if there is no UUID in cmdObj.
*
* Returns a heap allocated QueryRequest on success or an error if 'cmdObj' is not well
* formed.
@@ -71,6 +76,12 @@ public:
bool isExplain);
/**
+ * If _uuid exists for this QueryRequest, use it to update the value of _nss via the
+ * UUIDCatalog associated with opCtx.
+ */
+ void refreshNSS(OperationContext* opCtx);
+
+ /**
* Converts this QR into a find command.
*/
BSONObj asFindCommand() const;
@@ -131,13 +142,10 @@ public:
static const std::string metaTextScore;
const NamespaceString& nss() const {
+ invariant(!_nss.isEmpty());
return _nss;
}
- const std::string& ns() const {
- return _nss.ns();
- }
-
const BSONObj& getFilter() const {
return _filter;
}
@@ -412,6 +420,8 @@ public:
int queryOptions);
private:
+ static StatusWith<std::unique_ptr<QueryRequest>> parseFromFindCommand(
+ std::unique_ptr<QueryRequest> qr, const BSONObj& cmdObj, bool isExplain);
Status init(int ntoskip,
int ntoreturn,
int queryOptions,
@@ -443,7 +453,8 @@ private:
*/
void addMetaProjection();
- const NamespaceString _nss;
+ NamespaceString _nss;
+ OptionalCollectionUUID _uuid;
BSONObj _filter;
BSONObj _proj;
diff --git a/src/mongo/s/balancer_configuration_test.cpp b/src/mongo/s/balancer_configuration_test.cpp
index 834d3d12157..da21e716f18 100644
--- a/src/mongo/s/balancer_configuration_test.cpp
+++ b/src/mongo/s/balancer_configuration_test.cpp
@@ -74,7 +74,7 @@ protected:
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), "config.settings");
+ ASSERT_EQ(query->nss().ns(), "config.settings");
ASSERT_BSONOBJ_EQ(query->getFilter(), BSON("_id" << key));
checkReadConcern(request.cmdObj, Timestamp(0, 0), repl::OpTime::kUninitializedTerm);
diff --git a/src/mongo/s/catalog/sharding_catalog_test.cpp b/src/mongo/s/catalog/sharding_catalog_test.cpp
index 425e08473b2..de9aee82029 100644
--- a/src/mongo/s/catalog/sharding_catalog_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_test.cpp
@@ -110,7 +110,7 @@ TEST_F(ShardingCatalogClientTest, GetCollectionExisting) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
// Ensure the query is correct
- ASSERT_EQ(query->ns(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), CollectionType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(),
BSON(CollectionType::fullNs(expectedColl.getNs().ns())));
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
@@ -174,7 +174,7 @@ TEST_F(ShardingCatalogClientTest, GetDatabaseExisting) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), DatabaseType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), DatabaseType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSON(DatabaseType::name(expectedDb.getName())));
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
ASSERT(!query->getLimit());
@@ -294,7 +294,7 @@ TEST_F(ShardingCatalogClientTest, GetAllShardsValid) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), ShardType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), ShardType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
ASSERT_FALSE(query->getLimit().is_initialized());
@@ -392,7 +392,7 @@ TEST_F(ShardingCatalogClientTest, GetChunksForNSWithSortAndLimit) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), ChunkType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), ChunkType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), chunksQuery);
ASSERT_BSONOBJ_EQ(query->getSort(), BSON(ChunkType::lastmod() << -1));
ASSERT_EQ(query->getLimit().get(), 1);
@@ -446,7 +446,7 @@ TEST_F(ShardingCatalogClientTest, GetChunksForNSNoSortNoLimit) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), ChunkType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), ChunkType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), chunksQuery);
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
ASSERT_FALSE(query->getLimit().is_initialized());
@@ -808,7 +808,7 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsValidResultsNoDb) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), CollectionType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
@@ -866,7 +866,7 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsValidResultsWithDb) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), CollectionType::ConfigNS);
{
BSONObjBuilder b;
b.appendRegex(CollectionType::fullNs(), "^test\\.");
@@ -915,7 +915,7 @@ TEST_F(ShardingCatalogClientTest, GetCollectionsInvalidCollectionType) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), CollectionType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), CollectionType::ConfigNS);
{
BSONObjBuilder b;
b.appendRegex(CollectionType::fullNs(), "^test\\.");
@@ -962,7 +962,7 @@ TEST_F(ShardingCatalogClientTest, GetDatabasesForShardValid) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), DatabaseType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), DatabaseType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(),
BSON(DatabaseType::primary(dbt1.getPrimary().toString())));
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());
@@ -1038,7 +1038,7 @@ TEST_F(ShardingCatalogClientTest, GetTagsForCollection) {
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), TagsType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), TagsType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSON(TagsType::ns("TestDB.TestColl")));
ASSERT_BSONOBJ_EQ(query->getSort(), BSON(TagsType::min() << 1));
@@ -1664,7 +1664,7 @@ TEST_F(ShardingCatalogClientTest, GetNewKeys) {
fromjson("{purpose: 'none',"
"expiresAt: {$gt: {$timestamp: {t: 1234, i: 5678}}}}"));
- ASSERT_EQ(KeysCollectionDocument::ConfigNS, query->ns());
+ ASSERT_EQ(KeysCollectionDocument::ConfigNS, query->nss().ns());
ASSERT_BSONOBJ_EQ(expectedQuery, query->getFilter());
ASSERT_BSONOBJ_EQ(BSON("expiresAt" << 1), query->getSort());
ASSERT_FALSE(query->getLimit().is_initialized());
@@ -1717,7 +1717,7 @@ TEST_F(ShardingCatalogClientTest, GetNewKeysWithEmptyCollection) {
fromjson("{purpose: 'none',"
"expiresAt: {$gt: {$timestamp: {t: 1234, i: 5678}}}}"));
- ASSERT_EQ(KeysCollectionDocument::ConfigNS, query->ns());
+ ASSERT_EQ(KeysCollectionDocument::ConfigNS, query->nss().ns());
ASSERT_BSONOBJ_EQ(expectedQuery, query->getFilter());
ASSERT_BSONOBJ_EQ(BSON("expiresAt" << 1), query->getSort());
ASSERT_FALSE(query->getLimit().is_initialized());
diff --git a/src/mongo/s/cluster_identity_loader_test.cpp b/src/mongo/s/cluster_identity_loader_test.cpp
index 24b77c5d8eb..213fec88d7e 100644
--- a/src/mongo/s/cluster_identity_loader_test.cpp
+++ b/src/mongo/s/cluster_identity_loader_test.cpp
@@ -83,7 +83,7 @@ public:
auto query = assertGet(QueryRequest::makeFromFindCommand(nss, request.cmdObj, false));
- ASSERT_EQ(query->ns(), "config.version");
+ ASSERT_EQ(query->nss().ns(), "config.version");
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_FALSE(query->getLimit().is_initialized());
diff --git a/src/mongo/s/sharding_test_fixture.cpp b/src/mongo/s/sharding_test_fixture.cpp
index aad4203cde3..9f4583f485a 100644
--- a/src/mongo/s/sharding_test_fixture.cpp
+++ b/src/mongo/s/sharding_test_fixture.cpp
@@ -308,7 +308,7 @@ void ShardingTestFixture::expectGetShards(const std::vector<ShardType>& shards)
ASSERT_OK(queryResult.getStatus());
const auto& query = queryResult.getValue();
- ASSERT_EQ(query->ns(), ShardType::ConfigNS);
+ ASSERT_EQ(query->nss().ns(), ShardType::ConfigNS);
ASSERT_BSONOBJ_EQ(query->getFilter(), BSONObj());
ASSERT_BSONOBJ_EQ(query->getSort(), BSONObj());