0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-11-28 07:59:02 +01:00

SERVER-17570: Fix NT Service shutdown race condition

This commit is contained in:
Mark Benvenuto 2015-03-16 11:48:45 -04:00
parent 7854198178
commit 0f6f2e9a19
16 changed files with 143 additions and 22 deletions

View File

@ -241,7 +241,7 @@ env.CppUnitTest('sock_test', ['util/net/sock_test.cpp'],
env.CppUnitTest('curop_test',
['db/curop_test.cpp'],
LIBDEPS=['serveronly', 'coredb', 'coreserver'],
LIBDEPS=['serveronly', 'coredb', 'coreserver', 'ntservice_mock'],
NO_CRUTCH=True)
env.Library('index_names',["db/index_names.cpp"])
@ -583,7 +583,10 @@ env.Library('ntservice', ['util/ntservice.cpp'],
if windows:
env.CppUnitTest('ntservice_test', 'util/ntservice_test.cpp',
LIBDEPS=['ntservice'],
LIBS=['shell32', env['LIBS']])
LIBS=['shell32', env['LIBS']],
NO_CRUTCH=True)
env.Library('ntservice_mock', ['util/ntservice_mock.cpp'])
env.Library(
target='scripting_common',
@ -895,7 +898,8 @@ env.CppUnitTest("scoped_db_conn_test", [ "client/scoped_db_conn_test.cpp" ],
"coreshard",
"mongocommon",
"message_server_port",
"mongoscore"],
"mongoscore",
"ntservice_mock"],
NO_CRUTCH=True)
env.CppUnitTest("shard_test", [ "s/shard_test.cpp" ],
@ -936,6 +940,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/serveronly",
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)
@ -949,6 +954,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/serveronly",
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)
@ -962,6 +968,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/serveronly",
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)
@ -1124,6 +1131,7 @@ env.Install(
"tools/mongobridge_options_init.cpp"
],
LIBDEPS=[
"ntservice_mock",
"serveronly",
"coreserver",
"coredb",
@ -1135,6 +1143,7 @@ env.Install(
"client/examples/mongoperf.cpp",
],
LIBDEPS=[
"ntservice_mock",
"serveronly",
"coreserver",
"coredb",
@ -1227,6 +1236,7 @@ env.Install('$BUILD_ROOT/', env.Program('file_allocator_bench',
'serveronly',
'coredb',
'coreserver',
"ntservice_mock",
]))
env.Alias('file_allocator_bench', "$BUILD_ROOT/" + add_exe("file_allocator_bench"))

View File

@ -77,6 +77,8 @@ namespace mongo {
return shuttingDown;
}
void signalShutdown() {}
DBClientBase* createDirectClient(OperationContext* txn) { return NULL; }
void dbexit(ExitCode rc, const char *why){

View File

@ -58,6 +58,7 @@
#include "mongo/util/fail_point_service.h"
#include "mongo/util/log.h"
#include "mongo/util/md5.hpp"
#include "mongo/util/ntservice.h"
#include "mongo/util/processinfo.h"
#include "mongo/util/ramlog.h"
#include "mongo/util/version_reporting.h"
@ -323,8 +324,23 @@ namespace mongo {
log() << "terminating, shutdown command received" << endl;
exitCleanly(EXIT_CLEAN); // this never returns
invariant(false);
#if defined(_WIN32)
// Signal the ServiceMain thread to shutdown.
if(ntservice::shouldStartService()) {
signalShutdown();
// Client expects us to abruptly close the socket as part of exiting
// so this function is not allowed to return.
// The ServiceMain thread will quit for us so just sleep until it does.
while (true)
sleepsecs(60); // Loop forever
}
else
#endif
{
exitCleanly(EXIT_CLEAN); // this never returns
invariant(false);
}
}
/* for testing purposes only */

View File

@ -87,6 +87,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/mocklib",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)
@ -102,6 +103,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/mocklib",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)
@ -116,6 +118,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/serveronly",
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)

View File

@ -1105,12 +1105,25 @@ namespace mongo {
getGlobalEnvironment()->shutdownGlobalStorageEngineCleanly();
}
// shutdownLock
//
// Protects:
// Ensures shutdown is single threaded.
// Lock Ordering:
// No restrictions
boost::mutex shutdownLock;
void signalShutdown() {
// Notify all threads shutdown has started
shutdownInProgress.fetchAndAdd(1);
}
void exitCleanly(ExitCode code) {
if (shutdownInProgress.compareAndSwap(0, 1) != 0) {
while (true) {
sleepsecs(1000);
}
}
// Notify all threads shutdown has started
shutdownInProgress.fetchAndAdd(1);
// Grab the shutdown lock to prevent concurrent callers
boost::lock_guard<boost::mutex> lockguard(shutdownLock);
// Global storage engine may not be started in all cases before we exit
if (getGlobalEnvironment()->getGlobalStorageEngine() == NULL) {

View File

@ -61,6 +61,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/mocklib",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)
@ -236,6 +237,7 @@ env.CppUnitTest(
"$BUILD_DIR/mongo/coreserver",
"$BUILD_DIR/mongo/coredb",
"$BUILD_DIR/mongo/mocklib",
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True,
)

View File

@ -209,5 +209,6 @@ env.CppUnitTest('isself_test',
'$BUILD_DIR/mongo/serveronly',
'$BUILD_DIR/mongo/coreserver',
'$BUILD_DIR/mongo/coredb',
"$BUILD_DIR/mongo/ntservice_mock",
],
NO_CRUTCH = True)

View File

@ -89,6 +89,7 @@ env.CppUnitTest(
'$BUILD_DIR/mongo/serveronly',
'$BUILD_DIR/mongo/coreserver',
'$BUILD_DIR/mongo/coredb',
'$BUILD_DIR/mongo/ntservice_mock',
],
NO_CRUTCH=True,
)

View File

@ -88,6 +88,7 @@ if wiredtiger:
'$BUILD_DIR/mongo/serveronly',
'$BUILD_DIR/mongo/coreserver',
'$BUILD_DIR/mongo/coredb',
'$BUILD_DIR/mongo/ntservice_mock',
],
NO_CRUTCH=True,
)

