diff options
author | Blake Oler <blake.oler@mongodb.com> | 2018-10-10 10:48:11 -0400 |
---|---|---|
committer | Blake Oler <blake.oler@mongodb.com> | 2018-10-13 17:47:24 -0400 |
commit | 6894b72f134534c3739a66ed9eee11e265b9c1e1 (patch) | |
tree | 141d2c0600511357c8edf93ba5c4a7070be47b0f | |
parent | aa89fef4ac12249077ff8701b465d0b9f733fd2c (diff) | |
download | mongo-6894b72f134534c3739a66ed9eee11e265b9c1e1.tar.gz |
SERVER-36964 Prevent secondaries in SessionsCollectionRS from attempting to set up the sessions collection.
-rw-r--r-- | jstests/replsets/refresh_sessions_rs.js | 6 | ||||
-rw-r--r-- | jstests/replsets/sessions_collection_auto_healing.js | 14 | ||||
-rw-r--r-- | src/mongo/db/logical_session_cache_impl.cpp | 23 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection.h | 7 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_config_server.cpp | 4 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_config_server.h | 5 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_mock.h | 4 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_rs.cpp | 31 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_rs.h | 5 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_sharded.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_sharded.h | 6 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_standalone.cpp | 21 | ||||
-rw-r--r-- | src/mongo/db/sessions_collection_standalone.h | 5 |
14 files changed, 113 insertions, 28 deletions
diff --git a/jstests/replsets/refresh_sessions_rs.js b/jstests/replsets/refresh_sessions_rs.js index 3a5cdd98218..4539e667d07 100644 --- a/jstests/replsets/refresh_sessions_rs.js +++ b/jstests/replsets/refresh_sessions_rs.js @@ -26,9 +26,13 @@ var res; - // Trigger an initial refresh on all members, as a sanity check. + // The primary needs to create the sessions collection so that the secondaries can act upon it. + // This is done by an initial refresh of the primary. res = db1.runCommand(refresh); assert.commandWorked(res, "failed to refresh"); + replTest.awaitReplication(); + + // Trigger an initial refresh on secondaries as a sanity check. res = db2.runCommand(refresh); assert.commandWorked(res, "failed to refresh"); res = db3.runCommand(refresh); diff --git a/jstests/replsets/sessions_collection_auto_healing.js b/jstests/replsets/sessions_collection_auto_healing.js index c56fb24639a..ed332241921 100644 --- a/jstests/replsets/sessions_collection_auto_healing.js +++ b/jstests/replsets/sessions_collection_auto_healing.js @@ -45,7 +45,7 @@ load('jstests/libs/sessions_collection.js'); validateSessionsCollection(secondary, false, false); } - // Test that a refresh on a secondary creates the sessions collection. + // Test that a refresh on a secondary does not create the sessions collection. { validateSessionsCollection(primary, false, false); @@ -54,15 +54,13 @@ load('jstests/libs/sessions_collection.js'); assert.commandWorked(secondaryAdmin.runCommand({refreshLogicalSessionCacheNow: 1})); - validateSessionsCollection(primary, true, true); + validateSessionsCollection(primary, false, false); replTest.awaitReplication(); - validateSessionsCollection(secondary, true, true); + validateSessionsCollection(secondary, false, false); } // Test that a refresh on the primary creates the sessions collection. { - assert.commandWorked(primary.getDB("config").runCommand( - {drop: "system.sessions", writeConcern: {w: "majority"}})); validateSessionsCollection(primary, false, false); replTest.awaitReplication(); @@ -73,7 +71,7 @@ load('jstests/libs/sessions_collection.js'); validateSessionsCollection(primary, true, true); } - // Test that a refresh on a secondary will create the TTL index on the sessions collection. + // Test that a refresh on a secondary will not create the TTL index on the sessions collection. { assert.commandWorked(primary.getDB("config").system.sessions.dropIndex({lastUse: 1})); @@ -81,13 +79,11 @@ load('jstests/libs/sessions_collection.js'); assert.commandWorked(secondaryAdmin.runCommand({refreshLogicalSessionCacheNow: 1})); - validateSessionsCollection(primary, true, true); + validateSessionsCollection(primary, true, false); } // Test that a refresh on the primary will create the TTL index on the sessions collection. { - assert.commandWorked(primary.getDB("config").system.sessions.dropIndex({lastUse: 1})); - validateSessionsCollection(primary, true, false); assert.commandWorked(primaryAdmin.runCommand({refreshLogicalSessionCacheNow: 1})); diff --git a/src/mongo/db/logical_session_cache_impl.cpp b/src/mongo/db/logical_session_cache_impl.cpp index 1b7fceb0f4e..834c29f86f3 100644 --- a/src/mongo/db/logical_session_cache_impl.cpp +++ b/src/mongo/db/logical_session_cache_impl.cpp @@ -219,10 +219,18 @@ Status LogicalSessionCacheImpl::_reap(Client* client) { return uniqueCtx->get(); }(); - auto res = _sessionsColl->setupSessionsCollection(opCtx); - if (!res.isOK()) { - log() << "Sessions collection is not set up; " - << "waiting until next sessions reap interval: " << res.reason(); + auto existsStatus = _sessionsColl->checkSessionsCollectionExists(opCtx); + if (!existsStatus.isOK()) { + StringData notSetUpWarning = + "Sessions collection is not set up; " + "waiting until next sessions reap interval"; + if (existsStatus.code() != ErrorCodes::NamespaceNotFound || + existsStatus.code() != ErrorCodes::NamespaceNotSharded) { + log() << notSetUpWarning << ": " << existsStatus.reason(); + } else { + log() << notSetUpWarning; + } + return Status::OK(); } @@ -282,10 +290,11 @@ void LogicalSessionCacheImpl::_refresh(Client* client) { return uniqueCtx->get(); }(); - auto res = _sessionsColl->setupSessionsCollection(opCtx); - if (!res.isOK()) { + auto setupStatus = _sessionsColl->setupSessionsCollection(opCtx); + + if (!setupStatus.isOK()) { log() << "Sessions collection is not set up; " - << "waiting until next sessions refresh interval: " << res.reason(); + << "waiting until next sessions refresh interval: " << setupStatus.reason(); return; } diff --git a/src/mongo/db/sessions_collection.cpp b/src/mongo/db/sessions_collection.cpp index 612b918792a..0f550f273c9 100644 --- a/src/mongo/db/sessions_collection.cpp +++ b/src/mongo/db/sessions_collection.cpp @@ -46,6 +46,8 @@ namespace mongo { +constexpr StringData SessionsCollection::kSessionsTTLIndex; + namespace { // This batch size is chosen to ensure that we don't form requests larger than the 16mb limit. @@ -299,7 +301,7 @@ StatusWith<LogicalSessionIdSet> SessionsCollection::doFetch(const NamespaceStrin BSONObj SessionsCollection::generateCreateIndexesCmd() { NewIndexSpec index; index.setKey(BSON("lastUse" << 1)); - index.setName("lsidTTLIndex"); + index.setName(kSessionsTTLIndex); index.setExpireAfterSeconds(localLogicalSessionTimeoutMinutes * 60); std::vector<NewIndexSpec> indexes; diff --git a/src/mongo/db/sessions_collection.h b/src/mongo/db/sessions_collection.h index 7635124c5a7..f134fea3e09 100644 --- a/src/mongo/db/sessions_collection.h +++ b/src/mongo/db/sessions_collection.h @@ -47,6 +47,8 @@ class OperationContext; class SessionsCollection { public: + static constexpr StringData kSessionsTTLIndex = "lsidTTLIndex"_sd; + virtual ~SessionsCollection(); /** @@ -55,6 +57,11 @@ public: virtual Status setupSessionsCollection(OperationContext* opCtx) = 0; /** + * Checks if the sessions collection exists and has the proper indexes. + */ + virtual Status checkSessionsCollectionExists(OperationContext* opCtx) = 0; + + /** * Updates the last-use times on the given sessions to be greater than * or equal to the given time. Returns an error if a networking issue occurred. */ diff --git a/src/mongo/db/sessions_collection_config_server.cpp b/src/mongo/db/sessions_collection_config_server.cpp index 41920462aa4..7b3cc8dd389 100644 --- a/src/mongo/db/sessions_collection_config_server.cpp +++ b/src/mongo/db/sessions_collection_config_server.cpp @@ -122,4 +122,8 @@ Status SessionsCollectionConfigServer::setupSessionsCollection(OperationContext* } } +Status SessionsCollectionConfigServer::checkSessionsCollectionExists(OperationContext* opCtx) { + return _checkCacheForSessionsCollection(opCtx); +} + } // namespace mongo diff --git a/src/mongo/db/sessions_collection_config_server.h b/src/mongo/db/sessions_collection_config_server.h index 33eb6e8543f..4437e4ea984 100644 --- a/src/mongo/db/sessions_collection_config_server.h +++ b/src/mongo/db/sessions_collection_config_server.h @@ -54,6 +54,11 @@ public: */ Status setupSessionsCollection(OperationContext* opCtx) override; + /** + * Checks if the sessions collection exists. + */ + Status checkSessionsCollectionExists(OperationContext* opCtx) override; + private: Status _shardCollectionIfNeeded(OperationContext* opCtx); Status _generateIndexesIfNeeded(OperationContext* opCtx); diff --git a/src/mongo/db/sessions_collection_mock.h b/src/mongo/db/sessions_collection_mock.h index ff2c536467c..9ed87792dbe 100644 --- a/src/mongo/db/sessions_collection_mock.h +++ b/src/mongo/db/sessions_collection_mock.h @@ -108,6 +108,10 @@ public: return Status::OK(); } + Status checkSessionsCollectionExists(OperationContext* opCtx) override { + return Status::OK(); + } + Status refreshSessions(OperationContext* opCtx, const LogicalSessionRecordSet& sessions) override { return _impl->refreshSessions(sessions); diff --git a/src/mongo/db/sessions_collection_rs.cpp b/src/mongo/db/sessions_collection_rs.cpp index 4cf406ac658..216392f3e48 100644 --- a/src/mongo/db/sessions_collection_rs.cpp +++ b/src/mongo/db/sessions_collection_rs.cpp @@ -162,15 +162,28 @@ Status SessionsCollectionRS::setupSessionsCollection(OperationContext* opCtx) { return Status::OK(); }, - [&](DBClientBase* client) { - BSONObj info; - auto cmd = generateCreateIndexesCmd(); - if (!client->runCommand( - NamespaceString::kLogicalSessionsNamespace.db().toString(), cmd, info)) { - return getStatusFromCommandResult(info); - } - return Status::OK(); - }); + [&](DBClientBase*) { return checkSessionsCollectionExists(opCtx); }); +} + +Status SessionsCollectionRS::checkSessionsCollectionExists(OperationContext* opCtx) { + DBDirectClient client(opCtx); + + auto indexes = client.getIndexSpecs(NamespaceString::kLogicalSessionsNamespace.toString()); + + if (indexes.size() == 0u) { + return Status{ErrorCodes::NamespaceNotFound, "config.system.sessions does not exist"}; + } + + auto indexExists = std::find_if(indexes.begin(), indexes.end(), [](const BSONObj& index) { + return index.getField("name").String() == kSessionsTTLIndex; + }); + + if (indexExists == indexes.end()) { + return Status{ErrorCodes::IndexNotFound, + "config.system.sessions does not have the required TTL index"}; + } + + return Status::OK(); } Status SessionsCollectionRS::refreshSessions(OperationContext* opCtx, diff --git a/src/mongo/db/sessions_collection_rs.h b/src/mongo/db/sessions_collection_rs.h index ac2563cdee8..676fe98db27 100644 --- a/src/mongo/db/sessions_collection_rs.h +++ b/src/mongo/db/sessions_collection_rs.h @@ -59,6 +59,11 @@ public: Status setupSessionsCollection(OperationContext* opCtx) override; /** + * Checks if the sessions collection exists and has the proper indexes. + */ + Status checkSessionsCollectionExists(OperationContext* opCtx) override; + + /** * Updates the last-use times on the given sessions to be greater than * or equal to the current time. * diff --git a/src/mongo/db/sessions_collection_sharded.cpp b/src/mongo/db/sessions_collection_sharded.cpp index 9a10be835e7..35d13f1eb85 100644 --- a/src/mongo/db/sessions_collection_sharded.cpp +++ b/src/mongo/db/sessions_collection_sharded.cpp @@ -74,10 +74,14 @@ Status SessionsCollectionSharded::_checkCacheForSessionsCollection(OperationCont return Status::OK(); } - return {ErrorCodes::NamespaceNotFound, "config.system.sessions is not yet sharded"}; + return {ErrorCodes::NamespaceNotFound, "config.system.sessions does not exist"}; } Status SessionsCollectionSharded::setupSessionsCollection(OperationContext* opCtx) { + return checkSessionsCollectionExists(opCtx); +} + +Status SessionsCollectionSharded::checkSessionsCollectionExists(OperationContext* opCtx) { return _checkCacheForSessionsCollection(opCtx); } diff --git a/src/mongo/db/sessions_collection_sharded.h b/src/mongo/db/sessions_collection_sharded.h index d8f5c6cf3f2..5d3dc7bdede 100644 --- a/src/mongo/db/sessions_collection_sharded.h +++ b/src/mongo/db/sessions_collection_sharded.h @@ -50,6 +50,12 @@ public: Status setupSessionsCollection(OperationContext* opCtx) override; /** + * Checks if the sessions collection exists. Does not check if the index exists in the sharded + * version of this function. + */ + virtual Status checkSessionsCollectionExists(OperationContext* opCtx) override; + + /** * Updates the last-use times on the given sessions to be greater than * or equal to the current time. */ diff --git a/src/mongo/db/sessions_collection_standalone.cpp b/src/mongo/db/sessions_collection_standalone.cpp index 1f4b5ec17cf..d43abd7ea01 100644 --- a/src/mongo/db/sessions_collection_standalone.cpp +++ b/src/mongo/db/sessions_collection_standalone.cpp @@ -55,6 +55,27 @@ Status SessionsCollectionStandalone::setupSessionsCollection(OperationContext* o return Status::OK(); } +Status SessionsCollectionStandalone::checkSessionsCollectionExists(OperationContext* opCtx) { + DBDirectClient client(opCtx); + + auto indexes = client.getIndexSpecs(NamespaceString::kLogicalSessionsNamespace.toString()); + + if (indexes.size() == 0u) { + return Status{ErrorCodes::NamespaceNotFound, "config.system.sessions does not exist"}; + } + + auto indexExists = std::find_if(indexes.begin(), indexes.end(), [](const BSONObj& index) { + return index.getField("name").String() == kSessionsTTLIndex; + }); + + if (indexExists == indexes.end()) { + return Status{ErrorCodes::IndexNotFound, + "config.system.sessions does not have the required TTL index"}; + }; + + return Status::OK(); +} + Status SessionsCollectionStandalone::refreshSessions(OperationContext* opCtx, const LogicalSessionRecordSet& sessions) { DBDirectClient client(opCtx); diff --git a/src/mongo/db/sessions_collection_standalone.h b/src/mongo/db/sessions_collection_standalone.h index 9f12516f2ff..a550fc42c3b 100644 --- a/src/mongo/db/sessions_collection_standalone.h +++ b/src/mongo/db/sessions_collection_standalone.h @@ -48,6 +48,11 @@ public: Status setupSessionsCollection(OperationContext* opCtx) override; /** + * Checks if the sessions collection exists and has the proper indexes. + */ + Status checkSessionsCollectionExists(OperationContext* opCtx) override; + + /** * Updates the last-use times on the given sessions to be greater than * or equal to the current time. */ |