1
2 /**
3 * Copyright (C) 2018-present MongoDB, Inc.
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the Server Side Public License, version 1,
7 * as published by MongoDB, Inc.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * Server Side Public License for more details.
13 *
14 * You should have received a copy of the Server Side Public License
15 * along with this program. If not, see
16 * <http://www.mongodb.com/licensing/server-side-public-license>.
17 *
18 * As a special exception, the copyright holders give permission to link the
19 * code of portions of this program with the OpenSSL library under certain
20 * conditions as described in each individual source file and distribute
21 * linked combinations including the program with the OpenSSL library. You
22 * must comply with the Server Side Public License in all respects for
23 * all of the code used other than as permitted herein. If you modify file(s)
24 * with this exception, you may extend this exception to your version of the
25 * file(s), but you are not obligated to do so. If you do not wish to do so,
26 * delete this exception statement from your version. If you delete this
27 * exception statement from all source files in the program, then also delete
28 * it in the license file.
29 */
30
31 #define MONGO_LOG_DEFAULT_COMPONENT ::mongo::logger::LogComponent::kStorage
32
33 #include "mongo/platform/basic.h"
34
35 #include "mongo/db/dbmain.h"
36
37 #include <boost/filesystem/operations.hpp>
38 #include <boost/optional.hpp>
39 #include <fstream>
40 #include <iostream>
41 #include <limits>
42 #include <signal.h>
43 #include <string>
44
45 #include "mongo/base/checked_cast.h"
46 #include "mongo/base/init.h"
47 #include "mongo/base/initializer.h"
48 #include "mongo/base/status.h"
49 #include "mongo/client/global_conn_pool.h"
50 #include "mongo/client/replica_set_monitor.h"
51 #include "mongo/config.h"
52 #include "mongo/db/audit.h"
53 #include "mongo/db/auth/authorization_manager.h"
54 #include "mongo/db/auth/authorization_manager_global.h"
55 #include "mongo/db/auth/sasl_options.h"
56 #include "mongo/db/catalog/collection.h"
57 #include "mongo/db/catalog/create_collection.h"
58 #include "mongo/db/catalog/database.h"
59 #include "mongo/db/catalog/database_catalog_entry.h"
60 #include "mongo/db/catalog/database_holder.h"
61 #include "mongo/db/catalog/health_log.h"
62 #include "mongo/db/catalog/index_catalog.h"
63 #include "mongo/db/catalog/index_key_validate.h"
64 #include "mongo/db/client.h"
65 #include "mongo/db/clientcursor.h"
66 #include "mongo/db/commands/feature_compatibility_version.h"
67 #include "mongo/db/concurrency/d_concurrency.h"
68 #include "mongo/db/concurrency/lock_state.h"
69 #include "mongo/db/concurrency/write_conflict_exception.h"
70 #include "mongo/db/db_raii.h"
71 #include "mongo/db/dbdirectclient.h"
72 #include "mongo/db/dbhelpers.h"
73 #include "mongo/db/dbmessage.h"
74 #include "mongo/db/exec/working_set_common.h"
75 #include "mongo/db/ftdc/ftdc_mongod.h"
76 #include "mongo/db/generic_cursor_manager.h"
77 #include "mongo/db/generic_cursor_manager_mongod.h"
78 #include "mongo/db/index_names.h"
79 #include "mongo/db/index_rebuilder.h"
80 #include "mongo/db/initialize_server_global_state.h"
81 #include "mongo/db/initialize_snmp.h"
82 #include "mongo/db/introspect.h"
83 #include "mongo/db/json.h"
84 #include "mongo/db/keys_collection_client_direct.h"
85 #include "mongo/db/keys_collection_client_sharded.h"
86 #include "mongo/db/keys_collection_manager.h"
87 #include "mongo/db/keys_collection_manager_sharding.h"
88 #include "mongo/db/kill_sessions.h"
89 #include "mongo/db/kill_sessions_local.h"
90 #include "mongo/db/log_process_details.h"
91 #include "mongo/db/logical_clock.h"
92 #include "mongo/db/logical_session_cache.h"
93 #include "mongo/db/logical_session_cache_factory_mongod.h"
94 #include "mongo/db/logical_time_metadata_hook.h"
95 #include "mongo/db/logical_time_validator.h"
96 #include "mongo/db/mongod_options.h"
97 #include "mongo/db/op_observer_impl.h"
98 #include "mongo/db/operation_context.h"
99 #include "mongo/db/query/internal_plans.h"
100 #include "mongo/db/repair_database.h"
101 #include "mongo/db/repl/drop_pending_collection_reaper.h"
102 #include "mongo/db/repl/oplog.h"
103 #include "mongo/db/repl/repl_settings.h"
104 #include "mongo/db/repl/replication_consistency_markers_impl.h"
105 #include "mongo/db/repl/replication_coordinator_external_state_impl.h"
106 #include "mongo/db/repl/replication_coordinator_global.h"
107 #include "mongo/db/repl/replication_coordinator_impl.h"
108 #include "mongo/db/repl/replication_process.h"
109 #include "mongo/db/repl/replication_recovery.h"
110 #include "mongo/db/repl/storage_interface_impl.h"
111 #include "mongo/db/repl/topology_coordinator.h"
112 #include "mongo/db/s/balancer/balancer.h"
113 #include "mongo/db/s/sharded_connection_info.h"
114 #include "mongo/db/s/sharding_initialization_mongod.h"
115 #include "mongo/db/s/sharding_state.h"
116 #include "mongo/db/s/sharding_state_recovery.h"
117 #include "mongo/db/s/type_shard_identity.h"
118 #include "mongo/db/server_options.h"
119 #include "mongo/db/server_parameters.h"
120 #include "mongo/db/service_context.h"
121 #include "mongo/db/service_context_d.h"
122 #include "mongo/db/service_entry_point_mongod.h"
123 #include "mongo/db/session_catalog.h"
124 #include "mongo/db/session_killer.h"
125 #include "mongo/db/startup_warnings_mongod.h"
126 #include "mongo/db/stats/counters.h"
127 #include "mongo/db/storage/encryption_hooks.h"
128 #include "mongo/db/storage/mmap_v1/mmap_v1_options.h"
129 #include "mongo/db/storage/storage_engine.h"
130 #include "mongo/db/storage/storage_engine_lock_file.h"
131 #include "mongo/db/storage/storage_options.h"
132 #include "mongo/db/system_index.h"
133 #include "mongo/db/ttl.h"
134 #include "mongo/db/wire_version.h"
135 #include "mongo/executor/network_connection_hook.h"
136 #include "mongo/executor/network_interface_factory.h"
137 #include "mongo/executor/network_interface_thread_pool.h"
138 #include "mongo/executor/thread_pool_task_executor.h"
139 #include "mongo/platform/process_id.h"
140 #include "mongo/platform/random.h"
141 #include "mongo/rpc/metadata/egress_metadata_hook_list.h"
142 #include "mongo/s/catalog/sharding_catalog_manager.h"
143 #include "mongo/s/client/shard_registry.h"
144 #include "mongo/s/grid.h"
145 #include "mongo/s/sharding_initialization.h"
146 #include "mongo/scripting/dbdirectclient_factory.h"
147 #include "mongo/scripting/engine.h"
148 #include "mongo/stdx/future.h"
149 #include "mongo/stdx/memory.h"
150 #include "mongo/stdx/thread.h"
151 #include "mongo/transport/transport_layer_manager.h"
152 #include "mongo/util/assert_util.h"
153 #include "mongo/util/background.h"
154 #include "mongo/util/cmdline_utils/censor_cmdline.h"
155 #include "mongo/util/concurrency/idle_thread_block.h"
156 #include "mongo/util/concurrency/thread_name.h"
157 #include "mongo/util/exception_filter_win32.h"
158 #include "mongo/util/exit.h"
159 #include "mongo/util/fail_point_service.h"
160 #include "mongo/util/fast_clock_source_factory.h"
161 #include "mongo/util/log.h"
162 #include "mongo/util/net/listen.h"
163 #include "mongo/util/net/ssl_manager.h"
164 #include "mongo/util/ntservice.h"
165 #include "mongo/util/options_parser/startup_options.h"
166 #include "mongo/util/periodic_runner.h"
167 #include "mongo/util/periodic_runner_factory.h"
168 #include "mongo/util/quick_exit.h"
169 #include "mongo/util/ramlog.h"
170 #include "mongo/util/scopeguard.h"
171 #include "mongo/util/sequence_util.h"
172 #include "mongo/util/signal_handlers.h"
173 #include "mongo/util/stacktrace.h"
174 #include "mongo/util/startup_test.h"
175 #include "mongo/util/text.h"
176 #include "mongo/util/time_support.h"
177 #include "mongo/util/version.h"
178
179 #ifdef MONGO_CONFIG_SSL
180 #include "mongo/util/net/ssl_options.h"
181 #endif
182
183 #if !defined(_WIN32)
184 #include <sys/file.h>
185 #endif
186
187 namespace mongo {
188
189 using logger::LogComponent;
190 using std::endl;
191
192 namespace {
193
194 constexpr StringData upgradeLink = "http://dochub.mongodb.org/core/3.6-upgrade-fcv"_sd;
195 constexpr StringData mustDowngradeErrorMsg =
196 "UPGRADE PROBLEM: The data files need to be fully upgraded to version 3.4 before attempting an upgrade to 3.6; see http://dochub.mongodb.org/core/3.6-upgrade-fcv for more details."_sd;
197
restoreMissingFeatureCompatibilityVersionDocument(OperationContext * opCtx,const std::vector<std::string> & dbNames)198 Status restoreMissingFeatureCompatibilityVersionDocument(OperationContext* opCtx,
199 const std::vector<std::string>& dbNames) {
200 bool isMmapV1 = opCtx->getServiceContext()->getGlobalStorageEngine()->isMmapV1();
201 // Check whether there are any collections with UUIDs.
202 bool collsHaveUuids = false;
203 bool allCollsHaveUuids = true;
204 for (const auto& dbName : dbNames) {
205 Database* db = dbHolder().openDb(opCtx, dbName);
206 invariant(db);
207 for (auto collectionIt = db->begin(); collectionIt != db->end(); ++collectionIt) {
208 Collection* coll = *collectionIt;
209 if (coll->uuid()) {
210 collsHaveUuids = true;
211 } else if (!coll->uuid() && (!isMmapV1 ||
212 !(coll->ns().coll() == "system.indexes" ||
213 coll->ns().coll() == "system.namespaces"))) {
214 // Exclude system.indexes and system.namespaces from the UUID check until
215 // SERVER-29926 and SERVER-30095 are addressed, respectively.
216 allCollsHaveUuids = false;
217 }
218 }
219 }
220
221 if (!collsHaveUuids) {
222 return {ErrorCodes::MustDowngrade, mustDowngradeErrorMsg};
223 }
224
225 // Restore the featureCompatibilityVersion document if it is missing.
226 NamespaceString nss(FeatureCompatibilityVersion::kCollection);
227
228 Database* db = dbHolder().get(opCtx, nss.db());
229
230 // If the admin database does not exist, create it.
231 if (!db) {
232 log() << "Re-creating admin database that was dropped.";
233 }
234
235 db = dbHolder().openDb(opCtx, nss.db());
236 invariant(db);
237
238 // If admin.system.version does not exist, create it without a UUID.
239 if (!db->getCollection(opCtx, FeatureCompatibilityVersion::kCollection)) {
240 log() << "Re-creating admin.system.version collection that was dropped.";
241 allCollsHaveUuids = false;
242 BSONObjBuilder bob;
243 bob.append("create", nss.coll());
244 BSONObj createObj = bob.done();
245 uassertStatusOK(createCollection(opCtx, nss.db().toString(), createObj));
246 }
247
248 Collection* versionColl = db->getCollection(opCtx, FeatureCompatibilityVersion::kCollection);
249 invariant(versionColl);
250 BSONObj featureCompatibilityVersion;
251 if (!Helpers::findOne(opCtx,
252 versionColl,
253 BSON("_id" << FeatureCompatibilityVersion::kParameterName),
254 featureCompatibilityVersion)) {
255 log() << "Re-creating featureCompatibilityVersion document that was deleted.";
256 BSONObjBuilder bob;
257 bob.append("_id", FeatureCompatibilityVersion::kParameterName);
258 if (allCollsHaveUuids) {
259 // If all collections have UUIDs, create a featureCompatibilityVersion document with
260 // version equal to 3.6.
261 bob.append(FeatureCompatibilityVersion::kVersionField,
262 FeatureCompatibilityVersionCommandParser::kVersion36);
263 } else {
264 // If some collections do not have UUIDs, create a featureCompatibilityVersion document
265 // with version equal to 3.4 and targetVersion 3.6.
266 bob.append(FeatureCompatibilityVersion::kVersionField,
267 FeatureCompatibilityVersionCommandParser::kVersion34);
268 bob.append(FeatureCompatibilityVersion::kTargetVersionField,
269 FeatureCompatibilityVersionCommandParser::kVersion36);
270 }
271 auto fcvObj = bob.done();
272 writeConflictRetry(opCtx, "insertFCVDocument", nss.ns(), [&] {
273 WriteUnitOfWork wunit(opCtx);
274 OpDebug* const nullOpDebug = nullptr;
275 uassertStatusOK(
276 versionColl->insertDocument(opCtx, InsertStatement(fcvObj), nullOpDebug, false));
277 wunit.commit();
278 });
279 }
280 invariant(Helpers::findOne(opCtx,
281 versionColl,
282 BSON("_id" << FeatureCompatibilityVersion::kParameterName),
283 featureCompatibilityVersion));
284 return Status::OK();
285 }
286
287 const NamespaceString startupLogCollectionName("local.startup_log");
288 const NamespaceString kSystemReplSetCollection("local.system.replset");
289
290 MONGO_EXPORT_SERVER_PARAMETER(waitForStepDownOnNonCommandShutdown, bool, true);
291
292 #ifdef _WIN32
293 const ntservice::NtServiceDefaultStrings defaultServiceStrings = {
294 L"MongoDB", L"MongoDB", L"MongoDB Server"};
295 #endif
296
logStartup(OperationContext * opCtx)297 void logStartup(OperationContext* opCtx) {
298 BSONObjBuilder toLog;
299 std::stringstream id;
300 id << getHostNameCached() << "-" << jsTime().asInt64();
301 toLog.append("_id", id.str());
302 toLog.append("hostname", getHostNameCached());
303
304 toLog.appendTimeT("startTime", time(0));
305 toLog.append("startTimeLocal", dateToCtimeString(Date_t::now()));
306
307 toLog.append("cmdLine", serverGlobalParams.parsedOpts);
308 toLog.append("pid", ProcessId::getCurrent().asLongLong());
309
310
311 BSONObjBuilder buildinfo(toLog.subobjStart("buildinfo"));
312 VersionInfoInterface::instance().appendBuildInfo(&buildinfo);
313 appendStorageEngineList(&buildinfo);
314 buildinfo.doneFast();
315
316 BSONObj o = toLog.obj();
317
318 Lock::GlobalWrite lk(opCtx);
319 AutoGetOrCreateDb autoDb(opCtx, startupLogCollectionName.db(), mongo::MODE_X);
320 Database* db = autoDb.getDb();
321 Collection* collection = db->getCollection(opCtx, startupLogCollectionName);
322 WriteUnitOfWork wunit(opCtx);
323 if (!collection) {
324 BSONObj options = BSON("capped" << true << "size" << 10 * 1024 * 1024);
325 repl::UnreplicatedWritesBlock uwb(opCtx);
326 uassertStatusOK(userCreateNS(opCtx, db, startupLogCollectionName.ns(), options));
327 collection = db->getCollection(opCtx, startupLogCollectionName);
328 }
329 invariant(collection);
330
331 OpDebug* const nullOpDebug = nullptr;
332 uassertStatusOK(collection->insertDocument(opCtx, InsertStatement(o), nullOpDebug, false));
333 wunit.commit();
334 }
335
336 /**
337 * If we are in a replset, every replicated collection must have an _id index.
338 * As we scan each database, we also gather a list of drop-pending collection namespaces for
339 * the DropPendingCollectionReaper to clean up eventually.
340 */
checkForIdIndexesAndDropPendingCollections(OperationContext * opCtx,Database * db)341 void checkForIdIndexesAndDropPendingCollections(OperationContext* opCtx, Database* db) {
342 if (db->name() == "local") {
343 // Collections in the local database are not replicated, so we do not need an _id index on
344 // any collection. For the same reason, it is not possible for the local database to contain
345 // any drop-pending collections (drops are effective immediately).
346 return;
347 }
348
349 std::list<std::string> collectionNames;
350 db->getDatabaseCatalogEntry()->getCollectionNamespaces(&collectionNames);
351
352 for (const auto& collectionName : collectionNames) {
353 const NamespaceString ns(collectionName);
354
355 if (ns.isDropPendingNamespace()) {
356 auto dropOpTime = fassertStatusOK(40459, ns.getDropPendingNamespaceOpTime());
357 log() << "Found drop-pending namespace " << ns << " with drop optime " << dropOpTime;
358 repl::DropPendingCollectionReaper::get(opCtx)->addDropPendingNamespace(dropOpTime, ns);
359 }
360
361 if (ns.isSystem())
362 continue;
363
364 Collection* coll = db->getCollection(opCtx, collectionName);
365 if (!coll)
366 continue;
367
368 if (coll->getIndexCatalog()->findIdIndex(opCtx))
369 continue;
370
371 log() << "WARNING: the collection '" << collectionName << "' lacks a unique index on _id."
372 << " This index is needed for replication to function properly" << startupWarningsLog;
373 log() << "\t To fix this, you need to create a unique index on _id."
374 << " See http://dochub.mongodb.org/core/build-replica-set-indexes"
375 << startupWarningsLog;
376 }
377 }
378
379 /**
380 * Checks if this server was started without --replset but has a config in local.system.replset
381 * (meaning that this is probably a replica set member started in stand-alone mode).
382 *
383 * @returns the number of documents in local.system.replset or 0 if this was started with
384 * --replset.
385 */
checkIfReplMissingFromCommandLine(OperationContext * opCtx)386 unsigned long long checkIfReplMissingFromCommandLine(OperationContext* opCtx) {
387 // This is helpful for the query below to work as you can't open files when readlocked
388 Lock::GlobalWrite lk(opCtx);
389 if (!repl::getGlobalReplicationCoordinator()->getSettings().usingReplSets()) {
390 DBDirectClient c(opCtx);
391 return c.count(kSystemReplSetCollection.ns());
392 }
393 return 0;
394 }
395
396 /**
397 * Check that the oplog is capped, and abort the process if it is not.
398 * Caller must lock DB before calling this function.
399 */
checkForCappedOplog(OperationContext * opCtx,Database * db)400 void checkForCappedOplog(OperationContext* opCtx, Database* db) {
401 const NamespaceString oplogNss(NamespaceString::kRsOplogNamespace);
402 invariant(opCtx->lockState()->isDbLockedForMode(oplogNss.db(), MODE_IS));
403 Collection* oplogCollection = db->getCollection(opCtx, oplogNss);
404 if (oplogCollection && !oplogCollection->isCapped()) {
405 severe() << "The oplog collection " << oplogNss
406 << " is not capped; a capped oplog is a requirement for replication to function.";
407 fassertFailedNoTrace(40115);
408 }
409 }
410
411 /**
412 * Return an error status if the wrong mongod version was used for these datafiles. The boolean
413 * represents whether there are non-local databases.
414 */
repairDatabasesAndCheckVersion(OperationContext * opCtx)415 StatusWith<bool> repairDatabasesAndCheckVersion(OperationContext* opCtx) {
416 LOG(1) << "enter repairDatabases (to check pdfile version #)";
417
418 auto const storageEngine = opCtx->getServiceContext()->getGlobalStorageEngine();
419
420 Lock::GlobalWrite lk(opCtx);
421
422 std::vector<std::string> dbNames;
423 storageEngine->listDatabases(&dbNames);
424
425 // Repair all databases first, so that we do not try to open them if they are in bad shape
426 if (storageGlobalParams.repair) {
427 invariant(!storageGlobalParams.readOnly);
428 for (const auto& dbName : dbNames) {
429 LOG(1) << " Repairing database: " << dbName;
430 fassert(18506, repairDatabase(opCtx, storageEngine, dbName));
431 }
432
433 // Attempt to restore the featureCompatibilityVersion document if it is missing.
434 NamespaceString nss(FeatureCompatibilityVersion::kCollection);
435
436 Database* db = dbHolder().get(opCtx, nss.db());
437 Collection* versionColl;
438 BSONObj featureCompatibilityVersion;
439 if (!db || !(versionColl = db->getCollection(opCtx, nss)) ||
440 !Helpers::findOne(opCtx,
441 versionColl,
442 BSON("_id" << FeatureCompatibilityVersion::kParameterName),
443 featureCompatibilityVersion)) {
444 auto status = restoreMissingFeatureCompatibilityVersionDocument(opCtx, dbNames);
445 if (!status.isOK()) {
446 return status;
447 }
448 }
449 }
450
451 const repl::ReplSettings& replSettings = repl::getGlobalReplicationCoordinator()->getSettings();
452
453 if (!storageGlobalParams.readOnly) {
454 StatusWith<std::vector<StorageEngine::CollectionIndexNamePair>> swIndexesToRebuild =
455 storageEngine->reconcileCatalogAndIdents(opCtx);
456 fassertStatusOK(40593, swIndexesToRebuild);
457 for (auto&& collIndexPair : swIndexesToRebuild.getValue()) {
458 const std::string& coll = collIndexPair.first;
459 const std::string& indexName = collIndexPair.second;
460 DatabaseCatalogEntry* dbce =
461 storageEngine->getDatabaseCatalogEntry(opCtx, NamespaceString(coll).db());
462 invariant(dbce);
463 CollectionCatalogEntry* cce = dbce->getCollectionCatalogEntry(coll);
464 invariant(cce);
465
466 StatusWith<IndexNameObjs> swIndexToRebuild(
467 getIndexNameObjs(opCtx, dbce, cce, [&indexName](const std::string& str) {
468 return str == indexName;
469 }));
470 if (!swIndexToRebuild.isOK() || swIndexToRebuild.getValue().first.empty()) {
471 severe() << "Unable to get indexes for collection. Collection: " << coll;
472 fassertFailedNoTrace(40590);
473 }
474
475 invariant(swIndexToRebuild.getValue().first.size() == 1 &&
476 swIndexToRebuild.getValue().second.size() == 1);
477 fassertStatusOK(
478 40592, rebuildIndexesOnCollection(opCtx, dbce, cce, swIndexToRebuild.getValue()));
479 }
480
481 // We open the "local" database before calling checkIfReplMissingFromCommandLine() to
482 // ensure the in-memory catalog entries for the 'kSystemReplSetCollection' collection have
483 // been populated if the collection exists. If the "local" database didn't exist at this
484 // point yet, then it will be created. If the mongod is running in a read-only mode, then
485 // it is fine to not open the "local" database and populate the catalog entries because we
486 // won't attempt to drop the temporary collections anyway.
487 Lock::DBLock dbLock(opCtx, kSystemReplSetCollection.db(), MODE_X);
488 dbHolder().openDb(opCtx, kSystemReplSetCollection.db());
489 }
490
491 // On replica set members we only clear temp collections on DBs other than "local" during
492 // promotion to primary. On pure slaves, they are only cleared when the oplog tells them
493 // to. The local DB is special because it is not replicated. See SERVER-10927 for more
494 // details.
495 const bool shouldClearNonLocalTmpCollections =
496 !(checkIfReplMissingFromCommandLine(opCtx) || replSettings.usingReplSets() ||
497 replSettings.isSlave());
498
499 // To check whether we are upgrading to 3.6 or have already upgraded to 3.6.
500 bool collsHaveUuids = false;
501
502 // To check whether a featureCompatibilityVersion document exists.
503 bool fcvDocumentExists = false;
504
505 // To check whether we have databases other than local.
506 bool nonLocalDatabases = false;
507
508 // Refresh list of database names to include newly-created admin, if it exists.
509 dbNames.clear();
510 storageEngine->listDatabases(&dbNames);
511 for (const auto& dbName : dbNames) {
512 if (dbName != "local") {
513 nonLocalDatabases = true;
514 }
515 LOG(1) << " Recovering database: " << dbName;
516
517 Database* db = dbHolder().openDb(opCtx, dbName);
518 invariant(db);
519
520 // First thing after opening the database is to check for file compatibility,
521 // otherwise we might crash if this is a deprecated format.
522 auto status = db->getDatabaseCatalogEntry()->currentFilesCompatible(opCtx);
523 if (!status.isOK()) {
524 if (status.code() == ErrorCodes::CanRepairToDowngrade) {
525 // Convert CanRepairToDowngrade statuses to MustUpgrade statuses to avoid logging a
526 // potentially confusing and inaccurate message.
527 //
528 // TODO SERVER-24097: Log a message informing the user that they can start the
529 // current version of mongod with --repair and then proceed with normal startup.
530 status = {ErrorCodes::MustUpgrade, status.reason()};
531 }
532 severe() << "Unable to start mongod due to an incompatibility with the data files and"
533 " this version of mongod: "
534 << redact(status);
535 severe() << "Please consult our documentation when trying to downgrade to a previous"
536 " major release";
537 quickExit(EXIT_NEED_UPGRADE);
538 MONGO_UNREACHABLE;
539 }
540
541 // Check if admin.system.version contains an invalid featureCompatibilityVersion.
542 // If a valid featureCompatibilityVersion is present, cache it as a server parameter.
543 if (dbName == "admin") {
544 if (Collection* versionColl =
545 db->getCollection(opCtx, FeatureCompatibilityVersion::kCollection)) {
546 BSONObj featureCompatibilityVersion;
547 if (Helpers::findOne(opCtx,
548 versionColl,
549 BSON("_id" << FeatureCompatibilityVersion::kParameterName),
550 featureCompatibilityVersion)) {
551 auto swVersion =
552 FeatureCompatibilityVersion::parse(featureCompatibilityVersion);
553 if (!swVersion.isOK()) {
554 severe() << swVersion.getStatus();
555 // Note this error path captures all cases of an FCV document existing,
556 // but with any value other than "3.4" or "3.6". This includes unexpected
557 // cases with no path forward such as the FCV value not being a string.
558 return {ErrorCodes::MustDowngrade,
559 str::stream()
560 << "UPGRADE PROBLEM: Unable to parse the "
561 "featureCompatibilityVersion document. The data files need "
562 "to be fully upgraded to version 3.4 before attempting an "
563 "upgrade to 3.6. If you are upgrading to 3.6, see "
564 << upgradeLink
565 << "."};
566 }
567 fcvDocumentExists = true;
568 auto version = swVersion.getValue();
569 serverGlobalParams.featureCompatibility.setVersion(version);
570 FeatureCompatibilityVersion::updateMinWireVersion();
571
572 // On startup, if the version is in an upgrading or downrading state, print a
573 // warning.
574 if (version ==
575 ServerGlobalParams::FeatureCompatibility::Version::kUpgradingTo36) {
576 log() << "** WARNING: A featureCompatibilityVersion upgrade did not "
577 << "complete." << startupWarningsLog;
578 log() << "** The current featureCompatibilityVersion is "
579 << FeatureCompatibilityVersion::toString(version) << "."
580 << startupWarningsLog;
581 log() << "** To fix this, use the setFeatureCompatibilityVersion "
582 << "command to resume upgrade to 3.6." << startupWarningsLog;
583 } else if (version == ServerGlobalParams::FeatureCompatibility::Version::
584 kDowngradingTo34) {
585 log() << "** WARNING: A featureCompatibilityVersion downgrade did not "
586 << "complete. " << startupWarningsLog;
587 log() << "** The current featureCompatibilityVersion is "
588 << FeatureCompatibilityVersion::toString(version) << "."
589 << startupWarningsLog;
590 log() << "** To fix this, use the setFeatureCompatibilityVersion "
591 << "command to resume downgrade to 3.4." << startupWarningsLog;
592 }
593 }
594 }
595 }
596
597 // Iterate through collections and check for UUIDs.
598 for (auto collectionIt = db->begin(); !collsHaveUuids && collectionIt != db->end();
599 ++collectionIt) {
600 Collection* coll = *collectionIt;
601 if (coll->uuid()) {
602 collsHaveUuids = true;
603 }
604 }
605
606 // Major versions match, check indexes
607 const NamespaceString systemIndexes(db->name(), "system.indexes");
608
609 Collection* coll = db->getCollection(opCtx, systemIndexes);
610 auto exec = InternalPlanner::collectionScan(
611 opCtx, systemIndexes.ns(), coll, PlanExecutor::NO_YIELD);
612
613 BSONObj index;
614 PlanExecutor::ExecState state;
615 while (PlanExecutor::ADVANCED == (state = exec->getNext(&index, NULL))) {
616 const BSONObj key = index.getObjectField("key");
617 const auto plugin = IndexNames::findPluginName(key);
618
619 if (db->getDatabaseCatalogEntry()->isOlderThan24(opCtx)) {
620 if (IndexNames::existedBefore24(plugin)) {
621 continue;
622 }
623
624 log() << "Index " << index << " claims to be of type '" << plugin << "', "
625 << "which is either invalid or did not exist before v2.4. "
626 << "See the upgrade section: "
627 << "http://dochub.mongodb.org/core/upgrade-2.4" << startupWarningsLog;
628 }
629
630 if (index["v"].isNumber() && index["v"].numberInt() == 0) {
631 log() << "WARNING: The index: " << index << " was created with the deprecated"
632 << " v:0 format. This format will not be supported in a future release."
633 << startupWarningsLog;
634 log() << "\t To fix this, you need to rebuild this index."
635 << " For instructions, see http://dochub.mongodb.org/core/rebuild-v0-indexes"
636 << startupWarningsLog;
637 }
638 }
639
640 // Non-yielding collection scans from InternalPlanner will never error.
641 invariant(PlanExecutor::IS_EOF == state);
642
643 if (replSettings.usingReplSets()) {
644 // We only care about _id indexes and drop-pending collections if we are in a replset.
645 checkForIdIndexesAndDropPendingCollections(opCtx, db);
646 // Ensure oplog is capped (mmap does not guarantee order of inserts on noncapped
647 // collections)
648 if (db->name() == "local") {
649 checkForCappedOplog(opCtx, db);
650 }
651 }
652
653 if (!storageGlobalParams.readOnly &&
654 (shouldClearNonLocalTmpCollections || dbName == "local")) {
655 db->clearTmpCollections(opCtx);
656 }
657 }
658
659 // Fail to start up if there is no featureCompatibilityVersion document and there are non-local
660 // databases present.
661 if (!fcvDocumentExists && nonLocalDatabases) {
662 if (collsHaveUuids) {
663 severe()
664 << "Unable to start up mongod due to missing featureCompatibilityVersion document.";
665 if (opCtx->getServiceContext()->getGlobalStorageEngine()->isMmapV1()) {
666 severe()
667 << "Please run with --journalOptions "
668 << static_cast<int>(MMAPV1Options::JournalRecoverOnly)
669 << " to recover the journal. Then run with --repair to restore the document.";
670 } else {
671 severe() << "Please run with --repair to restore the document.";
672 }
673 fassertFailedNoTrace(40652);
674 } else {
675 return {ErrorCodes::MustDowngrade, mustDowngradeErrorMsg};
676 }
677 }
678
679 LOG(1) << "done repairDatabases";
680 return nonLocalDatabases;
681 }
682
initWireSpec()683 void initWireSpec() {
684 WireSpec& spec = WireSpec::instance();
685
686 // The featureCompatibilityVersion behavior defaults to the downgrade behavior while the
687 // in-memory version is unset.
688
689 spec.incomingInternalClient.minWireVersion = RELEASE_2_4_AND_BEFORE;
690 spec.incomingInternalClient.maxWireVersion = LATEST_WIRE_VERSION;
691
692 spec.outgoing.minWireVersion = RELEASE_2_4_AND_BEFORE;
693 spec.outgoing.maxWireVersion = LATEST_WIRE_VERSION;
694
695 spec.isInternalClient = true;
696 }
697
698 MONGO_FP_DECLARE(shutdownAtStartup);
699
_initAndListen(int listenPort)700 ExitCode _initAndListen(int listenPort) {
701 Client::initThread("initandlisten");
702
703 initWireSpec();
704 auto serviceContext = checked_cast<ServiceContextMongoD*>(getGlobalServiceContext());
705
706 serviceContext->setFastClockSource(FastClockSourceFactory::create(Milliseconds(10)));
707 serviceContext->setOpObserver(stdx::make_unique<OpObserverImpl>());
708
709 DBDirectClientFactory::get(serviceContext).registerImplementation([](OperationContext* opCtx) {
710 return std::unique_ptr<DBClientBase>(new DBDirectClient(opCtx));
711 });
712
713 const repl::ReplSettings& replSettings =
714 repl::ReplicationCoordinator::get(serviceContext)->getSettings();
715
716 {
717 ProcessId pid = ProcessId::getCurrent();
718 LogstreamBuilder l = log(LogComponent::kControl);
719 l << "MongoDB starting : pid=" << pid << " port=" << serverGlobalParams.port
720 << " dbpath=" << storageGlobalParams.dbpath;
721 if (replSettings.isMaster())
722 l << " master=" << replSettings.isMaster();
723 if (replSettings.isSlave())
724 l << " slave=" << (int)replSettings.isSlave();
725
726 const bool is32bit = sizeof(int*) == 4;
727 l << (is32bit ? " 32" : " 64") << "-bit host=" << getHostNameCached() << endl;
728 }
729
730 DEV log(LogComponent::kControl) << "DEBUG build (which is slower)" << endl;
731
732 #if defined(_WIN32)
733 VersionInfoInterface::instance().logTargetMinOS();
734 #endif
735
736 logProcessDetails();
737
738 serviceContext->createLockFile();
739
740 serviceContext->setServiceEntryPoint(
741 stdx::make_unique<ServiceEntryPointMongod>(serviceContext));
742
743 {
744 auto tl =
745 transport::TransportLayerManager::createWithConfig(&serverGlobalParams, serviceContext);
746 auto res = tl->setup();
747 if (!res.isOK()) {
748 error() << "Failed to set up listener: " << res;
749 return EXIT_NET_ERROR;
750 }
751 serviceContext->setTransportLayer(std::move(tl));
752 }
753
754 serviceContext->initializeGlobalStorageEngine();
755
756 #ifdef MONGO_CONFIG_WIREDTIGER_ENABLED
757 if (EncryptionHooks::get(serviceContext)->restartRequired()) {
758 exitCleanly(EXIT_CLEAN);
759 }
760 #endif
761
762 // Warn if we detect configurations for multiple registered storage engines in the same
763 // configuration file/environment.
764 if (serverGlobalParams.parsedOpts.hasField("storage")) {
765 BSONElement storageElement = serverGlobalParams.parsedOpts.getField("storage");
766 invariant(storageElement.isABSONObj());
767 for (auto&& e : storageElement.Obj()) {
768 // Ignore if field name under "storage" matches current storage engine.
769 if (storageGlobalParams.engine == e.fieldName()) {
770 continue;
771 }
772
773 // Warn if field name matches non-active registered storage engine.
774 if (serviceContext->isRegisteredStorageEngine(e.fieldName())) {
775 warning() << "Detected configuration for non-active storage engine "
776 << e.fieldName() << " when current storage engine is "
777 << storageGlobalParams.engine;
778 }
779 }
780 }
781
782 logMongodStartupWarnings(storageGlobalParams, serverGlobalParams, serviceContext);
783
784 #ifdef MONGO_CONFIG_SSL
785 if (sslGlobalParams.sslAllowInvalidCertificates &&
786 ((serverGlobalParams.clusterAuthMode.load() == ServerGlobalParams::ClusterAuthMode_x509) ||
787 sequenceContains(saslGlobalParams.authenticationMechanisms, "MONGODB-X509"))) {
788 log() << "** WARNING: While invalid X509 certificates may be used to" << startupWarningsLog;
789 log() << "** connect to this server, they will not be considered"
790 << startupWarningsLog;
791 log() << "** permissible for authentication." << startupWarningsLog;
792 log() << startupWarningsLog;
793 }
794 #endif
795
796 {
797 std::stringstream ss;
798 ss << endl;
799 ss << "*********************************************************************" << endl;
800 ss << " ERROR: dbpath (" << storageGlobalParams.dbpath << ") does not exist." << endl;
801 ss << " Create this directory or give existing directory in --dbpath." << endl;
802 ss << " See http://dochub.mongodb.org/core/startingandstoppingmongo" << endl;
803 ss << "*********************************************************************" << endl;
804 uassert(10296, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.dbpath));
805 }
806
807 {
808 std::stringstream ss;
809 ss << "repairpath (" << storageGlobalParams.repairpath << ") does not exist";
810 uassert(12590, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.repairpath));
811 }
812
813 initializeSNMP();
814
815 if (!storageGlobalParams.readOnly) {
816 boost::filesystem::remove_all(storageGlobalParams.dbpath + "/_tmp/");
817 }
818
819 if (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalRecoverOnly)
820 return EXIT_NET_ERROR;
821
822 if (mongodGlobalParams.scriptingEnabled) {
823 ScriptEngine::setup();
824 }
825
826 auto startupOpCtx = serviceContext->makeOperationContext(&cc());
827
828 bool canCallFCVSetIfCleanStartup = !storageGlobalParams.readOnly &&
829 !(replSettings.isSlave() || storageGlobalParams.engine == "devnull");
830 if (canCallFCVSetIfCleanStartup && !replSettings.usingReplSets()) {
831 Lock::GlobalWrite lk(startupOpCtx.get());
832 FeatureCompatibilityVersion::setIfCleanStartup(startupOpCtx.get(),
833 repl::StorageInterface::get(serviceContext));
834 }
835
836 auto swNonLocalDatabases = repairDatabasesAndCheckVersion(startupOpCtx.get());
837 if (!swNonLocalDatabases.isOK()) {
838 // SERVER-31611 introduced a return value to `repairDatabasesAndCheckVersion`. Previously,
839 // a failing condition would fassert. SERVER-31611 covers a case where the binary (3.6) is
840 // refusing to start up because it refuses acknowledgement of FCV 3.2 and requires the
841 // user to start up with an older binary. Thus shutting down the server must leave the
842 // datafiles in a state that the older binary can start up. This requires going through a
843 // clean shutdown.
844 //
845 // The invariant is *not* a statement that `repairDatabasesAndCheckVersion` must return
846 // `MustDowngrade`. Instead, it is meant as a guardrail to protect future developers from
847 // accidentally buying into this behavior. New errors that are returned from the method
848 // may or may not want to go through a clean shutdown, and they likely won't want the
849 // program to return an exit code of `EXIT_NEED_DOWNGRADE`.
850 severe(LogComponent::kControl) << "** IMPORTANT: "
851 << swNonLocalDatabases.getStatus().reason();
852 invariant(swNonLocalDatabases == ErrorCodes::MustDowngrade);
853 exitCleanly(EXIT_NEED_DOWNGRADE);
854 }
855
856 // Assert that the in-memory featureCompatibilityVersion parameter has been explicitly set. If
857 // we are part of a replica set and are started up with no data files, we do not set the
858 // featureCompatibilityVersion until a primary is chosen. For this case, we expect the in-memory
859 // featureCompatibilityVersion parameter to still be uninitialized until after startup.
860 if (canCallFCVSetIfCleanStartup &&
861 (!replSettings.usingReplSets() || swNonLocalDatabases.getValue())) {
862 invariant(serverGlobalParams.featureCompatibility.isVersionInitialized());
863 }
864
865 if (storageGlobalParams.upgrade) {
866 log() << "finished checking dbs";
867 exitCleanly(EXIT_CLEAN);
868 }
869
870 // Start up health log writer thread.
871 HealthLog::get(startupOpCtx.get()).startup();
872
873 auto const globalAuthzManager = AuthorizationManager::get(serviceContext);
874 uassertStatusOK(globalAuthzManager->initialize(startupOpCtx.get()));
875
876 // This is for security on certain platforms (nonce generation)
877 srand((unsigned)(curTimeMicros64()) ^ (unsigned(uintptr_t(&startupOpCtx))));
878
879 if (globalAuthzManager->shouldValidateAuthSchemaOnStartup()) {
880 Status status = verifySystemIndexes(startupOpCtx.get());
881 if (!status.isOK()) {
882 log() << redact(status);
883 if (status == ErrorCodes::AuthSchemaIncompatible) {
884 exitCleanly(EXIT_NEED_UPGRADE);
885 } else if (status == ErrorCodes::NotMaster) {
886 // Try creating the indexes if we become master. If we do not become master,
887 // the master will create the indexes and we will replicate them.
888 } else {
889 quickExit(EXIT_FAILURE);
890 }
891 }
892
893 // SERVER-14090: Verify that auth schema version is schemaVersion26Final.
894 int foundSchemaVersion;
895 status =
896 globalAuthzManager->getAuthorizationVersion(startupOpCtx.get(), &foundSchemaVersion);
897 if (!status.isOK()) {
898 log() << "Auth schema version is incompatible: "
899 << "User and role management commands require auth data to have "
900 << "at least schema version " << AuthorizationManager::schemaVersion26Final
901 << " but startup could not verify schema version: " << status;
902 exitCleanly(EXIT_NEED_UPGRADE);
903 }
904
905 if (foundSchemaVersion < AuthorizationManager::schemaVersion26Final) {
906 log() << "Auth schema version is incompatible: "
907 << "User and role management commands require auth data to have "
908 << "at least schema version " << AuthorizationManager::schemaVersion26Final
909 << " but found " << foundSchemaVersion << ". In order to upgrade "
910 << "the auth schema, first downgrade MongoDB binaries to version "
911 << "2.6 and then run the authSchemaUpgrade command.";
912 exitCleanly(EXIT_NEED_UPGRADE);
913 }
914
915 if (foundSchemaVersion <= AuthorizationManager::schemaVersion26Final) {
916 log() << startupWarningsLog;
917 log() << "** WARNING: This server is using MONGODB-CR, a deprecated authentication "
918 << "mechanism." << startupWarningsLog;
919 log() << "** Support will be dropped in a future release."
920 << startupWarningsLog;
921 log() << "** See http://dochub.mongodb.org/core/3.0-upgrade-to-scram-sha-1"
922 << startupWarningsLog;
923 }
924 } else if (globalAuthzManager->isAuthEnabled()) {
925 error() << "Auth must be disabled when starting without auth schema validation";
926 exitCleanly(EXIT_BADOPTIONS);
927 } else {
928 // If authSchemaValidation is disabled and server is running without auth,
929 // warn the user and continue startup without authSchema metadata checks.
930 log() << startupWarningsLog;
931 log() << "** WARNING: Startup auth schema validation checks are disabled for the "
932 "database."
933 << startupWarningsLog;
934 log() << "** This mode should only be used to manually repair corrupted auth "
935 "data."
936 << startupWarningsLog;
937 }
938
939 SessionCatalog::create(serviceContext);
940
941 // This function may take the global lock.
942 auto shardingInitialized =
943 uassertStatusOK(ShardingState::get(startupOpCtx.get())
944 ->initializeShardingAwarenessIfNeeded(startupOpCtx.get()));
945 if (shardingInitialized) {
946 waitForShardRegistryReload(startupOpCtx.get()).transitional_ignore();
947 }
948
949 if (!storageGlobalParams.readOnly) {
950 logStartup(startupOpCtx.get());
951
952 startMongoDFTDC();
953
954 restartInProgressIndexesFromLastShutdown(startupOpCtx.get());
955
956 if (serverGlobalParams.clusterRole == ClusterRole::ShardServer) {
957 // Note: For replica sets, ShardingStateRecovery happens on transition to primary.
958 if (!repl::getGlobalReplicationCoordinator()->isReplEnabled()) {
959 uassertStatusOK(ShardingStateRecovery::recover(startupOpCtx.get()));
960 }
961 } else if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) {
962 ShardedConnectionInfo::addHook(startupOpCtx->getServiceContext());
963
964 uassertStatusOK(
965 initializeGlobalShardingStateForMongod(startupOpCtx.get(),
966 ConnectionString::forLocal(),
967 kDistLockProcessIdForConfigServer));
968
969 Balancer::create(startupOpCtx->getServiceContext());
970
971 ShardingCatalogManager::create(
972 startupOpCtx->getServiceContext(),
973 makeShardingTaskExecutor(executor::makeNetworkInterface("AddShard-TaskExecutor")));
974
975 Grid::get(startupOpCtx.get())->setShardingInitialized();
976 } else if (replSettings.usingReplSets()) { // standalone replica set
977 auto keysCollectionClient = stdx::make_unique<KeysCollectionClientDirect>();
978 auto keyManager = std::make_shared<KeysCollectionManagerSharding>(
979 KeysCollectionManager::kKeyManagerPurposeString,
980 std::move(keysCollectionClient),
981 Seconds(KeysRotationIntervalSec));
982 keyManager->startMonitoring(startupOpCtx->getServiceContext());
983
984 LogicalTimeValidator::set(startupOpCtx->getServiceContext(),
985 stdx::make_unique<LogicalTimeValidator>(keyManager));
986 }
987
988 repl::ReplicationCoordinator::get(startupOpCtx.get())->startup(startupOpCtx.get());
989 const unsigned long long missingRepl =
990 checkIfReplMissingFromCommandLine(startupOpCtx.get());
991 if (missingRepl) {
992 log() << startupWarningsLog;
993 log() << "** WARNING: mongod started without --replSet yet " << missingRepl
994 << " documents are present in local.system.replset" << startupWarningsLog;
995 log() << "** Restart with --replSet unless you are doing maintenance and "
996 << " no other clients are connected." << startupWarningsLog;
997 log() << "** The TTL collection monitor will not start because of this."
998 << startupWarningsLog;
999 log() << "** ";
1000 log() << " For more info see http://dochub.mongodb.org/core/ttlcollections";
1001 log() << startupWarningsLog;
1002 } else {
1003 startTTLBackgroundJob();
1004 }
1005
1006 if (replSettings.usingReplSets() || (!replSettings.isMaster() && replSettings.isSlave()) ||
1007 !internalValidateFeaturesAsMaster) {
1008 serverGlobalParams.validateFeaturesAsMaster.store(false);
1009 }
1010 }
1011
1012 startClientCursorMonitor();
1013
1014 PeriodicTask::startRunningPeriodicTasks();
1015
1016 // Set up the periodic runner for background job execution
1017 auto runner = makePeriodicRunner(serviceContext);
1018 runner->startup();
1019 serviceContext->setPeriodicRunner(std::move(runner));
1020
1021 SessionKiller::set(serviceContext,
1022 std::make_shared<SessionKiller>(serviceContext, killSessionsLocal));
1023
1024 GenericCursorManager::set(serviceContext, stdx::make_unique<GenericCursorManagerMongod>());
1025
1026 // Set up the logical session cache
1027 LogicalSessionCacheServer kind = LogicalSessionCacheServer::kStandalone;
1028 if (serverGlobalParams.clusterRole == ClusterRole::ShardServer) {
1029 kind = LogicalSessionCacheServer::kSharded;
1030 } else if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) {
1031 kind = LogicalSessionCacheServer::kConfigServer;
1032 } else if (replSettings.usingReplSets()) {
1033 kind = LogicalSessionCacheServer::kReplicaSet;
1034 }
1035
1036 auto sessionCache = makeLogicalSessionCacheD(serviceContext, kind);
1037 LogicalSessionCache::set(serviceContext, std::move(sessionCache));
1038
1039 // MessageServer::run will return when exit code closes its socket and we don't need the
1040 // operation context anymore
1041 startupOpCtx.reset();
1042
1043 auto start = serviceContext->getServiceExecutor()->start();
1044 if (!start.isOK()) {
1045 error() << "Failed to start the service executor: " << start;
1046 return EXIT_NET_ERROR;
1047 }
1048
1049 start = serviceContext->getServiceEntryPoint()->start();
1050 if (!start.isOK()) {
1051 error() << "Failed to start the service entry point: " << start;
1052 return EXIT_NET_ERROR;
1053 }
1054
1055 start = serviceContext->getTransportLayer()->start();
1056 if (!start.isOK()) {
1057 error() << "Failed to start the listener: " << start.toString();
1058 return EXIT_NET_ERROR;
1059 }
1060
1061 serviceContext->notifyStartupComplete();
1062
1063 #ifndef _WIN32
1064 mongo::signalForkSuccess();
1065 #else
1066 if (ntservice::shouldStartService()) {
1067 ntservice::reportStatus(SERVICE_RUNNING);
1068 log() << "Service running";
1069 }
1070 #endif
1071
1072 if (MONGO_FAIL_POINT(shutdownAtStartup)) {
1073 log() << "starting clean exit via failpoint";
1074 exitCleanly(EXIT_CLEAN);
1075 }
1076
1077 MONGO_IDLE_THREAD_BLOCK;
1078 return waitForShutdown();
1079 }
1080
initAndListen(int listenPort)1081 ExitCode initAndListen(int listenPort) {
1082 try {
1083 return _initAndListen(listenPort);
1084 } catch (DBException& e) {
1085 log() << "exception in initAndListen: " << e.toString() << ", terminating";
1086 return EXIT_UNCAUGHT;
1087 } catch (std::exception& e) {
1088 log() << "exception in initAndListen std::exception: " << e.what() << ", terminating";
1089 return EXIT_UNCAUGHT;
1090 } catch (int& n) {
1091 log() << "exception in initAndListen int: " << n << ", terminating";
1092 return EXIT_UNCAUGHT;
1093 } catch (...) {
1094 log() << "exception in initAndListen, terminating";
1095 return EXIT_UNCAUGHT;
1096 }
1097 }
1098
1099 #if defined(_WIN32)
initService()1100 ExitCode initService() {
1101 return initAndListen(serverGlobalParams.port);
1102 }
1103 #endif
1104
1105 MONGO_INITIALIZER_GENERAL(ForkServer, ("EndStartupOptionHandling"), ("default"))
1106 (InitializerContext* context) {
1107 mongo::forkServerOrDie();
1108 return Status::OK();
1109 }
1110
1111 /*
1112 * This function should contain the startup "actions" that we take based on the startup config.
1113 * It is intended to separate the actions from "storage" and "validation" of our startup
1114 * configuration.
1115 */
startupConfigActions(const std::vector<std::string> & args)1116 void startupConfigActions(const std::vector<std::string>& args) {
1117 // The "command" option is deprecated. For backward compatibility, still support the "run"
1118 // and "dbppath" command. The "run" command is the same as just running mongod, so just
1119 // falls through.
1120 if (moe::startupOptionsParsed.count("command")) {
1121 const auto command = moe::startupOptionsParsed["command"].as<std::vector<std::string>>();
1122
1123 if (command[0].compare("dbpath") == 0) {
1124 std::cout << storageGlobalParams.dbpath << endl;
1125 quickExit(EXIT_SUCCESS);
1126 }
1127
1128 if (command[0].compare("run") != 0) {
1129 std::cout << "Invalid command: " << command[0] << endl;
1130 printMongodHelp(moe::startupOptions);
1131 quickExit(EXIT_FAILURE);
1132 }
1133
1134 if (command.size() > 1) {
1135 std::cout << "Too many parameters to 'run' command" << endl;
1136 printMongodHelp(moe::startupOptions);
1137 quickExit(EXIT_FAILURE);
1138 }
1139 }
1140
1141 #ifdef _WIN32
1142 ntservice::configureService(initService,
1143 moe::startupOptionsParsed,
1144 defaultServiceStrings,
1145 std::vector<std::string>(),
1146 args);
1147 #endif // _WIN32
1148
1149 #ifdef __linux__
1150 if (moe::startupOptionsParsed.count("shutdown") &&
1151 moe::startupOptionsParsed["shutdown"].as<bool>() == true) {
1152 bool failed = false;
1153
1154 std::string name =
1155 (boost::filesystem::path(storageGlobalParams.dbpath) / kLockFileBasename.toString())
1156 .string();
1157 if (!boost::filesystem::exists(name) || boost::filesystem::file_size(name) == 0)
1158 failed = true;
1159
1160 pid_t pid;
1161 std::string procPath;
1162 if (!failed) {
1163 try {
1164 std::ifstream f(name.c_str());
1165 f >> pid;
1166 procPath = (str::stream() << "/proc/" << pid);
1167 if (!boost::filesystem::exists(procPath))
1168 failed = true;
1169 } catch (const std::exception& e) {
1170 std::cerr << "Error reading pid from lock file [" << name << "]: " << e.what()
1171 << endl;
1172 failed = true;
1173 }
1174 }
1175
1176 if (failed) {
1177 std::cerr << "There doesn't seem to be a server running with dbpath: "
1178 << storageGlobalParams.dbpath << std::endl;
1179 quickExit(EXIT_FAILURE);
1180 }
1181
1182 std::cout << "killing process with pid: " << pid << endl;
1183 int ret = kill(pid, SIGTERM);
1184 if (ret) {
1185 int e = errno;
1186 std::cerr << "failed to kill process: " << errnoWithDescription(e) << endl;
1187 quickExit(EXIT_FAILURE);
1188 }
1189
1190 while (boost::filesystem::exists(procPath)) {
1191 sleepsecs(1);
1192 }
1193
1194 quickExit(EXIT_SUCCESS);
1195 }
1196 #endif
1197 }
1198
makeReplicationExecutor(ServiceContext * serviceContext)1199 auto makeReplicationExecutor(ServiceContext* serviceContext) {
1200 ThreadPool::Options tpOptions;
1201 tpOptions.poolName = "replexec";
1202 tpOptions.maxThreads = 50;
1203 tpOptions.onCreateThread = [](const std::string& threadName) {
1204 Client::initThread(threadName.c_str());
1205 };
1206 auto hookList = stdx::make_unique<rpc::EgressMetadataHookList>();
1207 hookList->addHook(stdx::make_unique<rpc::LogicalTimeMetadataHook>(serviceContext));
1208 return stdx::make_unique<executor::ThreadPoolTaskExecutor>(
1209 stdx::make_unique<ThreadPool>(tpOptions),
1210 executor::makeNetworkInterface(
1211 "NetworkInterfaceASIO-Replication", nullptr, std::move(hookList)));
1212 }
1213
1214 MONGO_INITIALIZER_WITH_PREREQUISITES(CreateReplicationManager,
1215 ("SetGlobalEnvironment", "SSLManager", "default"))
1216 (InitializerContext* context) {
1217 auto serviceContext = getGlobalServiceContext();
1218 repl::StorageInterface::set(serviceContext, stdx::make_unique<repl::StorageInterfaceImpl>());
1219 auto storageInterface = repl::StorageInterface::get(serviceContext);
1220
1221 auto consistencyMarkers =
1222 stdx::make_unique<repl::ReplicationConsistencyMarkersImpl>(storageInterface);
1223 auto recovery = stdx::make_unique<repl::ReplicationRecoveryImpl>(storageInterface,
1224 consistencyMarkers.get());
1225 repl::ReplicationProcess::set(
1226 serviceContext,
1227 stdx::make_unique<repl::ReplicationProcess>(
1228 storageInterface, std::move(consistencyMarkers), std::move(recovery)));
1229 auto replicationProcess = repl::ReplicationProcess::get(serviceContext);
1230
1231 repl::DropPendingCollectionReaper::set(
1232 serviceContext, stdx::make_unique<repl::DropPendingCollectionReaper>(storageInterface));
1233 auto dropPendingCollectionReaper = repl::DropPendingCollectionReaper::get(serviceContext);
1234
1235 repl::TopologyCoordinator::Options topoCoordOptions;
1236 topoCoordOptions.maxSyncSourceLagSecs = Seconds(repl::maxSyncSourceLagSecs);
1237 topoCoordOptions.clusterRole = serverGlobalParams.clusterRole;
1238
1239 auto logicalClock = stdx::make_unique<LogicalClock>(serviceContext);
1240 LogicalClock::set(serviceContext, std::move(logicalClock));
1241
1242 auto replCoord = stdx::make_unique<repl::ReplicationCoordinatorImpl>(
1243 serviceContext,
1244 getGlobalReplSettings(),
1245 stdx::make_unique<repl::ReplicationCoordinatorExternalStateImpl>(
1246 serviceContext, dropPendingCollectionReaper, storageInterface, replicationProcess),
1247 makeReplicationExecutor(serviceContext),
1248 stdx::make_unique<repl::TopologyCoordinator>(topoCoordOptions),
1249 replicationProcess,
1250 storageInterface,
1251 SecureRandom::create()->nextInt64());
1252 repl::ReplicationCoordinator::set(serviceContext, std::move(replCoord));
1253 repl::setOplogCollectionName();
1254 return Status::OK();
1255 }
1256
1257 #ifdef MONGO_CONFIG_SSL
1258 MONGO_INITIALIZER_GENERAL(setSSLManagerType, MONGO_NO_PREREQUISITES, ("SSLManager"))
1259 (InitializerContext* context) {
1260 isSSLServer = true;
1261 return Status::OK();
1262 }
1263 #endif
1264
1265 #if !defined(__has_feature)
1266 #define __has_feature(x) 0
1267 #endif
1268
1269 // NOTE: This function may be called at any time after registerShutdownTask is called below. It
1270 // must not depend on the prior execution of mongo initializers or the existence of threads.
shutdownTask(const ShutdownTaskArgs & shutdownArgs)1271 void shutdownTask(const ShutdownTaskArgs& shutdownArgs) {
1272 // This client initiation pattern is only to be used here, with plans to eliminate this pattern
1273 // down the line.
1274 if (!haveClient())
1275 Client::initThread(getThreadName());
1276
1277 auto const client = Client::getCurrent();
1278 auto const serviceContext = client->getServiceContext();
1279
1280 // If we don't have shutdownArgs, we're shutting down from a signal, or other clean shutdown
1281 // path.
1282 //
1283 // In that case, do a default step down, still shutting down if stepDown fails.
1284 {
1285 auto replCoord = repl::ReplicationCoordinator::get(serviceContext);
1286 if (replCoord && !shutdownArgs.isUserInitiated) {
1287 replCoord->enterTerminalShutdown();
1288 ServiceContext::UniqueOperationContext uniqueOpCtx;
1289 OperationContext* opCtx = client->getOperationContext();
1290 if (!opCtx) {
1291 uniqueOpCtx = client->makeOperationContext();
1292 opCtx = uniqueOpCtx.get();
1293 }
1294
1295 // If this is a single node replica set, then we don't have to wait
1296 // for any secondaries. Ignore stepdown.
1297 if (repl::ReplicationCoordinator::get(serviceContext)->getConfig().getNumMembers() !=
1298 1) {
1299 try {
1300 // For faster tests, we allow a short wait time with setParameter.
1301 auto waitTime = waitForStepDownOnNonCommandShutdown.load()
1302 ? Milliseconds(Seconds(10))
1303 : Milliseconds(100);
1304
1305 uassertStatusOK(
1306 replCoord->stepDown(opCtx, false /* force */, waitTime, Seconds(120)));
1307 } catch (const ExceptionFor<ErrorCodes::NotMaster>&) {
1308 // ignore not master errors
1309 } catch (const DBException& e) {
1310 log() << "Failed to stepDown in non-command initiated shutdown path "
1311 << e.toString();
1312 }
1313 }
1314 }
1315 }
1316
1317 // Terminate the balancer thread so it doesn't leak memory.
1318 if (auto balancer = Balancer::get(serviceContext)) {
1319 balancer->interruptBalancer();
1320 balancer->waitForBalancerToStop();
1321 }
1322
1323 // Shutdown the TransportLayer so that new connections aren't accepted
1324 if (auto tl = serviceContext->getTransportLayer()) {
1325 log(LogComponent::kNetwork) << "shutdown: going to close listening sockets...";
1326 tl->shutdown();
1327 }
1328
1329 // Shut down the global dbclient pool so callers stop waiting for connections.
1330 globalConnPool.shutdown();
1331
1332 // Shut down the background periodic task runner
1333 if (auto runner = serviceContext->getPeriodicRunner()) {
1334 runner->shutdown();
1335 }
1336
1337 if (serviceContext->getGlobalStorageEngine()) {
1338 ServiceContext::UniqueOperationContext uniqueOpCtx;
1339 OperationContext* opCtx = client->getOperationContext();
1340 if (!opCtx) {
1341 uniqueOpCtx = client->makeOperationContext();
1342 opCtx = uniqueOpCtx.get();
1343 }
1344
1345 if (serverGlobalParams.featureCompatibility.getVersion() !=
1346 ServerGlobalParams::FeatureCompatibility::Version::kFullyUpgradedTo36) {
1347 log(LogComponent::kReplication) << "shutdown: removing all drop-pending collections...";
1348 repl::DropPendingCollectionReaper::get(serviceContext)
1349 ->dropCollectionsOlderThan(opCtx, repl::OpTime::max());
1350
1351 // If we are in fCV 3.4, drop the 'checkpointTimestamp' collection so if we downgrade
1352 // and then upgrade again, we do not trust a stale 'checkpointTimestamp'.
1353 log(LogComponent::kReplication)
1354 << "shutdown: removing checkpointTimestamp collection...";
1355 Status status =
1356 repl::StorageInterface::get(serviceContext)
1357 ->dropCollection(opCtx,
1358 NamespaceString(repl::ReplicationConsistencyMarkersImpl::
1359 kDefaultCheckpointTimestampNamespace));
1360 if (!status.isOK()) {
1361 warning(LogComponent::kReplication)
1362 << "shutdown: dropping checkpointTimestamp collection failed: "
1363 << redact(status.toString());
1364 }
1365 }
1366
1367 // This can wait a long time while we drain the secondary's apply queue, especially if it
1368 // is building an index.
1369 repl::ReplicationCoordinator::get(serviceContext)->shutdown(opCtx);
1370
1371 ShardingState::get(serviceContext)->shutDown(opCtx);
1372 }
1373
1374 serviceContext->setKillAllOperations();
1375
1376 ReplicaSetMonitor::shutdown();
1377
1378 if (auto sr = Grid::get(serviceContext)->shardRegistry()) {
1379 sr->shutdown();
1380 }
1381
1382 // Validator shutdown must be called after setKillAllOperations is called. Otherwise, this can
1383 // deadlock.
1384 if (auto validator = LogicalTimeValidator::get(serviceContext)) {
1385 validator->shutDown();
1386 }
1387
1388 #if __has_feature(address_sanitizer)
1389 // When running under address sanitizer, we get false positive leaks due to disorder around
1390 // the lifecycle of a connection and request. When we are running under ASAN, we try a lot
1391 // harder to dry up the server from active connections before going on to really shut down.
1392
1393 // Shutdown the Service Entry Point and its sessions and give it a grace period to complete.
1394 if (auto sep = serviceContext->getServiceEntryPoint()) {
1395 if (!sep->shutdown(Seconds(10))) {
1396 log(LogComponent::kNetwork)
1397 << "Service entry point failed to shutdown within timelimit.";
1398 }
1399 }
1400
1401 // Shutdown and wait for the service executor to exit
1402 if (auto svcExec = serviceContext->getServiceExecutor()) {
1403 Status status = svcExec->shutdown(Seconds(10));
1404 if (!status.isOK()) {
1405 log(LogComponent::kNetwork) << "Service executor failed to shutdown within timelimit: "
1406 << status.reason();
1407 }
1408 }
1409 #endif
1410
1411 // Shutdown Full-Time Data Capture
1412 stopMongoDFTDC();
1413
1414 HealthLog::get(serviceContext).shutdown();
1415
1416 // We should always be able to acquire the global lock at shutdown.
1417 //
1418 // TODO: This call chain uses the locker directly, because we do not want to start an
1419 // operation context, which also instantiates a recovery unit. Also, using the
1420 // lockGlobalBegin/lockGlobalComplete sequence, we avoid taking the flush lock.
1421 //
1422 // For a Windows service, dbexit does not call exit(), so we must leak the lock outside
1423 // of this function to prevent any operations from running that need a lock.
1424 //
1425 DefaultLockerImpl* globalLocker = new DefaultLockerImpl();
1426 LockResult result = globalLocker->lockGlobalBegin(MODE_X, Milliseconds::max());
1427 if (result == LOCK_WAITING) {
1428 result = globalLocker->lockGlobalComplete(Milliseconds::max());
1429 }
1430
1431 invariant(LOCK_OK == result);
1432
1433 // Global storage engine may not be started in all cases before we exit
1434 if (serviceContext->getGlobalStorageEngine()) {
1435 serviceContext->shutdownGlobalStorageEngineCleanly();
1436 }
1437
1438 // We drop the scope cache because leak sanitizer can't see across the
1439 // thread we use for proxying MozJS requests. Dropping the cache cleans up
1440 // the memory and makes leak sanitizer happy.
1441 ScriptEngine::dropScopeCache();
1442
1443 log(LogComponent::kControl) << "now exiting";
1444
1445 audit::logShutdown(client);
1446 }
1447
1448
1449 } // namespace
1450
mongoDbMain(int argc,char * argv[],char ** envp)1451 int mongoDbMain(int argc, char* argv[], char** envp) {
1452 registerShutdownTask(shutdownTask);
1453
1454 setupSignalHandlers();
1455
1456 srand(static_cast<unsigned>(curTimeMicros64()));
1457
1458 Status status = mongo::runGlobalInitializers(argc, argv, envp);
1459 if (!status.isOK()) {
1460 severe(LogComponent::kControl) << "Failed global initialization: " << status;
1461 quickExit(EXIT_FAILURE);
1462 }
1463
1464 startupConfigActions(std::vector<std::string>(argv, argv + argc));
1465 cmdline_utils::censorArgvArray(argc, argv);
1466
1467 if (!initializeServerGlobalState())
1468 quickExit(EXIT_FAILURE);
1469
1470 // Per SERVER-7434, startSignalProcessingThread() must run after any forks
1471 // (initializeServerGlobalState()) and before creation of any other threads.
1472 startSignalProcessingThread();
1473
1474 #if defined(_WIN32)
1475 if (ntservice::shouldStartService()) {
1476 ntservice::startService();
1477 // exits directly and so never reaches here either.
1478 }
1479 #endif
1480
1481 StartupTest::runTests();
1482 ExitCode exitCode = initAndListen(serverGlobalParams.port);
1483 exitCleanly(exitCode);
1484 return 0;
1485 }
1486
1487 } // namespace mongo
1488