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