summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorsamantharitter <samantha.ritter@10gen.com>2017-10-06 15:12:40 -0400
committerKaloian Manassiev <kaloian.manassiev@mongodb.com>2017-10-11 00:52:09 -0400
commit45d35fe3fcefefe1282b8e0dfc8cd76cb247951d (patch)
tree6643f175807ae1c20902885846d29e888127f9a6 /src/mongo
parent8b3694d704d4c472adba87e8fb0827372324c215 (diff)
downloadmongo-45d35fe3fcefefe1282b8e0dfc8cd76cb247951d.tar.gz
SERVER-31184 Make servers automatically set up config.system.sessions
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/db/SConscript19
-rw-r--r--src/mongo/db/catalog/database_impl.cpp4
-rw-r--r--src/mongo/db/create_indexes.idl88
-rw-r--r--src/mongo/db/db.cpp2
-rw-r--r--src/mongo/db/logical_session_cache_factory_mongod.cpp3
-rw-r--r--src/mongo/db/logical_session_cache_factory_mongod.h2
-rw-r--r--src/mongo/db/logical_session_cache_impl.cpp43
-rw-r--r--src/mongo/db/logical_session_cache_test.cpp7
-rw-r--r--src/mongo/db/ops/insert.cpp6
-rw-r--r--src/mongo/db/sessions_collection.cpp17
-rw-r--r--src/mongo/db/sessions_collection.h10
-rw-r--r--src/mongo/db/sessions_collection_config_server.cpp117
-rw-r--r--src/mongo/db/sessions_collection_config_server.h65
-rw-r--r--src/mongo/db/sessions_collection_mock.h4
-rw-r--r--src/mongo/db/sessions_collection_rs.cpp23
-rw-r--r--src/mongo/db/sessions_collection_rs.h5
-rw-r--r--src/mongo/db/sessions_collection_sharded.cpp23
-rw-r--r--src/mongo/db/sessions_collection_sharded.h9
-rw-r--r--src/mongo/db/sessions_collection_standalone.cpp12
-rw-r--r--src/mongo/db/sessions_collection_standalone.h5
-rw-r--r--src/mongo/db/system_index.cpp46
-rw-r--r--src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp23
-rw-r--r--src/mongo/s/catalog/sharding_catalog_manager.h6
-rw-r--r--src/mongo/s/catalog/sharding_catalog_manager_shard_operations.cpp37
-rw-r--r--src/mongo/s/client/shard_registry.cpp6
-rw-r--r--src/mongo/s/client/shard_registry.h2
-rw-r--r--src/mongo/s/commands/cluster_remove_shard_cmd.cpp39
-rw-r--r--src/mongo/shell/shardingtest.js14
28 files changed, 545 insertions, 92 deletions
diff --git a/src/mongo/db/SConscript b/src/mongo/db/SConscript
index c7f3ce2a887..73a03f0e499 100644
--- a/src/mongo/db/SConscript
+++ b/src/mongo/db/SConscript
@@ -574,7 +574,6 @@ env.Library(
LIBDEPS=[
'db_raii',
'catalog/index_key_validate',
- 'logical_session_cache',
],
)
@@ -977,6 +976,7 @@ env.Library(
target='sessions_collection',
source=[
'sessions_collection.cpp',
+ env.Idlc('create_indexes.idl')[0],
],
LIBDEPS=[
'$BUILD_DIR/mongo/base',
@@ -1045,6 +1045,22 @@ env.Library(
)
env.Library(
+ target='sessions_collection_config_server',
+ source=[
+ 'sessions_collection_config_server.cpp',
+ ],
+ LIBDEPS=[
+ '$BUILD_DIR/mongo/s/client/sharding_client',
+ '$BUILD_DIR/mongo/s/commands/shared_cluster_commands',
+ '$BUILD_DIR/mongo/s/coreshard',
+ '$BUILD_DIR/mongo/s/sharding_request_types',
+ 'dbdirectclient',
+ 'sessions_collection',
+ 'sessions_collection_sharded',
+ ],
+)
+
+env.Library(
target='logical_session_cache',
source=[
'logical_session_cache.cpp',
@@ -1122,6 +1138,7 @@ envWithAsio.Library(
'logical_session_cache',
'logical_session_cache_impl',
'service_liason_mongod',
+ 'sessions_collection_config_server',
'sessions_collection_rs',
'sessions_collection_sharded',
'sessions_collection_standalone',
diff --git a/src/mongo/db/catalog/database_impl.cpp b/src/mongo/db/catalog/database_impl.cpp
index 87630ec52b1..b7d2df997ca 100644
--- a/src/mongo/db/catalog/database_impl.cpp
+++ b/src/mongo/db/catalog/database_impl.cpp
@@ -64,6 +64,7 @@
#include "mongo/db/server_options.h"
#include "mongo/db/server_parameters.h"
#include "mongo/db/service_context.h"
+#include "mongo/db/sessions_collection.h"
#include "mongo/db/stats/top.h"
#include "mongo/db/storage/recovery_unit.h"
#include "mongo/db/storage/storage_engine.h"
@@ -451,7 +452,8 @@ Status DatabaseImpl::dropCollection(OperationContext* opCtx,
if (_profile != 0)
return Status(ErrorCodes::IllegalOperation,
"turn off profiling before dropping system.profile collection");
- } else if (!(nss.isSystemDotViews() || nss.isHealthlog())) {
+ } else if (!(nss.isSystemDotViews() || nss.isHealthlog() ||
+ nss == SessionsCollection::kSessionsNamespaceString)) {
return Status(ErrorCodes::IllegalOperation,
str::stream() << "can't drop system collection " << fullns);
}
diff --git a/src/mongo/db/create_indexes.idl b/src/mongo/db/create_indexes.idl
new file mode 100644
index 00000000000..decbf9e6c9b
--- /dev/null
+++ b/src/mongo/db/create_indexes.idl
@@ -0,0 +1,88 @@
+# Copyright (C) 2017 MongoDB Inc.
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3,
+# as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+# This IDL file describes the BSON format for a LogicalSessionId, and
+# handles the serialization to and deserialization from its BSON representation
+# for that class.
+
+global:
+ cpp_namespace: "mongo"
+
+imports:
+ - "mongo/idl/basic_types.idl"
+
+structs:
+
+ NewIndexSpec:
+ description: "A type representing a spec for a new index"
+ strict: true
+ fields:
+ key: object
+ name: string
+ background:
+ type: bool
+ optional: true
+ unique:
+ type: bool
+ optional: true
+ partialFilterExpression:
+ type: object
+ optional: true
+ sparse:
+ type: bool
+ optional: true
+ expireAfterSeconds:
+ type: int
+ optional: true
+ storageEngine:
+ type: object
+ optional: true
+ weights:
+ type: object
+ optional: true
+ default_language:
+ type: string
+ optional: true
+ language_override:
+ type: string
+ optional: true
+ textIndexVersion:
+ type: int
+ optional: true
+ 2dsphereIndexVersion:
+ type: int
+ optional: true
+ bits:
+ type: int
+ optional: true
+ min:
+ type: double
+ optional: true
+ max:
+ type: double
+ optional: true
+ bucketSize:
+ type: double
+ optional: true
+ collation:
+ type: object
+ optional: true
+
+ CreateIndexesCmd:
+ description: "A struct representing a createIndexes command"
+ strict: false
+ fields:
+ createIndexes: string
+ indexes: array<NewIndexSpec>
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 26fd4faab3b..d2cc915c0a0 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -804,6 +804,8 @@ ExitCode _initAndListen(int listenPort) {
LogicalSessionCacheServer kind = LogicalSessionCacheServer::kStandalone;
if (serverGlobalParams.clusterRole == ClusterRole::ShardServer) {
kind = LogicalSessionCacheServer::kSharded;
+ } else if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) {
+ kind = LogicalSessionCacheServer::kConfigServer;
} else if (replSettings.usingReplSets()) {
kind = LogicalSessionCacheServer::kReplicaSet;
}
diff --git a/src/mongo/db/logical_session_cache_factory_mongod.cpp b/src/mongo/db/logical_session_cache_factory_mongod.cpp
index 0fdc1135d56..2672b41a4cc 100644
--- a/src/mongo/db/logical_session_cache_factory_mongod.cpp
+++ b/src/mongo/db/logical_session_cache_factory_mongod.cpp
@@ -36,6 +36,7 @@
#include "mongo/db/logical_session_cache_impl.h"
#include "mongo/db/service_liason_mongod.h"
+#include "mongo/db/sessions_collection_config_server.h"
#include "mongo/db/sessions_collection_rs.h"
#include "mongo/db/sessions_collection_sharded.h"
#include "mongo/db/sessions_collection_standalone.h"
@@ -51,6 +52,8 @@ std::shared_ptr<SessionsCollection> makeSessionsCollection(LogicalSessionCacheSe
switch (state) {
case LogicalSessionCacheServer::kSharded:
return std::make_shared<SessionsCollectionSharded>();
+ case LogicalSessionCacheServer::kConfigServer:
+ return std::make_shared<SessionsCollectionConfigServer>();
case LogicalSessionCacheServer::kReplicaSet:
return std::make_shared<SessionsCollectionRS>();
case LogicalSessionCacheServer::kStandalone:
diff --git a/src/mongo/db/logical_session_cache_factory_mongod.h b/src/mongo/db/logical_session_cache_factory_mongod.h
index b6ac0430fd0..faee5c56a1a 100644
--- a/src/mongo/db/logical_session_cache_factory_mongod.h
+++ b/src/mongo/db/logical_session_cache_factory_mongod.h
@@ -35,7 +35,7 @@
namespace mongo {
-enum class LogicalSessionCacheServer { kSharded, kReplicaSet, kStandalone };
+enum class LogicalSessionCacheServer { kSharded, kConfigServer, kReplicaSet, kStandalone };
class ServiceContext;
diff --git a/src/mongo/db/logical_session_cache_impl.cpp b/src/mongo/db/logical_session_cache_impl.cpp
index e52285edbbe..6cb5287f32b 100644
--- a/src/mongo/db/logical_session_cache_impl.cpp
+++ b/src/mongo/db/logical_session_cache_impl.cpp
@@ -35,6 +35,7 @@
#include "mongo/db/logical_session_id.h"
#include "mongo/db/logical_session_id_helpers.h"
#include "mongo/db/operation_context.h"
+#include "mongo/db/server_options.h"
#include "mongo/db/server_parameters.h"
#include "mongo/db/service_context.h"
#include "mongo/platform/atomic_word.h"
@@ -115,8 +116,6 @@ Status LogicalSessionCacheImpl::refreshSessions(OperationContext* opCtx,
Status LogicalSessionCacheImpl::refreshSessions(OperationContext* opCtx,
const RefreshSessionsCmdFromClusterMember& cmd) {
- LogicalSessionRecordSet toRefresh{};
-
// Update the timestamps of all these records in our cache.
auto records = cmd.getRefreshSessionsInternal();
for (const auto& record : records) {
@@ -124,11 +123,9 @@ Status LogicalSessionCacheImpl::refreshSessions(OperationContext* opCtx,
// This is a new record, insert it.
_addToCache(record);
}
- toRefresh.insert(record);
}
- // Write to the sessions collection now.
- return _sessionsColl->refreshSessions(opCtx, toRefresh);
+ return Status::OK();
}
void LogicalSessionCacheImpl::vivify(OperationContext* opCtx, const LogicalSessionId& lsid) {
@@ -201,6 +198,30 @@ Status LogicalSessionCacheImpl::_reap(Client* client) {
}
void LogicalSessionCacheImpl::_refresh(Client* client) {
+ // Do not run this job if we are not in FCV 3.6
+ if (!serverGlobalParams.featureCompatibility.isFullyUpgradedTo36()) {
+ LOG(1) << "Skipping session refresh job while feature compatibility version is not 3.6";
+ return;
+ }
+
+ // get or make an opCtx
+ boost::optional<ServiceContext::UniqueOperationContext> uniqueCtx;
+ auto* const opCtx = [&client, &uniqueCtx] {
+ if (client->getOperationContext()) {
+ return client->getOperationContext();
+ }
+
+ uniqueCtx.emplace(client->makeOperationContext());
+ return uniqueCtx->get();
+ }();
+
+ auto res = _sessionsColl->setupSessionsCollection(opCtx);
+ if (!res.isOK()) {
+ log() << "Sessions collection is not set up; "
+ << "waiting until next sessions refresh interval: " << res.reason();
+ return;
+ }
+
LogicalSessionIdSet staleSessions;
LogicalSessionIdSet explicitlyEndingSessions;
LogicalSessionIdMap<LogicalSessionRecord> activeSessions;
@@ -229,18 +250,6 @@ void LogicalSessionCacheImpl::_refresh(Client* client) {
auto activeSessionsBackSwapper = backSwapper(_activeSessions, activeSessions);
auto explicitlyEndingBackSwaper = backSwapper(_endingSessions, explicitlyEndingSessions);
- // get or make an opCtx
-
- boost::optional<ServiceContext::UniqueOperationContext> uniqueCtx;
- auto* const opCtx = [&client, &uniqueCtx] {
- if (client->getOperationContext()) {
- return client->getOperationContext();
- }
-
- uniqueCtx.emplace(client->makeOperationContext());
- return uniqueCtx->get();
- }();
-
// remove all explicitlyEndingSessions from activeSessions
for (const auto& lsid : explicitlyEndingSessions) {
activeSessions.erase(lsid);
diff --git a/src/mongo/db/logical_session_cache_test.cpp b/src/mongo/db/logical_session_cache_test.cpp
index 9001ab59a9a..5e96394a515 100644
--- a/src/mongo/db/logical_session_cache_test.cpp
+++ b/src/mongo/db/logical_session_cache_test.cpp
@@ -45,6 +45,7 @@
#include "mongo/db/sessions_collection_mock.h"
#include "mongo/stdx/future.h"
#include "mongo/stdx/memory.h"
+#include "mongo/unittest/ensure_fcv.h"
#include "mongo/unittest/unittest.h"
namespace mongo {
@@ -55,6 +56,7 @@ const Milliseconds kForceRefresh =
duration_cast<Milliseconds>(LogicalSessionCacheImpl::kLogicalSessionDefaultRefresh);
using SessionList = std::list<LogicalSessionId>;
+using unittest::EnsureFCV;
/**
* Test fixture that sets up a session cache attached to a mock service liason
@@ -64,7 +66,8 @@ class LogicalSessionCacheTest : public unittest::Test {
public:
LogicalSessionCacheTest()
: _service(std::make_shared<MockServiceLiasonImpl>()),
- _sessions(std::make_shared<MockSessionsCollectionImpl>()) {}
+ _sessions(std::make_shared<MockSessionsCollectionImpl>()),
+ _fcv(EnsureFCV::Version::k36) {}
void setUp() override {
auto localManagerState = stdx::make_unique<AuthzManagerExternalStateMock>();
@@ -137,6 +140,8 @@ private:
std::unique_ptr<LogicalSessionCache> _cache;
Client* _client;
+
+ EnsureFCV _fcv;
};
// Test that the getFromCache method does not make calls to the sessions collection
diff --git a/src/mongo/db/ops/insert.cpp b/src/mongo/db/ops/insert.cpp
index de02fda5642..8ed9abbd634 100644
--- a/src/mongo/db/ops/insert.cpp
+++ b/src/mongo/db/ops/insert.cpp
@@ -261,6 +261,12 @@ Status userAllowedCreateNS(StringData db, StringData coll) {
// some special rules
if (coll.find(".system.") != string::npos) {
+ // If this is metadata for the sessions collection, shard servers need to be able to
+ // write to it.
+ if (coll.find(".system.sessions") != string::npos) {
+ return Status::OK();
+ }
+
// this matches old (2.4 and older) behavior, but I'm not sure its a good idea
return Status(ErrorCodes::BadValue,
str::stream() << "cannot write to '" << db << "." << coll << "'");
diff --git a/src/mongo/db/sessions_collection.cpp b/src/mongo/db/sessions_collection.cpp
index 69e420f40b8..ec0d2f43a8b 100644
--- a/src/mongo/db/sessions_collection.cpp
+++ b/src/mongo/db/sessions_collection.cpp
@@ -35,6 +35,7 @@
#include "mongo/bson/bsonobjbuilder.h"
#include "mongo/client/dbclientinterface.h"
+#include "mongo/db/create_indexes_gen.h"
#include "mongo/db/logical_session_id.h"
#include "mongo/db/ops/write_ops.h"
#include "mongo/db/refresh_sessions_gen.h"
@@ -204,6 +205,7 @@ Status SessionsCollection::doRefresh(const NamespaceString& ns,
auto init = [ns](BSONObjBuilder* batch) {
batch->append("update", ns.coll());
batch->append("ordered", false);
+ batch->append("allowImplicitCollectionCreation", false);
};
auto add = [](BSONArrayBuilder* entries, const LogicalSessionRecord& record) {
@@ -309,4 +311,19 @@ StatusWith<LogicalSessionIdSet> SessionsCollection::doFetch(const NamespaceStrin
return removed;
}
+BSONObj SessionsCollection::generateCreateIndexesCmd() {
+ NewIndexSpec index;
+ index.setKey(BSON("lastUse" << 1));
+ index.setName("lsidTTLIndex");
+ index.setExpireAfterSeconds(localLogicalSessionTimeoutMinutes * 60);
+
+ std::vector<NewIndexSpec> indexes;
+ indexes.push_back(std::move(index));
+
+ CreateIndexesCmd createIndexes;
+ createIndexes.setCreateIndexes(kSessionsCollection.toString());
+ createIndexes.setIndexes(std::move(indexes));
+
+ return createIndexes.toBSON();
+}
} // namespace mongo
diff --git a/src/mongo/db/sessions_collection.h b/src/mongo/db/sessions_collection.h
index 63fd34667cf..3f6baaac2d0 100644
--- a/src/mongo/db/sessions_collection.h
+++ b/src/mongo/db/sessions_collection.h
@@ -56,6 +56,11 @@ public:
static const NamespaceString kSessionsNamespaceString;
/**
+ * Ensures that the sessions collection exists and has the proper indexes.
+ */
+ virtual Status setupSessionsCollection(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.
*/
@@ -83,6 +88,11 @@ public:
virtual StatusWith<LogicalSessionIdSet> findRemovedSessions(
OperationContext* opCtx, const LogicalSessionIdSet& sessions) = 0;
+ /**
+ * Generates a createIndexes command for the sessions collection TTL index.
+ */
+ static BSONObj generateCreateIndexesCmd();
+
protected:
/**
* Makes a send function for the given client.
diff --git a/src/mongo/db/sessions_collection_config_server.cpp b/src/mongo/db/sessions_collection_config_server.cpp
new file mode 100644
index 00000000000..9051a73f849
--- /dev/null
+++ b/src/mongo/db/sessions_collection_config_server.cpp
@@ -0,0 +1,117 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kControl
+
+#include "mongo/platform/basic.h"
+
+#include "mongo/db/sessions_collection_config_server.h"
+
+#include "mongo/client/query.h"
+#include "mongo/db/dbdirectclient.h"
+#include "mongo/db/logical_session_id.h"
+#include "mongo/db/operation_context.h"
+#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/s/client/shard_registry.h"
+#include "mongo/s/commands/cluster_commands_helpers.h"
+#include "mongo/s/grid.h"
+#include "mongo/s/request_types/shard_collection_gen.h"
+#include "mongo/util/log.h"
+
+namespace mongo {
+
+// Returns an error if the collection didn't exist and we couldn't
+// shard it into existence, either.
+Status SessionsCollectionConfigServer::_shardCollectionIfNeeded(OperationContext* opCtx) {
+ // First, check if the collection is already sharded.
+ auto res = _checkCacheForSessionsCollection(opCtx);
+ if (res.isOK()) {
+ return res;
+ }
+
+ // If we don't have any shards, we can't set up this collection yet.
+ if (Grid::get(opCtx)->shardRegistry()->getNumShards() == 0) {
+ return {ErrorCodes::ShardNotFound,
+ "Cannot create config.system.sessions until there are shards"};
+ }
+
+ // First, shard the sessions collection to create it.
+ ConfigsvrShardCollectionRequest shardCollection;
+ shardCollection.set_configsvrShardCollection(
+ NamespaceString(SessionsCollection::kSessionsFullNS.toString()));
+ shardCollection.setKey(BSON("_id" << 1));
+
+ DBDirectClient client(opCtx);
+ BSONObj info;
+ if (!client.runCommand("admin", shardCollection.toBSON(), info)) {
+ return getStatusFromCommandResult(info);
+ }
+
+ return Status::OK();
+}
+
+Status SessionsCollectionConfigServer::_generateIndexesIfNeeded(OperationContext* opCtx) {
+ auto res =
+ scatterGatherOnlyVersionIfUnsharded(opCtx,
+ SessionsCollection::kSessionsDb.toString(),
+ NamespaceString(SessionsCollection::kSessionsFullNS),
+ SessionsCollection::generateCreateIndexesCmd(),
+ ReadPreferenceSetting::get(opCtx),
+ Shard::RetryPolicy::kNoRetry);
+ return res.getStatus();
+}
+
+Status SessionsCollectionConfigServer::setupSessionsCollection(OperationContext* opCtx) {
+ stdx::lock_guard<stdx::mutex> lk(_mutex);
+ {
+ // Only try to set up this collection until we have done so successfully once.
+ // Note: if there is a config server election, it's possible that two different
+ // primaries could both run the createIndexes scatter-gather query; this is ok.
+ if (_collectionSetUp) {
+ return Status::OK();
+ }
+
+ auto res = _shardCollectionIfNeeded(opCtx);
+ if (!res.isOK()) {
+ log() << "Failed to create config.system.sessions: " << res.reason()
+ << ", will try again at the next refresh interval";
+ return res;
+ }
+
+ res = _generateIndexesIfNeeded(opCtx);
+ if (!res.isOK()) {
+ log() << "Failed to generate TTL index for config.system.sessions on all shards, "
+ << "will try again on the next refresh interval";
+ }
+
+ _collectionSetUp = true;
+ return res;
+ }
+}
+
+} // namespace mongo
diff --git a/src/mongo/db/sessions_collection_config_server.h b/src/mongo/db/sessions_collection_config_server.h
new file mode 100644
index 00000000000..2de7c109e41
--- /dev/null
+++ b/src/mongo/db/sessions_collection_config_server.h
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2017 MongoDB Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * As a special exception, the copyright holders give permission to link the
+ * code of portions of this program with the OpenSSL library under certain
+ * conditions as described in each individual source file and distribute
+ * linked combinations including the program with the OpenSSL library. You
+ * must comply with the GNU Affero General Public License in all respects for
+ * all of the code used other than as permitted herein. If you modify file(s)
+ * with this exception, you may extend this exception to your version of the
+ * file(s), but you are not obligated to do so. If you do not wish to do so,
+ * delete this exception statement from your version. If you delete this
+ * exception statement from all source files in the program, then also delete
+ * it in the license file.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "mongo/db/logical_session_id.h"
+#include "mongo/db/sessions_collection_sharded.h"
+#include "mongo/stdx/mutex.h"
+#include "mongo/util/time_support.h"
+
+namespace mongo {
+
+class OperationContext;
+
+/**
+ * Accesses the sessions collection for config servers.
+ */
+class SessionsCollectionConfigServer : public SessionsCollectionSharded {
+public:
+ /**
+ * Ensures that the sessions collection has been set up for this cluster,
+ * sharded, and with the proper indexes.
+ *
+ * This method may safely be called multiple times.
+ *
+ * If there are no shards in this cluster, this method will do nothing.
+ */
+ Status setupSessionsCollection(OperationContext* opCtx) override;
+
+private:
+ Status _shardCollectionIfNeeded(OperationContext* opCtx);
+ Status _generateIndexesIfNeeded(OperationContext* opCtx);
+
+ stdx::mutex _mutex;
+ bool _collectionSetUp;
+};
+
+} // namespace mongo
diff --git a/src/mongo/db/sessions_collection_mock.h b/src/mongo/db/sessions_collection_mock.h
index fb20533ed60..ff2c536467c 100644
--- a/src/mongo/db/sessions_collection_mock.h
+++ b/src/mongo/db/sessions_collection_mock.h
@@ -104,6 +104,10 @@ public:
explicit MockSessionsCollection(std::shared_ptr<MockSessionsCollectionImpl> impl)
: _impl(std::move(impl)) {}
+ Status setupSessionsCollection(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 4cfbffff3c3..cc65d9df574 100644
--- a/src/mongo/db/sessions_collection_rs.cpp
+++ b/src/mongo/db/sessions_collection_rs.cpp
@@ -44,6 +44,7 @@
#include "mongo/db/operation_context.h"
#include "mongo/db/repl/repl_set_config.h"
#include "mongo/db/repl/replication_coordinator.h"
+#include "mongo/rpc/get_status_from_command_result.h"
#include "mongo/stdx/memory.h"
namespace mongo {
@@ -131,6 +132,28 @@ auto dispatch(const NamespaceString& ns,
} // namespace
+Status SessionsCollectionRS::setupSessionsCollection(OperationContext* opCtx) {
+ return dispatch(kSessionsNamespaceString,
+ MODE_IX,
+ opCtx,
+ [&] {
+ // Creating the TTL index will auto-generate the collection.
+ DBDirectClient client(opCtx);
+ BSONObj info;
+ auto cmd = generateCreateIndexesCmd();
+ if (!client.runCommand(kSessionsDb.toString(), cmd, info)) {
+ return getStatusFromCommandResult(info);
+ }
+
+ return Status::OK();
+ },
+ [&](DBClientBase*) {
+ // If we are not the primary, we aren't going to do writes
+ // anyway, so just return ok.
+ return Status::OK();
+ });
+}
+
Status SessionsCollectionRS::refreshSessions(OperationContext* opCtx,
const LogicalSessionRecordSet& sessions) {
return dispatch(
diff --git a/src/mongo/db/sessions_collection_rs.h b/src/mongo/db/sessions_collection_rs.h
index 08459d6ff4f..88645bed5ad 100644
--- a/src/mongo/db/sessions_collection_rs.h
+++ b/src/mongo/db/sessions_collection_rs.h
@@ -54,6 +54,11 @@ public:
SessionsCollectionRS() = default;
/**
+ * Ensures that the sessions collection exists and has the proper indexes.
+ */
+ Status setupSessionsCollection(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 bbcf195d8dd..de7699eb962 100644
--- a/src/mongo/db/sessions_collection_sharded.cpp
+++ b/src/mongo/db/sessions_collection_sharded.cpp
@@ -35,7 +35,10 @@
#include "mongo/db/query/canonical_query.h"
#include "mongo/db/query/query_request.h"
#include "mongo/db/sessions_collection_rs.h"
+#include "mongo/rpc/get_status_from_command_result.h"
+#include "mongo/s/catalog_cache.h"
#include "mongo/s/commands/cluster_write.h"
+#include "mongo/s/grid.h"
#include "mongo/s/query/cluster_find.h"
#include "mongo/s/write_ops/batch_write_exec.h"
#include "mongo/s/write_ops/batched_command_request.h"
@@ -52,6 +55,26 @@ BSONObj lsidQuery(const LogicalSessionId& lsid) {
} // namespace
+Status SessionsCollectionSharded::_checkCacheForSessionsCollection(OperationContext* opCtx) {
+ // If the collection doesn't exist, fail. Only the config servers generate it.
+ auto res = Grid::get(opCtx)->catalogCache()->getShardedCollectionRoutingInfoWithRefresh(
+ opCtx, NamespaceString(SessionsCollection::kSessionsFullNS.toString()));
+ if (!res.isOK()) {
+ return res.getStatus();
+ }
+
+ auto routingInfo = res.getValue();
+ if (routingInfo.cm()) {
+ return Status::OK();
+ }
+
+ return {ErrorCodes::NamespaceNotFound, "config.system.sessions is not yet sharded"};
+}
+
+Status SessionsCollectionSharded::setupSessionsCollection(OperationContext* opCtx) {
+ return _checkCacheForSessionsCollection(opCtx);
+}
+
Status SessionsCollectionSharded::refreshSessions(OperationContext* opCtx,
const LogicalSessionRecordSet& sessions) {
auto send = [&](BSONObj toSend) {
diff --git a/src/mongo/db/sessions_collection_sharded.h b/src/mongo/db/sessions_collection_sharded.h
index 01ac730e09a..d8f5c6cf3f2 100644
--- a/src/mongo/db/sessions_collection_sharded.h
+++ b/src/mongo/db/sessions_collection_sharded.h
@@ -44,6 +44,12 @@ class OperationContext;
class SessionsCollectionSharded : public SessionsCollection {
public:
/**
+ * Ensures that the sessions collection exists, is sharded,
+ * and has the proper indexes.
+ */
+ Status setupSessionsCollection(OperationContext* opCtx) override;
+
+ /**
* Updates the last-use times on the given sessions to be greater than
* or equal to the current time.
*/
@@ -60,6 +66,9 @@ public:
Status removeTransactionRecords(OperationContext* opCtx,
const LogicalSessionIdSet& sessions) override;
+
+protected:
+ Status _checkCacheForSessionsCollection(OperationContext* opCtx);
};
} // namespace mongo
diff --git a/src/mongo/db/sessions_collection_standalone.cpp b/src/mongo/db/sessions_collection_standalone.cpp
index 84c2b4daae8..8fcc2acfbee 100644
--- a/src/mongo/db/sessions_collection_standalone.cpp
+++ b/src/mongo/db/sessions_collection_standalone.cpp
@@ -34,6 +34,7 @@
#include "mongo/client/query.h"
#include "mongo/db/dbdirectclient.h"
#include "mongo/db/operation_context.h"
+#include "mongo/rpc/get_status_from_command_result.h"
namespace mongo {
@@ -44,6 +45,17 @@ BSONObj lsidQuery(const LogicalSessionId& lsid) {
}
} // namespace
+Status SessionsCollectionStandalone::setupSessionsCollection(OperationContext* opCtx) {
+ DBDirectClient client(opCtx);
+ auto cmd = generateCreateIndexesCmd();
+ BSONObj info;
+ if (!client.runCommand(kSessionsDb.toString(), cmd, info)) {
+ return getStatusFromCommandResult(info);
+ }
+
+ 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 ad5f155dd64..9f12516f2ff 100644
--- a/src/mongo/db/sessions_collection_standalone.h
+++ b/src/mongo/db/sessions_collection_standalone.h
@@ -43,6 +43,11 @@ class OperationContext;
class SessionsCollectionStandalone : public SessionsCollection {
public:
/**
+ * Ensures that the sessions collection exists and has the proper indexes.
+ */
+ Status setupSessionsCollection(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/system_index.cpp b/src/mongo/db/system_index.cpp
index be95f1d0758..ccc6ccab06c 100644
--- a/src/mongo/db/system_index.cpp
+++ b/src/mongo/db/system_index.cpp
@@ -47,7 +47,6 @@
#include "mongo/db/db_raii.h"
#include "mongo/db/index/index_descriptor.h"
#include "mongo/db/jsobj.h"
-#include "mongo/db/logical_session_cache.h"
#include "mongo/util/assert_util.h"
#include "mongo/util/log.h"
@@ -59,13 +58,10 @@ namespace {
BSONObj v1SystemUsersKeyPattern;
BSONObj v3SystemUsersKeyPattern;
BSONObj v3SystemRolesKeyPattern;
-BSONObj v1SystemSessionsKeyPattern;
std::string v3SystemUsersIndexName;
std::string v3SystemRolesIndexName;
-std::string v1SystemSessionsIndexName;
IndexSpec v3SystemUsersIndexSpec;
IndexSpec v3SystemRolesIndexSpec;
-IndexSpec v1SystemSessionsIndexSpec;
const NamespaceString sessionCollectionNamespace("config.system.sessions");
@@ -77,7 +73,6 @@ MONGO_INITIALIZER(AuthIndexKeyPatterns)(InitializerContext*) {
v3SystemRolesKeyPattern = BSON(
AuthorizationManager::ROLE_NAME_FIELD_NAME << 1 << AuthorizationManager::ROLE_DB_FIELD_NAME
<< 1);
- v1SystemSessionsKeyPattern = BSON("lastUse" << 1);
v3SystemUsersIndexName =
std::string(str::stream() << AuthorizationManager::USER_NAME_FIELD_NAME << "_1_"
<< AuthorizationManager::USER_DB_FIELD_NAME
@@ -86,7 +81,6 @@ MONGO_INITIALIZER(AuthIndexKeyPatterns)(InitializerContext*) {
std::string(str::stream() << AuthorizationManager::ROLE_NAME_FIELD_NAME << "_1_"
<< AuthorizationManager::ROLE_DB_FIELD_NAME
<< "_1");
- v1SystemSessionsIndexName = "lastUse_1";
v3SystemUsersIndexSpec.addKeys(v3SystemUsersKeyPattern);
v3SystemUsersIndexSpec.unique();
@@ -96,11 +90,6 @@ MONGO_INITIALIZER(AuthIndexKeyPatterns)(InitializerContext*) {
v3SystemRolesIndexSpec.unique();
v3SystemRolesIndexSpec.name(v3SystemRolesIndexName);
- v1SystemSessionsIndexSpec.addKeys(v1SystemSessionsKeyPattern);
- v1SystemSessionsIndexSpec.expireAfterSeconds(
- durationCount<Seconds>(Minutes(localLogicalSessionTimeoutMinutes)));
- v1SystemSessionsIndexSpec.name(v1SystemSessionsIndexName);
-
return Status::OK();
}
@@ -200,33 +189,6 @@ Status verifySystemIndexes(OperationContext* opCtx) {
}
}
- // Create indexes for system collections in the config db.
- {
- AutoGetDb autoDb(opCtx, sessionCollectionNamespace.db(), MODE_X);
- if (!autoDb.getDb()) {
- return Status::OK();
- }
-
- // Ensure that system indexes exist for the sessions collection, if it exists.
- auto collection = autoDb.getDb()->getCollection(opCtx, sessionCollectionNamespace);
- if (collection) {
- IndexCatalog* indexCatalog = collection->getIndexCatalog();
- invariant(indexCatalog);
-
- std::vector<IndexDescriptor*> indexes;
- indexCatalog->findIndexesByKeyPattern(
- opCtx, v1SystemSessionsKeyPattern, false, &indexes);
- if (indexes.empty()) {
- try {
- generateSystemIndexForExistingCollection(
- opCtx, collection, sessionCollectionNamespace, v1SystemSessionsIndexSpec);
- } catch (...) {
- return exceptionToStatus();
- }
- }
- }
- }
-
return Status::OK();
}
@@ -249,14 +211,6 @@ void createSystemIndexes(OperationContext* opCtx, Collection* collection) {
fassertStatusOK(
40458, collection->getIndexCatalog()->createIndexOnEmptyCollection(opCtx, indexSpec));
- } else if (ns == sessionCollectionNamespace) {
- auto indexSpec = fassertStatusOK(
- 40493,
- index_key_validate::validateIndexSpec(
- v1SystemSessionsIndexSpec.toBSON(), ns, serverGlobalParams.featureCompatibility));
-
- fassertStatusOK(
- 40494, collection->getIndexCatalog()->createIndexOnEmptyCollection(opCtx, indexSpec));
}
}
diff --git a/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp b/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp
index 4c2e0e6e61b..5ce39eba1bf 100644
--- a/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_add_shard_test.cpp
@@ -120,6 +120,19 @@ protected:
});
}
+ void expectCollectionDrop(const HostAndPort& target, const NamespaceString& nss) {
+ onCommandForAddShard([&](const RemoteCommandRequest& request) {
+ ASSERT_EQ(request.target, target);
+ ASSERT_EQ(request.dbname, nss.db());
+ ASSERT_BSONOBJ_EQ(request.cmdObj,
+ BSON("drop" << nss.coll() << "writeConcern" << BSON("w"
+ << "majority")));
+ ASSERT_BSONOBJ_EQ(rpc::makeEmptyMetadata(), request.metadata);
+
+ return BSON("ok" << 1);
+ });
+ }
+
void expectSetFeatureCompatibilityVersion(const HostAndPort& target,
StatusWith<BSONObj> response) {
onCommandForAddShard([&, target, response](const RemoteCommandRequest& request) {
@@ -401,6 +414,8 @@ TEST_F(AddShardTest, StandaloneBasicSuccess) {
BSON("name" << discoveredDB1.getName() << "sizeOnDisk" << 2000),
BSON("name" << discoveredDB2.getName() << "sizeOnDisk" << 5000)});
+ expectCollectionDrop(shardTarget, NamespaceString("config", "system.sessions"));
+
// The shardIdentity doc inserted into the admin.system.version collection on the shard.
expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName);
@@ -484,6 +499,8 @@ TEST_F(AddShardTest, StandaloneGenerateName) {
BSON("name" << discoveredDB1.getName() << "sizeOnDisk" << 2000),
BSON("name" << discoveredDB2.getName() << "sizeOnDisk" << 5000)});
+ expectCollectionDrop(shardTarget, NamespaceString("config", "system.sessions"));
+
// The shardIdentity doc inserted into the admin.system.version collection on the shard.
expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName);
@@ -909,6 +926,8 @@ TEST_F(AddShardTest, SuccessfullyAddReplicaSet) {
// Get databases list from new shard
expectListDatabases(shardTarget, std::vector<BSONObj>{BSON("name" << discoveredDB.getName())});
+ expectCollectionDrop(shardTarget, NamespaceString("config", "system.sessions"));
+
// The shardIdentity doc inserted into the admin.system.version collection on the shard.
expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName);
@@ -974,6 +993,8 @@ TEST_F(AddShardTest, ReplicaSetExtraHostsDiscovered) {
// Get databases list from new shard
expectListDatabases(shardTarget, std::vector<BSONObj>{BSON("name" << discoveredDB.getName())});
+ expectCollectionDrop(shardTarget, NamespaceString("config", "system.sessions"));
+
// The shardIdentity doc inserted into the admin.system.version collection on the shard.
expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName);
@@ -1055,6 +1076,8 @@ TEST_F(AddShardTest, AddShardSucceedsEvenIfAddingDBsFromNewShardFails) {
BSON("name" << discoveredDB1.getName() << "sizeOnDisk" << 2000),
BSON("name" << discoveredDB2.getName() << "sizeOnDisk" << 5000)});
+ expectCollectionDrop(shardTarget, NamespaceString("config", "system.sessions"));
+
// The shardIdentity doc inserted into the admin.system.version collection on the shard.
expectShardIdentityUpsertReturnSuccess(shardTarget, expectedShardName);
diff --git a/src/mongo/s/catalog/sharding_catalog_manager.h b/src/mongo/s/catalog/sharding_catalog_manager.h
index e49fd77f727..ae5d181f58c 100644
--- a/src/mongo/s/catalog/sharding_catalog_manager.h
+++ b/src/mongo/s/catalog/sharding_catalog_manager.h
@@ -381,6 +381,12 @@ private:
const ConnectionString& connectionString);
/**
+ * Drops the sessions collection on the specified host.
+ */
+ Status _dropSessionsCollection(OperationContext* opCtx,
+ std::shared_ptr<RemoteCommandTargeter> targeter);
+
+ /**
* Runs the listDatabases command on the specified host and returns the names of all databases
* it returns excluding those named local, config and admin, since they serve administrative
* purposes.
diff --git a/src/mongo/s/catalog/sharding_catalog_manager_shard_operations.cpp b/src/mongo/s/catalog/sharding_catalog_manager_shard_operations.cpp
index e1ebbee383a..6aaa1b4f8bc 100644
--- a/src/mongo/s/catalog/sharding_catalog_manager_shard_operations.cpp
+++ b/src/mongo/s/catalog/sharding_catalog_manager_shard_operations.cpp
@@ -52,6 +52,7 @@
#include "mongo/db/repl/repl_set_config.h"
#include "mongo/db/repl/replication_coordinator.h"
#include "mongo/db/s/type_shard_identity.h"
+#include "mongo/db/sessions_collection.h"
#include "mongo/db/wire_version.h"
#include "mongo/executor/task_executor.h"
#include "mongo/rpc/get_status_from_command_result.h"
@@ -468,6 +469,30 @@ StatusWith<ShardType> ShardingCatalogManager::_validateHostAsShard(
return shard;
}
+Status ShardingCatalogManager::_dropSessionsCollection(
+ OperationContext* opCtx, std::shared_ptr<RemoteCommandTargeter> targeter) {
+
+ BSONObjBuilder builder;
+ builder.append("drop", SessionsCollection::kSessionsCollection.toString());
+ {
+ BSONObjBuilder wcBuilder(builder.subobjStart("writeConcern"));
+ wcBuilder.append("w", "majority");
+ }
+
+ auto swCommandResponse = _runCommandForAddShard(
+ opCtx, targeter.get(), SessionsCollection::kSessionsDb.toString(), builder.done());
+ if (!swCommandResponse.isOK()) {
+ return swCommandResponse.getStatus();
+ }
+
+ auto cmdStatus = std::move(swCommandResponse.getValue().commandStatus);
+ if (!cmdStatus.isOK() && cmdStatus.code() != ErrorCodes::NamespaceNotFound) {
+ return cmdStatus;
+ }
+
+ return Status::OK();
+}
+
StatusWith<std::vector<std::string>> ShardingCatalogManager::_getDBNamesListFromShard(
OperationContext* opCtx, std::shared_ptr<RemoteCommandTargeter> targeter) {
@@ -592,6 +617,18 @@ StatusWith<std::string> ShardingCatalogManager::addShard(
}
}
+ // Check that the shard candidate does not have a local config.system.sessions collection
+ auto res = _dropSessionsCollection(opCtx, targeter);
+
+ if (!res.isOK()) {
+ return Status(
+ res.code(),
+ str::stream()
+ << "can't add shard with a local copy of config.system.sessions due to "
+ << res.reason()
+ << ", please drop this collection from the shard manually and try again.");
+ }
+
// If a name for a shard wasn't provided, generate one
if (shardType.getName().empty()) {
auto result = generateNewShardName(opCtx);
diff --git a/src/mongo/s/client/shard_registry.cpp b/src/mongo/s/client/shard_registry.cpp
index a64eace6ba4..82c5471def1 100644
--- a/src/mongo/s/client/shard_registry.cpp
+++ b/src/mongo/s/client/shard_registry.cpp
@@ -170,6 +170,12 @@ void ShardRegistry::getAllShardIds(vector<ShardId>* all) const {
all->assign(seen.begin(), seen.end());
}
+int ShardRegistry::getNumShards() const {
+ std::set<ShardId> seen;
+ _data.getAllShardIds(seen);
+ return seen.size();
+}
+
void ShardRegistry::toBSON(BSONObjBuilder* result) const {
_data.toBSON(result);
}
diff --git a/src/mongo/s/client/shard_registry.h b/src/mongo/s/client/shard_registry.h
index 13b48b95ce4..af1f11e8f06 100644
--- a/src/mongo/s/client/shard_registry.h
+++ b/src/mongo/s/client/shard_registry.h
@@ -233,6 +233,8 @@ public:
std::shared_ptr<Shard> lookupRSName(const std::string& name) const;
void getAllShardIds(std::vector<ShardId>* all) const;
+ int getNumShards() const;
+
void toBSON(BSONObjBuilder* result) const;
bool isUp() const;
diff --git a/src/mongo/s/commands/cluster_remove_shard_cmd.cpp b/src/mongo/s/commands/cluster_remove_shard_cmd.cpp
index 4e5cea30cd2..b441f68c4fa 100644
--- a/src/mongo/s/commands/cluster_remove_shard_cmd.cpp
+++ b/src/mongo/s/commands/cluster_remove_shard_cmd.cpp
@@ -31,59 +31,48 @@
#include "mongo/platform/basic.h"
#include <string>
-#include <vector>
-#include "mongo/client/connpool.h"
#include "mongo/db/commands.h"
-#include "mongo/db/operation_context.h"
-#include "mongo/s/catalog/sharding_catalog_client.h"
-#include "mongo/s/catalog/type_chunk.h"
#include "mongo/s/client/shard.h"
#include "mongo/s/client/shard_registry.h"
-#include "mongo/s/commands/cluster_commands_helpers.h"
#include "mongo/s/grid.h"
#include "mongo/util/log.h"
namespace mongo {
-
-using std::string;
-using std::vector;
-
namespace {
class RemoveShardCmd : public BasicCommand {
public:
RemoveShardCmd() : BasicCommand("removeShard", "removeshard") {}
- virtual bool slaveOk() const {
- return false;
+ void help(std::stringstream& help) const override {
+ help << "remove a shard from the system.";
}
- virtual bool adminOnly() const {
- return true;
+ bool slaveOk() const override {
+ return false;
}
- virtual bool supportsWriteConcern(const BSONObj& cmd) const override {
+ bool adminOnly() const override {
return true;
}
- virtual void help(std::stringstream& help) const {
- help << "remove a shard from the system.";
+ bool supportsWriteConcern(const BSONObj& cmd) const override {
+ return true;
}
- virtual void addRequiredPrivileges(const std::string& dbname,
- const BSONObj& cmdObj,
- std::vector<Privilege>* out) {
+ void addRequiredPrivileges(const std::string& dbname,
+ const BSONObj& cmdObj,
+ std::vector<Privilege>* out) override {
ActionSet actions;
actions.addAction(ActionType::removeShard);
out->push_back(Privilege(ResourcePattern::forClusterResource(), actions));
}
- virtual bool run(OperationContext* opCtx,
- const std::string& dbname,
- const BSONObj& cmdObj,
- BSONObjBuilder& result) {
-
+ bool run(OperationContext* opCtx,
+ const std::string& dbname,
+ const BSONObj& cmdObj,
+ BSONObjBuilder& result) override {
uassert(ErrorCodes::TypeMismatch,
str::stream() << "Field '" << cmdObj.firstElement().fieldName()
<< "' must be of type string",
diff --git a/src/mongo/shell/shardingtest.js b/src/mongo/shell/shardingtest.js
index 5ee8132e2c9..cc46c16b7c5 100644
--- a/src/mongo/shell/shardingtest.js
+++ b/src/mongo/shell/shardingtest.js
@@ -1506,6 +1506,20 @@ var ShardingTest = function(params) {
return true;
}, "waiting for all mongos servers to return cluster times", 60 * 1000, 500);
}
+
+ // Ensure that the sessions collection exists so jstests can run things with
+ // logical sessions and test them. We do this by forcing an immediate cache refresh
+ // on the config server, which auto-shards the collection for the cluster.
+ var lastStableBinVersion = MongoRunner.getBinVersionFor('last-stable');
+ if ((!otherParams.configOptions) ||
+ (otherParams.configOptions && !otherParams.configOptions.binVersion) ||
+ (otherParams.configOptions && otherParams.configOptions.binVersion &&
+ MongoRunner.areBinVersionsTheSame(
+ lastStableBinVersion,
+ MongoRunner.getBinVersionFor(otherParams.configOptions.binVersion)))) {
+ this.configRS.getPrimary().getDB("admin").runCommand({refreshLogicalSessionCacheNow: 1});
+ }
+
};
// Stub for a hook to check that collection UUIDs are consistent across shards and the config