View File

@ -135,6 +135,14 @@ namespace mongo {
}
} // namespace dbtests
#ifdef _WIN32
namespace ntservice {
bool shouldStartService() {
return false;
}
}
#endif
} // namespace mongo
void mongo::unittest::onCurrentTestNameChange( const std::string &testName ) {

View File

@ -475,6 +475,11 @@ int main(int argc, char* argv[], char** envp) {
#undef exit
void mongo::signalShutdown() {
// Notify all threads shutdown has started
dbexitCalled = true;
}
void mongo::exitCleanly(ExitCode code) {
// TODO: do we need to add anything?
mongo::dbexit( code );
@ -483,7 +488,11 @@ void mongo::exitCleanly(ExitCode code) {
void mongo::dbexit( ExitCode rc, const char *why ) {
dbexitCalled = true;
audit::logShutdown(ClientBasic::getCurrent());
#if defined(_WIN32)
// Windows Service Controller wants to be told when we are done shutting down
// and call quickExit itself.
//
if ( rc == EXIT_WINDOWS_SERVICE_STOP ) {
log() << "dbexit: exiting because Windows service was stopped" << endl;
return;

View File

@ -64,4 +64,14 @@ namespace mongo {
invariant(!"unittests shouldn't call exitCleanly");
}
#ifdef _WIN32
void signalShutdown() {}
namespace ntservice {
bool shouldStartService() {
return false;
}
}
#endif
} // namespace mongo

View File

@ -65,4 +65,12 @@ namespace mongo {
*/
void exitCleanly(ExitCode code);
/**
* Signal main or ServiceMain thread to exit
* Important for the ServiceMain thread to do the exit when mongod/s are running as NT Services
* on Windows.
* It is not required to be called before exitCleanly in the general case, only for
* proper NT Service shutdown.
*/
void signalShutdown();
} // namespace mongo

View File

@ -525,12 +525,12 @@ namespace {
// Stop the process
// During clean shutdown, ie NT SCM signals us, _serviceCallback returns here
// as part of the listener loop terminating so we do not have to stop twice in this case
if ( ! inShutdown() ) {
// TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
// the "terminate process" functionality in exitCleanly.
exitCleanly( EXIT_WINDOWS_SERVICE_STOP );
}
// as part of the listener loop terminating.
// exitCleanly is supposed to return. If it blocks, some other thread must be exiting.
//
// TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
// the "terminate process" functionality in exitCleanly.
exitCleanly( EXIT_WINDOWS_SERVICE_STOP );
reportStatus(SERVICE_STOPPED, 0, exitCode);
}
@ -543,12 +543,9 @@ namespace {
reportStatus( SERVICE_STOP_PENDING );
if ( ! inShutdown() ) {
// TODO: SERVER-5703, separate the "cleanup for shutdown" functionality from
// the "terminate process" functionality in exitCleanly.
// Note: This triggers _serviceCallback to stop by setting inShutdown() == true
exitCleanly( EXIT_WINDOWS_SERVICE_STOP );
}
// Note: This triggers _serviceCallback, ie ServiceMain,
// to stop by setting inShutdown() == true
signalShutdown();
// Note: we will report exit status in initService
}

View File

@ -0,0 +1,37 @@
/**
* Copyright (C) 2015 MongoDB Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* As a special exception, the copyright holders give permission to link the
* code of portions of this program with the OpenSSL library under certain
* conditions as described in each individual source file and distribute
* linked combinations including the program with the OpenSSL library. You
* must comply with the GNU Affero General Public License in all respects for
* all of the code used other than as permitted herein. If you modify file(s)
* with this exception, you may extend this exception to your version of the
* file(s), but you are not obligated to do so. If you do not wish to do so,
* delete this exception statement from your version. If you delete this
* exception statement from all source files in the program, then also delete
* it in the license file.
*/
namespace mongo {
namespace ntservice {
bool shouldStartService() {
return false;
}
} // namespace ntservice
} // namespace mongo

View File

@ -117,4 +117,7 @@ namespace mongo {
void Client::initThread(const char* desc, AbstractMessagingPort* mp) {
}
void removeControlCHandler() {}
void signalShutdown() {}
bool inShutdown() { return false; }
void exitCleanly(ExitCode code) { }
} // namespace mongo