diff options
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 |