/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include "Configuration.hpp" #include #include "vm/SimBlockList.hpp" #include "ThreadConfig.hpp" #include #include #include #include #include #include #include #include #include #if defined NDB_SOLARIS // ok #include // For system informatio #endif #if !defined NDB_SOFTOSE && !defined NDB_OSE #include // For process signals #endif extern EventLogger g_eventLogger; void catchsigs(bool ignore); // for process signal handling extern "C" void handler(int signo); // for process signal handling // Shows system information void systemInfo(const Configuration & conf, const LogLevel & ll); const char programName[] = "NDB Kernel"; NDB_MAIN(ndb_kernel){ // Print to stdout/console g_eventLogger.createConsoleHandler(); g_eventLogger.setCategory("NDB"); g_eventLogger.enable(Logger::LL_INFO, Logger::LL_ALERT); // Log INFO to ALERT globalEmulatorData.create(); // Parse command line options Configuration* theConfig = globalEmulatorData.theConfiguration; if(!theConfig->init(argc, argv)){ return 0; } { // Do configuration signal(SIGPIPE, SIG_IGN); theConfig->fetch_configuration(); } if (theConfig->getDaemonMode()) { // Become a daemon char *lockfile= NdbConfig_PidFileName(globalData.ownId); char *logfile= NdbConfig_StdoutFileName(globalData.ownId); NdbAutoPtr tmp_aptr1(lockfile), tmp_aptr2(logfile); if (NdbDaemon_Make(lockfile, logfile, 0) == -1) { ndbout << "Cannot become daemon: " << NdbDaemon_ErrorText << endl; return 1; } } for(pid_t child = fork(); child != 0; child = fork()){ /** * Parent */ catchsigs(true); int status = 0; while(waitpid(child, &status, 0) != child); if(WIFEXITED(status)){ switch(WEXITSTATUS(status)){ case NRT_Default: g_eventLogger.info("Angel shutting down"); exit(0); break; case NRT_NoStart_Restart: theConfig->setInitialStart(false); globalData.theRestartFlag = initial_state; break; case NRT_NoStart_InitialStart: theConfig->setInitialStart(true); globalData.theRestartFlag = initial_state; break; case NRT_DoStart_InitialStart: theConfig->setInitialStart(true); globalData.theRestartFlag = perform_start; break; default: if(theConfig->stopOnError()){ /** * Error shutdown && stopOnError() */ exit(0); } // Fall-through case NRT_DoStart_Restart: theConfig->setInitialStart(false); globalData.theRestartFlag = perform_start; break; } } else if(theConfig->stopOnError()){ /** * Error shutdown && stopOnError() */ exit(0); } g_eventLogger.info("Ndb has terminated (pid %d) restarting", child); theConfig->fetch_configuration(); } g_eventLogger.info("Angel pid: %d ndb pid: %d", getppid(), getpid()); theConfig->setupConfiguration(); systemInfo(* theConfig, * theConfig->m_logLevel); // Load blocks globalEmulatorData.theSimBlockList->load(* theConfig); // Set thread concurrency for Solaris' light weight processes int status; status = NdbThread_SetConcurrencyLevel(30); assert(status == 0); #ifdef VM_TRACE // Create a signal logger char *buf= NdbConfig_SignalLogFileName(globalData.ownId); NdbAutoPtr tmp_aptr(buf); FILE * signalLog = fopen(buf, "a"); globalSignalLoggers.setOwnNodeId(globalData.ownId); globalSignalLoggers.setOutputStream(signalLog); #endif catchsigs(false); /** * Do startup */ switch(globalData.theRestartFlag){ case initial_state: globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI); break; case perform_start: globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI); globalEmulatorData.theThreadConfig->doStart(NodeState::SL_STARTING); break; default: assert("Illegal state globalData.theRestartFlag" == 0); } SocketServer socket_server; globalTransporterRegistry.startSending(); globalTransporterRegistry.startReceiving(); if (!globalTransporterRegistry.start_service(socket_server)){ ndbout_c("globalTransporterRegistry.start_service() failed"); exit(-1); } if (!globalTransporterRegistry.start_clients()){ ndbout_c("globalTransporterRegistry.start_clients() failed"); exit(-1); } globalEmulatorData.theWatchDog->doStart(); socket_server.startServer(); // theConfig->closeConfiguration(); globalEmulatorData.theThreadConfig->ipControlLoop(); NdbShutdown(NST_Normal); socket_server.stopServer(); socket_server.stopSessions(); globalTransporterRegistry.stop_clients(); return NRT_Default; } void systemInfo(const Configuration & config, const LogLevel & logLevel){ #ifdef NDB_WIN32 int processors = 0; int speed; SYSTEM_INFO sinfo; GetSystemInfo(&sinfo); processors = sinfo.dwNumberOfProcessors; HKEY hKey; if(ERROR_SUCCESS==RegOpenKeyEx (HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), 0, KEY_READ, &hKey)) { DWORD dwMHz; DWORD cbData = sizeof(dwMHz); if(ERROR_SUCCESS==RegQueryValueEx(hKey, "~MHz", 0, 0, (LPBYTE)&dwMHz, &cbData)) { speed = int(dwMHz); } RegCloseKey(hKey); } #elif defined NDB_SOLARIS // ok // Search for at max 16 processors among the first 256 processor ids processor_info_t pinfo; memset(&pinfo, 0, sizeof(pinfo)); int pid = 0; while(processors < 16 && pid < 256){ if(!processor_info(pid++, &pinfo)) processors++; } speed = pinfo.pi_clock; #endif if(logLevel.getLogLevel(LogLevel::llStartUp) > 0){ g_eventLogger.info("NDB Cluster -- DB node %d", globalData.ownId); g_eventLogger.info("%s --", NDB_VERSION_STRING); #ifdef NDB_SOLARIS // ok g_eventLogger.info("NDB is running on a machine with %d processor(s) at %d MHz", processor, speed); #endif } if(logLevel.getLogLevel(LogLevel::llStartUp) > 3){ Uint32 t = config.timeBetweenWatchDogCheck(); g_eventLogger.info("WatchDog timer is set to %d ms", t); } } void catchsigs(bool ignore){ #if ! defined NDB_SOFTOSE && !defined NDB_OSE #if defined SIGRTMIN #define MAX_SIG_CATCH SIGRTMIN #elif defined NSIG #define MAX_SIG_CATCH NSIG #else #error "neither SIGRTMIN or NSIG is defined on this platform, please report bug at bugs.mysql.com" #endif // Makes the main process catch process signals, eg installs a // handler named "handler". "handler" will then be called is instead // of the defualt process signal handler) if(ignore){ for(int i = 1; i < MAX_SIG_CATCH; i++){ if(i != SIGCHLD) signal(i, SIG_IGN); } } else { for(int i = 1; i < MAX_SIG_CATCH; i++){ signal(i, handler); } } #endif } extern "C" void handler(int sig){ switch(sig){ case SIGHUP: /* 1 - Hang up */ case SIGINT: /* 2 - Interrupt */ case SIGQUIT: /* 3 - Quit */ case SIGTERM: /* 15 - Terminate */ #ifdef SIGPWR case SIGPWR: /* 19 - Power fail */ #endif #ifdef SIGPOLL case SIGPOLL: /* 22 */ #endif case SIGSTOP: /* 23 */ case SIGTSTP: /* 24 */ case SIGTTIN: /* 26 */ case SIGTTOU: /* 27 */ globalData.theRestartFlag = perform_stop; break; #ifdef SIGWINCH case SIGWINCH: #endif case SIGPIPE: /** * Can happen in TCP Transporter * * Just ignore */ break; default: // restart the system char errorData[40]; snprintf(errorData, 40, "Signal %d received", sig); ERROR_SET(fatal, 0, errorData, __FILE__); break; } }