diff options
author | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-05-30 09:56:36 -0400 |
---|---|---|
committer | Kaloian Manassiev <kaloian.manassiev@mongodb.com> | 2014-05-30 11:44:18 -0400 |
commit | 4edbe14669b7804180d8b58549e257ceb679bb1d (patch) | |
tree | a72389bb84137c11755fd4f55d7218f190b0456c /src/mongo | |
parent | bee249ac8907cc9de6b19ba87c3fcb074d84b1a3 (diff) | |
download | mongo-4edbe14669b7804180d8b58549e257ceb679bb1d.tar.gz |
SERVER-13961 Pass LockState to DBWrite and DBRead directly
This is part of the changes to move LockState be part of OperationContext
and not retrieved from TLS.
Diffstat (limited to 'src/mongo')
144 files changed, 948 insertions, 700 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 c3466c922eb..cc60b795c0a 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() { @@ -493,8 +493,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, @@ -513,7 +515,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(); @@ -549,7 +552,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; } @@ -562,7 +565,7 @@ namespace mongo { break; case schemaVersion26Final: case schemaVersion26Upgrade: - status = _fetchUserV2(userName, &user); + status = _fetchUserV2(txn, userName, &user); break; case schemaVersion24: status = Status(ErrorCodes::AuthSchemaIncompatible, mongoutils::str::stream() << @@ -600,10 +603,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; } @@ -700,9 +704,10 @@ namespace mongo { return _externalState->releaseAuthzUpdateLock(); } - 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; } @@ -717,7 +722,8 @@ namespace mongo { } } - 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, @@ -726,7 +732,7 @@ namespace mongo { 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 be11d634e83..c03e5b3eb66 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, @@ -389,7 +390,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 @@ -404,7 +406,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 @@ -448,7 +450,9 @@ 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); /** * 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..5e6c680cd16 100644 --- a/src/mongo/db/auth/authorization_manager_global.cpp +++ b/src/mongo/db/auth/authorization_manager_global.cpp @@ -44,7 +44,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 +60,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 0e4c71447bb..e230dc1e405 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" @@ -186,8 +187,10 @@ namespace { "roles" << BSON_ARRAY(BSON("role" << "clusterAdmin" << "db" << "admin"))), BSONObj())); + OperationContextNoop txn; + 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()); @@ -198,7 +201,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()); diff --git a/src/mongo/db/auth/authorization_session.cpp b/src/mongo/db/auth/authorization_session.cpp index 2946cbfd352..f731266721c 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; } @@ -251,7 +252,8 @@ namespace { << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName("admin"), ActionType::grantRole)) { + 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"); @@ -271,7 +273,8 @@ namespace { << resource.databaseToMatch() << "database"); } } else if (!isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName("admin"), ActionType::revokeRole)) { + 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"); @@ -281,14 +284,14 @@ namespace { bool AuthorizationSession::isAuthorizedToGrantRole(const RoleName& role) { return isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(role.getDB()), - ActionType::grantRole); + ResourcePattern::forDatabaseName(role.getDB()), + ActionType::grantRole); } bool AuthorizationSession::isAuthorizedToRevokeRole(const RoleName& role) { return isAuthorizedForActionsOnResource( - ResourcePattern::forDatabaseName(role.getDB()), - ActionType::revokeRole); + ResourcePattern::forDatabaseName(role.getDB()), + ActionType::revokeRole); } bool AuthorizationSession::isAuthorizedForPrivilege(const Privilege& privilege) { @@ -322,12 +325,14 @@ namespace { bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns, ActionType action) { - return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), action)); + return isAuthorizedForPrivilege( + Privilege(ResourcePattern::forExactNamespace(ns), action)); } bool AuthorizationSession::isAuthorizedForActionsOnNamespace(const NamespaceString& ns, - const ActionSet& actions) { - return isAuthorizedForPrivilege(Privilege(ResourcePattern::forExactNamespace(ns), actions)); + const ActionSet& actions) { + return isAuthorizedForPrivilege( + Privilege(ResourcePattern::forExactNamespace(ns), actions)); } static const int resourceSearchListCapacity = 5; @@ -422,7 +427,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 +439,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. @@ -490,7 +495,6 @@ namespace { for (UserSet::iterator it = _authenticatedUsers.begin(); it != _authenticatedUsers.end(); ++it) { User* user = *it; - for (int i = 0; i < resourceSearchListLength; ++i) { ActionSet userActions = user->getActionsForResource(resourceSearchList[i]); unmetRequirements.removeAllActionsFromSet(userActions); diff --git a/src/mongo/db/auth/authorization_session.h b/src/mongo/db/auth/authorization_session.h index 1a12a0719e0..f0484e26f1b 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. @@ -182,7 +182,8 @@ namespace mongo { // Utility function for // isAuthorizedForActionsOnResource(ResourcePattern::forExactNamespace(ns), actions). - bool isAuthorizedForActionsOnNamespace(const NamespaceString& ns, const ActionSet& actions); + bool isAuthorizedForActionsOnNamespace(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,7 +204,7 @@ 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 diff --git a/src/mongo/db/auth/authorization_session_test.cpp b/src/mongo/db/auth/authorization_session_test.cpp index f9410440af8..8c25e9b6e3d 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: @@ -72,6 +74,7 @@ namespace { class AuthorizationSessionTest : public ::mongo::unittest::Test { public: FailureCapableAuthzManagerExternalStateMock* managerState; + OperationContextNoop _txn; AuthzSessionExternalStateMock* sessionState; scoped_ptr<AuthorizationManager> authzManager; scoped_ptr<AuthorizationSession> authzSession; @@ -129,7 +132,7 @@ namespace { // 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,7 +144,7 @@ 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)); @@ -158,7 +161,7 @@ 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( ResourcePattern::forExactNamespace( @@ -203,7 +206,7 @@ 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)); @@ -247,7 +250,7 @@ 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)); @@ -267,7 +270,7 @@ namespace { 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)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( @@ -286,7 +289,7 @@ namespace { 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)); @@ -307,7 +310,7 @@ namespace { // 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)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( @@ -335,7 +338,7 @@ 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)); @@ -362,7 +365,7 @@ 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)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( @@ -379,7 +382,7 @@ 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)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( @@ -396,7 +399,7 @@ 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)); @@ -426,7 +429,7 @@ 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)); ASSERT_TRUE(authzSession->isAuthorizedForActionsOnResource( @@ -435,7 +438,7 @@ namespace { // 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)); ASSERT_FALSE(authzSession->isAuthorizedForActionsOnResource( diff --git a/src/mongo/db/auth/authz_manager_external_state.cpp b/src/mongo/db/auth/authz_manager_external_state.cpp index 5a369cade31..4b9b3501a11 100644 --- a/src/mongo/db/auth/authz_manager_external_state.cpp +++ b/src/mongo/db/auth/authz_manager_external_state.cpp @@ -40,9 +40,10 @@ namespace mongo { AuthzManagerExternalState::AuthzManagerExternalState() {} AuthzManagerExternalState::~AuthzManagerExternalState() {} - 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 47226e9735b..397d7cb718f 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 @@ -114,7 +117,7 @@ namespace mongo { /** * 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. @@ -153,7 +156,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..a62b472e5ab 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 @@ -49,7 +49,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 +61,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..766bb3cd4a0 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( + 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/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..144ea90b01b 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,22 +184,24 @@ 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") { - return _authenticateX509(user, cmdObj); + return _authenticateX509(txn, user, cmdObj); } #endif 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; } @@ -317,7 +319,8 @@ namespace mongo { return true; } - Status CmdAuthenticate::_authenticateX509(const UserName& user, const BSONObj& cmdObj) { + Status CmdAuthenticate::_authenticateX509( + OperationContext* txn, const UserName& user, const BSONObj& cmdObj) { if (!getSSLManager()) { return Status(ErrorCodes::ProtocolError, "SSL support is required for the MONGODB-X509 mechanism."); @@ -356,7 +359,7 @@ namespace mongo { return Status(ErrorCodes::BadValue, _x509AuthenticationDisabledMessage); } - Status status = authorizationSession->addAndAuthorizeUser(user); + Status 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..e6b0dd87ab5 100644 --- a/src/mongo/db/commands/authentication_commands.h +++ b/src/mongo/db/commands/authentication_commands.h @@ -71,11 +71,14 @@ 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 _authenticateX509(const UserName& user, const BSONObj& cmdObj); + Status _authenticateCR( + OperationContext* txn, const UserName& user, const BSONObj& cmdObj); + Status _authenticateX509( + OperationContext* txn, const UserName& user, const BSONObj& cmdObj); bool _clusterIdMatch(const std::string& subjectName, const std::string& srvSubjectName); }; diff --git a/src/mongo/db/commands/clone.cpp b/src/mongo/db/commands/clone.cpp index b75ee5ceb69..2e367e3dfaf 100644 --- a/src/mongo/db/commands/clone.cpp +++ b/src/mongo/db/commands/clone.cpp @@ -118,7 +118,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/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..db0025f43b2 100644 --- a/src/mongo/db/commands/copydb.cpp +++ b/src/mongo/db/commands/copydb.cpp @@ -155,8 +155,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/create_indexes.cpp b/src/mongo/db/commands/create_indexes.cpp index 2519bc75cc4..841f9522ace 100644 --- a/src/mongo/db/commands/create_indexes.cpp +++ b/src/mongo/db/commands/create_indexes.cpp @@ -57,7 +57,7 @@ namespace mongo { ActionSet actions; actions.addAction(ActionType::createIndex); Privilege p(parseResourcePattern(dbname, cmdObj), actions); - if ( client->getAuthorizationSession()->isAuthorizedForPrivilege(p) ) + if (client->getAuthorizationSession()->isAuthorizedForPrivilege(p)) return Status::OK(); return Status(ErrorCodes::Unauthorized, "Unauthorized"); } @@ -132,9 +132,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 +162,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 79b93f14e28..37d777b2da3 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..94920e4d61e 100644 --- a/src/mongo/db/commands/group.cpp +++ b/src/mongo/db/commands/group.cpp @@ -254,7 +254,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..efc92edd3a3 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,8 +144,9 @@ namespace mongo { ss << helpText; } - Status IndexFilterCommand::checkAuthForCommand(ClientBasic* client, const std::string& dbname, - const BSONObj& cmdObj) { + Status IndexFilterCommand::checkAuthForCommand(ClientBasic* client, + const std::string& dbname, + const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); @@ -159,9 +160,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 +222,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 +313,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..f6ba8fa9efb 100644 --- a/src/mongo/db/commands/index_filter_commands.h +++ b/src/mongo/db/commands/index_filter_commands.h @@ -76,7 +76,8 @@ namespace mongo { * One action type defined for index filter commands: * - planCacheIndexFilter */ - virtual Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, const BSONObj& cmdObj); /** @@ -85,7 +86,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 +105,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 +127,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 +158,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/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/parallel_collection_scan.cpp b/src/mongo/db/commands/parallel_collection_scan.cpp index 061175638cd..593912cf0d4 100644 --- a/src/mongo/db/commands/parallel_collection_scan.cpp +++ b/src/mongo/db/commands/parallel_collection_scan.cpp @@ -165,7 +165,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..a8d32641646 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,7 +138,8 @@ namespace mongo { ss << helpText; } - Status PlanCacheCommand::checkAuthForCommand(ClientBasic* client, const std::string& dbname, + Status PlanCacheCommand::checkAuthForCommand(ClientBasic* client, + const std::string& dbname, const BSONObj& cmdObj) { AuthorizationSession* authzSession = client->getAuthorizationSession(); ResourcePattern pattern = parseResourcePattern(dbname, cmdObj); @@ -206,10 +207,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 +255,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 +327,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..507d4fe4927 100644 --- a/src/mongo/db/commands/plan_cache_commands.h +++ b/src/mongo/db/commands/plan_cache_commands.h @@ -72,7 +72,8 @@ namespace mongo { * - planCacheRead * - planCacheWrite */ - virtual Status checkAuthForCommand(ClientBasic* client, const std::string& dbname, + virtual Status checkAuthForCommand(ClientBasic* client, + const std::string& dbname, const BSONObj& cmdObj); /** * Subset of command arguments used by plan cache commands @@ -80,7 +81,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 +106,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 +132,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 +158,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/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..4682f9a055b 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; } @@ -265,9 +266,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 +284,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; } @@ -434,7 +437,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); } @@ -579,7 +582,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); } @@ -668,7 +671,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); } @@ -754,7 +757,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); } @@ -836,7 +839,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 +859,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); } @@ -934,7 +937,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 +957,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); } @@ -1049,7 +1052,8 @@ namespace mongo { return appendCommandStatus(result, status); } - status = requireAuthSchemaVersion26UpgradeOrFinal(getGlobalAuthorizationManager()); + status = requireAuthSchemaVersion26UpgradeOrFinal(txn, + getGlobalAuthorizationManager()); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -1068,7 +1072,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 +1111,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); } @@ -1252,7 +1256,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); } @@ -1369,7 +1373,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); } @@ -1459,7 +1463,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); } @@ -1595,7 +1599,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); } @@ -1755,7 +1759,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); } @@ -1851,7 +1855,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); } @@ -1970,7 +1974,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); } @@ -2146,7 +2150,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); } @@ -2292,7 +2296,8 @@ namespace mongo { return appendCommandStatus(result, status); } - status = requireAuthSchemaVersion26UpgradeOrFinal(getGlobalAuthorizationManager()); + status = requireAuthSchemaVersion26UpgradeOrFinal(txn, + getGlobalAuthorizationManager()); if (!status.isOK()) { return appendCommandStatus(result, status); } @@ -2840,7 +2845,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); } 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/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..e751dbaeebb 100644 --- a/src/mongo/db/dbcommands.cpp +++ b/src/mongo/db/dbcommands.cpp @@ -353,7 +353,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 +403,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 +457,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 +528,7 @@ namespace mongo { // This acquires the DB read lock // - Client::ReadContext ctx(ns); + Client::ReadContext ctx(txn, ns); string err; int errCode; @@ -621,7 +621,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 +667,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 +695,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 +812,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 +920,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 +1037,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 +1114,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 +1244,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 ); @@ -1395,8 +1395,10 @@ namespace mongo { std::vector<UserName> parsedUserNames; AuthorizationSession* authSession = client.getAuthorizationSession(); bool fieldIsPresent = false; - audit::parseAndRemoveImpersonatedUserField(cmdObj, authSession, - &parsedUserNames, &fieldIsPresent); + audit::parseAndRemoveImpersonatedUserField(cmdObj, + authSession, + &parsedUserNames, + &fieldIsPresent); ImpersonationSessionGuard impersonationSession(authSession, fieldIsPresent, parsedUserNames); 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..3e2566bde51 100644 --- a/src/mongo/db/instance.cpp +++ b/src/mongo/db/instance.cpp @@ -182,6 +182,7 @@ namespace mongo { DbMessage d(m); QueryMessage q(d); BSONObj obj; + const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource( ResourcePattern::forClusterResource(), ActionType::killop); audit::logKillOpAuthzCheck(&cc(), @@ -210,6 +211,7 @@ namespace mongo { bool _unlockFsync(); void unlockFsync(const char *ns, Message& m, DbResponse &dbresponse) { BSONObj obj; + const bool isAuthorized = cc().getAuthorizationSession()->isAuthorizedForActionsOnResource( ResourcePattern::forClusterResource(), ActionType::unlock); audit::logFsyncUnlockAuthzCheck( @@ -341,7 +343,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 +530,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; @@ -603,7 +605,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 @@ -643,7 +645,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 ) ) @@ -717,7 +719,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; @@ -880,7 +882,7 @@ namespace mongo { 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 +926,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 +935,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 +1004,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 +1017,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/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 81c1941c8d3..b041b4d4e5a 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 @@ -477,7 +480,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; @@ -487,7 +490,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 ); @@ -500,7 +503,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 ); @@ -614,16 +617,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 ); @@ -658,6 +663,7 @@ namespace mongo { private: string _ns; + OperationContext* _txn; Collection* _collection; }; @@ -713,7 +719,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; @@ -730,7 +736,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; @@ -1042,8 +1048,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; @@ -1204,7 +1211,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 @@ -1587,7 +1594,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; @@ -1618,7 +1625,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 ); @@ -1653,7 +1660,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 ) { @@ -1703,7 +1710,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; @@ -1749,7 +1756,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 ) ) { @@ -1944,7 +1951,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(); @@ -1979,7 +1986,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..7bb1d4d82d7 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"; @@ -275,7 +275,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"; @@ -824,7 +824,7 @@ namespace mongo { maxVersion.incMinor(); { - Lock::DBWrite writeLk( ns ); + Lock::DBWrite writeLk(txn->lockState(), ns); shardingState.splitChunk( ns , min , max , splitKeys , maxVersion ); } @@ -858,7 +858,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..08560b9149a 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 @@ -1241,7 +1242,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/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 diff --git a/src/mongo/util/net/ssl_options.cpp b/src/mongo/util/net/ssl_options.cpp index 382513c7079..b651c95d07c 100644 --- a/src/mongo/util/net/ssl_options.cpp +++ b/src/mongo/util/net/ssl_options.cpp @@ -25,6 +25,8 @@ * then also delete it in the license file. */ +#include "mongo/platform/basic.h" + #include "mongo/util/net/ssl_options.h" #include <boost/filesystem/operations.hpp> |