diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-05-23 13:17:22 -0400 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-05-28 16:13:48 -0400 |
commit | 0672061deb58aac931912bed68d014247c581968 (patch) | |
tree | 5ef08865cb578ee3f46995809b9ac6c7eb3e13df | |
parent | ee3fb776c7f36d59b593db7e4165b0611a7a503f (diff) | |
download | mongo-0672061deb58aac931912bed68d014247c581968.tar.gz |
SERVER-13961 Pass LockState to DBWrite and DBRead directly
This is part of the changes to move LockState be part of OperationContext
and not retrieved from TLS.
169 files changed, 1446 insertions, 1036 deletions
diff --git a/src/mongo/db/auth/auth_index_d.cpp b/src/mongo/db/auth/auth_index_d.cpp index 2b510698b60..b8ed201226e 100644 --- a/src/mongo/db/auth/auth_index_d.cpp +++ b/src/mongo/db/auth/auth_index_d.cpp @@ -72,9 +72,10 @@ namespace { } // namespace - void configureSystemIndexes(const StringData& dbname) { + void configureSystemIndexes(OperationContext* txn, const StringData& dbname) { int authzVersion; - Status status = getGlobalAuthorizationManager()->getAuthorizationVersion(&authzVersion); + Status status = getGlobalAuthorizationManager()->getAuthorizationVersion( + txn, &authzVersion); if (!status.isOK()) { return; } @@ -83,8 +84,8 @@ namespace { NamespaceString systemUsers(dbname, "system.users"); // Make sure the old unique index from v2.4 on system.users doesn't exist. - Client::WriteContext wctx(systemUsers); OperationContextImpl txn; + Client::WriteContext wctx(&txn, systemUsers); Collection* collection = wctx.ctx().db()->getCollection(NamespaceString(systemUsers)); if (!collection) { return; diff --git a/src/mongo/db/auth/auth_index_d.h b/src/mongo/db/auth/auth_index_d.h index 3d3cf711e40..964eec9fbb0 100644 --- a/src/mongo/db/auth/auth_index_d.h +++ b/src/mongo/db/auth/auth_index_d.h @@ -50,7 +50,7 @@ namespace authindex { * It is appropriate to call this function on new or existing databases, though it is * primarily intended for use on existing databases. */ - void configureSystemIndexes(const StringData& dbname); + void configureSystemIndexes(OperationContext* txn, const StringData& dbname); } // namespace authindex } // namespace mongo diff --git a/src/mongo/db/auth/authorization_manager.cpp b/src/mongo/db/auth/authorization_manager.cpp index 3f6e3f620b5..d7960d784ae 100644 --- a/src/mongo/db/auth/authorization_manager.cpp +++ b/src/mongo/db/auth/authorization_manager.cpp @@ -258,14 +258,14 @@ namespace mongo { } } - Status AuthorizationManager::getAuthorizationVersion(int* version) { + Status AuthorizationManager::getAuthorizationVersion(OperationContext* txn, int* version) { CacheGuard guard(this, CacheGuard::fetchSynchronizationManual); int newVersion = _version; if (schemaVersionInvalid == newVersion) { while (guard.otherUpdateInFetchPhase()) guard.wait(); guard.beginFetchPhase(); - Status status = _externalState->getStoredAuthorizationVersion(&newVersion); + Status status = _externalState->getStoredAuthorizationVersion(txn, &newVersion); guard.endFetchPhase(); if (!status.isOK()) { warning() << "Problem fetching the stored schema version of authorization data: " @@ -295,8 +295,8 @@ namespace mongo { return _authEnabled; } - bool AuthorizationManager::hasAnyPrivilegeDocuments() const { - return _externalState->hasAnyPrivilegeDocuments(); + bool AuthorizationManager::hasAnyPrivilegeDocuments(OperationContext* txn) const { + return _externalState->hasAnyPrivilegeDocuments(txn); } Status AuthorizationManager::writeAuthSchemaVersionIfNeeded() { @@ -528,8 +528,10 @@ namespace mongo { return Status::OK(); } - Status AuthorizationManager::getUserDescription(const UserName& userName, BSONObj* result) { - return _externalState->getUserDescription(userName, result); + Status AuthorizationManager::getUserDescription(OperationContext* txn, + const UserName& userName, + BSONObj* result) { + return _externalState->getUserDescription(txn, userName, result); } Status AuthorizationManager::getRoleDescription(const RoleName& roleName, @@ -548,7 +550,8 @@ namespace mongo { result); } - Status AuthorizationManager::acquireUser(const UserName& userName, User** acquiredUser) { + Status AuthorizationManager::acquireUser( + OperationContext* txn, const UserName& userName, User** acquiredUser) { if (userName == internalSecurity.user->getName()) { *acquiredUser = internalSecurity.user; return Status::OK(); @@ -584,7 +587,7 @@ namespace mongo { Status status = Status::OK(); for (int i = 0; i < maxAcquireRetries; ++i) { if (authzVersion == schemaVersionInvalid) { - Status status = _externalState->getStoredAuthorizationVersion(&authzVersion); + Status status = _externalState->getStoredAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) return status; } @@ -597,10 +600,10 @@ namespace mongo { break; case schemaVersion26Final: case schemaVersion26Upgrade: - status = _fetchUserV2(userName, &user); + status = _fetchUserV2(txn, userName, &user); break; case schemaVersion24: - status = _fetchUserV1(userName, &user); + status = _fetchUserV1(txn, userName, &user); break; } if (status.isOK()) @@ -633,10 +636,11 @@ namespace mongo { return Status::OK(); } - Status AuthorizationManager::_fetchUserV2(const UserName& userName, + Status AuthorizationManager::_fetchUserV2(OperationContext* txn, + const UserName& userName, std::auto_ptr<User>* acquiredUser) { BSONObj userObj; - Status status = getUserDescription(userName, &userObj); + Status status = getUserDescription(txn, userName, &userObj); if (!status.isOK()) { return status; } @@ -653,7 +657,8 @@ namespace mongo { return Status::OK(); } - Status AuthorizationManager::_fetchUserV1(const UserName& userName, + Status AuthorizationManager::_fetchUserV1(OperationContext* txn, + const UserName& userName, std::auto_ptr<User>* acquiredUser) { BSONObj privDoc; @@ -673,7 +678,7 @@ namespace mongo { // Users from databases other than "$external" must have an associated privilege // document in their database. Status status = _externalState->getPrivilegeDocumentV1( - userName.getDB(), userName, &privDoc); + txn, userName.getDB(), userName, &privDoc); if (!status.isOK()) return status; @@ -691,7 +696,7 @@ namespace mongo { // Users from databases other than "admin" probe the "admin" database at login, to // ensure that the acquire any privileges derived from "otherDBRoles" fields in // admin.system.users. - Status status = _externalState->getPrivilegeDocumentV1("admin", userName, &privDoc); + Status status = _externalState->getPrivilegeDocumentV1(txn, "admin", userName, &privDoc); if (status.isOK()) { status = parser.initializeUserRolesFromUserDocument(user.get(), privDoc, "admin"); if (!status.isOK()) @@ -709,7 +714,7 @@ namespace mongo { } Status AuthorizationManager::acquireV1UserProbedForDb( - const UserName& userName, const StringData& dbname, User** acquiredUser) { + OperationContext* txn, const UserName& userName, const StringData& dbname, User** acquiredUser) { if (userName == internalSecurity.user->getName()) { *acquiredUser = internalSecurity.user; @@ -750,12 +755,12 @@ namespace mongo { guard.beginFetchPhase(); if (!user.get()) { - Status status = _fetchUserV1(userName, &user); + Status status = _fetchUserV1(txn, userName, &user); if (status == ErrorCodes::AuthSchemaIncompatible) { // Must early-return from this if block, because we end the fetch phase. Since the // auth schema is incompatible with schemaVersion24, make a best effort to do the // schemaVersion26(Upgrade|Final) user acquisition, and return. - status = _fetchUserV2(userName, &user); + status = _fetchUserV2(txn, userName, &user); guard.endFetchPhase(); if (status.isOK()) { // Not safe to throw from here until the function returns. @@ -777,7 +782,7 @@ namespace mongo { if (!user->hasProbedV1(dbname)) { BSONObj privDoc; - Status status = _externalState->getPrivilegeDocumentV1(dbname, userName, &privDoc); + Status status = _externalState->getPrivilegeDocumentV1(txn, dbname, userName, &privDoc); if (status.isOK()) { V1UserDocumentParser parser; status = parser.initializeUserRolesFromUserDocument(user.get(), privDoc, dbname); @@ -1290,9 +1295,10 @@ namespace { } } // namespace - Status AuthorizationManager::upgradeSchemaStep(const BSONObj& writeConcern, bool* isDone) { + Status AuthorizationManager::upgradeSchemaStep( + OperationContext* txn, const BSONObj& writeConcern, bool* isDone) { int authzVersion; - Status status = getAuthorizationVersion(&authzVersion); + Status status = getAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) { return status; } @@ -1316,7 +1322,8 @@ namespace { } } - Status AuthorizationManager::upgradeSchema(int maxSteps, const BSONObj& writeConcern) { + Status AuthorizationManager::upgradeSchema( + OperationContext* txn, int maxSteps, const BSONObj& writeConcern) { if (maxSteps < 1) { return Status(ErrorCodes::BadValue, @@ -1325,7 +1332,7 @@ namespace { invalidateUserCache(); for (int i = 0; i < maxSteps; ++i) { bool isDone; - Status status = upgradeSchemaStep(writeConcern, &isDone); + Status status = upgradeSchemaStep(txn, writeConcern, &isDone); invalidateUserCache(); if (!status.isOK() || isDone) { return status; diff --git a/src/mongo/db/auth/authorization_manager.h b/src/mongo/db/auth/authorization_manager.h index b3a17c491c5..d6a40b3d838 100644 --- a/src/mongo/db/auth/authorization_manager.h +++ b/src/mongo/db/auth/authorization_manager.h @@ -53,6 +53,7 @@ namespace mongo { class AuthzManagerExternalState; class UserDocumentParser; + class OperationContext; /** * Internal secret key info. @@ -164,7 +165,7 @@ namespace mongo { * returns a non-OK status. When returning a non-OK status, *version will be set to * schemaVersionInvalid (0). */ - Status getAuthorizationVersion(int* version); + Status getAuthorizationVersion(OperationContext* txn, int* version); /** * Returns the user cache generation identifier. @@ -172,7 +173,7 @@ namespace mongo { OID getCacheGeneration(); // Returns true if there exists at least one privilege document in the system. - bool hasAnyPrivilegeDocuments() const; + bool hasAnyPrivilegeDocuments(OperationContext* txn) const; /** * Updates the auth schema version document to reflect that the system is upgraded to @@ -281,7 +282,7 @@ namespace mongo { * * If the user does not exist, returns ErrorCodes::UserNotFound. */ - Status getUserDescription(const UserName& userName, BSONObj* result); + Status getUserDescription(OperationContext* txn, const UserName& userName, BSONObj* result); /** * Writes into "result" a document describing the named role and returns Status::OK(). The @@ -324,7 +325,7 @@ namespace mongo { * The AuthorizationManager retains ownership of the returned User object. * On non-OK Status return values, acquiredUser will not be modified. */ - Status acquireUser(const UserName& userName, User** acquiredUser); + Status acquireUser(OperationContext* txn, const UserName& userName, User** acquiredUser); /** * Decrements the refcount of the given User object. If the refcount has gone to zero, @@ -339,8 +340,9 @@ namespace mongo { * * Bumps the returned **acquiredUser's reference count on success. */ - Status acquireV1UserProbedForDb( - const UserName& userName, const StringData& dbname, User** acquiredUser); + Status acquireV1UserProbedForDb(OperationContext* txn, + const UserName& userName, + const StringData& dbname, User** acquiredUser); /** * Marks the given user as invalid and removes it from the user cache. @@ -399,7 +401,8 @@ namespace mongo { * On failure, returns a status other than Status::OK(). In this case, is is typically safe * to try again. */ - Status upgradeSchemaStep(const BSONObj& writeConcern, bool* isDone); + Status upgradeSchemaStep( + OperationContext* txn, const BSONObj& writeConcern, bool* isDone); /** * Performs up to maxSteps steps in the process of upgrading the stored authorization data @@ -414,7 +417,7 @@ namespace mongo { * progress performing the upgrade, and the specific code and message in the returned status * may provide additional information. */ - Status upgradeSchema(int maxSteps, const BSONObj& writeConcern); + Status upgradeSchema(OperationContext* txn, int maxSteps, const BSONObj& writeConcern); /** * Hook called by replication code to let the AuthorizationManager observe changes @@ -458,14 +461,18 @@ namespace mongo { * Fetches user information from a v2-schema user document for the named user, * and stores a pointer to a new user object into *acquiredUser on success. */ - Status _fetchUserV2(const UserName& userName, std::auto_ptr<User>* acquiredUser); + Status _fetchUserV2(OperationContext* txn, + const UserName& userName, + std::auto_ptr<User>* acquiredUser); /** * Fetches user information from a v1-schema user document for the named user, possibly * examining system.users collections from userName.getDB() and admin.system.users in the * process. Stores a pointer to a new user object into *acquiredUser on success. */ - Status _fetchUserV1(const UserName& userName, std::auto_ptr<User>* acquiredUser); + Status _fetchUserV1(OperationContext* txn, + const UserName& userName, + std::auto_ptr<User>* acquiredUser); /** * True if access control enforcement is enabled in this AuthorizationManager. diff --git a/src/mongo/db/auth/authorization_manager_global.cpp b/src/mongo/db/auth/authorization_manager_global.cpp index 68e5cd1e7cb..92c140c4518 100644 --- a/src/mongo/db/auth/authorization_manager_global.cpp +++ b/src/mongo/db/auth/authorization_manager_global.cpp @@ -33,6 +33,7 @@ #include "mongo/client/auth_helpers.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/auth/authorization_manager_global.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/server_parameters.h" #include "mongo/util/assert_util.h" @@ -44,7 +45,7 @@ namespace { MONGO_DISALLOW_COPYING(AuthzVersionParameter); public: AuthzVersionParameter(ServerParameterSet* sps, const std::string& name); - virtual void append(BSONObjBuilder& b, const std::string& name); + virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name); virtual Status set(const BSONElement& newValueElement); virtual Status setFromString(const std::string& str); }; @@ -60,9 +61,11 @@ namespace { AuthzVersionParameter::AuthzVersionParameter(ServerParameterSet* sps, const std::string& name) : ServerParameter(sps, name, false, false) {} - void AuthzVersionParameter::append(BSONObjBuilder& b, const std::string& name) { + void AuthzVersionParameter::append( + OperationContext* txn, BSONObjBuilder& b, const std::string& name) { int authzVersion; - uassertStatusOK(getGlobalAuthorizationManager()->getAuthorizationVersion(&authzVersion)); + uassertStatusOK( + getGlobalAuthorizationManager()->getAuthorizationVersion(txn, &authzVersion)); b.append(name, authzVersion); } diff --git a/src/mongo/db/auth/authorization_manager_test.cpp b/src/mongo/db/auth/authorization_manager_test.cpp index 458a212ccb5..2686a82cc41 100644 --- a/src/mongo/db/auth/authorization_manager_test.cpp +++ b/src/mongo/db/auth/authorization_manager_test.cpp @@ -39,6 +39,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/unittest/unittest.h" #include "mongo/util/map_util.h" @@ -164,6 +165,8 @@ namespace { scoped_ptr<AuthorizationManager> authzManager; AuthzManagerExternalStateMock* externalState; + + OperationContextNoop _txn; }; TEST_F(AuthorizationManagerTest, testAcquireV0User) { @@ -183,7 +186,7 @@ namespace { ASSERT_OK(authzManager->initialize()); User* v0RW; - ASSERT_OK(authzManager->acquireUser(UserName("v0RW", "test"), &v0RW)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("v0RW", "test"), &v0RW)); ASSERT_EQUALS(UserName("v0RW", "test"), v0RW->getName()); ASSERT(v0RW->isValid()); ASSERT_EQUALS(1U, v0RW->getRefCount()); @@ -194,7 +197,7 @@ namespace { authzManager->releaseUser(v0RW); User* v0AdminRO; - ASSERT_OK(authzManager->acquireUser(UserName("v0AdminRO", "admin"), &v0AdminRO)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("v0AdminRO", "admin"), &v0AdminRO)); ASSERT(UserName("v0AdminRO", "admin") == v0AdminRO->getName()); ASSERT(v0AdminRO->isValid()); ASSERT_EQUALS((uint32_t)1, v0AdminRO->getRefCount()); @@ -222,7 +225,7 @@ namespace { BSONObj())); User* v1read; - ASSERT_OK(authzManager->acquireUser(UserName("v1read", "test"), &v1read)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("v1read", "test"), &v1read)); ASSERT_EQUALS(UserName("v1read", "test"), v1read->getName()); ASSERT(v1read->isValid()); ASSERT_EQUALS((uint32_t)1, v1read->getRefCount()); @@ -234,7 +237,7 @@ namespace { authzManager->releaseUser(v1read); User* v1cluster; - ASSERT_OK(authzManager->acquireUser(UserName("v1cluster", "admin"), &v1cluster)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("v1cluster", "admin"), &v1cluster)); ASSERT_EQUALS(UserName("v1cluster", "admin"), v1cluster->getName()); ASSERT(v1cluster->isValid()); ASSERT_EQUALS((uint32_t)1, v1cluster->getRefCount()); @@ -277,7 +280,7 @@ namespace { ASSERT_OK(status); User* readOnly; - ASSERT_OK(authzManager->acquireUser(UserName("readOnly", "test"), &readOnly)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("readOnly", "test"), &readOnly)); ASSERT_EQUALS(UserName("readOnly", "test"), readOnly->getName()); ASSERT(readOnly->isValid()); ASSERT_EQUALS(1U, readOnly->getRefCount()); @@ -288,7 +291,7 @@ namespace { authzManager->releaseUser(readOnly); User* clusterAdmin; - ASSERT_OK(authzManager->acquireUser(UserName("clusterAdmin", "$external"), &clusterAdmin)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("clusterAdmin", "$external"), &clusterAdmin)); ASSERT_EQUALS(UserName("clusterAdmin", "$external"), clusterAdmin->getName()); ASSERT(clusterAdmin->isValid()); ASSERT_EQUALS(1U, clusterAdmin->getRefCount()); @@ -299,16 +302,17 @@ namespace { authzManager->releaseUser(clusterAdmin); User* multiDB; - status = authzManager->acquireUser(UserName("readWriteMultiDB", "test2"), &multiDB); + status = authzManager->acquireUser(&_txn, UserName("readWriteMultiDB", "test2"), &multiDB); ASSERT_NOT_OK(status); ASSERT(status.code() == ErrorCodes::UserNotFound); - ASSERT_OK(authzManager->acquireUser(UserName("readWriteMultiDB", "test"), &multiDB)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("readWriteMultiDB", "test"), &multiDB)); ASSERT_EQUALS(UserName("readWriteMultiDB", "test"), multiDB->getName()); ASSERT(multiDB->isValid()); ASSERT_EQUALS(1U, multiDB->getRefCount()); User* multiDBProbed; ASSERT_OK(authzManager->acquireV1UserProbedForDb( + &_txn, UserName("readWriteMultiDB", "test"), "test2", &multiDBProbed)); @@ -357,7 +361,7 @@ namespace { BSONObj())); User* v2read; - ASSERT_OK(authzManager->acquireUser(UserName("v2read", "test"), &v2read)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("v2read", "test"), &v2read)); ASSERT_EQUALS(UserName("v2read", "test"), v2read->getName()); ASSERT(v2read->isValid()); ASSERT_EQUALS(1U, v2read->getRefCount()); @@ -368,7 +372,7 @@ namespace { authzManager->releaseUser(v2read); User* v2cluster; - ASSERT_OK(authzManager->acquireUser(UserName("v2cluster", "admin"), &v2cluster)); + ASSERT_OK(authzManager->acquireUser(&_txn, UserName("v2cluster", "admin"), &v2cluster)); ASSERT_EQUALS(UserName("v2cluster", "admin"), v2cluster->getName()); ASSERT(v2cluster->isValid()); ASSERT_EQUALS(1U, v2cluster->getRefCount()); @@ -459,7 +463,7 @@ namespace { // Verify that the expected users are present. ASSERT_EQUALS(3U, externalState->getCollectionContents(collectionName).size()); - ASSERT_OK(externalState->findOne(collectionName, + ASSERT_OK(externalState->findOne(&_txn, collectionName, BSON("user" << "clusterAdmin" << "userSource" << "$external"), &doc)); @@ -469,14 +473,14 @@ namespace { ASSERT_EQUALS(1U, doc["roles"].Array().size()); ASSERT_EQUALS("clusterAdmin", doc["roles"].Array()[0].str()); - ASSERT_OK(externalState->findOne(collectionName, + ASSERT_OK(externalState->findOne(&_txn, collectionName, BSON("user" << "otherdbroles" << "userSource" << "test"), &doc)); ASSERT_TRUE(doc["pwd"].eoo()); ASSERT_EQUALS(0U, doc["roles"].Array().size()); - ASSERT_OK(externalState->findOne(collectionName, + ASSERT_OK(externalState->findOne(&_txn, collectionName, BSON("user" << "mixedroles" << "userSource" << "test"), &doc)); @@ -488,7 +492,7 @@ namespace { BSONObj doc; // Verify that the admin.system.version document reflects correct upgrade. - ASSERT_OK(externalState->findOne( + ASSERT_OK(externalState->findOne(&_txn, AuthorizationManager::versionCollectionNamespace, BSON("_id" << "authSchema" << AuthorizationManager::schemaVersionFieldName << @@ -505,7 +509,7 @@ namespace { AuthorizationManager::usersCollectionNamespace).size()); // "readOnly@test" user - ASSERT_OK(externalState->findOne(AuthorizationManager::usersCollectionNamespace, + ASSERT_OK(externalState->findOne(&_txn, AuthorizationManager::usersCollectionNamespace, BSON("user" << "readOnly" << "db" << "test"), &doc)); ASSERT_EQUALS("readOnly", doc["user"].str()); @@ -514,7 +518,7 @@ namespace { ASSERT_EQUALS(1U, doc["roles"].Array().size()); // "clusterAdmin@$external" user - ASSERT_OK(externalState->findOne( + ASSERT_OK(externalState->findOne(&_txn, AuthorizationManager::usersCollectionNamespace, BSON("user" << "clusterAdmin" << "db" << "$external"), &doc)); @@ -523,7 +527,7 @@ namespace { ASSERT_EQUALS(1U, doc["roles"].Array().size()); // "readWriteMultiDB@test" user - ASSERT_OK(externalState->findOne( + ASSERT_OK(externalState->findOne(&_txn, AuthorizationManager::usersCollectionNamespace, BSON("user" << "readWriteMultiDB" << "db" << "test"), &doc)); @@ -533,7 +537,7 @@ namespace { ASSERT_EQUALS(2U, doc["roles"].Array().size()); // "otherdbroles@test" user - ASSERT_OK(externalState->findOne( + ASSERT_OK(externalState->findOne(&_txn, AuthorizationManager::usersCollectionNamespace, BSON("user" << "otherdbroles" << "db" << "test"), &doc)); @@ -550,7 +554,7 @@ namespace { ASSERT_EQUALS(1U, rolePairs.count(make_pair("readWrite", "test3"))); // "mixedroles@test" user - ASSERT_OK(externalState->findOne( + ASSERT_OK(externalState->findOne(&_txn, AuthorizationManager::usersCollectionNamespace, BSON("user" << "mixedroles" << "db" << "test"), &doc)); @@ -570,7 +574,7 @@ namespace { } void upgradeAuthCollections() { - ASSERT_OK(authzManager->upgradeSchema(10, BSONObj())); + ASSERT_OK(authzManager->upgradeSchema(&_txn, 10, BSONObj())); } }; @@ -587,8 +591,8 @@ namespace { externalState->setAuthzVersion(AuthorizationManager::schemaVersion24); setUpV1UserData(); ASSERT_EQUALS(ErrorCodes::OperationIncomplete, - authzManager->upgradeSchema(1, BSONObj())); - ASSERT_OK(authzManager->upgradeSchema(1, BSONObj())); + authzManager->upgradeSchema(&_txn, 1, BSONObj())); + ASSERT_OK(authzManager->upgradeSchema(&_txn, 1, BSONObj())); } TEST_F(AuthzUpgradeTest, upgradeUserDataFromV1ToV2WithSysVerDoc) { @@ -605,7 +609,7 @@ namespace { setUpV1UserData(); externalState->setAuthzVersion(AuthorizationManager::schemaVersion26Final); bool done; - ASSERT_OK(authzManager->upgradeSchemaStep(BSONObj(), &done)); + ASSERT_OK(authzManager->upgradeSchemaStep(&_txn, BSONObj(), &done)); ASSERT_TRUE(done); validateV1AdminUserData(AuthorizationManager::usersCollectionNamespace); int numRemoved; diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp index a934ee3aae6..fa0594b429f 100644 --- a/src/mongo/db/auth/authorization_session.cpp +++ b/src/mongo/db/auth/authorization_session.cpp @@ -67,14 +67,15 @@ namespace { return _externalState->getAuthorizationManager(); } - void AuthorizationSession::startRequest() { - _externalState->startRequest(); - _refreshUserInfoAsNeeded(); + void AuthorizationSession::startRequest(OperationContext* txn) { + _externalState->startRequest(txn); + _refreshUserInfoAsNeeded(txn); } - Status AuthorizationSession::addAndAuthorizeUser(const UserName& userName) { + Status AuthorizationSession::addAndAuthorizeUser( + OperationContext* txn, const UserName& userName) { User* user; - Status status = getAuthorizationManager().acquireUser(userName, &user); + Status status = getAuthorizationManager().acquireUser(txn, userName, &user); if (!status.isOK()) { return status; } @@ -160,29 +161,32 @@ namespace { return defaultPrivileges; } - Status AuthorizationSession::checkAuthForQuery(const NamespaceString& ns, + Status AuthorizationSession::checkAuthForQuery(OperationContext* txn, + const NamespaceString& ns, const BSONObj& query) { if (MONGO_unlikely(ns.isCommand())) { return Status(ErrorCodes::InternalError, mongoutils::str::stream() << "Checking query auth on command namespace " << ns.ns()); } - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) { + if (!isAuthorizedForActionsOnNamespace(txn, ns, ActionType::find)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized for query on " << ns.ns()); } return Status::OK(); } - Status AuthorizationSession::checkAuthForGetMore(const NamespaceString& ns, + Status AuthorizationSession::checkAuthForGetMore(OperationContext* txn, + const NamespaceString& ns, long long cursorID) { - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::find)) { + if (!isAuthorizedForActionsOnNamespace(txn, ns, ActionType::find)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized for getmore on " << ns.ns()); } return Status::OK(); } - Status AuthorizationSession::checkAuthForInsert(const NamespaceString& ns, + Status AuthorizationSession::checkAuthForInsert(OperationContext* txn, + const NamespaceString& ns, const BSONObj& document) { if (ns.coll() == StringData("system.indexes", StringData::LiteralTag())) { BSONElement nsElement = document["ns"]; @@ -191,13 +195,13 @@ namespace { "system.indexes documents without a string-typed \"ns\" field."); } NamespaceString indexNS(nsElement.str()); - if (!isAuthorizedForActionsOnNamespace(indexNS, ActionType::createIndex)) { + if (!isAuthorizedForActionsOnNamespace(txn, indexNS, ActionType::createIndex)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized to create index on " << indexNS.ns()); } } else { - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::insert)) { + if (!isAuthorizedForActionsOnNamespace(txn, ns, ActionType::insert)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized for insert on " << ns.ns()); @@ -207,12 +211,13 @@ namespace { return Status::OK(); } - Status AuthorizationSession::checkAuthForUpdate(const NamespaceString& ns, + Status AuthorizationSession::checkAuthForUpdate(OperationContext* txn, + const NamespaceString& ns, const BSONObj& query, const BSONObj& update, bool upsert) { if (!upsert) { - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::update)) { + if (!isAuthorizedForActionsOnNamespace(txn, ns, ActionType::update)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized for update on " << ns.ns()); @@ -222,7 +227,7 @@ namespace { ActionSet required; required.addAction(ActionType::update); required.addAction(ActionType::insert); - if (!isAuthorizedForActionsOnNamespace(ns, required)) { + if (!isAuthorizedForActionsOnNamespace(txn, ns, required)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized for upsert on " << ns.ns()); @@ -231,19 +236,22 @@ namespace { return Status::OK(); } - Status AuthorizationSession::checkAuthForDelete(const NamespaceString& ns, + Status AuthorizationSession::checkAuthForDelete(OperationContext* txn, + const NamespaceString& ns, const BSONObj& query) { - if (!isAuthorizedForActionsOnNamespace(ns, ActionType::remove)) { + if (!isAuthorizedForActionsOnNamespace(txn, ns, ActionType::remove)) { return Status(ErrorCodes::Unauthorized, mongoutils::str::stream() << "not authorized to remove from " << ns.ns()); } return Status::OK(); } - Status AuthorizationSession::checkAuthorizedToGrantPrivilege(const Privilege& privilege) { + Status AuthorizationSession::checkAuthorizedToGrantPrivilege( + OperationContext* txn, const Privilege& privilege) { const ResourcePattern& resource = privilege.getResourcePattern(); if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { if (!isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(resource.databaseToMatch()), ActionType::grantRole)) { return Status(ErrorCodes::Unauthorized, @@ -251,7 +259,9 @@ namespace { << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName("admin"), ActionType::grantRole)) { + txn, + ResourcePattern::forDatabaseName("admin"), + ActionType::grantRole)) { return Status(ErrorCodes::Unauthorized, "To grant privileges affecting multiple databases or the cluster," " must be authorized to grant roles from the admin database"); @@ -260,10 +270,12 @@ namespace { } - Status AuthorizationSession::checkAuthorizedToRevokePrivilege(const Privilege& privilege) { + Status AuthorizationSession::checkAuthorizedToRevokePrivilege( + OperationContext* txn, const Privilege& privilege) { const ResourcePattern& resource = privilege.getResourcePattern(); if (resource.isDatabasePattern() || resource.isExactNamespacePattern()) { if (!isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(resource.databaseToMatch()), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, @@ -271,7 +283,9 @@ namespace { << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName("admin"), ActionType::revokeRole)) { + txn, + ResourcePattern::forDatabaseName("admin"), + ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, "To revoke privileges affecting multiple databases or the cluster," " must be authorized to revoke roles from the admin database"); @@ -279,55 +293,62 @@ namespace { return Status::OK(); } - bool AuthorizationSession::isAuthorizedToGrantRole(const RoleName& role) { + bool AuthorizationSession::isAuthorizedToGrantRole( + OperationContext* txn, const RoleName& role) { return isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(role.getDB()), - ActionType::grantRole); + txn, + ResourcePattern::forDatabaseName(role.getDB()), + ActionType::grantRole); } - bool AuthorizationSession::isAuthorizedToRevokeRole(const RoleName& role) { + bool AuthorizationSession::isAuthorizedToRevokeRole( + OperationContext* txn, const RoleName& role) { return isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(role.getDB()), - ActionType::revokeRole); + txn, + ResourcePattern::forDatabaseName(role.getDB()), + ActionType::revokeRole); } - bool AuthorizationSession::isAuthorizedForPrivilege(const Privilege& privilege) { + bool AuthorizationSession::isAuthorizedForPrivilege( + OperationContext* txn, const Privilege& privilege) { if (_externalState->shouldIgnoreAuthChecks()) return true; - return _isAuthorizedForPrivilege(privilege); + return _isAuthorizedForPrivilege(txn, privilege); } - bool AuthorizationSession::isAuthorizedForPrivileges(const vector<Privilege>& privileges) { + bool AuthorizationSession::isAuthorizedForPrivileges( + OperationContext* txn, const vector<Privilege>& privileges) { if (_externalState->shouldIgnoreAuthChecks()) return true; for (size_t i = 0; i < privileges.size(); ++i) { - if (!_isAuthorizedForPrivilege(privileges[i])) + if (!_isAuthorizedForPrivilege(txn, privileges[i])) return false; } return true; } - bool AuthorizationSession::isAuthorizedForActionsOnResource(const ResourcePattern& resource, - ActionType action) { - return isAuthorizedForPrivilege(Privilege(resource, action)); + bool AuthorizationSession::isAuthorizedForActionsOnResource( + OperationContext* txn, const ResourcePattern& resource, ActionType action) { + return isAuthorizedForPrivilege(txn, Privilege(resource, action)); } - bool AuthorizationSession::isAuthorizedForActionsOnResource(const ResourcePattern& resource, - const ActionSet& actions) { - return isAuthorizedForPrivilege(Privilege(resource, actions)); + bool AuthorizationSession::isAuthorizedForActionsOnResource( + OperationContext* txn, const ResourcePattern& resource, const ActionSet& actions) { + return isAuthorizedForPrivilege(txn, Privilege(resource, actions)); } - bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns, - ActionType action) { - return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), action)); + bool AuthorizationSession::isAuthorizedForActionsOnNamespace( + OperationContext* txn, const NamespaceString& ns, ActionType action) { + return isAuthorizedForPrivilege(txn, Privilege(ResourcePattern::forExactNamespace(ns), action)); } - bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns, - const ActionSet& actions) { - return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), actions)); + bool AuthorizationSession::isAuthorizedForActionsOnNamespace( + OperationContext* txn, const NamespaceString& ns, const ActionSet& actions) { + return isAuthorizedForPrivilege( + txn, Privilege(ResourcePattern::forExactNamespace(ns), actions)); } static const int resourceSearchListCapacity = 5; @@ -422,7 +443,7 @@ namespace { return false; } - void AuthorizationSession::_refreshUserInfoAsNeeded() { + void AuthorizationSession::_refreshUserInfoAsNeeded(OperationContext* txn) { AuthorizationManager& authMan = getAuthorizationManager(); UserSet::iterator it = _authenticatedUsers.begin(); while (it != _authenticatedUsers.end()) { @@ -434,7 +455,7 @@ namespace { UserName name = user->getName(); User* updatedUser; - Status status = authMan.acquireUser(name, &updatedUser); + Status status = authMan.acquireUser(txn, name, &updatedUser); switch (status.code()) { case ErrorCodes::OK: { // Success! Replace the old User object with the updated one. @@ -463,7 +484,8 @@ namespace { } } - bool AuthorizationSession::_isAuthorizedForPrivilege(const Privilege& privilege) { + bool AuthorizationSession::_isAuthorizedForPrivilege( + OperationContext* txn, const Privilege& privilege) { const ResourcePattern& target(privilege.getResourcePattern()); ResourcePattern resourceSearchList[resourceSearchListCapacity]; @@ -498,6 +520,7 @@ namespace { UserName name = user->getName(); User* updatedUser; Status status = getAuthorizationManager().acquireV1UserProbedForDb( + txn, name, target.databaseToMatch(), &updatedUser); diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h index 1a12a0719e0..14232158266 100644 --- a/src/mongo/db/auth/authorization_session.h +++ b/src/mongo/db/auth/authorization_session.h @@ -71,13 +71,13 @@ namespace mongo { // Should be called at the beginning of every new request. This performs the checks // necessary to determine if localhost connections should be given full access. // TODO: try to eliminate the need for this call. - void startRequest(); + void startRequest(OperationContext* txn); /** * Adds the User identified by "UserName" to the authorization session, acquiring privileges * for it in the process. */ - Status addAndAuthorizeUser(const UserName& userName); + Status addAndAuthorizeUser(OperationContext* txn, const UserName& userName); // Returns the authenticated user with the given name. Returns NULL // if no such user is found. @@ -109,15 +109,16 @@ namespace mongo { // Checks if this connection has the privileges necessary to perform the given query on the // given namespace. - Status checkAuthForQuery(const NamespaceString& ns, const BSONObj& query); + Status checkAuthForQuery(OperationContext* txn, const NamespaceString& ns, const BSONObj& query); // Checks if this connection has the privileges necessary to perform a getMore on the given // cursor in the given namespace. - Status checkAuthForGetMore(const NamespaceString& ns, long long cursorID); + Status checkAuthForGetMore(OperationContext* txn, const NamespaceString& ns, long long cursorID); // Checks if this connection has the privileges necessary to perform the given update on the // given namespace. - Status checkAuthForUpdate(const NamespaceString& ns, + Status checkAuthForUpdate(OperationContext* txn, + const NamespaceString& ns, const BSONObj& query, const BSONObj& update, bool upsert); @@ -125,27 +126,29 @@ namespace mongo { // Checks if this connection has the privileges necessary to insert the given document // to the given namespace. Correctly interprets inserts to system.indexes and performs // the proper auth checks for index building. - Status checkAuthForInsert(const NamespaceString& ns, const BSONObj& document); + Status checkAuthForInsert( + OperationContext* txn, const NamespaceString& ns, const BSONObj& document); // Checks if this connection has the privileges necessary to perform a delete on the given // namespace. - Status checkAuthForDelete(const NamespaceString& ns, const BSONObj& query); + Status checkAuthForDelete( + OperationContext* txn, const NamespaceString& ns, const BSONObj& query); // Checks if this connection has the privileges necessary to grant the given privilege // to a role. - Status checkAuthorizedToGrantPrivilege(const Privilege& privilege); + Status checkAuthorizedToGrantPrivilege(OperationContext* txn, const Privilege& privilege); // Checks if this connection has the privileges necessary to revoke the given privilege // from a role. - Status checkAuthorizedToRevokePrivilege(const Privilege& privilege); + Status checkAuthorizedToRevokePrivilege(OperationContext* txn, const Privilege& privilege); // Utility function for isAuthorizedForActionsOnResource( // ResourcePattern::forDatabaseName(role.getDB()), ActionType::grantAnyRole) - bool isAuthorizedToGrantRole(const RoleName& role); + bool isAuthorizedToGrantRole(OperationContext* txn, const RoleName& role); // Utility function for isAuthorizedForActionsOnResource( // ResourcePattern::forDatabaseName(role.getDB()), ActionType::grantAnyRole) - bool isAuthorizedToRevokeRole(const RoleName& role); + bool isAuthorizedToRevokeRole(OperationContext* txn, const RoleName& role); // Returns true if the current session is authenticated as the given user and that user // is allowed to change his/her own password @@ -163,26 +166,31 @@ namespace mongo { // // Contains all the authorization logic including handling things like the localhost // exception. - bool isAuthorizedForPrivilege(const Privilege& privilege); + bool isAuthorizedForPrivilege(OperationContext* txn, const Privilege& privilege); // Like isAuthorizedForPrivilege, above, except returns true if the session is authorized // for all of the listed privileges. - bool isAuthorizedForPrivileges(const std::vector<Privilege>& privileges); + bool isAuthorizedForPrivileges( + OperationContext* txn, const std::vector<Privilege>& privileges); // Utility function for isAuthorizedForPrivilege(Privilege(resource, action)). - bool isAuthorizedForActionsOnResource(const ResourcePattern& resource, ActionType action); + bool isAuthorizedForActionsOnResource( + OperationContext* txn, const ResourcePattern& resource, ActionType action); // Utility function for isAuthorizedForPrivilege(Privilege(resource, actions)). - bool isAuthorizedForActionsOnResource(const ResourcePattern& resource, + bool isAuthorizedForActionsOnResource(OperationContext* txn, + const ResourcePattern& resource, const ActionSet& actions); // Utility function for // isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), action). - bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, ActionType action); + bool isAuthorizedForActionsOnNamespace( + OperationContext* txn, const NamespaceString& ns, ActionType action); // Utility function for // isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), actions). - bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, const ActionSet& actions); + bool isAuthorizedForActionsOnNamespace( + OperationContext* txn, const NamespaceString& ns, const ActionSet& actions); // Replaces the vector of UserNames that a system user is impersonating with a new vector. // The auditing system adds these to each audit record in the log. @@ -203,12 +211,12 @@ namespace mongo { // If any users authenticated on this session are marked as invalid this updates them with // up-to-date information. May require a read lock on the "admin" db to read the user data. - void _refreshUserInfoAsNeeded(); + void _refreshUserInfoAsNeeded(OperationContext* txn); // Checks if this connection is authorized for the given Privilege, ignoring whether or not // we should even be doing authorization checks in general. Note: this may acquire a read // lock on the admin database (to update out-of-date user privilege information). - bool _isAuthorizedForPrivilege(const Privilege& privilege); + bool _isAuthorizedForPrivilege(OperationContext* txn, const Privilege& privilege); scoped_ptr<AuthzSessionExternalState> _externalState; diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index 078ba1cfe01..75874d76c92 100644 --- a/src/mongo/db/auth/authorization_session_test.cpp +++ b/src/mongo/db/auth/authorization_session_test.cpp @@ -36,6 +36,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/jsobj.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/unittest/unittest.h" #include "mongo/util/map_util.h" @@ -53,7 +54,8 @@ namespace { void setFindsShouldFail(bool enable) { _findsShouldFail = enable; } - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { if (_findsShouldFail && @@ -62,7 +64,7 @@ namespace { return Status(ErrorCodes::UnknownError, "findOne on admin.system.users set to fail in mock."); } - return AuthzManagerExternalStateMock::findOne(collectionName, query, result); + return AuthzManagerExternalStateMock::findOne(txn, collectionName, query, result); } private: @@ -84,6 +86,9 @@ namespace { authzSession.reset(new AuthorizationSession(sessionState)); authzManager->setAuthEnabled(true); } + + protected: + OperationContextNoop _txn; }; const ResourcePattern testDBResource(ResourcePattern::forDatabaseName("test")); @@ -119,17 +124,17 @@ namespace { TEST_F(AuthorizationSessionTest, AddUserAndCheckAuthorization) { // Check that disabling auth checks works ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); sessionState->setReturnValueForShouldIgnoreAuthChecks(true); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); sessionState->setReturnValueForShouldIgnoreAuthChecks(false); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); // Check that you can't authorize a user that doesn't exist. ASSERT_EQUALS(ErrorCodes::UserNotFound, - authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); // Add a user with readWrite and dbAdmin on the test DB ASSERT_OK(managerState->insertPrivilegeDocument("admin", @@ -141,14 +146,14 @@ namespace { BSON("role" << "dbAdmin" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testDBResource, ActionType::dbStats)); + &_txn, testDBResource, ActionType::dbStats)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); // Add an admin user with readWriteAnyDatabase ASSERT_OK(managerState->insertPrivilegeDocument("admin", @@ -158,36 +163,37 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "readWriteAnyDatabase" << "db" << "admin"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("admin", "admin"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("admin", "admin"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( + &_txn, ResourcePattern::forExactNamespace( NamespaceString("anydb.somecollection")), ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherDBResource, ActionType::insert)); + &_txn, otherDBResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::collMod)); + &_txn, otherFooCollResource, ActionType::collMod)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); authzSession->logoutDatabase("test"); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); + &_txn, testFooCollResource, ActionType::collMod)); authzSession->logoutDatabase("admin"); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); + &_txn, testFooCollResource, ActionType::collMod)); } TEST_F(AuthorizationSessionTest, DuplicateRolesOK) { @@ -203,14 +209,14 @@ namespace { BSON("role" << "readWrite" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testDBResource, ActionType::dbStats)); + &_txn, testDBResource, ActionType::dbStats)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); } TEST_F(AuthorizationSessionTest, SystemCollectionsAccessControl) { @@ -247,83 +253,83 @@ namespace { "db" << "admin"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("rwany", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rwany", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); + &_txn, testUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); + &_txn, testUsersCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); + &_txn, otherUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); + &_txn, otherUsersCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); + &_txn, testIndexesCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); + &_txn, testProfileCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); + &_txn, otherIndexesCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); + &_txn, otherProfileCollResource, ActionType::find)); // Logging in as useradminany@test implicitly logs out rwany@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradminany", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradminany", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); + &_txn, testUsersCollResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); + &_txn, testUsersCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); + &_txn, otherUsersCollResource, ActionType::insert)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); + &_txn, otherUsersCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); + &_txn, testIndexesCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); + &_txn, testProfileCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); + &_txn, otherIndexesCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); + &_txn, otherProfileCollResource, ActionType::find)); // Logging in as rw@test implicitly logs out useradminany@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("rw", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("rw", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); + &_txn, testUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); + &_txn, testUsersCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); + &_txn, otherUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); + &_txn, otherUsersCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); + &_txn, testIndexesCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); + &_txn, testProfileCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); + &_txn, otherIndexesCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); + &_txn, otherProfileCollResource, ActionType::find)); // Logging in as useradmin@test implicitly logs out rw@test. - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("useradmin", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("useradmin", "test"))); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::insert)); + &_txn, testUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testUsersCollResource, ActionType::find)); + &_txn, testUsersCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::insert)); + &_txn, otherUsersCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherUsersCollResource, ActionType::find)); + &_txn, otherUsersCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testIndexesCollResource, ActionType::find)); + &_txn, testIndexesCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testProfileCollResource, ActionType::find)); + &_txn, testProfileCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherIndexesCollResource, ActionType::find)); + &_txn, otherIndexesCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - otherProfileCollResource, ActionType::find)); + &_txn, otherProfileCollResource, ActionType::find)); } TEST_F(AuthorizationSessionTest, InvalidateUser) { @@ -335,12 +341,12 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "readWrite" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); User* user = authzSession->lookupUser(UserName("spencer", "test")); ASSERT(user->isValid()); @@ -362,11 +368,11 @@ namespace { // Make sure that invalidating the user causes the session to reload its privileges. authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); user = authzSession->lookupUser(UserName("spencer", "test")); ASSERT(user->isValid()); @@ -379,11 +385,11 @@ namespace { &ignored); // Make sure that invalidating the user causes the session to reload its privileges. authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT_FALSE(authzSession->lookupUser(UserName("spencer", "test"))); } @@ -396,12 +402,12 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "readWrite" << "db" << "test"))), BSONObj())); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("spencer", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("spencer", "test"))); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); User* user = authzSession->lookupUser(UserName("spencer", "test")); ASSERT(user->isValid()); @@ -426,20 +432,20 @@ namespace { // document lookup to fail, the authz session should continue to use its known out-of-date // privilege data. authzManager->invalidateUserByName(user->getName()); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); // Once we configure document lookup to succeed again, authorization checks should // observe the new values. managerState->setFindsShouldFail(false); - authzSession->startRequest(); // Refreshes cached data for invalid users + authzSession->startRequest(&_txn); // Refreshes cached data for invalid users ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); } @@ -465,92 +471,92 @@ namespace { ASSERT_OK(authzManager->initialize()); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); + &_txn, testFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::find)); + &_txn, otherFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::collMod)); + &_txn, otherFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::find)); + &_txn, thirdFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::insert)); + &_txn, thirdFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::collMod)); + &_txn, thirdFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::find)); + &_txn, adminFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::insert)); + &_txn, adminFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::collMod)); + &_txn, adminFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::shutdown)); + &_txn, ResourcePattern::forClusterResource(), ActionType::shutdown)); - ASSERT_OK(authzSession->addAndAuthorizeUser(UserName("andy", "test"))); + ASSERT_OK(authzSession->addAndAuthorizeUser(&_txn, UserName("andy", "test"))); User* user = authzSession->lookupUser(UserName("andy", "test")); ASSERT(UserName("andy", "test") == user->getName()); ASSERT(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT(authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); + &_txn, testFooCollResource, ActionType::collMod)); ASSERT(authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::find)); + &_txn, otherFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::collMod)); + &_txn, otherFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::find)); + &_txn, thirdFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::insert)); + &_txn, thirdFooCollResource, ActionType::insert)); ASSERT(authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::collMod)); + &_txn, thirdFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::find)); + &_txn, adminFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::insert)); + &_txn, adminFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::collMod)); + &_txn, adminFooCollResource, ActionType::collMod)); ASSERT(authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::shutdown)); + &_txn, ResourcePattern::forClusterResource(), ActionType::shutdown)); authzSession->logoutDatabase("test"); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::find)); + &_txn, testFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::insert)); + &_txn, testFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - testFooCollResource, ActionType::collMod)); + &_txn, testFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::find)); + &_txn, otherFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::insert)); + &_txn, otherFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - otherFooCollResource, ActionType::collMod)); + &_txn, otherFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::find)); + &_txn, thirdFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::insert)); + &_txn, thirdFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - thirdFooCollResource, ActionType::collMod)); + &_txn, thirdFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::find)); + &_txn, adminFooCollResource, ActionType::find)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::insert)); + &_txn, adminFooCollResource, ActionType::insert)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - adminFooCollResource, ActionType::collMod)); + &_txn, adminFooCollResource, ActionType::collMod)); ASSERT(!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::shutdown)); + &_txn, ResourcePattern::forClusterResource(), ActionType::shutdown)); } } // namespace diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp index e5f63496799..25640191cec 100644 --- a/src/mongo/db/auth/authz_manager_external_state.cpp +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -40,7 +40,8 @@ namespace mongo { AuthzManagerExternalState::AuthzManagerExternalState() {} AuthzManagerExternalState::~AuthzManagerExternalState() {} - Status AuthzManagerExternalState::getPrivilegeDocumentV1(const StringData& dbname, + Status AuthzManagerExternalState::getPrivilegeDocumentV1(OperationContext* txn, + const StringData& dbname, const UserName& userName, BSONObj* result) { if (userName == internalSecurity.user->getName()) { @@ -69,7 +70,7 @@ namespace mongo { // Query for the privilege document BSONObj userBSONObj; - Status found = findOne(usersNamespace, queryBuilder.done(), &userBSONObj); + Status found = findOne(txn, usersNamespace, queryBuilder.done(), &userBSONObj); if (!found.isOK()) { if (found.code() == ErrorCodes::NoMatchingDocument) { // Return more detailed status that includes user name. @@ -97,9 +98,10 @@ namespace mongo { return Status::OK(); } - bool AuthzManagerExternalState::hasAnyPrivilegeDocuments() { + bool AuthzManagerExternalState::hasAnyPrivilegeDocuments(OperationContext* txn) { BSONObj userBSONObj; Status status = findOne( + txn, AuthorizationManager::usersCollectionNamespace, BSONObj(), &userBSONObj); diff --git a/src/mongo/db/auth/authz_manager_external_state.h b/src/mongo/db/auth/authz_manager_external_state.h index f637415ae91..7c97eb5ea38 100644 --- a/src/mongo/db/auth/authz_manager_external_state.h +++ b/src/mongo/db/auth/authz_manager_external_state.h @@ -41,6 +41,8 @@ namespace mongo { + class OperationContext; + /** * Public interface for a class that encapsulates all the information related to system * state not stored in AuthorizationManager. This is primarily to make AuthorizationManager @@ -64,7 +66,7 @@ namespace mongo { * Retrieves the schema version of the persistent data describing users and roles. * Will leave *outVersion unmodified on non-OK status return values. */ - virtual Status getStoredAuthorizationVersion(int* outVersion) = 0; + virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion) = 0; /** * Writes into "result" a document describing the named user and returns Status::OK(). The @@ -76,7 +78,8 @@ namespace mongo { * * If the user does not exist, returns ErrorCodes::UserNotFound. */ - virtual Status getUserDescription(const UserName& userName, BSONObj* result) = 0; + virtual Status getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result) = 0; /** * Writes into "result" a document describing the named role and returns Status::OK(). The @@ -119,13 +122,15 @@ namespace mongo { * On success, returns Status::OK() and stores a shared-ownership copy of the document into * "result". */ - Status getPrivilegeDocumentV1( - const StringData& dbname, const UserName& userName, BSONObj* result); + Status getPrivilegeDocumentV1(OperationContext* txn, + const StringData& dbname, + const UserName& userName, + BSONObj* result); /** * Returns true if there exists at least one privilege document in the system. */ - bool hasAnyPrivilegeDocuments(); + bool hasAnyPrivilegeDocuments(OperationContext* txn); /** * Creates the given user object in the given database. @@ -164,7 +169,8 @@ namespace mongo { * Returns Status::OK() on success. If no match is found, returns * ErrorCodes::NoMatchingDocument. Other errors returned as appropriate. */ - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) = 0; diff --git a/src/mongo/db/auth/authz_manager_external_state_d.cpp b/src/mongo/db/auth/authz_manager_external_state_d.cpp index 2c009314f48..852f6d96b71 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_d.cpp @@ -47,12 +47,13 @@ namespace mongo { AuthzManagerExternalStateMongod::AuthzManagerExternalStateMongod() {} AuthzManagerExternalStateMongod::~AuthzManagerExternalStateMongod() {} - Status AuthzManagerExternalStateMongod::_getUserDocument(const UserName& userName, - BSONObj* userDoc) { + Status AuthzManagerExternalStateMongod::_getUserDocument( + OperationContext* txn, const UserName& userName, BSONObj* userDoc) { + + Client::ReadContext ctx(txn, "admin"); - Client::ReadContext ctx("admin"); int authzVersion; - Status status = getStoredAuthorizationVersion(&authzVersion); + Status status = getStoredAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) return status; @@ -67,6 +68,7 @@ namespace mongo { } status = findOne( + txn, (authzVersion == AuthorizationManager::schemaVersion26Final ? AuthorizationManager::usersCollectionNamespace : AuthorizationManager::usersAltCollectionNamespace), @@ -102,11 +104,13 @@ namespace mongo { } Status AuthzManagerExternalStateMongod::findOne( + OperationContext* txn, const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { - Client::ReadContext ctx(collectionName.ns()); + Client::ReadContext ctx(txn, collectionName.ns()); + BSONObj found; if (Helpers::findOne(ctx.ctx().db()->getCollection(collectionName), query, diff --git a/src/mongo/db/auth/authz_manager_external_state_d.h b/src/mongo/db/auth/authz_manager_external_state_d.h index 380d4eb6bef..213fcc56152 100644 --- a/src/mongo/db/auth/authz_manager_external_state_d.h +++ b/src/mongo/db/auth/authz_manager_external_state_d.h @@ -52,7 +52,8 @@ namespace mongo { virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result); virtual Status query(const NamespaceString& collectionName, @@ -83,7 +84,8 @@ namespace mongo { virtual void releaseAuthzUpdateLock(); private: - virtual Status _getUserDocument(const UserName& userName, BSONObj* userDoc); + virtual Status _getUserDocument( + OperationContext* txn, const UserName& userName, BSONObj* userDoc); boost::timed_mutex _authzDataUpdateLock; }; diff --git a/src/mongo/db/auth/authz_manager_external_state_local.cpp b/src/mongo/db/auth/authz_manager_external_state_local.cpp index 099e5638020..926158bc740 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_local.cpp @@ -59,9 +59,11 @@ namespace mongo { return Status::OK(); } - Status AuthzManagerExternalStateLocal::getStoredAuthorizationVersion(int* outVersion) { + Status AuthzManagerExternalStateLocal::getStoredAuthorizationVersion( + OperationContext* txn, int* outVersion) { BSONObj versionDoc; - Status status = findOne(AuthorizationManager::versionCollectionNamespace, + Status status = findOne(txn, + AuthorizationManager::versionCollectionNamespace, AuthorizationManager::versionDocumentQuery, &versionDoc); if (status.isOK()) { @@ -85,7 +87,7 @@ namespace mongo { } } else if (status == ErrorCodes::NoMatchingDocument) { - if (hasAnyPrivilegeDocuments()) { + if (hasAnyPrivilegeDocuments(txn)) { *outVersion = AuthorizationManager::schemaVersion24; } else { @@ -136,11 +138,12 @@ namespace { } // namespace Status AuthzManagerExternalStateLocal::getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result) { BSONObj userDoc; - Status status = _getUserDocument(userName, &userDoc); + Status status = _getUserDocument(txn, userName, &userDoc); if (!status.isOK()) return status; diff --git a/src/mongo/db/auth/authz_manager_external_state_local.h b/src/mongo/db/auth/authz_manager_external_state_local.h index 2c49c4b7cc7..ba48862e277 100644 --- a/src/mongo/db/auth/authz_manager_external_state_local.h +++ b/src/mongo/db/auth/authz_manager_external_state_local.h @@ -53,8 +53,9 @@ namespace mongo { virtual Status initialize(); - virtual Status getStoredAuthorizationVersion(int* outVersion); - virtual Status getUserDescription(const UserName& userName, BSONObj* result); + virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion); + virtual Status getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result); virtual Status getRoleDescription(const RoleName& roleName, bool showPrivileges, BSONObj* result); @@ -88,7 +89,9 @@ namespace mongo { /** * Fetches the user document for "userName" from local storage, and stores it into "result". */ - virtual Status _getUserDocument(const UserName& userName, BSONObj* result) = 0; + virtual Status _getUserDocument(OperationContext* txn, + const UserName& userName, + BSONObj* result) = 0; Status _getRoleDescription_inlock(const RoleName& roleName, bool showPrivileges, diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.cpp b/src/mongo/db/auth/authz_manager_external_state_mock.cpp index 5ee19c863a5..809d4ecb747 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_mock.cpp @@ -97,10 +97,11 @@ namespace { BSONObj())); } - Status AuthzManagerExternalStateMock::_getUserDocument(const UserName& userName, + Status AuthzManagerExternalStateMock::_getUserDocument(OperationContext* txn, + const UserName& userName, BSONObj* userDoc) { int authzVersion; - Status status = getStoredAuthorizationVersion(&authzVersion); + Status status = getStoredAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) return status; @@ -115,6 +116,7 @@ namespace { } status = findOne( + txn, (authzVersion == AuthorizationManager::schemaVersion26Final ? AuthorizationManager::usersCollectionNamespace : AuthorizationManager::usersAltCollectionNamespace), @@ -139,18 +141,8 @@ namespace { return Status::OK(); } - Status AuthzManagerExternalStateMock::_findUser( - const std::string& usersNamespace, - const BSONObj& query, - BSONObj* result) { - if (!findOne(NamespaceString(usersNamespace), query, result).isOK()) { - return Status(ErrorCodes::UserNotFound, - "No matching user for query " + query.toString()); - } - return Status::OK(); - } - Status AuthzManagerExternalStateMock::findOne( + OperationContext* txn, const NamespaceString& collectionName, const BSONObj& query, BSONObj* result) { diff --git a/src/mongo/db/auth/authz_manager_external_state_mock.h b/src/mongo/db/auth/authz_manager_external_state_mock.h index 6ec06f97692..06db6b77890 100644 --- a/src/mongo/db/auth/authz_manager_external_state_mock.h +++ b/src/mongo/db/auth/authz_manager_external_state_mock.h @@ -60,7 +60,8 @@ namespace mongo { virtual Status getAllDatabaseNames(std::vector<std::string>* dbnames); - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result); @@ -101,16 +102,14 @@ namespace mongo { virtual bool tryAcquireAuthzUpdateLock(const StringData& why); virtual void releaseAuthzUpdateLock(); - Status _findUser(const std::string& usersNamespace, - const BSONObj& query, - BSONObj* result); std::vector<BSONObj> getCollectionContents(const NamespaceString& collectionName); private: typedef std::vector<BSONObj> BSONObjCollection; typedef std::map<NamespaceString, BSONObjCollection> NamespaceDocumentMap; - virtual Status _getUserDocument(const UserName& userName, BSONObj* userDoc); + virtual Status _getUserDocument( + OperationContext* txn, const UserName& userName, BSONObj* userDoc); Status _findOneIter(const NamespaceString& collectionName, const BSONObj& query, diff --git a/src/mongo/db/auth/authz_manager_external_state_s.cpp b/src/mongo/db/auth/authz_manager_external_state_s.cpp index 8f1dd6d1256..0cd3760258c 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.cpp +++ b/src/mongo/db/auth/authz_manager_external_state_s.cpp @@ -70,7 +70,8 @@ namespace mongo { } } - Status AuthzManagerExternalStateMongos::getStoredAuthorizationVersion(int* outVersion) { + Status AuthzManagerExternalStateMongos::getStoredAuthorizationVersion( + OperationContext* txn, int* outVersion) { scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection( AuthorizationManager::usersCollectionNamespace)); Status status = auth::getRemoteStoredAuthorizationVersion(conn->get(), outVersion); @@ -78,8 +79,8 @@ namespace mongo { return status; } - Status AuthzManagerExternalStateMongos::getUserDescription(const UserName& userName, - BSONObj* result) { + Status AuthzManagerExternalStateMongos::getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result) { try { scoped_ptr<ScopedDbConnection> conn(getConnectionForAuthzCollection( AuthorizationManager::usersCollectionNamespace)); @@ -190,6 +191,7 @@ namespace mongo { } Status AuthzManagerExternalStateMongos::findOne( + OperationContext* txn, const NamespaceString& collectionName, const BSONObj& queryDoc, BSONObj* result) { diff --git a/src/mongo/db/auth/authz_manager_external_state_s.h b/src/mongo/db/auth/authz_manager_external_state_s.h index 203ce25f5ac..c19e3ed056e 100644 --- a/src/mongo/db/auth/authz_manager_external_state_s.h +++ b/src/mongo/db/auth/authz_manager_external_state_s.h @@ -52,8 +52,9 @@ namespace mongo { virtual ~AuthzManagerExternalStateMongos(); virtual Status initialize(); - virtual Status getStoredAuthorizationVersion(int* outVersion); - virtual Status getUserDescription(const UserName& userName, BSONObj* result); + virtual Status getStoredAuthorizationVersion(OperationContext* txn, int* outVersion); + virtual Status getUserDescription( + OperationContext* txn, const UserName& userName, BSONObj* result); virtual Status getRoleDescription(const RoleName& roleName, bool showPrivileges, BSONObj* result); @@ -70,7 +71,8 @@ namespace mongo { * NOTE: The data returned from this helper may be from any config server or replica set * node. The first config server or primary node is preferred, when available. */ - virtual Status findOne(const NamespaceString& collectionName, + virtual Status findOne(OperationContext* txn, + const NamespaceString& collectionName, const BSONObj& query, BSONObj* result); diff --git a/src/mongo/db/auth/authz_session_external_state.h b/src/mongo/db/auth/authz_session_external_state.h index dbd838cb68f..2e1b41a0565 100644 --- a/src/mongo/db/auth/authz_session_external_state.h +++ b/src/mongo/db/auth/authz_session_external_state.h @@ -39,6 +39,7 @@ namespace mongo { class Principal; + class OperationContext; /** * Public interface for a class that encapsulates all the session information related to system @@ -68,7 +69,7 @@ namespace mongo { // Should be called at the beginning of every new request. This performs the checks // necessary to determine if localhost connections should be given full access. - virtual void startRequest() = 0; + virtual void startRequest(OperationContext* txn) = 0; protected: // This class should never be instantiated directly. diff --git a/src/mongo/db/auth/authz_session_external_state_d.cpp b/src/mongo/db/auth/authz_session_external_state_d.cpp index 0156ccf6c9b..614b5e67505 100644 --- a/src/mongo/db/auth/authz_session_external_state_d.cpp +++ b/src/mongo/db/auth/authz_session_external_state_d.cpp @@ -45,9 +45,9 @@ namespace mongo { AuthzSessionExternalStateServerCommon(authzManager) {} AuthzSessionExternalStateMongod::~AuthzSessionExternalStateMongod() {} - void AuthzSessionExternalStateMongod::startRequest() { + void AuthzSessionExternalStateMongod::startRequest(OperationContext* txn) { if (!Lock::isLocked()) { - _checkShouldAllowLocalhost(); + _checkShouldAllowLocalhost(txn); } } diff --git a/src/mongo/db/auth/authz_session_external_state_d.h b/src/mongo/db/auth/authz_session_external_state_d.h index f5b2c82cd03..0df26d507c7 100644 --- a/src/mongo/db/auth/authz_session_external_state_d.h +++ b/src/mongo/db/auth/authz_session_external_state_d.h @@ -47,7 +47,7 @@ namespace mongo { virtual bool shouldIgnoreAuthChecks() const; - virtual void startRequest(); + virtual void startRequest(OperationContext* txn); }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_session_external_state_mock.h b/src/mongo/db/auth/authz_session_external_state_mock.h index c884654ac91..0acc98366ea 100644 --- a/src/mongo/db/auth/authz_session_external_state_mock.h +++ b/src/mongo/db/auth/authz_session_external_state_mock.h @@ -62,7 +62,7 @@ namespace mongo { _allowLocalhostReturnValue = returnValue; } - virtual void startRequest() {} + virtual void startRequest(OperationContext* txn) {} private: bool _ignoreAuthChecksReturnValue; diff --git a/src/mongo/db/auth/authz_session_external_state_s.cpp b/src/mongo/db/auth/authz_session_external_state_s.cpp index 14801eae945..4009670c6c4 100644 --- a/src/mongo/db/auth/authz_session_external_state_s.cpp +++ b/src/mongo/db/auth/authz_session_external_state_s.cpp @@ -43,8 +43,8 @@ namespace mongo { AuthzSessionExternalStateServerCommon(authzManager) {} AuthzSessionExternalStateMongos::~AuthzSessionExternalStateMongos() {} - void AuthzSessionExternalStateMongos::startRequest() { - _checkShouldAllowLocalhost(); + void AuthzSessionExternalStateMongos::startRequest(OperationContext* txn) { + _checkShouldAllowLocalhost(txn); } } // namespace mongo diff --git a/src/mongo/db/auth/authz_session_external_state_s.h b/src/mongo/db/auth/authz_session_external_state_s.h index 6672957ced4..777082faadc 100644 --- a/src/mongo/db/auth/authz_session_external_state_s.h +++ b/src/mongo/db/auth/authz_session_external_state_s.h @@ -45,7 +45,7 @@ namespace mongo { AuthzSessionExternalStateMongos(AuthorizationManager* authzManager); virtual ~AuthzSessionExternalStateMongos(); - virtual void startRequest(); + virtual void startRequest(OperationContext* txn); }; } // namespace mongo diff --git a/src/mongo/db/auth/authz_session_external_state_server_common.cpp b/src/mongo/db/auth/authz_session_external_state_server_common.cpp index b5c6f6a4bc3..debef7d3120 100644 --- a/src/mongo/db/auth/authz_session_external_state_server_common.cpp +++ b/src/mongo/db/auth/authz_session_external_state_server_common.cpp @@ -31,6 +31,7 @@ #include "mongo/base/status.h" #include "mongo/db/auth/authorization_manager.h" #include "mongo/db/client.h" +#include "mongo/db/operation_context.h" #include "mongo/db/server_parameters.h" #include "mongo/util/debug_util.h" @@ -49,7 +50,7 @@ namespace { _allowLocalhost(enableLocalhostAuthBypass) {} AuthzSessionExternalStateServerCommon::~AuthzSessionExternalStateServerCommon() {} - void AuthzSessionExternalStateServerCommon::_checkShouldAllowLocalhost() { + void AuthzSessionExternalStateServerCommon::_checkShouldAllowLocalhost(OperationContext* txn) { if (!_authzManager->isAuthEnabled()) return; // If we know that an admin user exists, don't re-check. @@ -61,7 +62,7 @@ namespace { return; } - _allowLocalhost = !_authzManager->hasAnyPrivilegeDocuments(); + _allowLocalhost = !_authzManager->hasAnyPrivilegeDocuments(txn); if (_allowLocalhost) { ONCE { log() << "note: no users configured in admin.system.users, allowing localhost " diff --git a/src/mongo/db/auth/authz_session_external_state_server_common.h b/src/mongo/db/auth/authz_session_external_state_server_common.h index f6e1a97f4a9..59599a6befd 100644 --- a/src/mongo/db/auth/authz_session_external_state_server_common.h +++ b/src/mongo/db/auth/authz_session_external_state_server_common.h @@ -53,7 +53,7 @@ namespace mongo { // Checks whether or not localhost connections should be given full access and stores the // result in _allowLocalhost. Currently localhost connections are only given full access // if there are no users in the admin database. - virtual void _checkShouldAllowLocalhost(); + void _checkShouldAllowLocalhost(OperationContext* txn); private: diff --git a/src/mongo/db/catalog/collection_cursor_cache.cpp b/src/mongo/db/catalog/collection_cursor_cache.cpp index 926baf7a137..d4727a17ee2 100644 --- a/src/mongo/db/catalog/collection_cursor_cache.cpp +++ b/src/mongo/db/catalog/collection_cursor_cache.cpp @@ -98,11 +98,11 @@ namespace mongo { /** * works globally */ - bool eraseCursor( CursorId id, bool checkAuth ); + bool eraseCursor(OperationContext* txn, CursorId id, bool checkAuth); void appendStats( BSONObjBuilder& builder ); - std::size_t timeoutCursors( int millisSinceLastCall ); + std::size_t timeoutCursors(OperationContext* txn, int millisSinceLastCall); int64_t nextSeed(); @@ -159,7 +159,7 @@ namespace mongo { _idToNS.erase( id ); } - bool GlobalCursorIdCache::eraseCursor(CursorId id, bool checkAuth) { + bool GlobalCursorIdCache::eraseCursor(OperationContext* txn, CursorId id, bool checkAuth) { string ns; { SimpleMutex::scoped_lock lk( _mutex ); @@ -175,8 +175,8 @@ namespace mongo { if ( checkAuth ) { AuthorizationSession* as = cc().getAuthorizationSession(); - bool isAuthorized = as->isAuthorizedForActionsOnNamespace(nss, - ActionType::killCursors); + bool isAuthorized = as->isAuthorizedForActionsOnNamespace( + txn, nss, ActionType::killCursors); if ( !isAuthorized ) { audit::logKillCursorsAuthzCheck( currentClient.get(), nss, @@ -186,8 +186,8 @@ namespace mongo { } } - Lock::DBRead lock( ns ); - Database* db = dbHolder().get( ns, storageGlobalParams.dbpath ); + Lock::DBRead lock(txn->lockState(), ns); + Database* db = dbHolder().get(ns, storageGlobalParams.dbpath); if ( !db ) return false; Client::Context context( ns, db ); @@ -204,7 +204,7 @@ namespace mongo { return collection->cursorCache()->eraseCursor( id, checkAuth ); } - std::size_t GlobalCursorIdCache::timeoutCursors( int millisSinceLastCall ) { + std::size_t GlobalCursorIdCache::timeoutCursors(OperationContext* txn, int millisSinceLastCall) { vector<string> todo; { SimpleMutex::scoped_lock lk( _mutex ); @@ -216,7 +216,7 @@ namespace mongo { for ( unsigned i = 0; i < todo.size(); i++ ) { const string& ns = todo[i]; - Lock::DBRead lock( ns ); + Lock::DBRead lock(txn->lockState(), ns); Database* db = dbHolder().get( ns, storageGlobalParams.dbpath ); if ( !db ) continue; @@ -235,25 +235,25 @@ namespace mongo { // --- - std::size_t CollectionCursorCache::timeoutCursorsGlobal( int millisSinceLastCall ) { - return _globalCursorIdCache.timeoutCursors( millisSinceLastCall ); + std::size_t CollectionCursorCache::timeoutCursorsGlobal(OperationContext* txn, int millisSinceLastCall) {; + return _globalCursorIdCache.timeoutCursors(txn, millisSinceLastCall); } - int CollectionCursorCache::eraseCursorGlobalIfAuthorized(int n, long long* ids) { + int CollectionCursorCache::eraseCursorGlobalIfAuthorized(OperationContext* txn, int n, long long* ids) { int numDeleted = 0; for ( int i = 0; i < n; i++ ) { - if ( eraseCursorGlobalIfAuthorized( ids[i] ) ) + if ( eraseCursorGlobalIfAuthorized(txn, ids[i] ) ) numDeleted++; if ( inShutdown() ) break; } return numDeleted; } - bool CollectionCursorCache::eraseCursorGlobalIfAuthorized(CursorId id) { - return _globalCursorIdCache.eraseCursor( id, true ); + bool CollectionCursorCache::eraseCursorGlobalIfAuthorized(OperationContext* txn, CursorId id) { + return _globalCursorIdCache.eraseCursor(txn, id, true); } - bool CollectionCursorCache::eraseCursorGlobal( CursorId id ) { - return _globalCursorIdCache.eraseCursor( id, false ); + bool CollectionCursorCache::eraseCursorGlobal(OperationContext* txn, CursorId id) { + return _globalCursorIdCache.eraseCursor(txn, id, false ); } diff --git a/src/mongo/db/catalog/collection_cursor_cache.h b/src/mongo/db/catalog/collection_cursor_cache.h index bc057def73f..d08800d4d7b 100644 --- a/src/mongo/db/catalog/collection_cursor_cache.h +++ b/src/mongo/db/catalog/collection_cursor_cache.h @@ -109,15 +109,15 @@ namespace mongo { // ---------------------- - static int eraseCursorGlobalIfAuthorized( int n, long long* ids ); - static bool eraseCursorGlobalIfAuthorized( CursorId id ); + static int eraseCursorGlobalIfAuthorized(OperationContext* txn, int n, long long* ids); + static bool eraseCursorGlobalIfAuthorized(OperationContext* txn, CursorId id); - static bool eraseCursorGlobal( CursorId id ); + static bool eraseCursorGlobal(OperationContext* txn, CursorId id); /** * @return number timed out */ - static std::size_t timeoutCursorsGlobal( int millisSinceLastCall ); + static std::size_t timeoutCursorsGlobal(OperationContext* txn, int millisSinceLastCall); private: CursorId _allocateCursorId_inlock(); diff --git a/src/mongo/db/catalog/database_holder.cpp b/src/mongo/db/catalog/database_holder.cpp index 3516cc06a09..aeded6b196b 100644 --- a/src/mongo/db/catalog/database_holder.cpp +++ b/src/mongo/db/catalog/database_holder.cpp @@ -41,8 +41,7 @@ namespace mongo { - Database* DatabaseHolder::getOrCreate( const string& ns, const string& path, bool& justCreated ) { - OperationContextImpl txn; // TODO get rid of this once reads require transactions + Database* DatabaseHolder::getOrCreate(OperationContext* txn, const string& ns, const string& path, bool& justCreated) { string dbname = _todb( ns ); { SimpleMutex::scoped_lock lk(_m); @@ -74,7 +73,7 @@ namespace mongo { cc().writeHappened(); // this locks _m for defensive checks, so we don't want to be locked right here : - Database *db = new Database( &txn, dbname.c_str() , justCreated , path ); + Database *db = new Database(txn, dbname.c_str(), justCreated, path); { SimpleMutex::scoped_lock lk(_m); diff --git a/src/mongo/db/catalog/database_holder.h b/src/mongo/db/catalog/database_holder.h index a2901926db7..ad40b8601c4 100644 --- a/src/mongo/db/catalog/database_holder.h +++ b/src/mongo/db/catalog/database_holder.h @@ -82,7 +82,10 @@ namespace mongo { return 0; } - Database* getOrCreate( const std::string& ns , const std::string& path , bool& justCreated ); + Database* getOrCreate(OperationContext* txn, + const std::string& ns, + const std::string& path, + bool& justCreated); void erase( const std::string& ns , const std::string& path ) { SimpleMutex::scoped_lock lk(_m); diff --git a/src/mongo/db/client.cpp b/src/mongo/db/client.cpp index 21dd08f9b92..97e5ba1c71e 100644 --- a/src/mongo/db/client.cpp +++ b/src/mongo/db/client.cpp @@ -55,6 +55,7 @@ #include "mongo/db/instance.h" #include "mongo/db/json.h" #include "mongo/db/jsobj.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/repl/rs.h" #include "mongo/db/storage_options.h" #include "mongo/s/chunk_version.h" @@ -191,14 +192,13 @@ namespace mongo { /** "read lock, and set my context, all in one operation" * This handles (if not recursively locked) opening an unopened database. */ - Client::ReadContext::ReadContext(const string& ns, - const std::string& path, - bool doVersion) { + Client::ReadContext::ReadContext( + OperationContext* txn, const string& ns, bool doVersion) { { - lk.reset( new Lock::DBRead(ns) ); - Database *db = dbHolder().get(ns, path); + _lk.reset(new Lock::DBRead(txn->lockState(), ns)); + Database *db = dbHolder().get(ns, storageGlobalParams.dbpath); if( db ) { - c.reset( new Context(path, ns, db, doVersion) ); + _c.reset(new Context(storageGlobalParams.dbpath, ns, db, doVersion)); return; } } @@ -209,17 +209,18 @@ namespace mongo { if( Lock::isW() ) { // write locked already DEV RARELY log() << "write locked on ReadContext construction " << ns << endl; - c.reset(new Context(ns, path, doVersion)); + _c.reset(new Context(ns, storageGlobalParams.dbpath, doVersion)); } else if( !Lock::nested() ) { - lk.reset(0); + _lk.reset(0); { Lock::GlobalWrite w; - Context c(ns, path, doVersion); + Context c(ns, storageGlobalParams.dbpath, doVersion); } + // db could be closed at this interim point -- that is ok, we will throw, and don't mind throwing. - lk.reset( new Lock::DBRead(ns) ); - c.reset(new Context(ns, path, doVersion)); + _lk.reset(new Lock::DBRead(txn->lockState(), ns)); + _c.reset(new Context(ns, storageGlobalParams.dbpath, doVersion)); } else { uasserted(15928, str::stream() << "can't open a database from a nested read lock " << ns); @@ -231,9 +232,10 @@ namespace mongo { // it would be easy to first check that there is at least a .ns file, or something similar. } - Client::WriteContext::WriteContext(const string& ns, const std::string& path, bool doVersion) - : _lk( ns ) , - _c(ns, path, doVersion) { + Client::WriteContext::WriteContext( + OperationContext* opCtx, const std::string& ns, bool doVersion) + : _lk(opCtx->lockState(), ns), + _c(ns, storageGlobalParams.dbpath, doVersion) { } @@ -279,7 +281,8 @@ namespace mongo { uassert(14031, "Can't take a write lock while out of disk space", false); } - _db = dbHolderUnchecked().getOrCreate( _ns , _path , _justCreated ); + OperationContextImpl txn; // TODO get rid of this once reads require transactions + _db = dbHolderUnchecked().getOrCreate(&txn, _ns, _path, _justCreated); verify(_db); if( _doVersion ) checkNotStale(); massert( 16107 , str::stream() << "Don't have a lock on: " << _ns , Lock::atLeastReadLocked( _ns ) ); diff --git a/src/mongo/db/client.h b/src/mongo/db/client.h index 6d4179c506a..17beba12098 100644 --- a/src/mongo/db/client.h +++ b/src/mongo/db/client.h @@ -146,13 +146,13 @@ namespace mongo { */ class ReadContext : boost::noncopyable { public: - ReadContext(const std::string& ns, - const std::string& path=storageGlobalParams.dbpath, + ReadContext(OperationContext* txn, + const std::string& ns, bool doVersion = true); - Context& ctx() { return *c.get(); } + Context& ctx() { return *_c.get(); } private: - scoped_ptr<Lock::DBRead> lk; - scoped_ptr<Context> c; + scoped_ptr<Lock::DBRead> _lk; + scoped_ptr<Context> _c; }; /* Set database we want to use, then, restores when we finish (are out of scope) @@ -219,10 +219,9 @@ namespace mongo { class WriteContext : boost::noncopyable { public: - WriteContext(const std::string& ns, - const std::string& path=storageGlobalParams.dbpath, - bool doVersion = true); + WriteContext(OperationContext* opCtx, const std::string& ns, bool doVersion = true); Context& ctx() { return _c; } + private: Lock::DBWrite _lk; Context _c; diff --git a/src/mongo/db/clientcursor.cpp b/src/mongo/db/clientcursor.cpp index 628c4e110b7..3bac1b29535 100644 --- a/src/mongo/db/clientcursor.cpp +++ b/src/mongo/db/clientcursor.cpp @@ -45,6 +45,7 @@ #include "mongo/db/db.h" #include "mongo/db/jsobj.h" #include "mongo/db/kill_current_op.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/repl/rs.h" #include "mongo/db/repl/write_concern.h" @@ -219,8 +220,10 @@ namespace mongo { Client& client = cc(); Timer t; const int Secs = 4; - while ( ! inShutdown() ) { - cursorStatsTimedOut.increment( CollectionCursorCache::timeoutCursorsGlobal( t.millisReset() ) ); + while (!inShutdown()) { + OperationContextImpl txn; + cursorStatsTimedOut.increment( + CollectionCursorCache::timeoutCursorsGlobal(&txn, t.millisReset())); sleepsecs(Secs); } client.shutdown(); diff --git a/src/mongo/db/cloner.cpp b/src/mongo/db/cloner.cpp index d1b97e9be3a..519a1f6b9e8 100644 --- a/src/mongo/db/cloner.cpp +++ b/src/mongo/db/cloner.cpp @@ -301,7 +301,7 @@ namespace mongo { bool copyIndexes, bool logForRepl) { - Client::WriteContext ctx(ns); + Client::WriteContext ctx(txn, ns); // config string temp = ctx.ctx().db()->name() + ".system.namespaces"; diff --git a/src/mongo/db/commands.cpp b/src/mongo/db/commands.cpp index 524a7f916de..2d33d022da7 100644 --- a/src/mongo/db/commands.cpp +++ b/src/mongo/db/commands.cpp @@ -255,13 +255,15 @@ namespace mongo { return Status(ErrorCodes::Error(code), errmsg); } - Status Command::checkAuthForCommand(ClientBasic* client, + Status Command::checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { std::vector<Privilege> privileges; this->addRequiredPrivileges(dbname, cmdObj, &privileges); - if (client->getAuthorizationSession()->isAuthorizedForPrivileges(privileges)) + if (client->getAuthorizationSession()->isAuthorizedForPrivileges(txn, privileges)) { return Status::OK(); + } return Status(ErrorCodes::Unauthorized, "unauthorized"); } @@ -274,7 +276,8 @@ namespace mongo { } } - static Status _checkAuthorizationImpl(Command* c, + static Status _checkAuthorizationImpl(OperationContext* txn, + Command* c, ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj, @@ -285,7 +288,7 @@ namespace mongo { " may only be run against the admin database."); } if (client->getAuthorizationSession()->getAuthorizationManager().isAuthEnabled()) { - Status status = c->checkAuthForCommand(client, dbname, cmdObj); + Status status = c->checkAuthForCommand(txn, client, dbname, cmdObj); if (status == ErrorCodes::Unauthorized) { mmb::Document cmdToLog(cmdObj, mmb::Document::kInPlaceDisabled); c->redactForLogging(&cmdToLog); @@ -307,13 +310,14 @@ namespace mongo { return Status::OK(); } - Status Command::_checkAuthorization(Command* c, + Status Command::_checkAuthorization(OperationContext* txn, + Command* c, ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj, bool fromRepl) { namespace mmb = mutablebson; - Status status = _checkAuthorizationImpl(c, client, dbname, cmdObj, fromRepl); + Status status = _checkAuthorizationImpl(txn, c, client, dbname, cmdObj, fromRepl); if (!status.isOK()) { log() << status << std::endl; } diff --git a/src/mongo/db/commands.h b/src/mongo/db/commands.h index 4446020a94c..38c79f1971f 100644 --- a/src/mongo/db/commands.h +++ b/src/mongo/db/commands.h @@ -141,7 +141,8 @@ namespace mutablebson { * Checks if the given client is authorized to run this command on database "dbname" * with the invocation described by "cmdObj". */ - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj); @@ -256,7 +257,8 @@ namespace mutablebson { * ErrorCodes::Unauthorized otherwise, but any return other than Status::OK implies not * authorized. */ - static Status _checkAuthorization(Command* c, + static Status _checkAuthorization(OperationContext* txn, + Command* c, ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj, diff --git a/src/mongo/db/commands/apply_ops.cpp b/src/mongo/db/commands/apply_ops.cpp index ef3c2ea2ab9..37c72610627 100644 --- a/src/mongo/db/commands/apply_ops.cpp +++ b/src/mongo/db/commands/apply_ops.cpp @@ -127,7 +127,7 @@ namespace mongo { // operations are applied. We are already locked globally at this point, so taking // a DBWrite on the namespace creates a nested lock, and yields are disallowed for // operations that hold a nested lock. - Lock::DBWrite lk(ns); + Lock::DBWrite lk(txn->lockState(), ns); invariant(Lock::nested()); Client::Context ctx(ns); diff --git a/src/mongo/db/commands/auth_schema_upgrade_d.cpp b/src/mongo/db/commands/auth_schema_upgrade_d.cpp index 3a52792615e..4f63bacd173 100644 --- a/src/mongo/db/commands/auth_schema_upgrade_d.cpp +++ b/src/mongo/db/commands/auth_schema_upgrade_d.cpp @@ -147,7 +147,7 @@ namespace { if (!status.isOK()) return appendCommandStatus(result, status); - status = authzManager->upgradeSchema(maxSteps, writeConcern); + status = authzManager->upgradeSchema(txn, maxSteps, writeConcern); if (status.isOK()) result.append("done", true); return appendCommandStatus(result, status); diff --git a/src/mongo/db/commands/authentication_commands.cpp b/src/mongo/db/commands/authentication_commands.cpp index 651ecb6cca9..b0210188795 100644 --- a/src/mongo/db/commands/authentication_commands.cpp +++ b/src/mongo/db/commands/authentication_commands.cpp @@ -160,7 +160,7 @@ namespace mongo { if (mechanism.empty()) { mechanism = "MONGODB-CR"; } - Status status = _authenticate(mechanism, user, cmdObj); + Status status = _authenticate(txn, mechanism, user, cmdObj); audit::logAuthentication(ClientBasic::getCurrent(), mechanism, user, @@ -184,12 +184,13 @@ namespace mongo { return true; } - Status CmdAuthenticate::_authenticate(const std::string& mechanism, + Status CmdAuthenticate::_authenticate(OperationContext* txn, + const std::string& mechanism, const UserName& user, const BSONObj& cmdObj) { if (mechanism == "MONGODB-CR") { - return _authenticateCR(user, cmdObj); + return _authenticateCR(txn, user, cmdObj); } #ifdef MONGO_SSL if (mechanism == "MONGODB-X509") { @@ -199,7 +200,8 @@ namespace mongo { return Status(ErrorCodes::BadValue, "Unsupported mechanism: " + mechanism); } - Status CmdAuthenticate::_authenticateCR(const UserName& user, const BSONObj& cmdObj) { + Status CmdAuthenticate::_authenticateCR( + OperationContext* txn, const UserName& user, const BSONObj& cmdObj) { if (user == internalSecurity.user->getName() && serverGlobalParams.clusterAuthMode.load() == @@ -246,7 +248,7 @@ namespace mongo { } User* userObj; - Status status = getGlobalAuthorizationManager()->acquireUser(user, &userObj); + Status status = getGlobalAuthorizationManager()->acquireUser(txn, user, &userObj); if (!status.isOK()) { // Failure to find the privilege document indicates no-such-user, a fact that we do not // wish to reveal to the client. So, we return AuthenticationFailed rather than passing @@ -275,7 +277,7 @@ namespace mongo { AuthorizationSession* authorizationSession = ClientBasic::getCurrent()->getAuthorizationSession(); - status = authorizationSession->addAndAuthorizeUser(user); + status = authorizationSession->addAndAuthorizeUser(txn, user); if (!status.isOK()) { return status; } diff --git a/src/mongo/db/commands/authentication_commands.h b/src/mongo/db/commands/authentication_commands.h index 4ccfb464aa7..6fa2bc6a78a 100644 --- a/src/mongo/db/commands/authentication_commands.h +++ b/src/mongo/db/commands/authentication_commands.h @@ -71,10 +71,12 @@ namespace mongo { * mechanism, and ProtocolError, indicating an error in the use of the authentication * protocol. */ - Status _authenticate(const std::string& mechanism, + Status _authenticate(OperationContext* txn, + const std::string& mechanism, const UserName& user, const BSONObj& cmdObj); - Status _authenticateCR(const UserName& user, const BSONObj& cmdObj); + Status _authenticateCR( + OperationContext* txn, const UserName& user, const BSONObj& cmdObj); Status _authenticateX509(const UserName& user, const BSONObj& cmdObj); bool _clusterIdMatch(const std::string& subjectName, const std::string& srvSubjectName); }; diff --git a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp index dac324345bd..0746ec9398b 100644 --- a/src/mongo/db/commands/cleanup_orphaned_cmd.cpp +++ b/src/mongo/db/commands/cleanup_orphaned_cmd.cpp @@ -158,11 +158,12 @@ namespace mongo { virtual bool adminOnly() const { return true; } virtual bool localHostOnlyIfNoAuth( const BSONObj& cmdObj ) { return false; } - virtual Status checkAuthForCommand( ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj ) { + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj ) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::cleanupOrphaned)) { + txn, ResourcePattern::forClusterResource(), ActionType::cleanupOrphaned)) { return Status(ErrorCodes::Unauthorized, "Not authorized for cleanupOrphaned command."); } diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index b75ee5ceb69..5759c4dc528 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -75,14 +75,15 @@ namespace mongo { help << "{ clone : \"host13\" }"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { ActionSet actions; actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(dbname), actions)) { + txn, ResourcePattern::forDatabaseName(dbname), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } return Status::OK(); @@ -118,7 +119,7 @@ namespace mongo { set<string> clonedColls; - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context context( dbname ); Cloner cloner; diff --git a/src/mongo/db/commands/clone_collection.cpp b/src/mongo/db/commands/clone_collection.cpp index c0a124adbe3..d9cfb60819f 100644 --- a/src/mongo/db/commands/clone_collection.cpp +++ b/src/mongo/db/commands/clone_collection.cpp @@ -71,7 +71,8 @@ namespace mongo { return parseNsFullyQualified(dbname, cmdObj); } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { std::string ns = parseNs(dbname, cmdObj); @@ -81,7 +82,7 @@ namespace mongo { actions.addAction(ActionType::createIndex); // SERVER-11418 if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) { + txn, ResourcePattern::forExactNamespace(NamespaceString(ns)), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } return Status::OK(); diff --git a/src/mongo/db/commands/collection_to_capped.cpp b/src/mongo/db/commands/collection_to_capped.cpp index d2a909f4af4..0186a17b643 100644 --- a/src/mongo/db/commands/collection_to_capped.cpp +++ b/src/mongo/db/commands/collection_to_capped.cpp @@ -153,7 +153,7 @@ namespace mongo { return false; } - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(dbname); Status status = cloneCollectionAsCapped( txn, ctx.db(), from, to, size, temp, true ); diff --git a/src/mongo/db/commands/compact.cpp b/src/mongo/db/commands/compact.cpp index 3355e222570..1002ec82ffd 100644 --- a/src/mongo/db/commands/compact.cpp +++ b/src/mongo/db/commands/compact.cpp @@ -140,7 +140,7 @@ namespace mongo { compactOptions.validateDocuments = cmdObj["validate"].trueValue(); - Lock::DBWrite lk(ns.ns()); + Lock::DBWrite lk(txn->lockState(), ns.ns()); BackgroundOperation::assertNoBgOpInProgForNs(ns.ns()); Client::Context ctx(ns); diff --git a/src/mongo/db/commands/copydb.cpp b/src/mongo/db/commands/copydb.cpp index 0db7a7950bb..b1b9b2231bc 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -108,10 +108,11 @@ namespace mongo { virtual bool isWriteCommandForConfigServer() const { return false; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { - return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj); + return copydb::checkAuthForCopydbCommand(txn, client, dbname, cmdObj); } virtual void help( stringstream &help ) const { @@ -155,8 +156,8 @@ namespace mongo { // SERVER-4328 todo lock just the two db's not everything for the fromself case scoped_ptr<Lock::ScopedLock> lk( fromSelf ? - static_cast<Lock::ScopedLock*>( new Lock::GlobalWrite() ) : - static_cast<Lock::ScopedLock*>( new Lock::DBWrite( todb ) ) ); + static_cast<Lock::ScopedLock*>(new Lock::GlobalWrite()) : + static_cast<Lock::ScopedLock*>(new Lock::DBWrite(txn->lockState(), todb))); Cloner cloner; string username = cmdObj.getStringField( "username" ); diff --git a/src/mongo/db/commands/copydb.h b/src/mongo/db/commands/copydb.h index f7b2adfbe6d..9f27244f479 100644 --- a/src/mongo/db/commands/copydb.h +++ b/src/mongo/db/commands/copydb.h @@ -37,10 +37,12 @@ namespace mongo { class ClientBasic; + class OperationContext; namespace copydb { - Status checkAuthForCopydbCommand(ClientBasic* client, + Status checkAuthForCopydbCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj); diff --git a/src/mongo/db/commands/copydb_common.cpp b/src/mongo/db/commands/copydb_common.cpp index 5cebb8db021..e46cf94e4e2 100644 --- a/src/mongo/db/commands/copydb_common.cpp +++ b/src/mongo/db/commands/copydb_common.cpp @@ -42,7 +42,8 @@ namespace mongo { namespace copydb { - Status checkAuthForCopydbCommand(ClientBasic* client, + Status checkAuthForCopydbCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { bool fromSelf = StringData(cmdObj.getStringField("fromhost")).empty(); @@ -65,7 +66,7 @@ namespace copydb { actions.addAction(ActionType::insert); actions.addAction(ActionType::createIndex); if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(todb), actions)) { + txn, ResourcePattern::forDatabaseName(todb), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } @@ -73,7 +74,7 @@ namespace copydb { actions.addAction(ActionType::insert); for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace( - NamespaceString(todb, legalClientSystemCollections[i]), actions)) { + txn, NamespaceString(todb, legalClientSystemCollections[i]), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } } @@ -83,12 +84,12 @@ namespace copydb { actions.removeAllActions(); actions.addAction(ActionType::find); if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(fromdb), actions)) { + txn, ResourcePattern::forDatabaseName(fromdb), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } for (size_t i = 0; i < legalClientSystemCollections.size(); ++i) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace( - NamespaceString(fromdb, legalClientSystemCollections[i]), actions)) { + txn, NamespaceString(fromdb, legalClientSystemCollections[i]), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } } diff --git a/src/mongo/db/commands/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 2519bc75cc4..87582b75e07 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -51,13 +51,14 @@ namespace mongo { virtual bool isWriteCommandForConfigServer() const { return false; } virtual bool slaveOk() const { return false; } // TODO: this could be made true... - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { ActionSet actions; actions.addAction(ActionType::createIndex); Privilege p(parseResourcePattern(dbname, cmdObj), actions); - if ( client->getAuthorizationSession()->isAuthorizedForPrivilege(p) ) + if (client->getAuthorizationSession()->isAuthorizedForPrivilege(txn, p)) return Status::OK(); return Status(ErrorCodes::Unauthorized, "Unauthorized"); } @@ -132,9 +133,7 @@ namespace mongo { // as many calls are ensureIndex (and hence no-ops), this is good so its a shared // lock for common calls. We only take write lock if needed. // Note: createIndexes command does not currently respect shard versioning. - Client::ReadContext readContext( ns, - storageGlobalParams.dbpath, - false /* doVersion */ ); + Client::ReadContext readContext(txn, ns, false /* doVersion */); const Collection* collection = readContext.ctx().db()->getCollection( ns.ns() ); if ( collection ) { for ( size_t i = 0; i < specs.size(); i++ ) { @@ -164,9 +163,7 @@ namespace mongo { // now we know we have to create index(es) // Note: createIndexes command does not currently respect shard versioning. - Client::WriteContext writeContext( ns.ns(), - storageGlobalParams.dbpath, - false /* doVersion */ ); + Client::WriteContext writeContext(txn, ns.ns(), false /* doVersion */ ); Database* db = writeContext.ctx().db(); Collection* collection = db->getCollection( txn, ns.ns() ); diff --git a/src/mongo/db/commands/dbhash.cpp b/src/mongo/db/commands/dbhash.cpp index cddac188c94..3899e7f522d 100644 --- a/src/mongo/db/commands/dbhash.cpp +++ b/src/mongo/db/commands/dbhash.cpp @@ -145,7 +145,7 @@ namespace mongo { list<string> colls; const string ns = parseNs(dbname, cmdObj); - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Database* db = ctx.ctx().db(); if ( db ) db->getDatabaseCatalogEntry()->getCollectionNamespaces( &colls ); diff --git a/src/mongo/db/commands/distinct.cpp b/src/mongo/db/commands/distinct.cpp index bc05c80195a..4c3a6bb5955 100644 --- a/src/mongo/db/commands/distinct.cpp +++ b/src/mongo/db/commands/distinct.cpp @@ -90,7 +90,7 @@ namespace mongo { long long nscannedObjects = 0; // full objects looked at long long n = 0; // matches - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); diff --git a/src/mongo/db/commands/drop_indexes.cpp b/src/mongo/db/commands/drop_indexes.cpp index ab9144b7c96..c68aede5bc3 100644 --- a/src/mongo/db/commands/drop_indexes.cpp +++ b/src/mongo/db/commands/drop_indexes.cpp @@ -93,7 +93,7 @@ namespace mongo { CmdDropIndexes() : Command("dropIndexes", false, "deleteIndexes") { } bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& anObjBuilder, bool fromRepl) { - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); bool ok = wrappedRun(txn, dbname, jsobj, errmsg, anObjBuilder); if (ok && !fromRepl) repl::logOp(txn, "c",(dbname + ".$cmd").c_str(), jsobj); @@ -220,7 +220,7 @@ namespace mongo { MONGO_TLOG(0) << "CMD: reIndex " << toDeleteNs << endl; - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(toDeleteNs); Collection* collection = ctx.db()->getCollection( toDeleteNs ); diff --git a/src/mongo/db/commands/find_and_modify.cpp b/src/mongo/db/commands/find_and_modify.cpp index 44ca0e36609..c297d772530 100644 --- a/src/mongo/db/commands/find_and_modify.cpp +++ b/src/mongo/db/commands/find_and_modify.cpp @@ -93,7 +93,7 @@ namespace mongo { return false; } - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(ns); return runNoDirectClient( txn, ns , @@ -133,7 +133,7 @@ namespace mongo { BSONObjBuilder& result, string& errmsg) { - Lock::DBWrite lk( ns ); + Lock::DBWrite lk(txn->lockState(), ns); Client::Context cx( ns ); Collection* collection = cx.db()->getCollection( txn, ns ); @@ -325,7 +325,7 @@ namespace mongo { } } - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(ns); BSONObj out = db.findOne(ns, q, fields); diff --git a/src/mongo/db/commands/geonear.cpp b/src/mongo/db/commands/geonear.cpp index 5976d8a4e3d..ebbdd6efd69 100644 --- a/src/mongo/db/commands/geonear.cpp +++ b/src/mongo/db/commands/geonear.cpp @@ -76,7 +76,7 @@ namespace mongo { return false; } - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Database* db = ctx.ctx().db(); if ( !db ) { diff --git a/src/mongo/db/commands/group.cpp b/src/mongo/db/commands/group.cpp index 6e80bbef1f6..43a1fda05fc 100644 --- a/src/mongo/db/commands/group.cpp +++ b/src/mongo/db/commands/group.cpp @@ -56,12 +56,13 @@ namespace mongo { virtual void help( stringstream &help ) const { help << "http://dochub.mongodb.org/core/aggregation"; } - Status checkAuthForCommand(ClientBasic* client, + Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { std::string ns = parseNs(dbname, cmdObj); if (!client->getAuthorizationSession()->isAuthorizedForActionsOnNamespace( - NamespaceString(ns), ActionType::find)) { + txn, NamespaceString(ns), ActionType::find)) { return Status(ErrorCodes::Unauthorized, "unauthorized"); } return Status::OK(); @@ -254,7 +255,7 @@ namespace mongo { finalize = p["finalize"]._asCode(); const string ns = parseNs(dbname, jsobj); - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); return group( ctx.ctx().db() , ns , q , key , keyf , reduce._asCode() , reduce.type() != CodeWScope ? 0 : reduce.codeWScopeScopeDataUnsafe() , diff --git a/src/mongo/db/commands/index_filter_commands.cpp b/src/mongo/db/commands/index_filter_commands.cpp index 60346f782c4..776dad23792 100644 --- a/src/mongo/db/commands/index_filter_commands.cpp +++ b/src/mongo/db/commands/index_filter_commands.cpp @@ -124,7 +124,7 @@ namespace mongo { string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = parseNs(dbname, cmdObj); - Status status = runIndexFilterCommand(ns, cmdObj, &result); + Status status = runIndexFilterCommand(txn, ns, cmdObj, &result); if (!status.isOK()) { addStatus(status, result); @@ -144,12 +144,14 @@ namespace mongo { ss << helpText; } - Status IndexFilterCommand::checkAuthForCommand(ClientBasic* client, const std::string& dbname, - const BSONObj& cmdObj) { + Status IndexFilterCommand::checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); - if (authzSession->isAuthorizedForActionsOnResource(pattern, ActionType::planCacheIndexFilter)) { + if (authzSession->isAuthorizedForActionsOnResource(txn, pattern, ActionType::planCacheIndexFilter)) { return Status::OK(); } @@ -159,9 +161,12 @@ namespace mongo { ListFilters::ListFilters() : IndexFilterCommand("planCacheListFilters", "Displays index filters for all query shapes in a collection.") { } - Status ListFilters::runIndexFilterCommand(const string& ns, BSONObj& cmdObj, BSONObjBuilder* bob) { + Status ListFilters::runIndexFilterCommand(OperationContext* txn, + const string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob) { // This is a read lock. The query settings is owned by the collection. - Client::ReadContext readCtx(ns); + Client::ReadContext readCtx(txn, ns); Client::Context& ctx = readCtx.ctx(); QuerySettings* querySettings; PlanCache* unused; @@ -218,9 +223,12 @@ namespace mongo { "Clears index filter for a single query shape or, " "if the query shape is omitted, all filters for the collection.") { } - Status ClearFilters::runIndexFilterCommand(const string& ns, BSONObj& cmdObj, BSONObjBuilder* bob) { + Status ClearFilters::runIndexFilterCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob) { // This is a read lock. The query settings is owned by the collection. - Client::ReadContext readCtx(ns); + Client::ReadContext readCtx(txn, ns); Client::Context& ctx = readCtx.ctx(); QuerySettings* querySettings; PlanCache* planCache; @@ -306,9 +314,12 @@ namespace mongo { SetFilter::SetFilter() : IndexFilterCommand("planCacheSetFilter", "Sets index filter for a query shape. Overrides existing filter.") { } - Status SetFilter::runIndexFilterCommand(const string& ns, BSONObj& cmdObj, BSONObjBuilder* bob) { + Status SetFilter::runIndexFilterCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob) { // This is a read lock. The query settings is owned by the collection. - Client::ReadContext readCtx(ns); + Client::ReadContext readCtx(txn, ns); Client::Context& ctx = readCtx.ctx(); QuerySettings* querySettings; PlanCache* planCache; diff --git a/src/mongo/db/commands/index_filter_commands.h b/src/mongo/db/commands/index_filter_commands.h index a08ddd816db..4ae6824162f 100644 --- a/src/mongo/db/commands/index_filter_commands.h +++ b/src/mongo/db/commands/index_filter_commands.h @@ -76,7 +76,9 @@ namespace mongo { * One action type defined for index filter commands: * - planCacheIndexFilter */ - virtual Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, const BSONObj& cmdObj); /** @@ -85,7 +87,9 @@ namespace mongo { * Should contain just enough logic to invoke run*Command() function * in query_settings.h */ - virtual Status runIndexFilterCommand(const std::string& ns, BSONObj& cmdObj, + virtual Status runIndexFilterCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, BSONObjBuilder* bob) = 0; private: @@ -102,7 +106,10 @@ namespace mongo { public: ListFilters(); - virtual Status runIndexFilterCommand(const std::string& ns, BSONObj& cmdObj, BSONObjBuilder* bob); + virtual Status runIndexFilterCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob); /** * Looks up index filters from collection's query settings. @@ -121,7 +128,10 @@ namespace mongo { public: ClearFilters(); - virtual Status runIndexFilterCommand(const std::string& ns, BSONObj& cmdObj, BSONObjBuilder* bob); + virtual Status runIndexFilterCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob); /** * If query shape is provided, clears index filter for a query. @@ -149,7 +159,10 @@ namespace mongo { public: SetFilter(); - virtual Status runIndexFilterCommand(const std::string& ns, BSONObj& cmdObj, BSONObjBuilder* bob); + virtual Status runIndexFilterCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob); /** * Sets index filter for a query shape. diff --git a/src/mongo/db/commands/merge_chunks_cmd.cpp b/src/mongo/db/commands/merge_chunks_cmd.cpp index 24d2bf6dc39..f22689b89df 100644 --- a/src/mongo/db/commands/merge_chunks_cmd.cpp +++ b/src/mongo/db/commands/merge_chunks_cmd.cpp @@ -52,10 +52,12 @@ namespace mongo { << " (opt) shardName : <shard name> }"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::splitChunk)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); diff --git a/src/mongo/db/commands/mr.cpp b/src/mongo/db/commands/mr.cpp index af99dfa6818..97c5d1fb9b5 100644 --- a/src/mongo/db/commands/mr.cpp +++ b/src/mongo/db/commands/mr.cpp @@ -342,7 +342,7 @@ namespace mongo { if (_useIncremental) { // Create the inc collection and make sure we have index on "0" key. // Intentionally not replicating the inc collection to secondaries. - Client::WriteContext incCtx( _config.incLong ); + Client::WriteContext incCtx(_txn, _config.incLong); Collection* incColl = incCtx.ctx().db()->getCollection( _txn, _config.incLong ); if ( !incColl ) { CollectionOptions options; @@ -364,7 +364,7 @@ namespace mongo { { // copy indexes into temporary storage - Client::WriteContext finalCtx( _config.outputOptions.finalNamespace ); + Client::WriteContext finalCtx(_txn, _config.outputOptions.finalNamespace); Collection* finalColl = finalCtx.ctx().db()->getCollection( _config.outputOptions.finalNamespace ); if ( finalColl ) { @@ -392,7 +392,7 @@ namespace mongo { { // create temp collection and insert the indexes from temporary storage - Client::WriteContext tempCtx( _config.tempNamespace ); + Client::WriteContext tempCtx(_txn, _config.tempNamespace); Collection* tempColl = tempCtx.ctx().db()->getCollection( _txn, _config.tempNamespace ); if ( !tempColl ) { CollectionOptions options; @@ -559,7 +559,7 @@ namespace mongo { _safeCount(_db, _config.tempNamespace, BSONObj())); auto_ptr<DBClientCursor> cursor = _db.query( _config.tempNamespace , BSONObj() ); while ( cursor->more() ) { - Lock::DBWrite lock( _config.outputOptions.finalNamespace ); + Lock::DBWrite lock(_txn->lockState(), _config.outputOptions.finalNamespace); BSONObj o = cursor->nextSafe(); Helpers::upsert( _txn, _config.outputOptions.finalNamespace , o ); _txn->recoveryUnit()->commitIfNeeded(); @@ -619,7 +619,7 @@ namespace mongo { void State::insert( const string& ns , const BSONObj& o ) { verify( _onDisk ); - Client::WriteContext ctx( ns ); + Client::WriteContext ctx(_txn, ns ); Collection* coll = ctx.ctx().db()->getCollection( ns ); if ( !coll ) uasserted(13630, str::stream() << "attempted to insert into nonexistent" << @@ -645,7 +645,7 @@ namespace mongo { void State::_insertToInc( BSONObj& o ) { verify( _onDisk ); - Client::WriteContext ctx( _config.incLong ); + Client::WriteContext ctx(_txn, _config.incLong ); Collection* coll = ctx.ctx().db()->getCollection( _config.incLong ); if ( !coll ) uasserted(13631, str::stream() << "attempted to insert into nonexistent" @@ -921,7 +921,7 @@ namespace mongo { BSONObj sortKey = BSON( "0" << 1 ); { - Client::WriteContext incCtx( _config.incLong ); + Client::WriteContext incCtx(_txn, _config.incLong ); Collection* incColl = incCtx.ctx().db()->getCollection( _config.incLong ); bool foundIndex = false; @@ -940,7 +940,7 @@ namespace mongo { verify( foundIndex ); } - scoped_ptr<Client::ReadContext> ctx(new Client::ReadContext(_config.incLong)); + scoped_ptr<Client::ReadContext> ctx(new Client::ReadContext(_txn, _config.incLong)); BSONObj prev; BSONList all; @@ -989,7 +989,7 @@ namespace mongo { // reduce a finalize array finalReduce( all ); - ctx.reset(new Client::ReadContext(_config.incLong)); + ctx.reset(new Client::ReadContext(_txn, _config.incLong)); all.clear(); prev = o; @@ -1005,7 +1005,7 @@ namespace mongo { ctx.reset(); // reduce and finalize last array finalReduce( all ); - ctx.reset(new Client::ReadContext(_config.incLong)); + ctx.reset(new Client::ReadContext(_txn, _config.incLong)); pm.finished(); } @@ -1060,7 +1060,7 @@ namespace mongo { if ( ! _onDisk ) return; - Lock::DBWrite kl(_config.incLong); + Lock::DBWrite kl(_txn->lockState(), _config.incLong); for ( InMemory::iterator i=_temp->begin(); i!=_temp->end(); i++ ) { BSONList& all = i->second; @@ -1216,7 +1216,7 @@ namespace mongo { // Prevent sharding state from changing during the MR. auto_ptr<RangePreserver> rangePreserver; { - Client::ReadContext ctx(config.ns); + Client::ReadContext ctx(txn, config.ns); Collection* collection = ctx.ctx().db()->getCollection( config.ns ); if ( collection ) rangePreserver.reset(new RangePreserver(collection)); @@ -1278,7 +1278,7 @@ namespace mongo { // We've got a cursor preventing migrations off, now re-establish our useful cursor // Need lock and context to use it - scoped_ptr<Lock::DBRead> lock(new Lock::DBRead(config.ns)); + scoped_ptr<Lock::DBRead> lock(new Lock::DBRead(txn->lockState(), config.ns)); // This context does no version check, safe b/c we checked earlier and have an // open cursor @@ -1340,7 +1340,7 @@ namespace mongo { ctx.reset(); lock.reset(); state.reduceAndSpillInMemoryStateIfNeeded(); - lock.reset(new Lock::DBRead(config.ns)); + lock.reset(new Lock::DBRead(txn->lockState(), config.ns)); ctx.reset(new Client::Context(config.ns, storageGlobalParams.dbpath, false)); reduceTime += t.micros(); diff --git a/src/mongo/db/commands/oplog_note.cpp b/src/mongo/db/commands/oplog_note.cpp index 92ce1ebcd14..d59666dc461 100644 --- a/src/mongo/db/commands/oplog_note.cpp +++ b/src/mongo/db/commands/oplog_note.cpp @@ -47,11 +47,12 @@ namespace mongo { virtual void help( stringstream &help ) const { help << "Adds a no-op entry to the oplog"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::appendOplogNote)) { + txn, ResourcePattern::forClusterResource(), ActionType::appendOplogNote)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } return Status::OK(); diff --git a/src/mongo/db/commands/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp index 061175638cd..136e3095591 100644 --- a/src/mongo/db/commands/parallel_collection_scan.cpp +++ b/src/mongo/db/commands/parallel_collection_scan.cpp @@ -148,13 +148,14 @@ namespace mongo { virtual bool isWriteCommandForConfigServer() const { return false; } virtual bool slaveOk() const { return true; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { ActionSet actions; actions.addAction(ActionType::find); Privilege p(parseResourcePattern(dbname, cmdObj), actions); - if ( client->getAuthorizationSession()->isAuthorizedForPrivilege(p) ) + if ( client->getAuthorizationSession()->isAuthorizedForPrivilege(txn, p) ) return Status::OK(); return Status(ErrorCodes::Unauthorized, "Unauthorized"); } @@ -165,7 +166,7 @@ namespace mongo { NamespaceString ns( dbname, cmdObj[name].String() ); - Client::ReadContext ctx(ns.ns()); + Client::ReadContext ctx(txn, ns.ns()); Database* db = ctx.ctx().db(); Collection* collection = db->getCollection( ns ); diff --git a/src/mongo/db/commands/parameters.cpp b/src/mongo/db/commands/parameters.cpp index 981e04c26a5..a600be68787 100644 --- a/src/mongo/db/commands/parameters.cpp +++ b/src/mongo/db/commands/parameters.cpp @@ -96,7 +96,7 @@ namespace mongo { const ServerParameter::Map& m = ServerParameterSet::getGlobal()->getMap(); for ( ServerParameter::Map::const_iterator i = m.begin(); i != m.end(); ++i ) { if ( all || cmdObj.hasElement( i->first.c_str() ) ) { - i->second->append( result, i->second->name() ); + i->second->append(txn, result, i->second->name() ); } } @@ -177,7 +177,7 @@ namespace mongo { } if ( s == 0 ) - j->second->append( result, "was" ); + j->second->append(txn, result, "was" ); Status status = j->second->set( e ); if ( status.isOK() ) { @@ -203,7 +203,7 @@ namespace mongo { public: LogLevelSetting() : ServerParameter(ServerParameterSet::getGlobal(), "logLevel") {} - virtual void append(BSONObjBuilder& b, const std::string& name) { + virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name) { b << name << logger::globalLogDomain()->getMinimumLogSeverity().toInt(); } @@ -257,7 +257,8 @@ namespace mongo { } } - virtual void append(BSONObjBuilder& b, const std::string& name) { + virtual void append( + OperationContext* txn, BSONObjBuilder& b, const std::string& name) { b << name << sslModeStr(); } @@ -324,7 +325,8 @@ namespace mongo { } } - virtual void append(BSONObjBuilder& b, const std::string& name) { + virtual void append( + OperationContext* txn, BSONObjBuilder& b, const std::string& name) { b << name << clusterAuthModeStr(); } diff --git a/src/mongo/db/commands/pipeline_command.cpp b/src/mongo/db/commands/pipeline_command.cpp index ea373a92d1c..a43d77eeda0 100644 --- a/src/mongo/db/commands/pipeline_command.cpp +++ b/src/mongo/db/commands/pipeline_command.cpp @@ -317,7 +317,7 @@ namespace { // sharding version that we synchronize on here. This is also why we always need to // create a ClientCursor even when we aren't outputting to a cursor. See the comment // on ShardFilterStage for more details. - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection(ns); diff --git a/src/mongo/db/commands/plan_cache_commands.cpp b/src/mongo/db/commands/plan_cache_commands.cpp index f7e97c68072..f1a308504a2 100644 --- a/src/mongo/db/commands/plan_cache_commands.cpp +++ b/src/mongo/db/commands/plan_cache_commands.cpp @@ -118,7 +118,7 @@ namespace mongo { string& errmsg, BSONObjBuilder& result, bool fromRepl) { string ns = parseNs(dbname, cmdObj); - Status status = runPlanCacheCommand(ns, cmdObj, &result); + Status status = runPlanCacheCommand(txn, ns, cmdObj, &result); if (!status.isOK()) { addStatus(status, result); @@ -138,12 +138,14 @@ namespace mongo { ss << helpText; } - Status PlanCacheCommand::checkAuthForCommand(ClientBasic* client, const std::string& dbname, + Status PlanCacheCommand::checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); - if (authzSession->isAuthorizedForActionsOnResource(pattern, actionType)) { + if (authzSession->isAuthorizedForActionsOnResource(txn, pattern, actionType)) { return Status::OK(); } @@ -206,10 +208,12 @@ namespace mongo { "Displays all query shapes in a collection.", ActionType::planCacheRead) { } - Status PlanCacheListQueryShapes::runPlanCacheCommand(const string& ns, BSONObj& cmdObj, + Status PlanCacheListQueryShapes::runPlanCacheCommand(OperationContext* txn, + const string& ns, + BSONObj& cmdObj, BSONObjBuilder* bob) { // This is a read lock. The query cache is owned by the collection. - Client::ReadContext readCtx(ns); + Client::ReadContext readCtx(txn, ns); Client::Context& ctx = readCtx.ctx(); PlanCache* planCache; Status status = getPlanCache(ctx.db(), ns, &planCache); @@ -252,10 +256,12 @@ namespace mongo { "Drops one or all cached queries in a collection.", ActionType::planCacheWrite) { } - Status PlanCacheClear::runPlanCacheCommand(const string& ns, BSONObj& cmdObj, + Status PlanCacheClear::runPlanCacheCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, BSONObjBuilder* bob) { // This is a read lock. The query cache is owned by the collection. - Client::ReadContext readCtx(ns); + Client::ReadContext readCtx(txn, ns); Client::Context& ctx = readCtx.ctx(); PlanCache* planCache; Status status = getPlanCache(ctx.db(), ns, &planCache); @@ -322,9 +328,11 @@ namespace mongo { "Displays the cached plans for a query shape.", ActionType::planCacheRead) { } - Status PlanCacheListPlans::runPlanCacheCommand(const string& ns, BSONObj& cmdObj, + Status PlanCacheListPlans::runPlanCacheCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, BSONObjBuilder* bob) { - Client::ReadContext readCtx(ns); + Client::ReadContext readCtx(txn, ns); Client::Context& ctx = readCtx.ctx(); PlanCache* planCache; Status status = getPlanCache(ctx.db(), ns, &planCache); diff --git a/src/mongo/db/commands/plan_cache_commands.h b/src/mongo/db/commands/plan_cache_commands.h index 8e7eb9667a4..e78429509fd 100644 --- a/src/mongo/db/commands/plan_cache_commands.h +++ b/src/mongo/db/commands/plan_cache_commands.h @@ -72,7 +72,9 @@ namespace mongo { * - planCacheRead * - planCacheWrite */ - virtual Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, const BSONObj& cmdObj); /** * Subset of command arguments used by plan cache commands @@ -80,7 +82,9 @@ namespace mongo { * Should contain just enough logic to invoke run*Command() function * in plan_cache.h */ - virtual Status runPlanCacheCommand(const std::string& ns, BSONObj& cmdObj, + virtual Status runPlanCacheCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, BSONObjBuilder* bob) = 0; /** @@ -103,7 +107,10 @@ namespace mongo { class PlanCacheListQueryShapes : public PlanCacheCommand { public: PlanCacheListQueryShapes(); - virtual Status runPlanCacheCommand(const std::string& ns, BSONObj& cmdObj, BSONObjBuilder* bob); + virtual Status runPlanCacheCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob); /** * Looks up cache keys for collection's plan cache. @@ -126,7 +133,10 @@ namespace mongo { class PlanCacheClear : public PlanCacheCommand { public: PlanCacheClear(); - virtual Status runPlanCacheCommand(const std::string& ns, BSONObj& cmdObj, BSONObjBuilder* bob); + virtual Status runPlanCacheCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, + BSONObjBuilder* bob); /** * Clears collection's plan cache. @@ -149,7 +159,9 @@ namespace mongo { class PlanCacheListPlans : public PlanCacheCommand { public: PlanCacheListPlans(); - virtual Status runPlanCacheCommand(const std::string& ns, BSONObj& cmdObj, + virtual Status runPlanCacheCommand(OperationContext* txn, + const std::string& ns, + BSONObj& cmdObj, BSONObjBuilder* bob); /** diff --git a/src/mongo/db/commands/rename_collection.cpp b/src/mongo/db/commands/rename_collection.cpp index 851b783aa99..946686719fd 100644 --- a/src/mongo/db/commands/rename_collection.cpp +++ b/src/mongo/db/commands/rename_collection.cpp @@ -54,10 +54,12 @@ namespace mongo { return false; } virtual bool isWriteCommandForConfigServer() const { return true; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { - return rename_collection::checkAuthForRenameCollectionCommand(client, dbname, cmdObj); + return rename_collection::checkAuthForRenameCollectionCommand( + txn, client, dbname, cmdObj); } virtual void help( stringstream &help ) const { help << " example: { renameCollection: foo.a, to: bar.b }"; diff --git a/src/mongo/db/commands/rename_collection.h b/src/mongo/db/commands/rename_collection.h index f8651bccd4c..8ec1f7cc9b8 100644 --- a/src/mongo/db/commands/rename_collection.h +++ b/src/mongo/db/commands/rename_collection.h @@ -37,10 +37,12 @@ namespace mongo { class ClientBasic; + class OperationContext; namespace rename_collection { - Status checkAuthForRenameCollectionCommand(ClientBasic* client, + Status checkAuthForRenameCollectionCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj); diff --git a/src/mongo/db/commands/rename_collection_common.cpp b/src/mongo/db/commands/rename_collection_common.cpp index fba1daffc0b..4af10ce0f9d 100644 --- a/src/mongo/db/commands/rename_collection_common.cpp +++ b/src/mongo/db/commands/rename_collection_common.cpp @@ -42,7 +42,8 @@ namespace mongo { namespace rename_collection { - Status checkAuthForRenameCollectionCommand(ClientBasic* client, + Status checkAuthForRenameCollectionCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { NamespaceString sourceNS = NamespaceString(cmdObj.getStringField("renameCollection")); @@ -55,6 +56,7 @@ namespace rename_collection { // or dest collection, then you get can do the rename, even without insert on the // destination collection. bool canRename = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(sourceNS.db()), ActionType::renameCollectionSameDB); @@ -62,14 +64,15 @@ namespace rename_collection { if (dropTarget) { canDropTargetIfNeeded = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(targetNS), ActionType::dropCollection); } bool canReadSrc = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace(sourceNS), ActionType::find); + txn, ResourcePattern::forExactNamespace(sourceNS), ActionType::find); bool canReadDest = client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace(targetNS), ActionType::find); + txn, ResourcePattern::forExactNamespace(targetNS), ActionType::find); if (canRename && canDropTargetIfNeeded && (canReadSrc || !canReadDest)) { return Status::OK(); @@ -81,7 +84,7 @@ namespace rename_collection { actions.addAction(ActionType::find); actions.addAction(ActionType::dropCollection); if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace(sourceNS), actions)) { + txn, ResourcePattern::forExactNamespace(sourceNS), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } @@ -93,7 +96,7 @@ namespace rename_collection { actions.addAction(ActionType::dropCollection); } if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forExactNamespace(targetNS), actions)) { + txn, ResourcePattern::forExactNamespace(targetNS), actions)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); } diff --git a/src/mongo/db/commands/server_status.cpp b/src/mongo/db/commands/server_status.cpp index e5d9a791589..ab9567cba95 100644 --- a/src/mongo/db/commands/server_status.cpp +++ b/src/mongo/db/commands/server_status.cpp @@ -101,8 +101,9 @@ namespace mongo { std::vector<Privilege> requiredPrivileges; section->addRequiredPrivileges(&requiredPrivileges); - if (!authSession->isAuthorizedForPrivileges(requiredPrivileges)) + if (!authSession->isAuthorizedForPrivileges(txn, requiredPrivileges)) { continue; + } bool include = section->includeByDefault(); diff --git a/src/mongo/db/commands/test_commands.cpp b/src/mongo/db/commands/test_commands.cpp index 006a86d3677..7265270beef 100644 --- a/src/mongo/db/commands/test_commands.cpp +++ b/src/mongo/db/commands/test_commands.cpp @@ -62,7 +62,7 @@ namespace mongo { string ns = dbname + "." + coll; BSONObj obj = cmdObj[ "obj" ].embeddedObjectUserCheck(); - Lock::DBWrite lk(ns); + Lock::DBWrite lk(txn->lockState(), ns); Client::Context ctx( ns ); Database* db = ctx.db(); Collection* collection = db->getCollection( ns ); @@ -140,7 +140,7 @@ namespace mongo { int n = cmdObj.getIntField( "n" ); bool inc = cmdObj.getBoolField( "inc" ); // inclusive range? - Client::WriteContext ctx( nss.ns() ); + Client::WriteContext ctx(txn, nss.ns() ); Collection* collection = ctx.ctx().db()->getCollection( nss.ns() ); massert( 13417, "captrunc collection not found or empty", collection); @@ -185,7 +185,7 @@ namespace mongo { uassert( 13428, "emptycapped must specify a collection", !coll.empty() ); NamespaceString nss( dbname, coll ); - Client::WriteContext ctx( nss.ns() ); + Client::WriteContext ctx(txn, nss.ns() ); Database* db = ctx.ctx().db(); Collection* collection = db->getCollection( nss.ns() ); massert( 13429, "emptycapped no such collection", collection ); diff --git a/src/mongo/db/commands/touch.cpp b/src/mongo/db/commands/touch.cpp index 841a738abf2..ec2fc972659 100644 --- a/src/mongo/db/commands/touch.cpp +++ b/src/mongo/db/commands/touch.cpp @@ -104,7 +104,7 @@ namespace mongo { return false; } - Client::ReadContext context( nss.ns() ); + Client::ReadContext context(txn, nss.ns()); Database* db = context.ctx().db(); Collection* collection = db->getCollection( nss.ns() ); diff --git a/src/mongo/db/commands/user_management_commands.cpp b/src/mongo/db/commands/user_management_commands.cpp index 40999d0cbe5..21b97074545 100644 --- a/src/mongo/db/commands/user_management_commands.cpp +++ b/src/mongo/db/commands/user_management_commands.cpp @@ -118,12 +118,13 @@ namespace mongo { return Status::OK(); } - static Status getCurrentUserRoles(AuthorizationManager* authzManager, + static Status getCurrentUserRoles(OperationContext* txn, + AuthorizationManager* authzManager, const UserName& userName, unordered_set<RoleName>* roles) { User* user; authzManager->invalidateUserByName(userName); // Need to make sure cache entry is up to date - Status status = authzManager->acquireUser(userName, &user); + Status status = authzManager->acquireUser(txn, userName, &user); if (!status.isOK()) { return status; } @@ -135,10 +136,11 @@ namespace mongo { return Status::OK(); } - static Status checkAuthorizedToGrantRoles(AuthorizationSession* authzSession, + static Status checkAuthorizedToGrantRoles(OperationContext* txn, + AuthorizationSession* authzSession, const std::vector<RoleName>& roles) { for (size_t i = 0; i < roles.size(); ++i) { - if (!authzSession->isAuthorizedToGrantRole(roles[i])) { + if (!authzSession->isAuthorizedToGrantRole(txn, roles[i])) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to grant role: " << roles[i].getFullName()); @@ -147,10 +149,11 @@ namespace mongo { return Status::OK(); } - static Status checkAuthorizedToRevokeRoles(AuthorizationSession* authzSession, + static Status checkAuthorizedToRevokeRoles(OperationContext* txn, + AuthorizationSession* authzSession, const std::vector<RoleName>& roles) { for (size_t i = 0; i < roles.size(); ++i) { - if (!authzSession->isAuthorizedToRevokeRole(roles[i])) { + if (!authzSession->isAuthorizedToRevokeRole(txn, roles[i])) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to revoke role: " << roles[i].getFullName()); @@ -159,11 +162,12 @@ namespace mongo { return Status::OK(); } - static Status checkAuthorizedToGrantPrivileges(AuthorizationSession* authzSession, + static Status checkAuthorizedToGrantPrivileges(OperationContext* txn, + AuthorizationSession* authzSession, const PrivilegeVector& privileges) { for (PrivilegeVector::const_iterator it = privileges.begin(); it != privileges.end(); ++it) { - Status status = authzSession->checkAuthorizedToGrantPrivilege(*it); + Status status = authzSession->checkAuthorizedToGrantPrivilege(txn, *it); if (!status.isOK()) { return status; } @@ -172,11 +176,12 @@ namespace mongo { return Status::OK(); } - static Status checkAuthorizedToRevokePrivileges(AuthorizationSession* authzSession, + static Status checkAuthorizedToRevokePrivileges(OperationContext* txn, + AuthorizationSession* authzSession, const PrivilegeVector& privileges) { for (PrivilegeVector::const_iterator it = privileges.begin(); it != privileges.end(); ++it) { - Status status = authzSession->checkAuthorizedToRevokePrivilege(*it); + Status status = authzSession->checkAuthorizedToRevokePrivilege(txn, *it); if (!status.isOK()) { return status; } @@ -265,9 +270,10 @@ namespace mongo { return Status::OK(); } - static Status requireAuthSchemaVersion26Final(AuthorizationManager* authzManager) { + static Status requireAuthSchemaVersion26Final( + OperationContext* txn, AuthorizationManager* authzManager) { int foundSchemaVersion; - Status status = authzManager->getAuthorizationVersion(&foundSchemaVersion); + Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); if (!status.isOK()) { return status; } @@ -282,9 +288,10 @@ namespace mongo { return authzManager->writeAuthSchemaVersionIfNeeded(); } - static Status requireAuthSchemaVersion26UpgradeOrFinal(AuthorizationManager* authzManager) { + static Status requireAuthSchemaVersion26UpgradeOrFinal(OperationContext* txn, + AuthorizationManager* authzManager) { int foundSchemaVersion; - Status status = authzManager->getAuthorizationVersion(&foundSchemaVersion); + Status status = authzManager->getAuthorizationVersion(txn, &foundSchemaVersion); if (!status.isOK()) { return status; } @@ -320,7 +327,8 @@ namespace mongo { ss << "Adds a user to the system" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -334,6 +342,7 @@ namespace mongo { } if (!authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(args.userName.getDB()), ActionType::createUser)) { return Status(ErrorCodes::Unauthorized, @@ -341,7 +350,7 @@ namespace mongo { args.userName.getDB()); } - return checkAuthorizedToGrantRoles(authzSession, args.roles); + return checkAuthorizedToGrantRoles(txn, authzSession, args.roles); } bool run(OperationContext* txn, const string& dbname, @@ -434,7 +443,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -480,7 +489,8 @@ namespace mongo { ss << "Used to update a user, for example to change its password" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -496,6 +506,7 @@ namespace mongo { if (args.hasHashedPassword) { if (!authzSession->isAuthorizedToChangeOwnPasswordAsUser(args.userName) && !authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(args.userName.getDB()), ActionType::changePassword)) { return Status(ErrorCodes::Unauthorized, @@ -507,6 +518,7 @@ namespace mongo { if (args.hasCustomData) { if (!authzSession->isAuthorizedToChangeOwnCustomDataAsUser(args.userName) && !authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(args.userName.getDB()), ActionType::changeCustomData)) { return Status(ErrorCodes::Unauthorized, @@ -519,13 +531,13 @@ namespace mongo { // You don't know what roles you might be revoking, so require the ability to // revoke any role in the system. if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forAnyNormalResource(), ActionType::revokeRole)) { + txn, ResourcePattern::forAnyNormalResource(), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, "In order to use updateUser to set roles array, must be " "authorized to revoke any role in the system"); } - return checkAuthorizedToGrantRoles(authzSession, args.roles); + return checkAuthorizedToGrantRoles(txn, authzSession, args.roles); } return Status::OK(); } @@ -579,7 +591,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -631,7 +643,8 @@ namespace mongo { ss << "Drops a single user." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -646,7 +659,7 @@ namespace mongo { } if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(userName.getDB()), ActionType::dropUser)) { + txn, ResourcePattern::forDatabaseName(userName.getDB()), ActionType::dropUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop users from the " << userName.getDB() << " database"); @@ -668,7 +681,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -727,12 +740,13 @@ namespace mongo { ss << "Drops all users for a single database." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(dbname), ActionType::dropUser)) { + txn, ResourcePattern::forDatabaseName(dbname), ActionType::dropUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop users from the " << dbname << " database"); @@ -754,7 +768,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -802,7 +816,8 @@ namespace mongo { ss << "Grants roles to a user." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -819,7 +834,7 @@ namespace mongo { return status; } - return checkAuthorizedToGrantRoles(authzSession, roles); + return checkAuthorizedToGrantRoles(txn, authzSession, roles); } bool run(OperationContext* txn, const string& dbname, @@ -836,7 +851,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -856,7 +871,7 @@ namespace mongo { UserName userName(userNameString, dbname); unordered_set<RoleName> userRoles; - status = getCurrentUserRoles(authzManager, userName, &userRoles); + status = getCurrentUserRoles(txn, authzManager, userName, &userRoles); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -900,7 +915,8 @@ namespace mongo { ss << "Revokes roles from a user." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -917,7 +933,7 @@ namespace mongo { return status; } - return checkAuthorizedToRevokeRoles(authzSession, roles); + return checkAuthorizedToRevokeRoles(txn, authzSession, roles); } bool run(OperationContext* txn, const string& dbname, @@ -934,7 +950,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -954,7 +970,7 @@ namespace mongo { UserName userName(userNameString, dbname); unordered_set<RoleName> userRoles; - status = getCurrentUserRoles(authzManager, userName, &userRoles); + status = getCurrentUserRoles(txn, authzManager, userName, &userRoles); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1002,7 +1018,8 @@ namespace mongo { ss << "Returns information about users." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1014,7 +1031,7 @@ namespace mongo { if (args.allForDB) { if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(dbname), ActionType::viewUser)) { + txn, ResourcePattern::forDatabaseName(dbname), ActionType::viewUser)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to view users from the " << dbname << " database"); @@ -1025,6 +1042,7 @@ namespace mongo { continue; // Can always view users you are logged in as } if (!authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(args.userNames[i].getDB()), ActionType::viewUser)) { return Status(ErrorCodes::Unauthorized, @@ -1049,7 +1067,8 @@ namespace mongo { return appendCommandStatus(result, status); } - status = requireAuthSchemaVersion26UpgradeOrFinal(getGlobalAuthorizationManager()); + status = requireAuthSchemaVersion26UpgradeOrFinal( + txn, getGlobalAuthorizationManager()); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1068,7 +1087,7 @@ namespace mongo { for (size_t i = 0; i < args.userNames.size(); ++i) { BSONObj userDetails; status = getGlobalAuthorizationManager()->getUserDescription( - args.userNames[i], &userDetails); + txn, args.userNames[i], &userDetails); if (status.code() == ErrorCodes::UserNotFound) { continue; } @@ -1107,7 +1126,7 @@ namespace mongo { AuthorizationManager* authzManager = getGlobalAuthorizationManager(); int authzVersion; - Status status = authzManager->getAuthorizationVersion(&authzVersion); + Status status = authzManager->getAuthorizationVersion(txn, &authzVersion); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1149,7 +1168,8 @@ namespace mongo { ss << "Adds a role to the system" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1163,6 +1183,7 @@ namespace mongo { } if (!authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(args.roleName.getDB()), ActionType::createRole)) { return Status(ErrorCodes::Unauthorized, @@ -1170,12 +1191,12 @@ namespace mongo { args.roleName.getDB()); } - status = checkAuthorizedToGrantRoles(authzSession, args.roles); + status = checkAuthorizedToGrantRoles(txn, authzSession, args.roles); if (!status.isOK()) { return status; } - return checkAuthorizedToGrantPrivileges(authzSession, args.privileges); + return checkAuthorizedToGrantPrivileges(txn, authzSession, args.privileges); } bool run(OperationContext* txn, const string& dbname, @@ -1252,7 +1273,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1294,7 +1315,8 @@ namespace mongo { ss << "Used to update a role" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1310,18 +1332,18 @@ namespace mongo { // You don't know what roles or privileges you might be revoking, so require the ability // to revoke any role (or privilege) in the system. if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forAnyNormalResource(), ActionType::revokeRole)) { + txn, ResourcePattern::forAnyNormalResource(), ActionType::revokeRole)) { return Status(ErrorCodes::Unauthorized, "updateRole command required the ability to revoke any role in the " "system"); } - status = checkAuthorizedToGrantRoles(authzSession, args.roles); + status = checkAuthorizedToGrantRoles(txn, authzSession, args.roles); if (!status.isOK()) { return status; } - return checkAuthorizedToGrantPrivileges(authzSession, args.privileges); + return checkAuthorizedToGrantPrivileges(txn, authzSession, args.privileges); } bool run(OperationContext* txn, const string& dbname, @@ -1369,7 +1391,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1424,7 +1446,8 @@ namespace mongo { ss << "Grants privileges to a role" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1442,7 +1465,7 @@ namespace mongo { return status; } - return checkAuthorizedToGrantPrivileges(authzSession, privileges); + return checkAuthorizedToGrantPrivileges(txn, authzSession, privileges); } bool run(OperationContext* txn, const string& dbname, @@ -1459,7 +1482,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1560,7 +1583,8 @@ namespace mongo { ss << "Revokes privileges from a role" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1578,7 +1602,7 @@ namespace mongo { return status; } - return checkAuthorizedToRevokePrivileges(authzSession, privileges); + return checkAuthorizedToRevokePrivileges(txn, authzSession, privileges); } bool run(OperationContext* txn, const string& dbname, @@ -1595,7 +1619,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1698,7 +1722,8 @@ namespace mongo { ss << "Grants roles to another role." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1715,7 +1740,7 @@ namespace mongo { return status; } - return checkAuthorizedToGrantRoles(authzSession, roles); + return checkAuthorizedToGrantRoles(txn, authzSession, roles); } bool run(OperationContext* txn, const string& dbname, @@ -1755,7 +1780,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1817,7 +1842,8 @@ namespace mongo { ss << "Revokes roles from another role." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1834,7 +1860,7 @@ namespace mongo { return status; } - return checkAuthorizedToRevokeRoles(authzSession, roles); + return checkAuthorizedToRevokeRoles(txn, authzSession, roles); } bool run(OperationContext* txn, const string& dbname, @@ -1851,7 +1877,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1933,7 +1959,8 @@ namespace mongo { "removed from some user/roles but otherwise still exists."<< endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -1948,7 +1975,7 @@ namespace mongo { } if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(roleName.getDB()), ActionType::dropRole)) { + txn, ResourcePattern::forDatabaseName(roleName.getDB()), ActionType::dropRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop roles from the " << roleName.getDB() << " database"); @@ -1970,7 +1997,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - Status status = requireAuthSchemaVersion26Final(authzManager); + Status status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2111,12 +2138,13 @@ namespace mongo { "exist." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(dbname), ActionType::dropRole)) { + txn, ResourcePattern::forDatabaseName(dbname), ActionType::dropRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to drop roles from the " << dbname << " database"); @@ -2146,7 +2174,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2243,7 +2271,8 @@ namespace mongo { ss << "Returns information about roles." << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -2255,7 +2284,7 @@ namespace mongo { if (args.allForDB) { if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(dbname), ActionType::viewRole)) { + txn, ResourcePattern::forDatabaseName(dbname), ActionType::viewRole)) { return Status(ErrorCodes::Unauthorized, str::stream() << "Not authorized to view roles from the " << dbname << " database"); @@ -2267,6 +2296,7 @@ namespace mongo { } if (!authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(args.roleNames[i].getDB()), ActionType::viewRole)) { return Status(ErrorCodes::Unauthorized, @@ -2292,7 +2322,8 @@ namespace mongo { return appendCommandStatus(result, status); } - status = requireAuthSchemaVersion26UpgradeOrFinal(getGlobalAuthorizationManager()); + status = requireAuthSchemaVersion26UpgradeOrFinal( + txn, getGlobalAuthorizationManager()); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2348,12 +2379,13 @@ namespace mongo { ss << "Invalidates the in-memory cache of user information" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::invalidateUserCache)) { + txn, ResourcePattern::forClusterResource(), ActionType::invalidateUserCache)) { return Status(ErrorCodes::Unauthorized, "Not authorized to invalidate user cache"); } return Status::OK(); @@ -2392,12 +2424,13 @@ namespace mongo { ss << "internal" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::internal)) { + txn, ResourcePattern::forClusterResource(), ActionType::internal)) { return Status(ErrorCodes::Unauthorized, "Not authorized to get cache generation"); } return Status::OK(); @@ -2447,7 +2480,8 @@ namespace mongo { ss << "Internal command used by mongorestore for updating user/role data" << endl; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { auth::MergeAuthzCollectionsArgs args; @@ -2467,13 +2501,14 @@ namespace mongo { actions.addAction(ActionType::dropRole); } if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forAnyNormalResource(), actions)) { + txn, ResourcePattern::forAnyNormalResource(), actions)) { return Status(ErrorCodes::Unauthorized, "Not authorized to update user/role data using _mergeAuthzCollections" " command"); } if (!args.usersCollName.empty() && !authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(args.usersCollName)), ActionType::find)) { return Status(ErrorCodes::Unauthorized, @@ -2482,6 +2517,7 @@ namespace mongo { } if (!args.rolesCollName.empty() && !authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(args.rolesCollName)), ActionType::find)) { return Status(ErrorCodes::Unauthorized, @@ -2840,7 +2876,7 @@ namespace mongo { Status(ErrorCodes::LockBusy, "Could not lock auth data update lock.")); } - status = requireAuthSchemaVersion26Final(authzManager); + status = requireAuthSchemaVersion26Final(txn, authzManager); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2881,13 +2917,14 @@ namespace mongo { ss << "Upgrades the auth data storage schema"; } - Status CmdAuthSchemaUpgrade::checkAuthForCommand(ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj) { + Status CmdAuthSchemaUpgrade::checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (!authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::authSchemaUpgrade)) { + txn, ResourcePattern::forClusterResource(), ActionType::authSchemaUpgrade)) { return Status(ErrorCodes::Unauthorized, "Not authorized to run authSchemaUpgrade command."); } diff --git a/src/mongo/db/commands/user_management_commands.h b/src/mongo/db/commands/user_management_commands.h index f9350f768ca..448950eb5ed 100644 --- a/src/mongo/db/commands/user_management_commands.h +++ b/src/mongo/db/commands/user_management_commands.h @@ -42,7 +42,8 @@ namespace mongo { virtual bool adminOnly() const; virtual void help(std::stringstream& ss) const; - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj); }; diff --git a/src/mongo/db/commands/validate.cpp b/src/mongo/db/commands/validate.cpp index 28d06c9ae05..9b539a8b954 100644 --- a/src/mongo/db/commands/validate.cpp +++ b/src/mongo/db/commands/validate.cpp @@ -75,7 +75,7 @@ namespace mongo { MONGO_TLOG(0) << "CMD: validate " << ns << endl; } - Client::ReadContext ctx(ns_string.ns()); + Client::ReadContext ctx(txn, ns_string.ns()); Database* db = ctx.ctx().db(); if ( !db ) { diff --git a/src/mongo/db/commands/write_commands/batch_executor.cpp b/src/mongo/db/commands/write_commands/batch_executor.cpp index a6332a50288..b147446a93d 100644 --- a/src/mongo/db/commands/write_commands/batch_executor.cpp +++ b/src/mongo/db/commands/write_commands/batch_executor.cpp @@ -902,7 +902,7 @@ namespace mongo { } invariant(!_context.get()); - _writeLock.reset(new Lock::DBWrite(request->getNS())); + _writeLock.reset(new Lock::DBWrite(txn->lockState(), request->getNS())); if (!checkIsMasterForCollection(request->getNS(), result)) { return false; } @@ -1087,7 +1087,7 @@ namespace mongo { } /////////////////////////////////////////// - Lock::DBWrite writeLock( nsString.ns() ); + Lock::DBWrite writeLock(txn->lockState(), nsString.ns()); /////////////////////////////////////////// if ( !checkShardVersion( &shardingState, *updateItem.getRequest(), result ) ) @@ -1144,7 +1144,7 @@ namespace mongo { } /////////////////////////////////////////// - Lock::DBWrite writeLock( nss.ns() ); + Lock::DBWrite writeLock(txn->lockState(), nss.ns()); /////////////////////////////////////////// // Check version once we're locked diff --git a/src/mongo/db/commands/write_commands/write_commands.cpp b/src/mongo/db/commands/write_commands/write_commands.cpp index c9b77e1b831..9f14dec2bb2 100644 --- a/src/mongo/db/commands/write_commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands/write_commands.cpp @@ -82,11 +82,14 @@ namespace mongo { bool WriteCmd::isWriteCommandForConfigServer() const { return false; } - Status WriteCmd::checkAuthForCommand( ClientBasic* client, + Status WriteCmd::checkAuthForCommand( OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj ) { - Status status( auth::checkAuthForWriteCommand( client->getAuthorizationSession(), + Status status( auth::checkAuthForWriteCommand( + txn, + client->getAuthorizationSession(), _writeType, NamespaceString( parseNs( dbname, cmdObj ) ), cmdObj )); diff --git a/src/mongo/db/commands/write_commands/write_commands.h b/src/mongo/db/commands/write_commands/write_commands.h index c5f5da37cac..570eca9ba4d 100644 --- a/src/mongo/db/commands/write_commands/write_commands.h +++ b/src/mongo/db/commands/write_commands/write_commands.h @@ -65,7 +65,8 @@ namespace mongo { virtual bool isWriteCommandForConfigServer() const; - virtual Status checkAuthForCommand( ClientBasic* client, + virtual Status checkAuthForCommand( OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj ); diff --git a/src/mongo/db/commands/write_commands/write_commands_common.cpp b/src/mongo/db/commands/write_commands/write_commands_common.cpp index 72c132ae1c0..e2a77d85863 100644 --- a/src/mongo/db/commands/write_commands/write_commands_common.cpp +++ b/src/mongo/db/commands/write_commands/write_commands_common.cpp @@ -44,7 +44,8 @@ namespace auth { using std::string; using std::vector; - Status checkAuthForWriteCommand( AuthorizationSession* authzSession, + Status checkAuthForWriteCommand( OperationContext* txn, + AuthorizationSession* authzSession, BatchedCommandRequest::BatchType cmdType, const NamespaceString& cmdNSS, const BSONObj& cmdObj ) { @@ -89,8 +90,9 @@ namespace auth { ActionType::remove ) ); } - if ( authzSession->isAuthorizedForPrivileges( privileges ) ) + if (authzSession->isAuthorizedForPrivileges(txn, privileges)) { return Status::OK(); + } return Status( ErrorCodes::Unauthorized, "unauthorized" ); } diff --git a/src/mongo/db/commands/write_commands/write_commands_common.h b/src/mongo/db/commands/write_commands/write_commands_common.h index a1fe6bc9772..bc0e1f0be8e 100644 --- a/src/mongo/db/commands/write_commands/write_commands_common.h +++ b/src/mongo/db/commands/write_commands/write_commands_common.h @@ -38,9 +38,13 @@ */ namespace mongo { + + class OperationContext; + namespace auth { - Status checkAuthForWriteCommand( AuthorizationSession* authzSession, + Status checkAuthForWriteCommand( OperationContext* txn, + AuthorizationSession* authzSession, BatchedCommandRequest::BatchType cmdType, const NamespaceString& cmdNSS, const BSONObj& cmdObj ); diff --git a/src/mongo/db/d_concurrency.cpp b/src/mongo/db/d_concurrency.cpp index 7f84d776bb1..15ab51528fe 100644 --- a/src/mongo/db/d_concurrency.cpp +++ b/src/mongo/db/d_concurrency.cpp @@ -583,12 +583,12 @@ namespace mongo { lockNestable(nested); } - Lock::DBWrite::DBWrite( const StringData& ns ) + Lock::DBWrite::DBWrite(LockState* lockState, const StringData& ns) : ScopedLock( 'w' ), _what(ns.toString()), _nested(false) { lockDB( _what ); } - Lock::DBRead::DBRead( const StringData& ns ) + Lock::DBRead::DBRead(LockState* lockState, const StringData& ns) : ScopedLock( 'r' ), _what(ns.toString()), _nested(false) { lockDB( _what ); } diff --git a/src/mongo/db/d_concurrency.h b/src/mongo/db/d_concurrency.h index f99cb46184f..8359f23614d 100644 --- a/src/mongo/db/d_concurrency.h +++ b/src/mongo/db/d_concurrency.h @@ -112,6 +112,8 @@ namespace mongo { virtual void _tempRelease() = 0; virtual void _relock() = 0; + LockState* _lockState; + private: class ParallelBatchWriterSupport : boost::noncopyable { @@ -183,7 +185,7 @@ namespace mongo { void _relock(); public: - DBWrite(const StringData& dbOrNs); + DBWrite(LockState* lockState, const StringData& dbOrNs); virtual ~DBWrite(); private: @@ -207,7 +209,7 @@ namespace mongo { void _relock(); public: - DBRead(const StringData& dbOrNs); + DBRead(LockState* lockState, const StringData& dbOrNs); virtual ~DBRead(); private: diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp index cd9a98b3a7c..93408e92a23 100644 --- a/src/mongo/db/db.cpp +++ b/src/mongo/db/db.cpp @@ -752,14 +752,17 @@ namespace mongo { #ifndef _WIN32 mongo::signalForkSuccess(); #endif + { + OperationContextImpl txn; - if(getGlobalAuthorizationManager()->isAuthEnabled()) { - // open admin db in case we need to use it later. TODO this is not the right way to - // resolve this. - Client::WriteContext c("admin", storageGlobalParams.dbpath); - } + if (getGlobalAuthorizationManager()->isAuthEnabled()) { + // open admin db in case we need to use it later. TODO this is not the right way to + // resolve this. + Client::WriteContext ctx(&txn, "admin"); + } - authindex::configureSystemIndexes("admin"); + authindex::configureSystemIndexes(&txn, "admin"); + } getDeleter()->startWorkers(); diff --git a/src/mongo/db/dbcommands.cpp b/src/mongo/db/dbcommands.cpp index 3fa6918ad50..fa14f002391 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -321,7 +321,8 @@ namespace mongo { virtual bool isWriteCommandForConfigServer() const { return true; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); @@ -330,6 +331,7 @@ namespace mongo { // If you just want to get the current profiling level you can do so with just // read access to system.profile, even if you can't change the profiling level. if (authzSession->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(dbname, "system.profile")), ActionType::find)) { @@ -338,7 +340,7 @@ namespace mongo { } if (authzSession->isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(dbname), ActionType::enableProfiler)) { + txn, ResourcePattern::forDatabaseName(dbname), ActionType::enableProfiler)) { return Status::OK(); } @@ -353,7 +355,7 @@ namespace mongo { // Needs to be locked exclusively, because creates the system.profile collection // in the local database. // - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(dbname); BSONElement e = cmdObj.firstElement(); @@ -403,7 +405,7 @@ namespace mongo { // This doesn't look like it requires exclusive DB lock, because it uses its own diag // locking, but originally the lock was set to be WRITE, so preserving the behaviour. // - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(dbname); int was = _diaglog.setLevel( cmdObj.firstElement().numberInt() ); @@ -457,7 +459,7 @@ namespace mongo { return false; } - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(nsToDrop); Database* db = ctx.db(); @@ -528,7 +530,7 @@ namespace mongo { // This acquires the DB read lock // - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); string err; int errCode; @@ -572,22 +574,23 @@ namespace mongo { help << "create a collection explicitly\n" "{ create: <ns>[, capped: <bool>, size: <collSizeInBytes>, max: <nDocs>] }"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (cmdObj["capped"].trueValue()) { if (!authzSession->isAuthorizedForActionsOnResource( - parseResourcePattern(dbname, cmdObj), ActionType::convertToCapped)) { + txn, parseResourcePattern(dbname, cmdObj), ActionType::convertToCapped)) { return Status(ErrorCodes::Unauthorized, "unauthorized"); } } // ActionType::createCollection or ActionType::insert are both acceptable if (authzSession->isAuthorizedForActionsOnResource( - parseResourcePattern(dbname, cmdObj), ActionType::createCollection) || + txn, parseResourcePattern(dbname, cmdObj), ActionType::createCollection) || authzSession->isAuthorizedForActionsOnResource( - parseResourcePattern(dbname, cmdObj), ActionType::insert)) { + txn, parseResourcePattern(dbname, cmdObj), ActionType::insert)) { return Status::OK(); } @@ -621,7 +624,7 @@ namespace mongo { !options["capped"].trueValue() || options["size"].isNumber() || options.hasField("$nExtents")); - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(ns); // Create collection. @@ -667,7 +670,7 @@ namespace mongo { totalSize += size; { - Client::ReadContext rc( *i + ".system.namespaces" ); + Client::ReadContext rc(txn, *i + ".system.namespaces"); b.appendBool( "empty", rc.ctx().db()->isEmpty() ); } @@ -695,7 +698,7 @@ namespace mongo { b.append( "sizeOnDisk" , (double)1.0 ); { - Client::ReadContext ctx( name ); + Client::ReadContext ctx(txn, name); b.appendBool( "empty", ctx.ctx().db()->isEmpty() ); } @@ -812,7 +815,7 @@ namespace mongo { // Check shard version at startup. // This will throw before we've done any work if shard version is outdated - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Collection* coll = ctx.ctx().db()->getCollection(ns); CanonicalQuery* cq; @@ -920,7 +923,7 @@ namespace mongo { BSONObj keyPattern = jsobj.getObjectField( "keyPattern" ); bool estimate = jsobj["estimate"].trueValue(); - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); @@ -1037,7 +1040,7 @@ namespace mongo { bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { const string ns = dbname + "." + jsobj.firstElement().valuestr(); - Client::ReadContext cx( ns ); + Client::ReadContext cx(txn, ns); Database* db = cx.ctx().db(); Collection* collection = db->getCollection( ns ); if ( !collection ) { @@ -1114,7 +1117,7 @@ namespace mongo { bool run(OperationContext* txn, const string& dbname, BSONObj& jsobj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl ) { const string ns = dbname + "." + jsobj.firstElement().valuestr(); - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx( ns ); Collection* coll = ctx.db()->getCollection( ns ); @@ -1244,7 +1247,7 @@ namespace mongo { const string ns = parseNs(dbname, jsobj); - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Database* d = ctx.ctx().db(); d->getStats( &result, scale ); @@ -1401,7 +1404,7 @@ namespace mongo { fieldIsPresent, parsedUserNames); - Status status = _checkAuthorization(c, &client, dbname, cmdObj, fromRepl); + Status status = _checkAuthorization(txn, c, &client, dbname, cmdObj, fromRepl); if (!status.isOK()) { appendCommandStatus(result, status); return; diff --git a/src/mongo/db/dbhelpers.cpp b/src/mongo/db/dbhelpers.cpp index 767bf537d1f..1a2e0c4652f 100644 --- a/src/mongo/db/dbhelpers.cpp +++ b/src/mongo/db/dbhelpers.cpp @@ -297,10 +297,12 @@ namespace mongo { return kpBuilder.obj(); } - bool findShardKeyIndexPattern( const string& ns, - const BSONObj& shardKeyPattern, - BSONObj* indexPattern ) { - Client::ReadContext context( ns ); + static bool findShardKeyIndexPattern(OperationContext* txn, + const string& ns, + const BSONObj& shardKeyPattern, + BSONObj* indexPattern ) { + + Client::ReadContext context(txn, ns); Collection* collection = context.ctx().db()->getCollection( ns ); if ( !collection ) return false; @@ -332,7 +334,8 @@ namespace mongo { // The IndexChunk has a keyPattern that may apply to more than one index - we need to // select the index and get the full index keyPattern here. BSONObj indexKeyPatternDoc; - if ( !findShardKeyIndexPattern( ns, + if ( !findShardKeyIndexPattern( txn, + ns, range.keyPattern, &indexKeyPatternDoc ) ) { @@ -366,7 +369,7 @@ namespace mongo { while ( 1 ) { // Scoping for write lock. { - Client::WriteContext ctx(ns); + Client::WriteContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( txn, ns ); if ( !collection ) break; @@ -476,7 +479,9 @@ namespace mongo { // Used by migration clone step // TODO: Cannot hook up quite yet due to _trackerLocks in shared migration code. - Status Helpers::getLocsInRange( const KeyRange& range, + // TODO: This function is not used outside of tests + Status Helpers::getLocsInRange( OperationContext* txn, + const KeyRange& range, long long maxChunkSizeBytes, set<DiskLoc>* locs, long long* numDocs, @@ -486,7 +491,7 @@ namespace mongo { *estChunkSizeBytes = 0; *numDocs = 0; - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); if ( !collection ) return Status( ErrorCodes::NamespaceNotFound, ns ); diff --git a/src/mongo/db/dbhelpers.h b/src/mongo/db/dbhelpers.h index a5e9947f918..2cba18345d5 100644 --- a/src/mongo/db/dbhelpers.h +++ b/src/mongo/db/dbhelpers.h @@ -188,7 +188,8 @@ namespace mongo { * @return IndexNotFound if the index pattern doesn't match any indexes * @return InvalidLength if the estimated size exceeds maxChunkSizeBytes */ - static Status getLocsInRange( const KeyRange& range, + static Status getLocsInRange( OperationContext* txn, + const KeyRange& range, long long maxChunkSizeBytes, std::set<DiskLoc>* locs, long long* numDocs, diff --git a/src/mongo/db/dbwebserver.cpp b/src/mongo/db/dbwebserver.cpp index 26a0758ed67..66fbfeeebcd 100644 --- a/src/mongo/db/dbwebserver.cpp +++ b/src/mongo/db/dbwebserver.cpp @@ -99,13 +99,17 @@ namespace mongo { ss << "</pre>"; } - void _authorizePrincipal(const UserName& userName) { - Status status = cc().getAuthorizationSession()->addAndAuthorizeUser(userName); + void _authorizePrincipal(OperationContext* txn, const UserName& userName) { + Status status = cc().getAuthorizationSession()->addAndAuthorizeUser(txn, userName); uassertStatusOK(status); } - bool allowed( const char * rq , vector<string>& headers, const SockAddr &from ) { - if ( from.isLocalHost() || !_webUsers->haveAdminUsers() ) { + bool allowed(OperationContext* txn, + const char * rq, + vector<string>& headers, + const SockAddr &from) { + + if ( from.isLocalHost() || !_webUsers->haveAdminUsers(txn) ) { // TODO(spencer): should the above check use "&&" not "||"? Currently this is much // more permissive than the server's localhost auth bypass. cc().getAuthorizationSession()->grantInternalAuthorization(); @@ -131,7 +135,7 @@ namespace mongo { User* user; AuthorizationManager& authzManager = cc().getAuthorizationSession()->getAuthorizationManager(); - Status status = authzManager.acquireUser(userName, &user); + Status status = authzManager.acquireUser(txn, userName, &user); if (!status.isOK()) { if (status.code() != ErrorCodes::UserNotFound) { uasserted(17051, status.reason()); @@ -159,7 +163,7 @@ namespace mongo { string r1 = md5simpledigest( r.str() ); if ( r1 == parms["response"] ) { - _authorizePrincipal(userName); + _authorizePrincipal(txn, userName); return true; } } @@ -191,7 +195,7 @@ namespace mongo { if ( url.size() > 1 ) { - if ( ! allowed( rq , headers, from ) ) { + if (!allowed(txn.get(), rq, headers, from)) { responseCode = 401; headers.push_back( "Content-Type: text/plain;charset=utf-8" ); responseMsg = "not allowed\n"; @@ -240,7 +244,7 @@ namespace mongo { // generate home page - if ( ! allowed( rq , headers, from ) ) { + if (!allowed(txn.get(), rq, headers, from)) { responseCode = 401; headers.push_back( "Content-Type: text/plain;charset=utf-8" ); responseMsg = "not allowed\n"; diff --git a/src/mongo/db/exec/stagedebug_cmd.cpp b/src/mongo/db/exec/stagedebug_cmd.cpp index 5446d2b5c2d..ca10066c960 100644 --- a/src/mongo/db/exec/stagedebug_cmd.cpp +++ b/src/mongo/db/exec/stagedebug_cmd.cpp @@ -116,7 +116,7 @@ namespace mongo { string collName = collElt.String(); // Need a context to get the actual Collection* - Client::ReadContext ctx(dbname); + Client::ReadContext ctx(txn, dbname); // Make sure the collection is valid. Database* db = ctx.ctx().db(); diff --git a/src/mongo/db/fts/fts_command.cpp b/src/mongo/db/fts/fts_command.cpp index c95a6c52bb1..128b5a9f255 100644 --- a/src/mongo/db/fts/fts_command.cpp +++ b/src/mongo/db/fts/fts_command.cpp @@ -92,7 +92,7 @@ namespace mongo { projection = cmdObj["project"].Obj(); } - return _run( dbname, cmdObj, options, + return _run( txn, dbname, cmdObj, options, ns, search, language, limit, filter, projection, errmsg, result ); } diff --git a/src/mongo/db/fts/fts_command.h b/src/mongo/db/fts/fts_command.h index 4c0ced7efea..7f6b4d7bc4d 100644 --- a/src/mongo/db/fts/fts_command.h +++ b/src/mongo/db/fts/fts_command.h @@ -40,6 +40,8 @@ namespace mongo { + class OperationContext; + namespace fts { class FTSCommand : public Command { @@ -64,7 +66,8 @@ namespace mongo { bool fromRepl); protected: - bool _run( const std::string& dbName, + bool _run( OperationContext* txn, + const std::string& dbName, BSONObj& cmdObj, int cmdOptions, const std::string& ns, diff --git a/src/mongo/db/fts/fts_command_mongod.cpp b/src/mongo/db/fts/fts_command_mongod.cpp index 230c6d00fb4..c422d9d8863 100644 --- a/src/mongo/db/fts/fts_command_mongod.cpp +++ b/src/mongo/db/fts/fts_command_mongod.cpp @@ -54,7 +54,8 @@ namespace mongo { * @param fromRepl * @return true if successful, false otherwise */ - bool FTSCommand::_run(const string& dbname, + bool FTSCommand::_run(OperationContext* txn, + const string& dbname, BSONObj& cmdObj, int cmdOptions, const string& ns, @@ -92,7 +93,7 @@ namespace mongo { projBob.appendElements(sortSpec); BSONObj projObj = projBob.obj(); - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); CanonicalQuery* cq; Status canonicalizeStatus = diff --git a/src/mongo/db/fts/fts_command_mongos.cpp b/src/mongo/db/fts/fts_command_mongos.cpp index 0c0f09e957b..df152856e2d 100644 --- a/src/mongo/db/fts/fts_command_mongos.cpp +++ b/src/mongo/db/fts/fts_command_mongos.cpp @@ -54,7 +54,8 @@ namespace mongo { double score; }; - bool FTSCommand::_run(const string& dbName, + bool FTSCommand::_run(OperationContext* txn, + const string& dbName, BSONObj& cmdObj, int cmdOptions, const string& ns, diff --git a/src/mongo/db/geo/haystack.cpp b/src/mongo/db/geo/haystack.cpp index b5c61765b79..644c2ba60d2 100644 --- a/src/mongo/db/geo/haystack.cpp +++ b/src/mongo/db/geo/haystack.cpp @@ -71,7 +71,7 @@ namespace mongo { bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool fromRepl) { const string ns = dbname + "." + cmdObj.firstElement().valuestr(); - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); Database* db = ctx.ctx().db(); if ( !db ) { diff --git a/src/mongo/db/index_builder.cpp b/src/mongo/db/index_builder.cpp index 6014608300c..1e97c3da193 100644 --- a/src/mongo/db/index_builder.cpp +++ b/src/mongo/db/index_builder.cpp @@ -55,6 +55,8 @@ namespace mongo { void IndexBuilder::run() { LOG(2) << "IndexBuilder building index " << _index; + OperationContextImpl txn; + Client::initThread(name().c_str()); Lock::ParallelBatchWriterMode::iAmABatchParticipant(); @@ -62,8 +64,7 @@ namespace mongo { cc().curop()->reset(HostAndPort(), dbInsert); NamespaceString ns(_index["ns"].String()); - Client::WriteContext ctx(ns.getSystemIndexesCollection()); - OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns.getSystemIndexesCollection()); Database* db = dbHolder().get(ns.db().toString(), storageGlobalParams.dbpath); diff --git a/src/mongo/db/index_rebuilder.cpp b/src/mongo/db/index_rebuilder.cpp index 3e45d143cab..b9c89ab8b04 100644 --- a/src/mongo/db/index_rebuilder.cpp +++ b/src/mongo/db/index_rebuilder.cpp @@ -63,7 +63,9 @@ namespace mongo { for (std::vector<std::string>::const_iterator dbName = dbNames.begin(); dbName < dbNames.end(); dbName++) { - Client::ReadContext ctx(*dbName); + OperationContextImpl txn; + Client::ReadContext ctx(&txn, *dbName); + Database* db = ctx.ctx().db(); db->getDatabaseCatalogEntry()->getCollectionNamespaces(&collNames); } @@ -88,10 +90,11 @@ namespace mongo { LOG(3) << "IndexRebuilder::checkNS: " << ns; + OperationContextImpl txn; // XXX??? + // This write lock is held throughout the index building process // for this namespace. - Client::WriteContext ctx(ns); - OperationContextImpl txn; // XXX??? + Client::WriteContext ctx(&txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); if ( collection == NULL ) diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp index 613165ff4d2..373e7f2b3ca 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -121,8 +121,9 @@ namespace mongo { QueryMessage q(d); BSONObjBuilder b; + OperationContextImpl txn; const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::inprog); + &txn, ResourcePattern::forClusterResource(), ActionType::inprog); audit::logInProgAuthzCheck( &cc(), q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); @@ -182,8 +183,10 @@ namespace mongo { DbMessage d(m); QueryMessage q(d); BSONObj obj; + + OperationContextImpl txn; const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::killop); + &txn, ResourcePattern::forClusterResource(), ActionType::killop); audit::logKillOpAuthzCheck(&cc(), q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); @@ -210,8 +213,10 @@ namespace mongo { bool _unlockFsync(); void unlockFsync(const char *ns, Message& m, DbResponse &dbresponse) { BSONObj obj; + + OperationContextImpl txn; const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::unlock); + &txn, ResourcePattern::forClusterResource(), ActionType::unlock); audit::logFsyncUnlockAuthzCheck( &cc(), isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); if (!isAuthorized) { @@ -249,7 +254,7 @@ namespace mongo { if (!ns.isCommand()) { // Auth checking for Commands happens later. Client* client = &cc(); - Status status = client->getAuthorizationSession()->checkAuthForQuery(ns, q.query); + Status status = client->getAuthorizationSession()->checkAuthForQuery(txn, ns, q.query); audit::logQueryAuthzCheck(client, ns, q.query, status.code()); uassertStatusOK(status); } @@ -341,7 +346,7 @@ namespace mongo { Client& c = cc(); if (!c.isGod()) - c.getAuthorizationSession()->startRequest(); + c.getAuthorizationSession()->startRequest(txn); if ( op == dbQuery ) { if( strstr(ns, ".$cmd") ) { @@ -528,7 +533,7 @@ namespace mongo { verify( n < 30000 ); } - int found = CollectionCursorCache::eraseCursorGlobalIfAuthorized(n, (long long *) x); + int found = CollectionCursorCache::eraseCursorGlobalIfAuthorized(txn, n, (long long *) x); if ( logger::globalLogDomain()->shouldLog(logger::LogSeverity::Debug(1)) || found != n ) { LOG( found == n ? 1 : 0 ) << "killcursors: found " << found << " of " << n << endl; @@ -581,7 +586,8 @@ namespace mongo { bool multi = flags & UpdateOption_Multi; bool broadcast = flags & UpdateOption_Broadcast; - Status status = cc().getAuthorizationSession()->checkAuthForUpdate(ns, + Status status = cc().getAuthorizationSession()->checkAuthForUpdate(txn, + ns, query, toupdate, upsert); @@ -603,7 +609,7 @@ namespace mongo { UpdateExecutor executor(&request, &op.debug()); uassertStatusOK(executor.prepare()); - Lock::DBWrite lk(ns.ns()); + Lock::DBWrite lk(txn->lockState(), ns.ns()); // if this ever moves to outside of lock, need to adjust check // Client::Context::_finishInit @@ -630,7 +636,7 @@ namespace mongo { verify( d.moreJSObjs() ); BSONObj pattern = d.nextJsObj(); - Status status = cc().getAuthorizationSession()->checkAuthForDelete(ns, pattern); + Status status = cc().getAuthorizationSession()->checkAuthForDelete(txn, ns, pattern); audit::logDeleteAuthzCheck(&cc(), ns, pattern, status.code()); uassertStatusOK(status); @@ -643,7 +649,7 @@ namespace mongo { request.setUpdateOpLog(true); DeleteExecutor executor(&request); uassertStatusOK(executor.prepare()); - Lock::DBWrite lk(ns.ns()); + Lock::DBWrite lk(txn->lockState(), ns.ns()); // if this ever moves to outside of lock, need to adjust check Client::Context::_finishInit if ( ! broadcast && handlePossibleShardedMessage( m , 0 ) ) @@ -684,7 +690,7 @@ namespace mongo { uassert( 16258, str::stream() << "Invalid ns [" << ns << "]", nsString.isValid() ); Status status = cc().getAuthorizationSession()->checkAuthForGetMore( - nsString, cursorid); + txn, nsString, cursorid); audit::logGetMoreAuthzCheck(&cc(), nsString, cursorid, status.code()); uassertStatusOK(status); @@ -717,7 +723,7 @@ namespace mongo { // because it may now be out of sync with the client's iteration state. // SERVER-7952 // TODO Temporary code, see SERVER-4563 for a cleanup overview. - CollectionCursorCache::eraseCursorGlobal( cursorid ); + CollectionCursorCache::eraseCursorGlobal(txn, cursorid ); } ex.reset( new AssertionException( e.getInfo().msg, e.getCode() ) ); ok = false; @@ -875,12 +881,12 @@ namespace mongo { // Check auth for insert (also handles checking if this is an index build and checks // for the proper privileges in that case). const NamespaceString nsString(ns); - Status status = cc().getAuthorizationSession()->checkAuthForInsert(nsString, obj); + Status status = cc().getAuthorizationSession()->checkAuthForInsert(txn, nsString, obj); audit::logInsertAuthzCheck(&cc(), nsString, obj, status.code()); uassertStatusOK(status); } - Lock::DBWrite lk(ns); + Lock::DBWrite lk(txn->lockState(), ns); // CONCURRENCY TODO: is being read locked in big log sufficient here? // writelock is used to synchronize stepdowns w/ writes @@ -924,7 +930,7 @@ namespace mongo { local database does NOT count except for rsoplog collection. used to set the hasData field on replset heartbeat command response */ - bool replHasDatabases() { + bool replHasDatabases(OperationContext* txn) { vector<string> names; getDatabaseNames(names); if( names.size() >= 2 ) return true; @@ -933,7 +939,7 @@ namespace mongo { return true; // we have a local database. return true if oplog isn't empty { - Lock::DBRead lk(repl::rsoplog); + Lock::DBRead lk(txn->lockState(), repl::rsoplog); BSONObj o; if( Helpers::getFirst(repl::rsoplog, o) ) return true; @@ -1002,7 +1008,9 @@ namespace { } void DBDirectClient::killCursor( long long id ) { - CollectionCursorCache::eraseCursorGlobal( id ); + // The killCursor command on the DB client is only used by sharding, + // so no need to have it for MongoD. + verify(!"killCursor should not be used in MongoD"); } HostAndPort DBDirectClient::_clientHost = HostAndPort( "0.0.0.0" , 0 ); @@ -1013,7 +1021,9 @@ namespace { << " to zero in query: " << query << endl; skip = 0; } - Lock::DBRead lk( ns ); + + OperationContextImpl txn; + Lock::DBRead lk(txn.lockState(), ns); string errmsg; int errCode; long long res = runCount( ns, _countCmd( ns , query , options , limit , skip ) , errmsg, errCode ); diff --git a/src/mongo/db/instance.h b/src/mongo/db/instance.h index ff8e655b608..b7039b30c4c 100644 --- a/src/mongo/db/instance.h +++ b/src/mongo/db/instance.h @@ -79,7 +79,7 @@ namespace mongo { /* returns true if there is no data on this server. useful when starting replication. local database does NOT count. */ - bool replHasDatabases(); + bool replHasDatabases(OperationContext* txn); /** * Embedded calls to the local server using the DBClientBase API without going over the network. diff --git a/src/mongo/db/introspect.cpp b/src/mongo/db/introspect.cpp index 79894bf88c7..ff9004ab6e8 100644 --- a/src/mongo/db/introspect.cpp +++ b/src/mongo/db/introspect.cpp @@ -137,7 +137,7 @@ namespace { try { // NOTE: It's kind of weird that we lock the op's namespace, but have to for now since // we're sometimes inside the lock already - Lock::DBWrite lk( currentOp.getNS() ); + Lock::DBWrite lk(txn->lockState(), currentOp.getNS() ); if (dbHolder()._isLoaded(nsToDatabase(currentOp.getNS()), storageGlobalParams.dbpath)) { Client::Context cx(currentOp.getNS(), storageGlobalParams.dbpath, false); _profile(txn, c, cx.db(), diff --git a/src/mongo/db/pipeline/document_source_cursor.cpp b/src/mongo/db/pipeline/document_source_cursor.cpp index 87131cbc17b..70ac51d2000 100644 --- a/src/mongo/db/pipeline/document_source_cursor.cpp +++ b/src/mongo/db/pipeline/document_source_cursor.cpp @@ -78,7 +78,7 @@ namespace mongo { // We have already validated the sharding version when we constructed the Runner // so we shouldn't check it again. - Lock::DBRead lk(_ns); + Lock::DBRead lk(pExpCtx->opCtx->lockState(), _ns); Client::Context ctx(_ns, storageGlobalParams.dbpath, /*doVersion=*/false); _runner->restoreState(pExpCtx->opCtx); @@ -199,7 +199,7 @@ namespace { Status explainStatus(ErrorCodes::InternalError, ""); scoped_ptr<TypeExplain> plan; { - Lock::DBRead lk(_ns); + Lock::DBRead lk(pExpCtx->opCtx->lockState(), _ns); Client::Context ctx(_ns, storageGlobalParams.dbpath, /*doVersion=*/false); massert(17392, "No _runner. Were we disposed before explained?", _runner); diff --git a/src/mongo/db/pipeline/pipeline_d.cpp b/src/mongo/db/pipeline/pipeline_d.cpp index df8a6716987..4409b899c4c 100644 --- a/src/mongo/db/pipeline/pipeline_d.cpp +++ b/src/mongo/db/pipeline/pipeline_d.cpp @@ -64,7 +64,7 @@ namespace { } bool isCapped(const NamespaceString& ns) { - Client::ReadContext ctx(ns.ns()); + Client::ReadContext ctx(_ctx->opCtx, ns.ns()); Collection* collection = ctx.ctx().db()->getCollection(ns); return collection && collection->isCapped(); } diff --git a/src/mongo/db/prefetch.cpp b/src/mongo/db/prefetch.cpp index 7634b2d862a..36ad06ef964 100644 --- a/src/mongo/db/prefetch.cpp +++ b/src/mongo/db/prefetch.cpp @@ -55,8 +55,12 @@ namespace mongo { "repl.preload.docs", &prefetchDocStats ); + void prefetchIndexPages(Collection* collection, const BSONObj& obj); + void prefetchRecordPages(OperationContext* txn, const char* ns, const BSONObj& obj); + + // prefetch for an oplog operation - void prefetchPagesForReplicatedOp(Database* db, const BSONObj& op) { + void prefetchPagesForReplicatedOp(OperationContext* txn, Database* db, const BSONObj& op) { const char *opField; const char *opType = op.getStringField("op"); switch (*opType) { @@ -110,10 +114,11 @@ namespace mongo { // do not prefetch the data for capped collections because // they typically do not have an _id index for findById() to use. !collection->isCapped()) { - prefetchRecordPages(ns, obj); + prefetchRecordPages(txn, ns, obj); } } + // page in pages needed for all index lookups on a given object void prefetchIndexPages(Collection* collection, const BSONObj& obj) { DiskLoc unusedDl; // unused BSONObjSet unusedKeys; @@ -170,8 +175,8 @@ namespace mongo { } } - - void prefetchRecordPages(const char* ns, const BSONObj& obj) { + // page in the data pages for a record associated with an object + void prefetchRecordPages(OperationContext* txn, const char* ns, const BSONObj& obj) { BSONElement _id; if( obj.getObjectID(_id) ) { TimerHolder timer(&prefetchDocStats); @@ -181,7 +186,7 @@ namespace mongo { try { // we can probably use Client::Context here instead of ReadContext as we // have locked higher up the call stack already - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(txn, ns); if( Helpers::findById(ctx.ctx().db(), ns, builder.done(), result) ) { // do we want to use Record::touch() here? it's pretty similar. volatile char _dummy_char = '\0'; diff --git a/src/mongo/db/prefetch.h b/src/mongo/db/prefetch.h index 3e97753da23..36310b40676 100644 --- a/src/mongo/db/prefetch.h +++ b/src/mongo/db/prefetch.h @@ -33,13 +33,8 @@ namespace mongo { class Collection; class Database; + class OperationContext; // page in both index and data pages for an op from the oplog - void prefetchPagesForReplicatedOp(Database* db, const BSONObj& op); - - // page in pages needed for all index lookups on a given object - void prefetchIndexPages(Collection *nsd, const BSONObj& obj); - - // page in the data pages for a record associated with an object - void prefetchRecordPages(const char *ns, const BSONObj& obj); + void prefetchPagesForReplicatedOp(OperationContext* txn, Database* db, const BSONObj& op); } diff --git a/src/mongo/db/query/new_find.cpp b/src/mongo/db/query/new_find.cpp index d78032fed07..7ed222b9f06 100644 --- a/src/mongo/db/query/new_find.cpp +++ b/src/mongo/db/query/new_find.cpp @@ -152,7 +152,7 @@ namespace mongo { exhaust = false; // This is a read lock. - scoped_ptr<Client::ReadContext> ctx(new Client::ReadContext(ns)); + scoped_ptr<Client::ReadContext> ctx(new Client::ReadContext(txn, ns)); Collection* collection = ctx->ctx().db()->getCollection(ns); uassert( 17356, "collection dropped between getMore calls", collection ); @@ -459,7 +459,7 @@ namespace mongo { // This is a read lock. We require this because if we're parsing a $where, the // where-specific parsing code assumes we have a lock and creates execution machinery that // requires it. - Client::ReadContext ctx(q.ns); + Client::ReadContext ctx(txn, q.ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); // Parse the qm into a CanonicalQuery. diff --git a/src/mongo/db/range_deleter.cpp b/src/mongo/db/range_deleter.cpp index fd90b65c289..90cce2fcb4c 100644 --- a/src/mongo/db/range_deleter.cpp +++ b/src/mongo/db/range_deleter.cpp @@ -232,7 +232,10 @@ namespace mongo { _stats->incPendingDeletes_inlock(); } - _env->getCursorIds(ns, &toDelete->cursorsToWait); + { + boost::scoped_ptr<OperationContext> txn(transactionFactory()); + _env->getCursorIds(txn.get(), ns, &toDelete->cursorsToWait); + } { scoped_lock sl(_queueMutex); @@ -284,7 +287,7 @@ namespace mongo { } set<CursorId> cursorsToWait; - _env->getCursorIds(ns, &cursorsToWait); + _env->getCursorIds(txn, ns, &cursorsToWait); long long checkIntervalMillis = 5; @@ -295,7 +298,7 @@ namespace mongo { while (!cursorsToWait.empty()) { set<CursorId> cursorsNow; - _env->getCursorIds(ns, &cursorsNow); + _env->getCursorIds(txn, ns, &cursorsNow); set<CursorId> cursorsLeft; std::set_intersection(cursorsToWait.begin(), @@ -438,7 +441,11 @@ namespace mongo { RangeDeleteEntry* entry = *iter; set<CursorId> cursorsNow; - _env->getCursorIds(entry->ns, &cursorsNow); + { + boost::scoped_ptr<OperationContext> txn( + entry->transactionFactory()); // XXX? + _env->getCursorIds(txn.get(), entry->ns, &cursorsNow); + } set<CursorId> cursorsLeft; std::set_intersection(entry->cursorsToWait.begin(), diff --git a/src/mongo/db/range_deleter.h b/src/mongo/db/range_deleter.h index 9a3b8c6b1fa..15da3560513 100644 --- a/src/mongo/db/range_deleter.h +++ b/src/mongo/db/range_deleter.h @@ -304,7 +304,9 @@ namespace mongo { * Must be a synchronous call. CursorIds should be populated after call. * Must not throw exception. */ - virtual void getCursorIds(const StringData& ns, std::set<CursorId>* openCursors) = 0; + virtual void getCursorIds(OperationContext* txn, + const StringData& ns, + std::set<CursorId>* openCursors) = 0; }; } // namespace mongo diff --git a/src/mongo/db/range_deleter_db_env.cpp b/src/mongo/db/range_deleter_db_env.cpp index 0a99f21cc55..39e0c81a465 100644 --- a/src/mongo/db/range_deleter_db_env.cpp +++ b/src/mongo/db/range_deleter_db_env.cpp @@ -156,9 +156,10 @@ namespace mongo { return true; } - void RangeDeleterDBEnv::getCursorIds(const StringData& ns, + void RangeDeleterDBEnv::getCursorIds(OperationContext* txn, + const StringData& ns, std::set<CursorId>* openCursors) { - Client::ReadContext ctx(ns.toString()); + Client::ReadContext ctx(txn, ns.toString()); Collection* collection = ctx.ctx().db()->getCollection( ns ); if ( !collection ) return; diff --git a/src/mongo/db/range_deleter_db_env.h b/src/mongo/db/range_deleter_db_env.h index 9708fa49495..c5956db5b98 100644 --- a/src/mongo/db/range_deleter_db_env.h +++ b/src/mongo/db/range_deleter_db_env.h @@ -62,6 +62,8 @@ namespace mongo { /** * Gets the list of open cursors on a given namespace. */ - virtual void getCursorIds(const StringData& ns, std::set<CursorId>* openCursors); + virtual void getCursorIds(OperationContext* txn, + const StringData& ns, + std::set<CursorId>* openCursors); }; } diff --git a/src/mongo/db/range_deleter_mock_env.cpp b/src/mongo/db/range_deleter_mock_env.cpp index 2b40a3e7bc6..29877a1a252 100644 --- a/src/mongo/db/range_deleter_mock_env.cpp +++ b/src/mongo/db/range_deleter_mock_env.cpp @@ -139,7 +139,8 @@ namespace mongo { return true; } - void RangeDeleterMockEnv::getCursorIds(const StringData& ns, set<CursorId>* in) { + void RangeDeleterMockEnv::getCursorIds( + OperationContext* txn, const StringData& ns, set<CursorId>* in) { { scoped_lock sl(_cursorMapMutex); const set<CursorId>& _cursors = _cursorMap[ns.toString()]; diff --git a/src/mongo/db/range_deleter_mock_env.h b/src/mongo/db/range_deleter_mock_env.h index ce9457889d6..b1164ef830b 100644 --- a/src/mongo/db/range_deleter_mock_env.h +++ b/src/mongo/db/range_deleter_mock_env.h @@ -139,7 +139,7 @@ namespace mongo { * RangeDeleterEnv::getCursorIds. The cursors returned can be modified with * the setCursorId and clearCursorMap methods. */ - void getCursorIds(const StringData& ns, std::set<CursorId>* in); + void getCursorIds(OperationContext* txn, const StringData& ns, std::set<CursorId>* in); private: // mutex acquisition ordering: diff --git a/src/mongo/db/repair_database.cpp b/src/mongo/db/repair_database.cpp index 72620d77609..52ecec48a95 100644 --- a/src/mongo/db/repair_database.cpp +++ b/src/mongo/db/repair_database.cpp @@ -318,7 +318,7 @@ namespace mongo { Database* tempDatabase = NULL; { bool justCreated = false; - tempDatabase = dbHolderW().getOrCreate( dbName, reservedPathString, justCreated ); + tempDatabase = dbHolderW().getOrCreate(txn, dbName, reservedPathString, justCreated); invariant( justCreated ); } diff --git a/src/mongo/db/repl/heartbeat.cpp b/src/mongo/db/repl/heartbeat.cpp index 006998a57ef..5f1f1179aca 100644 --- a/src/mongo/db/repl/heartbeat.cpp +++ b/src/mongo/db/repl/heartbeat.cpp @@ -112,7 +112,7 @@ namespace repl { result.append("rs", true); if( cmdObj["checkEmpty"].trueValue() ) { - result.append("hasData", replHasDatabases()); + result.append("hasData", replHasDatabases(txn)); } if( (theReplSet == 0) || (theReplSet->startupStatus == ReplSetImpl::LOADINGCONFIG) ) { string from( cmdObj.getStringField("from") ); diff --git a/src/mongo/db/repl/master_slave.cpp b/src/mongo/db/repl/master_slave.cpp index 48226902b95..ff2ff4921f5 100644 --- a/src/mongo/db/repl/master_slave.cpp +++ b/src/mongo/db/repl/master_slave.cpp @@ -60,7 +60,7 @@ namespace mongo { namespace repl { - void pretouchOperation(const BSONObj& op); + void pretouchOperation(OperationContext* txn, const BSONObj& op); void pretouchN(vector<BSONObj>&, unsigned a, unsigned b); /* if 1 sync() is running */ @@ -162,8 +162,8 @@ namespace repl { void ReplSource::ensureMe() { string myname = getHostName(); { - Client::WriteContext ctx("local"); OperationContextImpl txn; + Client::WriteContext ctx(&txn, "local"); // local.me is an identifier for a server for getLastError w:2+ if (!Helpers::getSingleton("local.me", _me) || !_me.hasField("host") || @@ -560,6 +560,8 @@ namespace repl { if ( !only.empty() && only != clientName ) return; + OperationContextImpl txn; // XXX? + if (replSettings.pretouch && !alreadyLocked/*doesn't make sense if in write lock already*/) { if (replSettings.pretouch > 1) { @@ -588,18 +590,17 @@ namespace repl { a += m; } // we do one too... - pretouchOperation(op); + pretouchOperation(&txn, op); tp->join(); countdown = v.size(); } } else { - pretouchOperation(op); + pretouchOperation(&txn, op); } } scoped_ptr<Lock::GlobalWrite> lk( alreadyLocked ? 0 : new Lock::GlobalWrite() ); - OperationContextImpl txn; // XXX? if ( replAllDead ) { // hmmm why is this check here and not at top of this function? does it get set between top and here? @@ -679,7 +680,7 @@ namespace repl { int get() const { return _value; } - virtual void append( BSONObjBuilder& b, const string& name ) { + virtual void append(OperationContext* txn, BSONObjBuilder& b, const string& name) { b.append( name, _value ); } @@ -1276,7 +1277,7 @@ namespace repl { } } - void pretouchOperation(const BSONObj& op) { + void pretouchOperation(OperationContext* txn, const BSONObj& op) { if( Lock::somethingWriteLocked() ) return; // no point pretouching if write locked. not sure if this will ever fire, but just in case. @@ -1299,7 +1300,7 @@ namespace repl { BSONObjBuilder b; b.append(_id); BSONObj result; - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(txn, ns ); if( Helpers::findById(ctx.ctx().db(), ns, b.done(), result) ) _dummy_z += result.objsize(); // touch } diff --git a/src/mongo/db/repl/oplog.cpp b/src/mongo/db/repl/oplog.cpp index 5996e180401..474416dd250 100644 --- a/src/mongo/db/repl/oplog.cpp +++ b/src/mongo/db/repl/oplog.cpp @@ -113,8 +113,8 @@ namespace repl { todo : make _logOpRS() call this so we don't repeat ourself? */ void _logOpObjRS(const BSONObj& op) { - Lock::DBWrite lk("local"); OperationContextImpl txn; + Lock::DBWrite lk(txn.lockState(), "local"); const OpTime ts = op["ts"]._opTime(); long long h = op["h"].numberLong(); @@ -231,7 +231,7 @@ namespace repl { BSONObj *o2, bool *bb, bool fromMigrate ) { - Lock::DBWrite lk1("local"); + Lock::DBWrite lk1(txn->lockState(), "local"); if ( strncmp(ns, "local.", 6) == 0 ) { if ( strncmp(ns, "local.slaves", 12) == 0 ) @@ -321,7 +321,7 @@ namespace repl { BSONObj *o2, bool *bb, bool fromMigrate ) { - Lock::DBWrite lk("local"); + Lock::DBWrite lk(txn->lockState(), "local"); static BufBuilder bufbuilder(8*1024); // todo there is likely a mutex on this constructor if ( strncmp(ns, "local.", 6) == 0 ) { diff --git a/src/mongo/db/repl/repl_set_impl.cpp b/src/mongo/db/repl/repl_set_impl.cpp index 01f78853e04..5274e461f07 100644 --- a/src/mongo/db/repl/repl_set_impl.cpp +++ b/src/mongo/db/repl/repl_set_impl.cpp @@ -435,7 +435,8 @@ namespace { } void ReplSetImpl::loadLastOpTimeWritten(bool quiet) { - Lock::DBRead lk(rsoplog); + OperationContextImpl txn; // XXX? + Lock::DBRead lk(txn.lockState(), rsoplog); BSONObj o; if (Helpers::getLast(rsoplog, o)) { lastH = o["h"].numberLong(); @@ -445,7 +446,8 @@ namespace { } OpTime ReplSetImpl::getEarliestOpTimeWritten() const { - Lock::DBRead lk(rsoplog); + OperationContextImpl txn; // XXX? + Lock::DBRead lk(txn.lockState(), rsoplog); BSONObj o; uassert(17347, "Problem reading earliest entry from oplog", Helpers::getFirst(rsoplog, o)); return o["ts"]._opTime(); @@ -859,19 +861,20 @@ namespace { const BSONObj ReplSetImpl::_initialSyncFlag(BSON(_initialSyncFlagString << true)); void ReplSetImpl::clearInitialSyncFlag() { - Lock::DBWrite lk("local"); OperationContextImpl txn; // XXX? + Lock::DBWrite lk(txn.lockState(), "local"); Helpers::putSingleton(&txn, "local.replset.minvalid", BSON("$unset" << _initialSyncFlag)); } void ReplSetImpl::setInitialSyncFlag() { - Lock::DBWrite lk("local"); OperationContextImpl txn; // XXX? + Lock::DBWrite lk(txn.lockState(), "local"); Helpers::putSingleton(&txn, "local.replset.minvalid", BSON("$set" << _initialSyncFlag)); } bool ReplSetImpl::getInitialSyncFlag() { - Lock::DBRead lk ("local"); + OperationContextImpl txn; // XXX? + Lock::DBRead lk (txn.lockState(), "local"); BSONObj mv; if (Helpers::getSingleton("local.replset.minvalid", mv)) { return mv[_initialSyncFlagString].trueValue(); @@ -884,13 +887,15 @@ namespace { BSONObjBuilder subobj(builder.subobjStart("$set")); subobj.appendTimestamp("ts", obj["ts"].date()); subobj.done(); - Lock::DBWrite lk("local"); + OperationContextImpl txn; // XXX? + Lock::DBWrite lk(txn.lockState(), "local"); Helpers::putSingleton(&txn, "local.replset.minvalid", builder.obj()); } OpTime ReplSetImpl::getMinValid() { - Lock::DBRead lk("local.replset.minvalid"); + OperationContextImpl txn; // XXX? + Lock::DBRead lk(txn.lockState(), "local.replset.minvalid"); BSONObj mv; if (Helpers::getSingleton("local.replset.minvalid", mv)) { return mv["ts"]._opTime(); diff --git a/src/mongo/db/repl/repl_settings.cpp b/src/mongo/db/repl/repl_settings.cpp index e8cb54d8728..48dad4218cc 100644 --- a/src/mongo/db/repl/repl_settings.cpp +++ b/src/mongo/db/repl/repl_settings.cpp @@ -40,6 +40,7 @@ #include "mongo/db/repl/master_slave.h" #include "mongo/db/repl/oplogreader.h" #include "mongo/db/repl/rs.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/storage_options.h" #include "mongo/db/wire_version.h" #include "mongo/s/write_ops/batched_command_request.h" @@ -55,7 +56,7 @@ namespace repl { return replSettings.slave || replSettings.master || theReplSet; } - void appendReplicationInfo(BSONObjBuilder& result, int level) { + void appendReplicationInfo(OperationContext* txn, BSONObjBuilder& result, int level) { if ( replSet ) { if( theReplSet == 0 || theReplSet->state().shunned() ) { result.append("ismaster", false); @@ -88,7 +89,7 @@ namespace repl { list<BSONObj> src; { const char* localSources = "local.sources"; - Client::ReadContext ctx(localSources, storageGlobalParams.dbpath); + Client::ReadContext ctx(txn, localSources); auto_ptr<Runner> runner(InternalPlanner::collectionScan(localSources, ctx.ctx().db()->getCollection(localSources))); BSONObj obj; @@ -151,7 +152,9 @@ namespace repl { int level = configElement.numberInt(); BSONObjBuilder result; - appendReplicationInfo(result, level); + + OperationContextImpl txn; // XXX? + appendReplicationInfo(&txn, result, level); return result.obj(); } } replicationInfoServerStatus; @@ -196,7 +199,7 @@ namespace repl { if ( cmdObj["forShell"].trueValue() ) lastError.disableForCommand(); - appendReplicationInfo(result, 0); + appendReplicationInfo(txn, result, 0); result.appendNumber("maxBsonObjectSize", BSONObjMaxUserSize); result.appendNumber("maxMessageSizeBytes", MaxMessageSizeBytes); diff --git a/src/mongo/db/repl/rs.cpp b/src/mongo/db/repl/rs.cpp index 798269c7c29..ee32241039d 100644 --- a/src/mongo/db/repl/rs.cpp +++ b/src/mongo/db/repl/rs.cpp @@ -171,7 +171,7 @@ namespace repl { } } - virtual void append( BSONObjBuilder& b, const string& name ) { + virtual void append(OperationContext* txn, BSONObjBuilder& b, const string& name) { b.append( name, _value() ); } diff --git a/src/mongo/db/repl/rs_config.cpp b/src/mongo/db/repl/rs_config.cpp index 0e29c52e323..da705f14659 100644 --- a/src/mongo/db/repl/rs_config.cpp +++ b/src/mongo/db/repl/rs_config.cpp @@ -28,8 +28,6 @@ * it in the license file. */ -#include "mongo/pch.h" - #include <boost/algorithm/string.hpp> #include "mongo/db/dbhelpers.h" @@ -82,8 +80,8 @@ namespace repl { log() << "replSet info saving a newer config version to local.system.replset: " << newConfigBSON << rsLog; { - Client::WriteContext cx( rsConfigNs ); OperationContextImpl txn; + Client::WriteContext cx(&txn, rsConfigNs); //theReplSet->lastOpTimeWritten = ??; //rather than above, do a logOp()? probably diff --git a/src/mongo/db/repl/rs_initialsync.cpp b/src/mongo/db/repl/rs_initialsync.cpp index f3120fb246a..32d9d7e6e3c 100644 --- a/src/mongo/db/repl/rs_initialsync.cpp +++ b/src/mongo/db/repl/rs_initialsync.cpp @@ -99,8 +99,8 @@ namespace repl { else sethbmsg( str::stream() << "initial sync cloning indexes for : " << db , 0); - Client::WriteContext ctx(db); OperationContextImpl txn; + Client::WriteContext ctx(&txn, db); string err; int errCode; @@ -130,8 +130,9 @@ namespace repl { void _logOpObjRS(const BSONObj& op); static void emptyOplog() { - Client::WriteContext ctx(rsoplog); OperationContextImpl txn; + Client::WriteContext ctx(&txn, rsoplog); + Collection* collection = ctx.ctx().db()->getCollection(rsoplog); // temp @@ -321,7 +322,8 @@ namespace repl { log() << "replSet cleaning up [1]" << rsLog; { - Client::WriteContext cx( "local." ); + OperationContextImpl txn; // XXX? + Client::WriteContext cx(&txn, "local."); cx.ctx().db()->flushFiles(true); } log() << "replSet cleaning up [2]" << rsLog; @@ -465,7 +467,9 @@ namespace repl { verify( !box.getState().primary() ); // wouldn't make sense if we were. { - Client::WriteContext cx( "local." ); + OperationContextImpl txn; + Client::WriteContext cx(&txn, "local."); + cx.ctx().db()->flushFiles(true); try { log() << "replSet set minValid=" << minValid["ts"]._opTime().toString() << rsLog; diff --git a/src/mongo/db/repl/rs_rollback.cpp b/src/mongo/db/repl/rs_rollback.cpp index 45b24c899df..b8bc672753f 100644 --- a/src/mongo/db/repl/rs_rollback.cpp +++ b/src/mongo/db/repl/rs_rollback.cpp @@ -654,7 +654,8 @@ namespace repl { // check that we are at minvalid, otherwise we cannot rollback as we may be in an // inconsistent state { - Lock::DBRead lk("local.replset.minvalid"); + OperationContextImpl txn; + Lock::DBRead lk(txn.lockState(), "local.replset.minvalid"); BSONObj mv; if (Helpers::getSingleton("local.replset.minvalid", mv)) { OpTime minvalid = mv["ts"]._opTime(); diff --git a/src/mongo/db/repl/sync_source_feedback.cpp b/src/mongo/db/repl/sync_source_feedback.cpp index 8a8ac1da5f9..d30eb517898 100644 --- a/src/mongo/db/repl/sync_source_feedback.cpp +++ b/src/mongo/db/repl/sync_source_feedback.cpp @@ -66,8 +66,9 @@ namespace repl { void SyncSourceFeedback::ensureMe() { string myname = getHostName(); { - Client::WriteContext ctx("local"); OperationContextImpl txn; + Client::WriteContext ctx(&txn, "local"); + // local.me is an identifier for a server for getLastError w:2+ if (!Helpers::getSingleton("local.me", _me) || !_me.hasField("host") || diff --git a/src/mongo/db/repl/sync_tail.cpp b/src/mongo/db/repl/sync_tail.cpp index 4526c4af3d3..92eea631595 100644 --- a/src/mongo/db/repl/sync_tail.cpp +++ b/src/mongo/db/repl/sync_tail.cpp @@ -94,6 +94,7 @@ namespace repl { bool isCommand(op["op"].valuestrsafe()[0] == 'c'); + OperationContextImpl txn; boost::scoped_ptr<Lock::ScopedLock> lk; if(isCommand) { @@ -102,11 +103,10 @@ namespace repl { lk.reset(new Lock::GlobalWrite()); } else { // DB level lock for this operation - lk.reset(new Lock::DBWrite(ns)); + lk.reset(new Lock::DBWrite(txn.lockState(), ns)); } Client::Context ctx(ns, storageGlobalParams.dbpath); - OperationContextImpl txn; ctx.getClient()->curop()->reset(); // For non-initial-sync, we convert updates to upserts // to suppress errors when replaying oplog entries. @@ -126,8 +126,9 @@ namespace repl { try { // one possible tweak here would be to stay in the read lock for this database // for multiple prefetches if they are for the same database. - Client::ReadContext ctx(ns); - prefetchPagesForReplicatedOp(ctx.ctx().db(), op); + OperationContextImpl txn; + Client::ReadContext ctx(&txn, ns); + prefetchPagesForReplicatedOp(&txn, ctx.ctx().db(), op); } catch (const DBException& e) { LOG(2) << "ignoring exception in prefetchOp(): " << e.what() << endl; @@ -475,7 +476,9 @@ namespace repl { void SyncTail::applyOpsToOplog(std::deque<BSONObj>* ops) { { - Lock::DBWrite lk("local"); + OperationContextImpl txn; // XXX? + Lock::DBWrite lk(txn.lockState(), "local"); + while (!ops->empty()) { const BSONObj& op = ops->front(); // this updates theReplSet->lastOpTimeWritten diff --git a/src/mongo/db/restapi.cpp b/src/mongo/db/restapi.cpp index 1e9e2708efa..657dc627d16 100644 --- a/src/mongo/db/restapi.cpp +++ b/src/mongo/db/restapi.cpp @@ -260,9 +260,9 @@ namespace mongo { } restHandler; - bool RestAdminAccess::haveAdminUsers() const { + bool RestAdminAccess::haveAdminUsers(OperationContext* txn) const { AuthorizationSession* authzSession = cc().getAuthorizationSession(); - return authzSession->getAuthorizationManager().hasAnyPrivilegeDocuments(); + return authzSession->getAuthorizationManager().hasAnyPrivilegeDocuments(txn); } class LowLevelMongodStatus : public WebStatusPlugin { diff --git a/src/mongo/db/restapi.h b/src/mongo/db/restapi.h index e170e740b20..d73103ab785 100644 --- a/src/mongo/db/restapi.h +++ b/src/mongo/db/restapi.h @@ -43,7 +43,7 @@ namespace mongo { public: virtual ~RestAdminAccess() { } - virtual bool haveAdminUsers() const; + virtual bool haveAdminUsers(OperationContext* txn) const; }; } // namespace mongo diff --git a/src/mongo/db/server_parameters.h b/src/mongo/db/server_parameters.h index c4feb946ad5..9c281e4499c 100644 --- a/src/mongo/db/server_parameters.h +++ b/src/mongo/db/server_parameters.h @@ -39,6 +39,7 @@ namespace mongo { class ServerParameterSet; + class OperationContext; /** * Lets you make server level settings easily configurable. @@ -66,7 +67,7 @@ namespace mongo { bool allowedToChangeAtRuntime() const { return _allowedToChangeAtRuntime; } - virtual void append( BSONObjBuilder& b, const std::string& name ) = 0; + virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name ) = 0; virtual Status set( const BSONElement& newValueElement ) = 0; @@ -114,7 +115,7 @@ namespace mongo { _value( value ) {} virtual ~ExportedServerParameter() {} - virtual void append( BSONObjBuilder& b, const std::string& name ) { + virtual void append(OperationContext* txn, BSONObjBuilder& b, const std::string& name) { b.append( name, *_value ); } diff --git a/src/mongo/db/server_parameters_test.cpp b/src/mongo/db/server_parameters_test.cpp index 212b31dbacc..c2a6f56156c 100644 --- a/src/mongo/db/server_parameters_test.cpp +++ b/src/mongo/db/server_parameters_test.cpp @@ -30,6 +30,7 @@ #include "mongo/unittest/unittest.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/db/server_parameters.h" namespace mongo { @@ -68,7 +69,10 @@ namespace mongo { ASSERT_EQUALS( "c", v[2] ); BSONObjBuilder b; - vv.append( b, vv.name() ); + + OperationContextNoop txn; + vv.append(&txn, b, vv.name()); + BSONObj y = b.obj(); ASSERT( x.firstElement().woCompare( y.firstElement(), false ) == 0 ); diff --git a/src/mongo/db/ttl.cpp b/src/mongo/db/ttl.cpp index be47f16d3d3..c497c8ed7e4 100644 --- a/src/mongo/db/ttl.cpp +++ b/src/mongo/db/ttl.cpp @@ -113,9 +113,10 @@ namespace mongo { long long n = 0; { - string ns = idx["ns"].String(); - Client::WriteContext ctx( ns ); + const string ns = idx["ns"].String(); + OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns ); Collection* collection = ctx.ctx().db()->getCollection( ns ); if ( !collection ) { // collection was dropped @@ -171,7 +172,8 @@ namespace mongo { set<string> dbs; { - Lock::DBRead lk( "local" ); + OperationContextImpl txn; // XXX? + Lock::DBRead lk(txn.lockState(), "local"); dbHolder().getAllShortNames( dbs ); } diff --git a/src/mongo/dbtests/clienttests.cpp b/src/mongo/dbtests/clienttests.cpp index e47e67ea4ea..194cc048046 100644 --- a/src/mongo/dbtests/clienttests.cpp +++ b/src/mongo/dbtests/clienttests.cpp @@ -1,3 +1,5 @@ +// client.cpp + /* * Copyright (C) 2010 10gen Inc. * @@ -26,16 +28,13 @@ * then also delete it in the license file. */ -// client.cpp - -#include "mongo/pch.h" - #include "mongo/client/dbclientcursor.h" #include "mongo/db/catalog/collection.h" #include "mongo/db/catalog/database.h" -#include "mongo/db/d_concurrency.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/dbtests/dbtests.h" + namespace ClientTests { class Base { @@ -123,8 +122,8 @@ namespace ClientTests { public: BuildIndex() : Base("buildIndex") {} void run() { - Lock::DBWrite lock(ns()); - Client::WriteContext ctx(ns()); + OperationContextNoop txn; + Client::WriteContext ctx(&txn, ns()); db.insert(ns(), BSON("x" << 1 << "y" << 2)); db.insert(ns(), BSON("x" << 2 << "y" << 2)); diff --git a/src/mongo/dbtests/counttests.cpp b/src/mongo/dbtests/counttests.cpp index 1ff84d735f8..729443e2835 100644 --- a/src/mongo/dbtests/counttests.cpp +++ b/src/mongo/dbtests/counttests.cpp @@ -41,13 +41,16 @@ namespace CountTests { class Base { + OperationContextImpl _txn; Lock::DBWrite lk; + Client::Context _context; + Database* _database; Collection* _collection; - OperationContextImpl _txn; + public: - Base() : lk(ns()), _context( ns() ) { + Base() : lk(_txn.lockState(), ns()), _context( ns() ) { _database = _context.db(); _collection = _database->getCollection( ns() ); if ( _collection ) { diff --git a/src/mongo/dbtests/dbhelper_tests.cpp b/src/mongo/dbtests/dbhelper_tests.cpp index 535dab6124d..0cee60de170 100644 --- a/src/mongo/dbtests/dbhelper_tests.cpp +++ b/src/mongo/dbtests/dbhelper_tests.cpp @@ -58,8 +58,9 @@ namespace mongo { { // Remove _id range [_min, _max). OperationContextImpl txn; - Lock::DBWrite lk( ns ); + Lock::DBWrite lk(txn.lockState(), ns); Client::Context ctx( ns ); + KeyRange range( ns, BSON( "_id" << _min ), BSON( "_id" << _max ), @@ -112,6 +113,8 @@ namespace mongo { TEST(DBHelperTests, FindDiskLocs) { DBDirectClient client; + OperationContextImpl txn; + // Some unique tag we can use to make sure we're pulling back the right data OID tag = OID::gen(); client.remove( ns, BSONObj() ); @@ -128,14 +131,15 @@ namespace mongo { long long estSizeBytes; { // search _id range (0, 10) - Lock::DBRead lk( ns ); + Lock::DBRead lk(txn.lockState(), ns); KeyRange range( ns, BSON( "_id" << 0 ), BSON( "_id" << numDocsInserted ), BSON( "_id" << 1 ) ); - Status result = Helpers::getLocsInRange( range, + Status result = Helpers::getLocsInRange( &txn, + range, maxSizeBytes, &locs, &numDocsFound, @@ -164,6 +168,8 @@ namespace mongo { TEST(DBHelperTests, FindDiskLocsNoIndex) { DBDirectClient client; + OperationContextImpl txn; + client.remove( ns, BSONObj() ); client.insert( ns, BSON( "_id" << OID::gen() ) ); @@ -173,7 +179,7 @@ namespace mongo { long long numDocsFound; long long estSizeBytes; { - Lock::DBRead lk( ns ); + Lock::DBRead lk(txn.lockState(), ns); Client::Context ctx( ns ); // search invalid index range @@ -182,7 +188,8 @@ namespace mongo { BSON( "badIndex" << 10 ), BSON( "badIndex" << 1 ) ); - Status result = Helpers::getLocsInRange( range, + Status result = Helpers::getLocsInRange( &txn, + range, maxSizeBytes, &locs, &numDocsFound, @@ -203,6 +210,8 @@ namespace mongo { TEST(DBHelperTests, FindDiskLocsTooBig) { DBDirectClient client; + OperationContextImpl txn; + client.remove( ns, BSONObj() ); int numDocsInserted = 10; @@ -217,14 +226,15 @@ namespace mongo { long long numDocsFound; long long estSizeBytes; { - Lock::DBRead lk( ns ); + Lock::DBRead lk(txn.lockState(), ns); Client::Context ctx( ns ); KeyRange range( ns, BSON( "_id" << 0 ), BSON( "_id" << numDocsInserted ), BSON( "_id" << 1 ) ); - Status result = Helpers::getLocsInRange( range, + Status result = Helpers::getLocsInRange( &txn, + range, maxSizeBytes, &locs, &numDocsFound, diff --git a/src/mongo/dbtests/documentsourcetests.cpp b/src/mongo/dbtests/documentsourcetests.cpp index 593c310eb93..652958c2efe 100644 --- a/src/mongo/dbtests/documentsourcetests.cpp +++ b/src/mongo/dbtests/documentsourcetests.cpp @@ -166,7 +166,7 @@ namespace DocumentSourceTests { _registration.reset(); _runner.reset(); - Client::WriteContext ctx (ns); + Client::WriteContext ctx(&_opCtx, ns); CanonicalQuery* cq; uassertStatusOK(CanonicalQuery::canonicalize(ns, /*query=*/BSONObj(), &cq)); Runner* runnerBare; diff --git a/src/mongo/dbtests/indexcatalogtests.cpp b/src/mongo/dbtests/indexcatalogtests.cpp index 8afba25af39..bf9b61cf5d3 100644 --- a/src/mongo/dbtests/indexcatalogtests.cpp +++ b/src/mongo/dbtests/indexcatalogtests.cpp @@ -31,22 +31,25 @@ namespace IndexCatalogTests { class IndexIteratorTests { public: IndexIteratorTests() { - Client::WriteContext ctx(_ns); OperationContextImpl txn; + Client::WriteContext ctx(&txn, _ns); + _db = ctx.ctx().db(); _coll = _db->createCollection(&txn, _ns); _catalog = _coll->getIndexCatalog(); } ~IndexIteratorTests() { - Client::WriteContext ctx(_ns); OperationContextImpl txn; + Client::WriteContext ctx(&txn, _ns); + _db->dropCollection(&txn, _ns); } void run() { - Client::WriteContext ctx(_ns); OperationContextImpl txn; + Client::WriteContext ctx(&txn, _ns); + int numFinishedIndexesStart = _catalog->numIndexesReady(); BSONObjBuilder b1; diff --git a/src/mongo/dbtests/indexupdatetests.cpp b/src/mongo/dbtests/indexupdatetests.cpp index 7c2f03662f6..792c1071d3e 100644 --- a/src/mongo/dbtests/indexupdatetests.cpp +++ b/src/mongo/dbtests/indexupdatetests.cpp @@ -55,7 +55,7 @@ namespace IndexUpdateTests { class IndexBuildBase { public: IndexBuildBase() : - _ctx( _ns ) { + _ctx(&_txn, _ns) { _client.createCollection( _ns ); } ~IndexBuildBase() { @@ -91,8 +91,9 @@ namespace IndexUpdateTests { return collection()->getIndexCatalog()->findIndexByName( "a_1" ); } #endif - Client::WriteContext _ctx; + OperationContextImpl _txn; + Client::WriteContext _ctx; }; /** addKeysToPhaseOne() adds keys from a collection's documents to an external sorter. */ diff --git a/src/mongo/dbtests/matchertests.cpp b/src/mongo/dbtests/matchertests.cpp index 5bee238cda6..67bff7ef74b 100644 --- a/src/mongo/dbtests/matchertests.cpp +++ b/src/mongo/dbtests/matchertests.cpp @@ -33,6 +33,7 @@ #include "mongo/db/json.h" #include "mongo/db/matcher/matcher.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/dbtests/dbtests.h" #include "mongo/util/timer.h" @@ -216,7 +217,9 @@ namespace MatcherTests { class WhereSimple1 { public: void run() { - Client::ReadContext ctx( "unittests.matchertests" ); + OperationContextImpl txn; + Client::ReadContext ctx(&txn, "unittests.matchertests"); + M m(BSON("$where" << "function(){ return this.a == 1; }"), WhereCallbackReal(StringData("unittests"))); ASSERT( m.matches( BSON( "a" << 1 ) ) ); diff --git a/src/mongo/dbtests/pdfiletests.cpp b/src/mongo/dbtests/pdfiletests.cpp index 59d5f1bc483..5ef98e0b08b 100644 --- a/src/mongo/dbtests/pdfiletests.cpp +++ b/src/mongo/dbtests/pdfiletests.cpp @@ -164,7 +164,8 @@ namespace PdfileTests { void run() { SmallFilesControl c; - Client::ReadContext ctx( "local" ); + OperationContextImpl txn; + Client::ReadContext ctx(&txn, "local"); Database* db = ctx.ctx().db(); ExtentManager* em = db->getExtentManager(); diff --git a/src/mongo/dbtests/plan_ranking.cpp b/src/mongo/dbtests/plan_ranking.cpp index 970e59a97ca..02939707de3 100644 --- a/src/mongo/dbtests/plan_ranking.cpp +++ b/src/mongo/dbtests/plan_ranking.cpp @@ -37,6 +37,7 @@ #include "mongo/db/index/index_descriptor.h" #include "mongo/db/instance.h" #include "mongo/db/json.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/query/get_runner.h" #include "mongo/db/query/qlog.h" #include "mongo/db/query/query_knobs.h" @@ -45,6 +46,7 @@ #include "mongo/db/query/stage_builder.h" #include "mongo/dbtests/dbtests.h" + namespace mongo { // How we access the external setParameter testing bool. @@ -59,7 +61,7 @@ namespace PlanRankingTests { class PlanRankingTestBase { public: PlanRankingTestBase() : _internalQueryForceIntersectionPlans(internalQueryForceIntersectionPlans) { - Client::WriteContext ctx(ns); + Client::WriteContext ctx(&_txn, ns); _client.dropCollection(ns); } @@ -69,12 +71,12 @@ namespace PlanRankingTests { } void insert(const BSONObj& obj) { - Client::WriteContext ctx(ns); + Client::WriteContext ctx(&_txn, ns); _client.insert(ns, obj); } void addIndex(const BSONObj& obj) { - Client::WriteContext ctx(ns); + Client::WriteContext ctx(&_txn, ns); _client.ensureIndex(ns, obj); } @@ -85,7 +87,7 @@ namespace PlanRankingTests { * Takes ownership of 'cq'. Caller DOES NOT own the returned QuerySolution*. */ QuerySolution* pickBestPlan(CanonicalQuery* cq) { - Client::ReadContext ctx(ns); + Client::ReadContext ctx(&_txn, ns); Collection* collection = ctx.ctx().db()->getCollection(ns); QueryPlannerParams plannerParams; @@ -135,16 +137,17 @@ namespace PlanRankingTests { // determining the number of documents in the tests below. static const int N; + OperationContextImpl _txn; + private: - static DBDirectClient _client; + + DBDirectClient _client; scoped_ptr<MultiPlanStage> _mps; // Holds the value of global "internalQueryForceIntersectionPlans" setParameter flag. // Restored at end of test invocation regardless of test result. bool _internalQueryForceIntersectionPlans; }; - DBDirectClient PlanRankingTestBase::_client; - // static const int PlanRankingTestBase::N = internalQueryPlanEvaluationWorks + 1000; diff --git a/src/mongo/dbtests/query_multi_plan_runner.cpp b/src/mongo/dbtests/query_multi_plan_runner.cpp index bc853298488..99d1f61d172 100644 --- a/src/mongo/dbtests/query_multi_plan_runner.cpp +++ b/src/mongo/dbtests/query_multi_plan_runner.cpp @@ -38,6 +38,7 @@ #include "mongo/db/instance.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/catalog/collection.h" #include "mongo/dbtests/dbtests.h" @@ -92,7 +93,8 @@ namespace QueryMultiPlanRunner { class MPRCollectionScanVsHighlySelectiveIXScan : public MultiPlanRunnerBase { public: void run() { - Client::WriteContext ctx(ns()); + OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); const int N = 5000; for (int i = 0; i < N; ++i) { diff --git a/src/mongo/dbtests/query_single_solution_runner.cpp b/src/mongo/dbtests/query_single_solution_runner.cpp index 30d7ca0535f..3e2e1330323 100644 --- a/src/mongo/dbtests/query_single_solution_runner.cpp +++ b/src/mongo/dbtests/query_single_solution_runner.cpp @@ -39,6 +39,7 @@ #include "mongo/db/query/query_solution.h" #include "mongo/db/query/single_solution_runner.h" #include "mongo/db/catalog/collection.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/dbtests/dbtests.h" namespace QuerySingleSolutionRunner { @@ -147,7 +148,7 @@ namespace QuerySingleSolutionRunner { static const char* ns() { return "unittests.QueryStageSingleSolutionRunner"; } size_t numCursors() { - Client::ReadContext ctx( ns() ); + Client::ReadContext ctx(&_txn, ns() ); Collection* collection = ctx.ctx().db()->getCollection( ns() ); if ( !collection ) return 0; @@ -155,28 +156,29 @@ namespace QuerySingleSolutionRunner { } void registerRunner( Runner* runner ) { - Client::ReadContext ctx( ns() ); + Client::ReadContext ctx(&_txn, ns()); Collection* collection = ctx.ctx().db()->getOrCreateCollection( ns() ); return collection->cursorCache()->registerRunner( runner ); } void deregisterRunner( Runner* runner ) { - Client::ReadContext ctx( ns() ); + Client::ReadContext ctx(&_txn, ns()); Collection* collection = ctx.ctx().db()->getOrCreateCollection( ns() ); return collection->cursorCache()->deregisterRunner( runner ); } + protected: + OperationContextImpl _txn; + private: IndexDescriptor* getIndex(Database* db, const BSONObj& obj) { Collection* collection = db->getCollection( ns() ); return collection->getIndexCatalog()->findIndexByKeyPattern(obj); } - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient SingleSolutionRunnerBase::_client; - /** * Test dropping the collection while the * SingleSolutionRunner is doing a collection scan. @@ -184,7 +186,7 @@ namespace QuerySingleSolutionRunner { class DropCollScan : public SingleSolutionRunnerBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); insert(BSON("_id" << 1)); insert(BSON("_id" << 2)); @@ -212,7 +214,7 @@ namespace QuerySingleSolutionRunner { class DropIndexScan : public SingleSolutionRunnerBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); insert(BSON("_id" << 1 << "a" << 6)); insert(BSON("_id" << 2 << "a" << 7)); insert(BSON("_id" << 3 << "a" << 8)); @@ -283,7 +285,7 @@ namespace QuerySingleSolutionRunner { class SnapshotControl : public SnapshotBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); setupCollection(); BSONObj filterObj = fromjson("{a: {$gte: 2}}"); @@ -308,7 +310,7 @@ namespace QuerySingleSolutionRunner { class SnapshotTest : public SnapshotBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); setupCollection(); BSONObj indexSpec = BSON("_id" << 1); addIndex(indexSpec); @@ -339,7 +341,7 @@ namespace QuerySingleSolutionRunner { class Invalidate : public SingleSolutionRunnerBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); insert(BSON("a" << 1 << "b" << 1)); BSONObj filterObj = fromjson("{_id: {$gt: 0}, b: {$gt: 0}}"); @@ -364,7 +366,7 @@ namespace QuerySingleSolutionRunner { class InvalidatePinned : public SingleSolutionRunnerBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); insert(BSON("a" << 1 << "b" << 1)); Collection* collection = ctx.ctx().db()->getCollection(ns()); @@ -402,12 +404,12 @@ namespace QuerySingleSolutionRunner { public: void run() { { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); insert(BSON("a" << 1 << "b" << 1)); } { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); Collection* collection = ctx.ctx().db()->getCollection(ns()); BSONObj filterObj = fromjson("{_id: {$gt: 0}, b: {$gt: 0}}"); @@ -420,7 +422,7 @@ namespace QuerySingleSolutionRunner { // There should be one cursor before timeout, // and zero cursors after timeout. ASSERT_EQUALS(1U, numCursors()); - CollectionCursorCache::timeoutCursorsGlobal(600001); + CollectionCursorCache::timeoutCursorsGlobal(&_txn, 600001); ASSERT_EQUALS(0U, numCursors()); } }; diff --git a/src/mongo/dbtests/query_stage_and.cpp b/src/mongo/dbtests/query_stage_and.cpp index 3f9d3526f2e..f1d33ff7fb8 100644 --- a/src/mongo/dbtests/query_stage_and.cpp +++ b/src/mongo/dbtests/query_stage_and.cpp @@ -109,12 +109,13 @@ namespace QueryStageAnd { static const char* ns() { return "unittests.QueryStageAnd"; } + protected: + OperationContextImpl _txn; + private: - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient QueryStageAndBase::_client; - // // Hash AND tests // @@ -126,12 +127,12 @@ namespace QueryStageAnd { class QueryStageAndHashInvalidation : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -228,12 +229,12 @@ namespace QueryStageAnd { class QueryStageAndHashInvalidateLookahead : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -314,12 +315,12 @@ namespace QueryStageAnd { class QueryStageAndHashTwoLeaf : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -363,12 +364,12 @@ namespace QueryStageAnd { class QueryStageAndHashTwoLeafFirstChildLargeKeys : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } // Generate large keys for {foo: 1, big: 1} index. @@ -415,12 +416,12 @@ namespace QueryStageAnd { class QueryStageAndHashTwoLeafLastChildLargeKeys : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } // Generate large keys for {baz: 1, big: 1} index. @@ -466,12 +467,12 @@ namespace QueryStageAnd { class QueryStageAndHashThreeLeaf : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -527,12 +528,12 @@ namespace QueryStageAnd { class QueryStageAndHashThreeLeafMiddleChildLargeKeys : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } // Generate large keys for {bar: 1, big: 1} index. @@ -586,12 +587,12 @@ namespace QueryStageAnd { class QueryStageAndHashWithNothing : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -645,12 +646,12 @@ namespace QueryStageAnd { class QueryStageAndHashProducesNothing : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 10; ++i) { @@ -693,12 +694,12 @@ namespace QueryStageAnd { class QueryStageAndHashWithMatcher : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -749,12 +750,12 @@ namespace QueryStageAnd { class QueryStageAndSortedInvalidation : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } // Insert a bunch of data @@ -866,12 +867,12 @@ namespace QueryStageAnd { class QueryStageAndSortedThreeLeaf : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } // Insert a bunch of data @@ -919,12 +920,12 @@ namespace QueryStageAnd { class QueryStageAndSortedWithNothing : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } @@ -964,12 +965,12 @@ namespace QueryStageAnd { class QueryStageAndSortedProducesNothing : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -1012,12 +1013,12 @@ namespace QueryStageAnd { class QueryStageAndSortedWithMatcher : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { @@ -1057,12 +1058,12 @@ namespace QueryStageAnd { class QueryStageAndSortedByLastChild : public QueryStageAndBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } for (int i = 0; i < 50; ++i) { diff --git a/src/mongo/dbtests/query_stage_collscan.cpp b/src/mongo/dbtests/query_stage_collscan.cpp index aa0fb3a2e65..fc30e82ad99 100644 --- a/src/mongo/dbtests/query_stage_collscan.cpp +++ b/src/mongo/dbtests/query_stage_collscan.cpp @@ -315,7 +315,7 @@ namespace QueryStageCollectionScan { class QueryStageCollectionScanBase { public: QueryStageCollectionScanBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); for (int i = 0; i < numObj(); ++i) { BSONObjBuilder bob; @@ -325,7 +325,7 @@ namespace QueryStageCollectionScan { } virtual ~QueryStageCollectionScanBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); } @@ -334,7 +334,7 @@ namespace QueryStageCollectionScan { } int countResults(CollectionScanParams::Direction direction, const BSONObj& filterObj) { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); // Configure the scan. CollectionScanParams params; @@ -384,11 +384,13 @@ namespace QueryStageCollectionScan { static const char* ns() { return "unittests.QueryStageCollectionScan"; } + protected: + OperationContextImpl _txn; + private: - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient QueryStageCollectionScanBase::_client; // // Go forwards, get everything. @@ -442,7 +444,7 @@ namespace QueryStageCollectionScan { class QueryStageCollscanObjectsInOrderForward : public QueryStageCollectionScanBase { public: void run() { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); // Configure the scan. CollectionScanParams params; @@ -473,7 +475,7 @@ namespace QueryStageCollectionScan { class QueryStageCollscanObjectsInOrderBackward : public QueryStageCollectionScanBase { public: void run() { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); CollectionScanParams params; params.collection = ctx.ctx().db()->getCollection( ns() ); @@ -502,7 +504,7 @@ namespace QueryStageCollectionScan { class QueryStageCollscanInvalidateUpcomingObject : public QueryStageCollectionScanBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); Collection* coll = ctx.ctx().db()->getCollection( ns() ); @@ -564,7 +566,7 @@ namespace QueryStageCollectionScan { class QueryStageCollscanInvalidateUpcomingObjectBackward : public QueryStageCollectionScanBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); Collection* coll = ctx.ctx().db()->getCollection(ns()); // Get the DiskLocs that would be returned by an in-order scan. diff --git a/src/mongo/dbtests/query_stage_count.cpp b/src/mongo/dbtests/query_stage_count.cpp index 090bf068f63..0d0dcbc0673 100644 --- a/src/mongo/dbtests/query_stage_count.cpp +++ b/src/mongo/dbtests/query_stage_count.cpp @@ -37,6 +37,7 @@ #include "mongo/db/instance.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/pdfile.h" #include "mongo/db/catalog/collection.h" #include "mongo/dbtests/dbtests.h" @@ -51,7 +52,7 @@ namespace QueryStageCount { CountBase() { } virtual ~CountBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); } @@ -92,11 +93,13 @@ namespace QueryStageCount { static const char* ns() { return "unittests.QueryStageCount"; } + protected: + OperationContextImpl _txn; + private: - static DBDirectClient _client; + DBDirectClient _client; }; - - DBDirectClient CountBase::_client; + // // Check that dups are properly identified @@ -104,7 +107,7 @@ namespace QueryStageCount { class QueryStageCountDups : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert some docs insert(BSON("a" << BSON_ARRAY(5 << 7))); @@ -136,7 +139,7 @@ namespace QueryStageCount { class QueryStageCountInclusiveBounds : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert some docs for (int i = 0; i < 10; ++i) { @@ -168,7 +171,7 @@ namespace QueryStageCount { class QueryStageCountExclusiveBounds : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert some docs for (int i = 0; i < 10; ++i) { @@ -200,7 +203,7 @@ namespace QueryStageCount { class QueryStageCountLowerBound : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert doc, add index insert(BSON("a" << 2)); @@ -228,7 +231,7 @@ namespace QueryStageCount { class QueryStageCountNothingInInterval : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert documents, add index insert(BSON("a" << 2)); @@ -258,7 +261,7 @@ namespace QueryStageCount { class QueryStageCountNothingInIntervalFirstMatchTooHigh : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert some documents, add index insert(BSON("a" << 2)); @@ -288,7 +291,7 @@ namespace QueryStageCount { class QueryStageCountNoChangeDuringYield : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert documents, add index for (int i = 0; i < 10; ++i) { @@ -339,7 +342,7 @@ namespace QueryStageCount { class QueryStageCountDeleteDuringYield : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert documents, add index for (int i = 0; i < 10; ++i) { @@ -393,7 +396,7 @@ namespace QueryStageCount { class QueryStageCountInsertNewDocsDuringYield : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert documents, add index for (int i = 0; i < 10; ++i) { @@ -450,7 +453,7 @@ namespace QueryStageCount { class QueryStageCountBecomesMultiKeyDuringYield : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert documents, add index for (int i = 0; i < 10; ++i) { @@ -503,7 +506,7 @@ namespace QueryStageCount { class QueryStageCountUnusedKeys : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert docs, add index for (int i = 0; i < 10; ++i) { @@ -538,7 +541,7 @@ namespace QueryStageCount { class QueryStageCountUnusedEndKey : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert docs, add index for (int i = 0; i < 10; ++i) { @@ -571,7 +574,7 @@ namespace QueryStageCount { class QueryStageCountKeyBecomesUnusedDuringYield : public CountBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); // Insert documents, add index for (int i = 0; i < 10; ++i) { diff --git a/src/mongo/dbtests/query_stage_distinct.cpp b/src/mongo/dbtests/query_stage_distinct.cpp index 37a0a6473b1..ecbbbaf5561 100644 --- a/src/mongo/dbtests/query_stage_distinct.cpp +++ b/src/mongo/dbtests/query_stage_distinct.cpp @@ -32,6 +32,7 @@ #include "mongo/db/exec/plan_stage.h" #include "mongo/db/instance.h" #include "mongo/db/json.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/query/index_bounds_builder.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/catalog/collection.h" @@ -48,22 +49,22 @@ namespace QueryStageDistinct { DistinctBase() { } virtual ~DistinctBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); } void addIndex(const BSONObj& obj) { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.ensureIndex(ns(), obj); } void insert(const BSONObj& obj) { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.insert(ns(), obj); } IndexDescriptor* getIndex(const BSONObj& obj) { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); Collection* collection = ctx.ctx().db()->getCollection( ns() ); return collection->getIndexCatalog()->findIndexByKeyPattern( obj ); } @@ -96,11 +97,13 @@ namespace QueryStageDistinct { static const char* ns() { return "unittests.QueryStageDistinct"; } + protected: + OperationContextImpl _txn; + private: - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient DistinctBase::_client; // Tests distinct with single key indices. class QueryStageDistinctBasic : public DistinctBase { @@ -121,7 +124,7 @@ namespace QueryStageDistinct { // Make an index on a:1 addIndex(BSON("a" << 1)); - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); // Set up the distinct stage. DistinctParams params; @@ -184,7 +187,7 @@ namespace QueryStageDistinct { // Make an index on a:1 addIndex(BSON("a" << 1)); - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); // Set up the distinct stage. DistinctParams params; diff --git a/src/mongo/dbtests/query_stage_fetch.cpp b/src/mongo/dbtests/query_stage_fetch.cpp index 4aaaa2657b7..b99a95b1d87 100644 --- a/src/mongo/dbtests/query_stage_fetch.cpp +++ b/src/mongo/dbtests/query_stage_fetch.cpp @@ -87,8 +87,9 @@ namespace QueryStageFetch { class FetchStageAlreadyFetched : public QueryStageFetchBase { public: void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { @@ -145,8 +146,9 @@ namespace QueryStageFetch { class FetchStageFilter : public QueryStageFetchBase { public: void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { diff --git a/src/mongo/dbtests/query_stage_keep.cpp b/src/mongo/dbtests/query_stage_keep.cpp index c030387ff09..5ea488a37f2 100644 --- a/src/mongo/dbtests/query_stage_keep.cpp +++ b/src/mongo/dbtests/query_stage_keep.cpp @@ -104,8 +104,9 @@ namespace QueryStageKeep { class KeepStageBasic : public QueryStageKeepBase { public: void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { diff --git a/src/mongo/dbtests/query_stage_merge_sort.cpp b/src/mongo/dbtests/query_stage_merge_sort.cpp index 6ddf69290e5..43319528bb2 100644 --- a/src/mongo/dbtests/query_stage_merge_sort.cpp +++ b/src/mongo/dbtests/query_stage_merge_sort.cpp @@ -50,7 +50,7 @@ namespace QueryStageMergeSortTests { QueryStageMergeSortTestBase() { } virtual ~QueryStageMergeSortTestBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); } @@ -95,23 +95,25 @@ namespace QueryStageMergeSortTests { } static const char* ns() { return "unittests.QueryStageMergeSort"; } + + protected: + OperationContextImpl _txn; + private: - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient QueryStageMergeSortTestBase::_client; - // SERVER-1205: // find($or[{a:1}, {b:1}]).sort({c:1}) with indices {a:1, c:1} and {b:1, c:1}. class QueryStageMergeSortPrefixIndex : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } const int N = 50; @@ -170,12 +172,12 @@ namespace QueryStageMergeSortTests { class QueryStageMergeSortDups : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } const int N = 50; @@ -233,12 +235,12 @@ namespace QueryStageMergeSortTests { class QueryStageMergeSortDupsNoDedup : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } const int N = 50; @@ -297,12 +299,12 @@ namespace QueryStageMergeSortTests { class QueryStageMergeSortPrefixIndexReverse : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } const int N = 50; @@ -362,12 +364,12 @@ namespace QueryStageMergeSortTests { class QueryStageMergeSortOneStageEOF : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } const int N = 50; @@ -425,12 +427,12 @@ namespace QueryStageMergeSortTests { class QueryStageMergeSortManyShort : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } WorkingSet* ws = new WorkingSet(); @@ -478,12 +480,12 @@ namespace QueryStageMergeSortTests { class QueryStageMergeSortInvalidation : public QueryStageMergeSortTestBase { public: void run() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); OperationContextImpl txn; Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { - coll = db->createCollection(&txn, ns()); + coll = db->createCollection(&_txn, ns()); } WorkingSet ws; diff --git a/src/mongo/dbtests/query_stage_sort.cpp b/src/mongo/dbtests/query_stage_sort.cpp index f0605a7abbc..2440f67948f 100644 --- a/src/mongo/dbtests/query_stage_sort.cpp +++ b/src/mongo/dbtests/query_stage_sort.cpp @@ -169,10 +169,9 @@ namespace QueryStageSortTests { static const char* ns() { return "unittests.QueryStageSort"; } private: - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient QueryStageSortTestBase::_client; // Sort some small # of results in increasing order. class QueryStageSortInc: public QueryStageSortTestBase { @@ -180,8 +179,9 @@ namespace QueryStageSortTests { virtual int numObj() { return 100; } void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { @@ -199,8 +199,9 @@ namespace QueryStageSortTests { virtual int numObj() { return 100; } void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { @@ -227,8 +228,9 @@ namespace QueryStageSortTests { virtual int numObj() { return 10000; } void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { @@ -246,8 +248,9 @@ namespace QueryStageSortTests { virtual int numObj() { return 2000; } void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { @@ -336,8 +339,9 @@ namespace QueryStageSortTests { virtual int numObj() { return 100; } void run() { - Client::WriteContext ctx(ns()); OperationContextImpl txn; + Client::WriteContext ctx(&txn, ns()); + Database* db = ctx.ctx().db(); Collection* coll = db->getCollection(ns()); if (!coll) { diff --git a/src/mongo/dbtests/query_stage_tests.cpp b/src/mongo/dbtests/query_stage_tests.cpp index 3bf9b0ca31f..7e0b0f20c6e 100644 --- a/src/mongo/dbtests/query_stage_tests.cpp +++ b/src/mongo/dbtests/query_stage_tests.cpp @@ -33,6 +33,7 @@ #include "mongo/db/instance.h" #include "mongo/db/json.h" #include "mongo/db/matcher/expression_parser.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/query/plan_executor.h" #include "mongo/db/catalog/collection.h" #include "mongo/dbtests/dbtests.h" @@ -46,7 +47,7 @@ namespace QueryStageTests { class IndexScanBase { public: IndexScanBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); for (int i = 0; i < numObj(); ++i) { BSONObjBuilder bob; @@ -61,17 +62,17 @@ namespace QueryStageTests { } virtual ~IndexScanBase() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.dropCollection(ns()); } void addIndex(const BSONObj& obj) { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); _client.ensureIndex(ns(), obj); } int countResults(const IndexScanParams& params, BSONObj filterObj = BSONObj()) { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); StatusWithMatchExpression swme = MatchExpressionParser::parse(filterObj); verify(swme.isOK()); @@ -91,7 +92,7 @@ namespace QueryStageTests { } void makeGeoData() { - Client::WriteContext ctx(ns()); + Client::WriteContext ctx(&_txn, ns()); for (int i = 0; i < numObj(); ++i) { double lat = double(rand()) / RAND_MAX; @@ -101,7 +102,7 @@ namespace QueryStageTests { } IndexDescriptor* getIndex(const BSONObj& obj) { - Client::ReadContext ctx(ns()); + Client::ReadContext ctx(&_txn, ns()); Collection* collection = ctx.ctx().db()->getCollection( ns() ); return collection->getIndexCatalog()->findIndexByKeyPattern( obj ); } @@ -109,12 +110,13 @@ namespace QueryStageTests { static int numObj() { return 50; } static const char* ns() { return "unittests.IndexScan"; } + protected: + OperationContextImpl _txn; + private: - static DBDirectClient _client; + DBDirectClient _client; }; - DBDirectClient IndexScanBase::_client; - class QueryStageIXScanBasic : public IndexScanBase { public: virtual ~QueryStageIXScanBasic() { } diff --git a/src/mongo/dbtests/querytests.cpp b/src/mongo/dbtests/querytests.cpp index 0f834d1d50c..0e73c01e3b5 100644 --- a/src/mongo/dbtests/querytests.cpp +++ b/src/mongo/dbtests/querytests.cpp @@ -157,14 +157,13 @@ namespace QueryTests { // an empty object (one might be allowed inside a reserved namespace at some point). Lock::GlobalWrite lk; Client::Context ctx( "unittests.querytests" ); - OperationContextImpl txn; Database* db = ctx.db(); if ( db->getCollection( ns() ) ) { _collection = NULL; - db->dropCollection( &txn, ns() ); + db->dropCollection( &_txn, ns() ); } - _collection = db->createCollection( &txn, ns(), CollectionOptions(), true, false ); + _collection = db->createCollection( &_txn, ns(), CollectionOptions(), true, false ); ASSERT( _collection ); DBDirectClient cl; @@ -189,21 +188,25 @@ namespace QueryTests { ~ClientBase() { //mongo::lastError.release(); } + protected: - static void insert( const char *ns, BSONObj o ) { + void insert( const char *ns, BSONObj o ) { client_.insert( ns, o ); } - static void update( const char *ns, BSONObj q, BSONObj o, bool upsert = 0 ) { + void update( const char *ns, BSONObj q, BSONObj o, bool upsert = 0 ) { client_.update( ns, Query( q ), o, upsert ); } - static bool error() { + bool error() { return !client_.getPrevError().getField( "err" ).isNull(); } - DBDirectClient &client() const { return client_; } - static DBDirectClient client_; + const DBDirectClient& client() const { return client_; } + DBDirectClient& client() { return client_; } + + DBDirectClient client_; + + OperationContextImpl _txn; }; - DBDirectClient ClientBase::client_; class BoundedKey : public ClientBase { public: @@ -239,7 +242,7 @@ namespace QueryTests { { // Check internal server handoff to getmore. - Lock::DBWrite lk(ns); + Lock::DBWrite lk(_txn.lockState(), ns); Client::Context ctx( ns ); ClientCursorPin clientCursor( ctx.db()->getCollection(ns), cursorId ); // pq doesn't exist if it's a runner inside of the clientcursor. @@ -252,6 +255,9 @@ namespace QueryTests { ASSERT( cursor->more() ); ASSERT_EQUALS( 3, cursor->next().getIntField( "a" ) ); } + + protected: + OperationContextImpl _txn; }; /** @@ -294,10 +300,11 @@ namespace QueryTests { // Check that the cursor has been removed. { - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(&_txn, ns); ASSERT( 0 == ctx.ctx().db()->getCollection( ns )->cursorCache()->numCursors() ); } - ASSERT_FALSE( CollectionCursorCache::eraseCursorGlobal( cursorId ) ); + + ASSERT_FALSE(CollectionCursorCache::eraseCursorGlobal(&_txn, cursorId)); // Check that a subsequent get more fails with the cursor removed. ASSERT_THROWS( client().getMore( ns, cursorId ), UserException ); @@ -343,7 +350,7 @@ namespace QueryTests { // Check that the cursor still exists { - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(&_txn, ns); ASSERT( 1 == ctx.ctx().db()->getCollection( ns )->cursorCache()->numCursors() ); ASSERT( ctx.ctx().db()->getCollection( ns )->cursorCache()->find( cursorId, false ) ); } @@ -583,7 +590,7 @@ namespace QueryTests { } void run() { const char *ns = "unittests.querytests.OplogReplaySlaveReadTill"; - Lock::DBWrite lk(ns); + Lock::DBWrite lk(_txn.lockState(), ns); Client::Context ctx( ns ); BSONObj info; @@ -654,7 +661,7 @@ namespace QueryTests { count( 2 ); } private: - void count( unsigned long long c ) const { + void count( unsigned long long c ) { ASSERT_EQUALS( c, client().count( "unittests.querytests.BasicCount", BSON( "a" << 4 ) ) ); } }; @@ -749,8 +756,8 @@ namespace QueryTests { } static const char *ns() { return "unittests.querytests.AutoResetIndexCache"; } static const char *idxNs() { return "unittests.system.indexes"; } - void index() const { ASSERT( !client().findOne( idxNs(), BSON( "name" << NE << "_id_" ) ).isEmpty() ); } - void noIndex() const { + void index() { ASSERT( !client().findOne( idxNs(), BSON( "name" << NE << "_id_" ) ).isEmpty() ); } + void noIndex() { BSONObj o = client().findOne( idxNs(), BSON( "name" << NE << "_id_" ) ); if( !o.isEmpty() ) { cout << o.toString() << endl; @@ -1130,7 +1137,7 @@ namespace QueryTests { } size_t numCursorsOpen() { - Client::ReadContext ctx( _ns ); + Client::ReadContext ctx(&_txn, _ns); Collection* collection = ctx.ctx().db()->getCollection( _ns ); if ( !collection ) return 0; @@ -1172,16 +1179,13 @@ namespace QueryTests { } void run() { string err; - - Client::WriteContext ctx( "unittests" ); - OperationContextImpl txn; + Client::WriteContext ctx(&_txn, "unittests" ); // note that extents are always at least 4KB now - so this will get rounded up a bit. - ASSERT( userCreateNS( &txn, ctx.ctx().db(), ns(), + ASSERT( userCreateNS( &_txn, ctx.ctx().db(), ns(), fromjson( "{ capped : true, size : 2000 }" ), false ).isOK() ); for ( int i=0; i<200; i++ ) { insertNext(); -// cout << count() << endl; ASSERT( count() < 90 ); } @@ -1224,7 +1228,7 @@ namespace QueryTests { } void run() { - Client::WriteContext ctx( "unittests" ); + Client::WriteContext ctx(&_txn, "unittests" ); for ( int i=0; i<50; i++ ) { insert( ns() , BSON( "_id" << i << "x" << i * 2 ) ); @@ -1275,7 +1279,7 @@ namespace QueryTests { } void run() { - Client::WriteContext ctx( "unittests" ); + Client::WriteContext ctx(&_txn, "unittests" ); for ( int i=0; i<1000; i++ ) { insert( ns() , BSON( "_id" << i << "x" << i * 2 ) ); @@ -1298,7 +1302,7 @@ namespace QueryTests { } void run() { - Client::WriteContext ctx( "unittests" ); + Client::WriteContext ctx(&_txn, "unittests" ); for ( int i=0; i<1000; i++ ) { insert( ns() , BSON( "_id" << i << "x" << i * 2 ) ); @@ -1414,7 +1418,7 @@ namespace QueryTests { public: CollectionInternalBase( const char *nsLeaf ) : CollectionBase( nsLeaf ), - _lk( ns() ), + _lk(_txn.lockState(), ns() ), _ctx( ns() ) { } private: @@ -1439,8 +1443,7 @@ namespace QueryTests { DbMessage dbMessage( message ); QueryMessage queryMessage( dbMessage ); Message result; - OperationContextImpl txn; - string exhaust = newRunQuery( &txn, message, queryMessage, *cc().curop(), result ); + string exhaust = newRunQuery( &_txn, message, queryMessage, *cc().curop(), result ); ASSERT( exhaust.size() ); ASSERT_EQUALS( string( ns() ), exhaust ); } @@ -1459,7 +1462,7 @@ namespace QueryTests { ClientCursor *clientCursor = 0; { - Client::ReadContext ctx( ns() ); + Client::ReadContext ctx(&_txn, ns()); ClientCursorPin clientCursorPointer( ctx.ctx().db()->getCollection( ns() ), cursorId ); clientCursor = clientCursorPointer.c(); @@ -1497,10 +1500,11 @@ namespace QueryTests { long long cursorId = cursor->getCursorId(); { - Client::WriteContext ctx( ns() ); + Client::WriteContext ctx(&_txn, ns() ); ClientCursorPin pinCursor( ctx.ctx().db()->getCollection( ns() ), cursorId ); - - ASSERT_THROWS( client().killCursor( cursorId ), MsgAssertionException ); + + ASSERT_THROWS(CollectionCursorCache::eraseCursorGlobal(&_txn, cursorId), + MsgAssertionException); string expectedAssertion = str::stream() << "Cannot kill active cursor " << cursorId; ASSERT_EQUALS( expectedAssertion, client().getLastError() ); diff --git a/src/mongo/dbtests/replsettests.cpp b/src/mongo/dbtests/replsettests.cpp index fb2a2afdd0a..deb82f41e17 100644 --- a/src/mongo/dbtests/replsettests.cpp +++ b/src/mongo/dbtests/replsettests.cpp @@ -147,9 +147,10 @@ namespace ReplSetTests { DBDirectClient *client() const { return &client_; } static void insert( const BSONObj &o, bool god = false ) { - Lock::DBWrite lk(ns()); - Client::Context ctx(ns()); OperationContextImpl txn; + Lock::DBWrite lk(txn.lockState(), ns()); + Client::Context ctx(ns()); + Database* db = ctx.db(); Collection* coll = db->getCollection(ns()); if (!coll) { @@ -174,8 +175,8 @@ namespace ReplSetTests { } void drop() { - Client::WriteContext c(ns()); OperationContextImpl txn; + Client::WriteContext c(&txn, ns()); Database* db = c.ctx().db(); @@ -306,6 +307,8 @@ namespace ReplSetTests { class CappedInitialSync : public Base { string _cappedNs; + + OperationContextImpl _txn; Lock::DBWrite _lk; string spec() const { @@ -342,7 +345,8 @@ namespace ReplSetTests { return o; } public: - CappedInitialSync() : _cappedNs("unittests.foo.bar"), _lk(_cappedNs) { + CappedInitialSync() : + _cappedNs("unittests.foo.bar"), _lk(_txn.lockState(), _cappedNs) { dropCapped(); create(); } @@ -363,7 +367,8 @@ namespace ReplSetTests { } void run() { - Lock::DBWrite lk(_cappedNs); + OperationContextImpl txn; + Lock::DBWrite lk(txn.lockState(), _cappedNs); BSONObj op = updateFail(); diff --git a/src/mongo/dbtests/runner_registry.cpp b/src/mongo/dbtests/runner_registry.cpp index 8881ff2d4f3..b29088e36d8 100644 --- a/src/mongo/dbtests/runner_registry.cpp +++ b/src/mongo/dbtests/runner_registry.cpp @@ -51,7 +51,7 @@ namespace RunnerRegistry { class RunnerRegistryBase { public: RunnerRegistryBase() { - _ctx.reset(new Client::WriteContext(ns())); + _ctx.reset(new Client::WriteContext(&_opCtx, ns())); _client.dropCollection(ns()); for (int i = 0; i < N(); ++i) { @@ -269,7 +269,7 @@ namespace RunnerRegistry { // requires a "global write lock." _ctx.reset(); _client.dropDatabase("somesillydb"); - _ctx.reset(new Client::WriteContext(ns())); + _ctx.reset(new Client::WriteContext(&_opCtx, ns())); // Unregister and restore state. deregisterRunner(run.get()); @@ -285,7 +285,7 @@ namespace RunnerRegistry { // Drop our DB. Once again, must give up the lock. _ctx.reset(); _client.dropDatabase("unittests"); - _ctx.reset(new Client::WriteContext(ns())); + _ctx.reset(new Client::WriteContext(&_opCtx, ns())); // Unregister and restore state. deregisterRunner(run.get()); diff --git a/src/mongo/dbtests/threadedtests.cpp b/src/mongo/dbtests/threadedtests.cpp index b5537364525..96e6e0df7b4 100644 --- a/src/mongo/dbtests/threadedtests.cpp +++ b/src/mongo/dbtests/threadedtests.cpp @@ -35,6 +35,7 @@ #include "mongo/bson/util/atomic_int.h" #include "mongo/db/d_concurrency.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/dbtests/dbtests.h" #include "mongo/platform/atomic_word.h" #include "mongo/stdx/functional.h" @@ -115,6 +116,8 @@ namespace ThreadedTests { } virtual void subthread(int tnumber) { Client::initThread("mongomutextest"); + LockState lockState; + sleepmillis(0); for( int i = 0; i < N; i++ ) { int x = std::rand(); @@ -169,13 +172,13 @@ namespace ThreadedTests { } else if( i % 7 == 5 ) { { - Lock::DBRead r("foo"); + Lock::DBRead r(&lockState, "foo"); if( sometimes ) { Lock::TempRelease t; } } { - Lock::DBRead r("bar"); + Lock::DBRead r(&lockState, "bar"); } } else if( i % 7 == 6 ) { @@ -183,13 +186,13 @@ namespace ThreadedTests { int q = i % 11; if( q == 0 ) { char what = 'r'; - Lock::DBRead r("foo"); + Lock::DBRead r(&lockState, "foo"); ASSERT( Lock::isLocked() == what && Lock::atLeastReadLocked("foo") ); ASSERT( !Lock::nested() ); - Lock::DBRead r2("foo"); + Lock::DBRead r2(&lockState, "foo"); ASSERT( Lock::nested() ); ASSERT( Lock::isLocked() == what && Lock::atLeastReadLocked("foo") ); - Lock::DBRead r3("local"); + Lock::DBRead r3(&lockState, "local"); if( sometimes ) { Lock::TempRelease t; } @@ -199,41 +202,48 @@ namespace ThreadedTests { else if( q == 1 ) { // test locking local only -- with no preceeding lock { - Lock::DBRead x("local"); + Lock::DBRead x(&lockState, "local"); //Lock::DBRead y("q"); if( sometimes ) { Lock::TempRelease t; // we don't temprelease (cant=true) here thus this is just a check that nothing weird happens... } } - { - Lock::DBWrite x("local"); + { + OperationContextImpl txn; + Lock::DBWrite x(txn.lockState(), "local"); if( sometimes ) { Lock::TempRelease t; } } } else if( q == 1 ) { - { Lock::DBRead x("admin"); } - { Lock::DBWrite x("admin"); } + { Lock::DBRead x(&lockState, "admin"); } + { + OperationContextImpl txn; + Lock::DBWrite x(txn.lockState(), "admin"); + } } else if( q == 2 ) { /*Lock::DBWrite x("foo"); Lock::DBWrite y("admin"); { Lock::TempRelease t; }*/ } else if( q == 3 ) { - Lock::DBWrite x("foo"); - Lock::DBRead y("admin"); + OperationContextImpl txn; + Lock::DBWrite x(txn.lockState(), "foo"); + Lock::DBRead y(&lockState, "admin"); { Lock::TempRelease t; } } else if( q == 4 ) { - Lock::DBRead x("foo2"); - Lock::DBRead y("admin"); + Lock::DBRead x(&lockState, "foo2"); + Lock::DBRead y(&lockState, "admin"); { Lock::TempRelease t; } } else if ( q > 4 && q < 8 ) { static const char * const dbnames[] = { "bar0", "bar1", "bar2", "bar3", "bar4", "bar5", "bar6", "bar7", "bar8", "bar9", "bar10" }; - Lock::DBWrite w(dbnames[q]); + + OperationContextImpl txn; + Lock::DBWrite w(txn.lockState(), dbnames[q]); { Lock::UpgradeGlobalLockToExclusive wToX; if (wToX.gotUpgrade()) { @@ -245,21 +255,24 @@ namespace ThreadedTests { } } else { - Lock::DBWrite w("foo"); + OperationContextImpl txn; + Lock::DBWrite w(txn.lockState(), "foo"); + { Lock::TempRelease t; } - Lock::DBRead r2("foo"); - Lock::DBRead r3("local"); + + Lock::DBRead r2(&lockState, "foo"); + Lock::DBRead r3(&lockState, "local"); if( sometimes ) { Lock::TempRelease t; } } } else { - Lock::DBRead r("foo"); - Lock::DBRead r2("foo"); - Lock::DBRead r3("local"); + Lock::DBRead r(&lockState, "foo"); + Lock::DBRead r2(&lockState, "foo"); + Lock::DBRead r3(&lockState, "local"); } } pm.hit(); diff --git a/src/mongo/dbtests/updatetests.cpp b/src/mongo/dbtests/updatetests.cpp index 32e20bd9d01..e89997330cf 100644 --- a/src/mongo/dbtests/updatetests.cpp +++ b/src/mongo/dbtests/updatetests.cpp @@ -1060,14 +1060,11 @@ namespace UpdateTests { BSONObj result; BSONObj expected; - switch ( i ) { - default: - client().update( ns(), Query(), getUpdate(i) ); - result = client().findOne( ns(), Query() ); - expected = fromjson( "{'_id':0,x:[]}" ); - ASSERT_EQUALS( result, expected ); - break; - } + + client().update( ns(), Query(), getUpdate(i) ); + result = client().findOne( ns(), Query() ); + expected = fromjson( "{'_id':0,x:[]}" ); + ASSERT_EQUALS( result, expected ); } } }; @@ -1092,14 +1089,11 @@ namespace UpdateTests { BSONObj result; BSONObj expected; - switch ( i ) { - default: - client().update( ns(), Query(), getUpdate(i) ); - result = client().findOne( ns(), Query() ); - expected = fromjson( "{'_id':0,x:[]}" ); - ASSERT_EQUALS( result, expected ); - break; - } + + client().update( ns(), Query(), getUpdate(i) ); + result = client().findOne( ns(), Query() ); + expected = fromjson( "{'_id':0,x:[]}" ); + ASSERT_EQUALS( result, expected ); } } }; diff --git a/src/mongo/s/commands/auth_schema_upgrade_s.cpp b/src/mongo/s/commands/auth_schema_upgrade_s.cpp index 144d5c80380..41f569815b1 100644 --- a/src/mongo/s/commands/auth_schema_upgrade_s.cpp +++ b/src/mongo/s/commands/auth_schema_upgrade_s.cpp @@ -157,7 +157,7 @@ namespace { return appendCommandStatus(result, status); } - status = authzManager->upgradeSchema(maxSteps, writeConcern); + status = authzManager->upgradeSchema(txn, maxSteps, writeConcern); if (!status.isOK()) return appendCommandStatus(result, status); diff --git a/src/mongo/s/commands/cluster_index_filter_cmd.cpp b/src/mongo/s/commands/cluster_index_filter_cmd.cpp index 10855e96aaa..2bd84e2b982 100644 --- a/src/mongo/s/commands/cluster_index_filter_cmd.cpp +++ b/src/mongo/s/commands/cluster_index_filter_cmd.cpp @@ -64,13 +64,15 @@ namespace mongo { ss << _helpText; } - Status checkAuthForCommand( ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj ) { + Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj ) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); - if (authzSession->isAuthorizedForActionsOnResource(pattern, + if (authzSession->isAuthorizedForActionsOnResource(txn, + pattern, ActionType::planCacheIndexFilter)) { return Status::OK(); } diff --git a/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp b/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp index 2e79c431563..2fefe753a7a 100644 --- a/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp +++ b/src/mongo/s/commands/cluster_merge_chunks_cmd.cpp @@ -52,10 +52,12 @@ namespace mongo { << "usage: { mergeChunks : <ns>, bounds : [ <min key>, <max key> ] }"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::splitChunk)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); diff --git a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp index 1aa015a495b..15a0076163f 100644 --- a/src/mongo/s/commands/cluster_plan_cache_cmd.cpp +++ b/src/mongo/s/commands/cluster_plan_cache_cmd.cpp @@ -64,13 +64,14 @@ namespace mongo { ss << _helpText; } - Status checkAuthForCommand( ClientBasic* client, - const std::string& dbname, - const BSONObj& cmdObj ) { + Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj ) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); - if (authzSession->isAuthorizedForActionsOnResource(pattern, _actionType)) { + if (authzSession->isAuthorizedForActionsOnResource(txn, pattern, _actionType)) { return Status::OK(); } diff --git a/src/mongo/s/commands/cluster_write_cmd.cpp b/src/mongo/s/commands/cluster_write_cmd.cpp index 3e4a7ce290e..4ffc49f3857 100644 --- a/src/mongo/s/commands/cluster_write_cmd.cpp +++ b/src/mongo/s/commands/cluster_write_cmd.cpp @@ -62,11 +62,13 @@ namespace mongo { bool isWriteCommandForConfigServer() const { return false; } - Status checkAuthForCommand( ClientBasic* client, + Status checkAuthForCommand( OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj ) { - Status status = auth::checkAuthForWriteCommand( client->getAuthorizationSession(), + Status status = auth::checkAuthForWriteCommand( txn, + client->getAuthorizationSession(), _writeType, NamespaceString( parseNs( dbname, cmdObj ) ), diff --git a/src/mongo/s/commands_admin.cpp b/src/mongo/s/commands_admin.cpp index 5280ce55def..0e91748dfd8 100644 --- a/src/mongo/s/commands_admin.cpp +++ b/src/mongo/s/commands_admin.cpp @@ -192,10 +192,12 @@ namespace mongo { virtual void help( stringstream& help ) const { help << " example: { moveprimary : 'foo' , to : 'localhost:9999' }"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(parseNs(dbname, cmdObj)), ActionType::moveChunk)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -387,10 +389,12 @@ namespace mongo { << "Enable sharding for a db. (Use 'shardcollection' command afterwards.)\n" << " { enablesharding : \"<dbname>\" }\n"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forDatabaseName(parseNs(dbname, cmdObj)), ActionType::enableSharding)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -445,10 +449,12 @@ namespace mongo { << "Shard a collection. Requires key. Optional unique. Sharding must already be enabled for the database.\n" << " { enablesharding : \"<dbname>\" }\n"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::enableSharding)) { @@ -830,10 +836,12 @@ namespace mongo { virtual void help( stringstream& help ) const { help << " example: { getShardVersion : 'alleyinsider.foo' } "; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::getShardVersion)) { @@ -881,10 +889,12 @@ namespace mongo { << " NOTE: this does not move the chunks, it merely creates a logical separation \n" ; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::splitChunk)) { @@ -1043,10 +1053,12 @@ namespace mongo { << " { movechunk : 'test.foo' , bounds : [ { num : 0 } , { num : 10 } ] " << " , to : 'shard001' }\n"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::moveChunk)) { @@ -1866,7 +1878,8 @@ namespace mongo { virtual bool adminOnly() const { return true; } virtual bool isWriteCommandForConfigServer() const { return false; } virtual void help( stringstream& help ) const { help << "Not supported through mongos"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { return Status::OK(); // Require no auth since this command isn't supported in mongos diff --git a/src/mongo/s/commands_public.cpp b/src/mongo/s/commands_public.cpp index b98a4413967..4a8c586c15f 100644 --- a/src/mongo/s/commands_public.cpp +++ b/src/mongo/s/commands_public.cpp @@ -598,22 +598,29 @@ namespace mongo { class CreateCmd : public PublicGridCommand { public: CreateCmd() : PublicGridCommand( "create" ) {} - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); if (cmdObj["capped"].trueValue()) { if (!authzSession->isAuthorizedForActionsOnResource( - parseResourcePattern(dbname, cmdObj), ActionType::convertToCapped)) { + txn, + parseResourcePattern(dbname, cmdObj), + ActionType::convertToCapped)) { return Status(ErrorCodes::Unauthorized, "unauthorized"); } } // ActionType::createCollection or ActionType::insert are both acceptable if (authzSession->isAuthorizedForActionsOnResource( - parseResourcePattern(dbname, cmdObj), ActionType::createCollection) || + txn, + parseResourcePattern(dbname, cmdObj), + ActionType::createCollection) || authzSession->isAuthorizedForActionsOnResource( - parseResourcePattern(dbname, cmdObj), ActionType::insert)) { + txn, + parseResourcePattern(dbname, cmdObj), + ActionType::insert)) { return Status::OK(); } @@ -749,12 +756,12 @@ namespace mongo { class RenameCollectionCmd : public PublicGridCommand { public: RenameCollectionCmd() : PublicGridCommand( "renameCollection" ) {} - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { - return rename_collection::checkAuthForRenameCollectionCommand(client, - dbname, - cmdObj); + return rename_collection::checkAuthForRenameCollectionCommand( + txn, client, dbname, cmdObj); } virtual bool adminOnly() const { return true; @@ -787,10 +794,11 @@ namespace mongo { virtual bool adminOnly() const { return true; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { - return copydb::checkAuthForCopydbCommand(client, dbname, cmdObj); + return copydb::checkAuthForCopydbCommand(txn, client, dbname, cmdObj); } bool run(OperationContext* txn, const string& dbName, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { string todb = cmdObj.getStringField("todb"); @@ -1267,10 +1275,12 @@ namespace mongo { public: SplitVectorCmd() : NotAllowedOnShardedCollectionCmd("splitVector") {} virtual bool passOptions() const { return true; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::splitVector)) { diff --git a/src/mongo/s/cursors.cpp b/src/mongo/s/cursors.cpp index e13b5be44d3..5e1a26822f5 100644 --- a/src/mongo/s/cursors.cpp +++ b/src/mongo/s/cursors.cpp @@ -45,6 +45,7 @@ #include "mongo/db/commands.h" #include "mongo/db/jsobj.h" #include "mongo/db/max_time.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/util/concurrency/task.h" #include "mongo/util/net/listen.h" @@ -338,10 +339,12 @@ namespace mongo { { scoped_lock lk( _mutex ); + OperationContextNoop txn; + MapSharded::iterator i = _cursors.find( id ); if ( i != _cursors.end() ) { const bool isAuthorized = authSession->isAuthorizedForActionsOnNamespace( - NamespaceString(i->second->getNS()), ActionType::killCursors); + &txn, NamespaceString(i->second->getNS()), ActionType::killCursors); audit::logKillCursorsAuthzCheck( client, NamespaceString(i->second->getNS()), @@ -362,7 +365,7 @@ namespace mongo { } verify(refsNSIt != _refsNS.end()); const bool isAuthorized = authSession->isAuthorizedForActionsOnNamespace( - NamespaceString(refsNSIt->second), ActionType::killCursors); + &txn, NamespaceString(refsNSIt->second), ActionType::killCursors); audit::logKillCursorsAuthzCheck( client, NamespaceString(refsNSIt->second), diff --git a/src/mongo/s/d_merge.cpp b/src/mongo/s/d_merge.cpp index 748327e7d57..0d0f11c6469 100644 --- a/src/mongo/s/d_merge.cpp +++ b/src/mongo/s/d_merge.cpp @@ -28,6 +28,7 @@ #include "mongo/base/owned_pointer_vector.h" #include "mongo/db/d_concurrency.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/namespace_string.h" #include "mongo/s/d_logic.h" #include "mongo/s/distlock.h" @@ -290,7 +291,8 @@ namespace mongo { // { - Lock::DBWrite writeLk( nss.ns() ); + OperationContextImpl txn; // XXX? + Lock::DBWrite writeLk(txn.lockState(), nss.ns()); shardingState.mergeChunks( nss.ns(), minKey, maxKey, mergeVersion ); } diff --git a/src/mongo/s/d_migrate.cpp b/src/mongo/s/d_migrate.cpp index e0c8a6f5bca..4e11efc9c39 100644 --- a/src/mongo/s/d_migrate.cpp +++ b/src/mongo/s/d_migrate.cpp @@ -369,7 +369,7 @@ namespace mongo { * called from the dest of a migrate * transfers mods from src to dest */ - bool transferMods( string& errmsg , BSONObjBuilder& b ) { + bool transferMods(OperationContext* txn, string& errmsg, BSONObjBuilder& b) { if ( ! _getActive() ) { errmsg = "no active migration!"; return false; @@ -378,7 +378,7 @@ namespace mongo { long long size = 0; { - Client::ReadContext cx( _ns ); + Client::ReadContext cx(txn, _ns); xfer( cx.ctx().db(), &_deleted, b, "deleted", size, false ); xfer( cx.ctx().db(), &_reload, b, "reload", size, true ); @@ -396,8 +396,11 @@ namespace mongo { * @param errmsg filled with textual description of error if this call return false * @return false if approximate chunk size is too big to move or true otherwise */ - bool storeCurrentLocs( long long maxChunkSize , string& errmsg , BSONObjBuilder& result ) { - Client::ReadContext ctx( _ns ); + bool storeCurrentLocs(OperationContext* txn, + long long maxChunkSize, + string& errmsg, + BSONObjBuilder& result ) { + Client::ReadContext ctx(txn, _ns); Collection* collection = ctx.ctx().db()->getCollection( _ns ); if ( !collection ) { errmsg = "ns not found, should be impossible"; @@ -405,7 +408,7 @@ namespace mongo { } invariant( _dummyRunner.get() == NULL ); - _dummyRunner.reset( new DummyRunner( _ns, collection ) ); + _dummyRunner.reset(new DummyRunner(txn, _ns, collection)); // Allow multiKey based on the invariant that shard keys must be single-valued. // Therefore, any multi-key index prefixed by shard key cannot be multikey over @@ -476,7 +479,7 @@ namespace mongo { return true; } - bool clone( string& errmsg , BSONObjBuilder& result ) { + bool clone(OperationContext* txn, string& errmsg , BSONObjBuilder& result ) { if ( ! _getActive() ) { errmsg = "not active"; return false; @@ -486,7 +489,7 @@ namespace mongo { int allocSize; { - Client::ReadContext ctx( _ns ); + Client::ReadContext ctx(txn, _ns); Collection* collection = ctx.ctx().db()->getCollection( _ns ); verify( collection ); scoped_spinlock lk( _trackerLocks ); @@ -499,7 +502,7 @@ namespace mongo { while ( 1 ) { bool filledBuffer = false; - Client::ReadContext ctx( _ns ); + Client::ReadContext ctx(txn, _ns); Collection* collection = ctx.ctx().db()->getCollection( _ns ); scoped_spinlock lk( _trackerLocks ); @@ -613,16 +616,18 @@ namespace mongo { class DummyRunner : public Runner { public: - DummyRunner( const StringData& ns, - Collection* collection ) { + DummyRunner(OperationContext* txn, + const StringData& ns, + Collection* collection ) { _ns = ns.toString(); + _txn = txn; _collection = collection; _collection->cursorCache()->registerRunner( this ); } ~DummyRunner() { if ( !_collection ) return; - Client::ReadContext ctx( _ns ); + Client::ReadContext ctx(_txn, _ns); Collection* collection = ctx.ctx().db()->getCollection( _ns ); invariant( _collection == collection ); _collection->cursorCache()->deregisterRunner( this ); @@ -657,6 +662,7 @@ namespace mongo { private: string _ns; + OperationContext* _txn; Collection* _collection; }; @@ -712,7 +718,7 @@ namespace mongo { out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - return migrateFromStatus.transferMods( errmsg, result ); + return migrateFromStatus.transferMods(txn, errmsg, result); } } transferModsCommand; @@ -729,7 +735,7 @@ namespace mongo { out->push_back(Privilege(ResourcePattern::forClusterResource(), actions)); } bool run(OperationContext* txn, const string& , BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - return migrateFromStatus.clone( errmsg, result ); + return migrateFromStatus.clone(txn, errmsg, result); } } initialCloneCommand; @@ -757,10 +763,12 @@ namespace mongo { virtual bool slaveOk() const { return false; } virtual bool adminOnly() const { return true; } virtual bool isWriteCommandForConfigServer() const { return false; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::moveChunk)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -1041,8 +1049,9 @@ namespace mongo { { // this gets a read lock, so we know we have a checkpoint for mods - if ( ! migrateFromStatus.storeCurrentLocs( maxChunkSize , errmsg , result ) ) + if (!migrateFromStatus.storeCurrentLocs(txn, maxChunkSize, errmsg, result)) { return false; + } ScopedDbConnection connTo(toShard.getConnString()); BSONObj res; @@ -1203,7 +1212,7 @@ namespace mongo { myVersion.incMajor(); { - Lock::DBWrite lk( ns ); + Lock::DBWrite lk(txn->lockState(), ns ); verify( myVersion > shardingState.getVersion( ns ) ); // bump the metadata's version up and "forget" about the chunk being moved @@ -1586,7 +1595,7 @@ namespace mongo { if ( state != DONE ) { // Unprotect the range if needed/possible on unsuccessful TO migration - Lock::DBWrite lk( ns ); + Lock::DBWrite lk(txn->lockState(), ns); string errMsg; if ( !shardingState.forgetPending( ns, min, max, epoch, &errMsg ) ) { warning() << errMsg << endl; @@ -1617,7 +1626,7 @@ namespace mongo { { // 0. copy system.namespaces entry if collection doesn't already exist - Client::WriteContext ctx( ns ); + Client::WriteContext ctx(txn, ns ); // Only copy if ns doesn't already exist Database* db = ctx.ctx().db(); Collection* collection = db->getCollection( ns ); @@ -1652,7 +1661,7 @@ namespace mongo { for ( unsigned i=0; i<all.size(); i++ ) { BSONObj idx = all[i]; - Client::WriteContext ctx( ns ); + Client::WriteContext ctx(txn, ns ); Database* db = ctx.ctx().db(); Collection* collection = db->getCollection( txn, ns ); if ( !collection ) { @@ -1702,7 +1711,7 @@ namespace mongo { { // Protect the range by noting that we're now starting a migration to it - Lock::DBWrite lk( ns ); + Lock::DBWrite lk(txn->lockState(), ns); if ( !shardingState.notePending( ns, min, max, epoch, &errmsg ) ) { warning() << errmsg << endl; state = FAIL; @@ -1748,7 +1757,7 @@ namespace mongo { while( i.more() ) { BSONObj o = i.next().Obj(); { - Client::WriteContext cx( ns ); + Client::WriteContext cx(txn, ns ); BSONObj localDoc; if ( willOverrideLocalId( cx.ctx().db(), o, &localDoc ) ) { @@ -1943,7 +1952,7 @@ namespace mongo { BSONObjIterator i( xfer["deleted"].Obj() ); while ( i.more() ) { - Client::WriteContext cx(ns); + Client::WriteContext cx(txn, ns); BSONObj id = i.next().Obj(); @@ -1978,7 +1987,7 @@ namespace mongo { if ( xfer["reload"].isABSONObj() ) { BSONObjIterator i( xfer["reload"].Obj() ); while ( i.more() ) { - Client::WriteContext cx(ns); + Client::WriteContext cx(txn, ns); BSONObj it = i.next().Obj(); diff --git a/src/mongo/s/d_split.cpp b/src/mongo/s/d_split.cpp index 04e17d553e3..8d54a271e4c 100644 --- a/src/mongo/s/d_split.cpp +++ b/src/mongo/s/d_split.cpp @@ -119,7 +119,7 @@ namespace mongo { return false; } - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); if ( !collection ) { errmsg = "ns not found"; @@ -223,10 +223,12 @@ namespace mongo { " 'force' will produce one split point even if data is small; defaults to false\n" "NOTE: This command may take a while to run"; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::splitVector)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -275,7 +277,7 @@ namespace mongo { { // Get the size estimate for this namespace - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); if ( !collection ) { errmsg = "ns not found"; @@ -515,10 +517,12 @@ namespace mongo { virtual bool slaveOk() const { return false; } virtual bool adminOnly() const { return true; } virtual bool isWriteCommandForConfigServer() const { return false; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::splitChunk)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -824,7 +828,7 @@ namespace mongo { maxVersion.incMinor(); { - Lock::DBWrite writeLk( ns ); + Lock::DBWrite writeLk(txn->lockState(), ns); shardingState.splitChunk( ns , min , max , splitKeys , maxVersion ); } @@ -858,7 +862,7 @@ namespace mongo { // If one of the chunks has only one object in it we should move it for (int i=1; i >= 0 ; i--){ // high chunk more likely to have only one obj - Client::ReadContext ctx( ns ); + Client::ReadContext ctx(txn, ns); Collection* collection = ctx.ctx().db()->getCollection( ns ); verify( collection ); diff --git a/src/mongo/s/d_state.cpp b/src/mongo/s/d_state.cpp index c70ca52ea55..8b7d8990d18 100644 --- a/src/mongo/s/d_state.cpp +++ b/src/mongo/s/d_state.cpp @@ -48,6 +48,7 @@ #include "mongo/db/commands.h" #include "mongo/db/jsobj.h" #include "mongo/db/db.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/wire_version.h" #include "mongo/db/repl/is_master.h" #include "mongo/client/connpool.h" @@ -60,7 +61,6 @@ #include "mongo/util/concurrency/mutex.h" #include "mongo/util/concurrency/ticketholder.h" -using namespace std; namespace mongo { @@ -558,7 +558,8 @@ namespace mongo { { // DBLock needed since we're now potentially changing the metadata, and don't want // reads/writes to be ongoing. - Lock::DBWrite writeLk( ns ); + OperationContextImpl txn; + Lock::DBWrite writeLk(txn.lockState(), ns ); // // Get the metadata now that the load has completed @@ -1183,10 +1184,12 @@ namespace mongo { virtual bool isWriteCommandForConfigServer() const { return false; } - virtual Status checkAuthForCommand(ClientBasic* client, + virtual Status checkAuthForCommand(OperationContext* txn, + ClientBasic* client, const std::string& dbname, const BSONObj& cmdObj) { if (!client->getAuthorizationSession()->isAuthorizedForActionsOnResource( + txn, ResourcePattern::forExactNamespace(NamespaceString(parseNs(dbname, cmdObj))), ActionType::getShardVersion)) { return Status(ErrorCodes::Unauthorized, "Unauthorized"); @@ -1241,7 +1244,7 @@ namespace mongo { } bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int, string& errmsg, BSONObjBuilder& result, bool) { - Lock::DBWrite dbXLock(dbname); + Lock::DBWrite dbXLock(txn->lockState(), dbname); Client::Context ctx(dbname); shardingState.appendInfo( result ); diff --git a/src/mongo/s/request.cpp b/src/mongo/s/request.cpp index 73f891368d4..c4916fc2438 100644 --- a/src/mongo/s/request.cpp +++ b/src/mongo/s/request.cpp @@ -36,6 +36,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/dbmessage.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/db/stats/counters.h" #include "mongo/s/chunk.h" #include "mongo/s/client_info.h" @@ -52,6 +53,8 @@ namespace mongo { verify( _d.getns() ); _id = _m.header()->id; + _txn.reset(new OperationContextNoop()); + _clientInfo = ClientInfo::get(); if ( p ) { _clientInfo->newPeerRequest( p->remote() ); @@ -66,7 +69,7 @@ namespace mongo { return; _didInit = true; reset(); - _clientInfo->getAuthorizationSession()->startRequest(); + _clientInfo->getAuthorizationSession()->startRequest(_txn.get()); } // Deprecated, will move to the strategy itself diff --git a/src/mongo/s/request.h b/src/mongo/s/request.h index 3e494952005..7ca59139e66 100644 --- a/src/mongo/s/request.h +++ b/src/mongo/s/request.h @@ -41,6 +41,8 @@ namespace mongo { class OpCounters; class ClientInfo; + class OperationContext; + class Request : boost::noncopyable { public: @@ -93,6 +95,8 @@ namespace mongo { OpCounters* _counter; + boost::scoped_ptr<OperationContext> _txn; + bool _didInit; }; diff --git a/src/mongo/s/s_only.cpp b/src/mongo/s/s_only.cpp index bb6aeba7f17..a102d0ce836 100644 --- a/src/mongo/s/s_only.cpp +++ b/src/mongo/s/s_only.cpp @@ -134,7 +134,7 @@ namespace mongo { return; } - Status status = _checkAuthorization(c, &client, dbname, cmdObj, fromRepl); + Status status = _checkAuthorization(txn, c, &client, dbname, cmdObj, fromRepl); if (!status.isOK()) { appendCommandStatus(result, status); return; diff --git a/src/mongo/s/strategy.cpp b/src/mongo/s/strategy.cpp index fcca41f719d..8fe822f4645 100644 --- a/src/mongo/s/strategy.cpp +++ b/src/mongo/s/strategy.cpp @@ -40,6 +40,7 @@ #include "mongo/db/auth/authorization_session.h" #include "mongo/db/commands.h" #include "mongo/db/max_time.h" +#include "mongo/db/operation_context_noop.h" #include "mongo/db/server_parameters.h" #include "mongo/db/structure/catalog/index_details.h" #include "mongo/db/namespace_string.h" @@ -127,7 +128,9 @@ namespace mongo { NamespaceString ns(q.ns); ClientBasic* client = ClientBasic::getCurrent(); AuthorizationSession* authSession = client->getAuthorizationSession(); - Status status = authSession->checkAuthForQuery(ns, q.query); + + OperationContextNoop txn; + Status status = authSession->checkAuthForQuery(&txn, ns, q.query); audit::logQueryAuthzCheck(client, ns, q.query, status.code()); uassertStatusOK(status); @@ -299,8 +302,9 @@ namespace mongo { ClientBasic* client = ClientBasic::getCurrent(); AuthorizationSession* authSession = client->getAuthorizationSession(); if ( strcmp( ns , "inprog" ) == 0 ) { + OperationContextNoop txn; const bool isAuthorized = authSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::inprog); + &txn, ResourcePattern::forClusterResource(), ActionType::inprog); audit::logInProgAuthzCheck( client, q.query, isAuthorized ? ErrorCodes::OK : ErrorCodes::Unauthorized); uassert(ErrorCodes::Unauthorized, "not authorized to run inprog", isAuthorized); @@ -342,8 +346,9 @@ namespace mongo { arr.done(); } else if ( strcmp( ns , "killop" ) == 0 ) { + OperationContextNoop txn; const bool isAuthorized = authSession->isAuthorizedForActionsOnResource( - ResourcePattern::forClusterResource(), ActionType::killop); + &txn, ResourcePattern::forClusterResource(), ActionType::killop); audit::logKillOpAuthzCheck( client, q.query, @@ -453,7 +458,9 @@ namespace mongo { ClientBasic* client = ClientBasic::getCurrent(); NamespaceString nsString(ns); AuthorizationSession* authSession = client->getAuthorizationSession(); - Status status = authSession->checkAuthForGetMore( nsString, id ); + + OperationContextNoop txn; + Status status = authSession->checkAuthForGetMore(&txn, nsString, id ); audit::logGetMoreAuthzCheck( client, nsString, id, status.code() ); uassertStatusOK(status); diff --git a/src/mongo/tools/dump.cpp b/src/mongo/tools/dump.cpp index a7672e0b722..f699e76585e 100644 --- a/src/mongo/tools/dump.cpp +++ b/src/mongo/tools/dump.cpp @@ -41,6 +41,7 @@ #include "mongo/db/catalog/database_catalog_entry.h" #include "mongo/db/db.h" #include "mongo/db/namespace_string.h" +#include "mongo/db/operation_context_impl.h" #include "mongo/db/catalog/collection.h" #include "mongo/tools/mongodump_options.h" #include "mongo/tools/tool.h" @@ -252,7 +253,7 @@ public: int repair() { toolInfoLog() << "going to try and recover data from: " << toolGlobalParams.db << std::endl; - return _repair(toolGlobalParams.db); + return _repairByName(toolGlobalParams.db); } void _repairExtents(Collection* coll, Writer& writer) { @@ -330,9 +331,11 @@ public: << std::endl; } - int _repair( string dbname ) { - Client::WriteContext cx( dbname ); - Database * db = cx.ctx().db(); + int _repairByName(string dbname) { + OperationContextImpl txn; + Client::WriteContext cx(&txn, dbname); + + Database* db = dbHolderUnchecked().get(dbname, storageGlobalParams.dbpath); list<string> namespaces; db->getDatabaseCatalogEntry()->getCollectionNamespaces( &namespaces ); diff --git a/src/mongo/util/admin_access.h b/src/mongo/util/admin_access.h index 115004427b0..6f9834147df 100644 --- a/src/mongo/util/admin_access.h +++ b/src/mongo/util/admin_access.h @@ -36,6 +36,8 @@ namespace mongo { + class OperationContext; + /* * An AdminAccess is an interface class used to determine if certain users have * privileges to a given resource. @@ -48,14 +50,14 @@ namespace mongo { /** @return if there are any priviledge users. This should not * block for long and throw if can't get a lock if needed. */ - virtual bool haveAdminUsers() const = 0; + virtual bool haveAdminUsers(OperationContext* txn) const = 0; }; class NoAdminAccess : public AdminAccess { public: virtual ~NoAdminAccess() { } - virtual bool haveAdminUsers() const { return false; } + virtual bool haveAdminUsers(OperationContext* txn) const { return false; } }; } // namespace mongo |