main.cpp 9.39 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* 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 */

17
#include <ndb_global.h>
18
#include <my_pthread.h>
19

20 21
#include <ndb_version.h>
#include "Configuration.hpp"
22
#include <LocalConfig.hpp>
23 24
#include <TransporterRegistry.hpp>

tomas@poseidon.bredbandsbolaget.se's avatar
tomas@poseidon.bredbandsbolaget.se committed
25
#include "vm/SimBlockList.hpp"
26 27 28 29 30
#include "ThreadConfig.hpp"
#include <SignalLoggerManager.hpp>
#include <NdbOut.hpp>
#include <NdbMain.h>
#include <NdbDaemon.h>
31
#include <NdbSleep.h>
32 33 34 35
#include <NdbConfig.h>
#include <WatchDog.hpp>

#include <LogLevel.hpp>
36
#include <EventLogger.hpp>
37 38

#include <NdbAutoPtr.hpp>
39

40
#if defined NDB_SOLARIS // ok
41 42 43
#include <sys/processor.h> // For system informatio
#endif

44
extern EventLogger g_eventLogger;
45
extern NdbMutex * theShutdownMutex;
46

47
void catchsigs(bool ignore); // for process signal handling
48 49 50

extern "C" void handler_shutdown(int signum);  // for process signal handling
extern "C" void handler_error(int signum);  // for process signal handling
51

52 53 54 55
// Shows system information
void systemInfo(const Configuration & conf,
		const LogLevel & ll); 

56 57 58
int main(int argc, char** argv)
{
  NDB_INIT(argv[0]);
59 60 61 62 63
  // Print to stdout/console
  g_eventLogger.createConsoleHandler();
  g_eventLogger.setCategory("NDB");
  g_eventLogger.enable(Logger::LL_INFO, Logger::LL_ALERT); // Log INFO to ALERT

64
  globalEmulatorData.create();
65

66 67 68
  // Parse command line options
  Configuration* theConfig = globalEmulatorData.theConfiguration;
  if(!theConfig->init(argc, argv)){
69
    return NRT_Default;
70 71
  }
  
72 73 74 75 76 77 78
  LocalConfig local_config;
  if (!local_config.init(theConfig->getConnectString(),0)){
    local_config.printError();
    local_config.printUsage();
    return NRT_Default;
  }

79
  { // Do configuration
joreland@mysql.com's avatar
joreland@mysql.com committed
80
    signal(SIGPIPE, SIG_IGN);
81
    theConfig->fetch_configuration(local_config);
82
  }
joreland@mysql.com's avatar
joreland@mysql.com committed
83
  
84 85
  chdir(NdbConfig_get_path(0));

86 87
  if (theConfig->getDaemonMode()) {
    // Become a daemon
88 89 90 91
    char *lockfile= NdbConfig_PidFileName(globalData.ownId);
    char *logfile=  NdbConfig_StdoutFileName(globalData.ownId);
    NdbAutoPtr<char> tmp_aptr1(lockfile), tmp_aptr2(logfile);

92 93 94 95 96
    if (NdbDaemon_Make(lockfile, logfile, 0) == -1) {
      ndbout << "Cannot become daemon: " << NdbDaemon_ErrorText << endl;
      return 1;
    }
  }
97 98 99 100 101 102
  
  for(pid_t child = fork(); child != 0; child = fork()){
    /**
     * Parent
     */
    catchsigs(true);
joreland@mysql.com's avatar
joreland@mysql.com committed
103

104 105
    int status = 0;
    while(waitpid(child, &status, 0) != child);
joreland@mysql.com's avatar
joreland@mysql.com committed
106
    if(WIFEXITED(status)){
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
      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:
joreland@mysql.com's avatar
joreland@mysql.com committed
125 126 127 128 129 130 131
	if(theConfig->stopOnError()){
	  /**
	   * Error shutdown && stopOnError()
	   */
	  exit(0);
	}
	// Fall-through
132 133 134 135 136
      case NRT_DoStart_Restart:
	theConfig->setInitialStart(false);
	globalData.theRestartFlag = perform_start;
	break;
      }
joreland@mysql.com's avatar
joreland@mysql.com committed
137
    } else if(theConfig->stopOnError()){
138 139 140 141 142
      /**
       * Error shutdown && stopOnError()
       */
      exit(0);
    }
joreland@mysql.com's avatar
joreland@mysql.com committed
143
    g_eventLogger.info("Ndb has terminated (pid %d) restarting", child);
144
    theConfig->fetch_configuration(local_config);
145
  }
146

147
  g_eventLogger.info("Angel pid: %d ndb pid: %d", getppid(), getpid());
joreland@mysql.com's avatar
joreland@mysql.com committed
148
  theConfig->setupConfiguration();
149
  systemInfo(* theConfig, * theConfig->m_logLevel); 
joreland@mysql.com's avatar
joreland@mysql.com committed
150
  
151
    // Load blocks
152 153 154 155 156
  globalEmulatorData.theSimBlockList->load(* theConfig);
    
  // Set thread concurrency for Solaris' light weight processes
  int status;
  status = NdbThread_SetConcurrencyLevel(30);
joreland@mysql.com's avatar
joreland@mysql.com committed
157
  assert(status == 0);
158 159 160
  
#ifdef VM_TRACE
  // Create a signal logger
161 162 163
  char *buf= NdbConfig_SignalLogFileName(globalData.ownId);
  NdbAutoPtr<char> tmp_aptr(buf);
  FILE * signalLog = fopen(buf, "a");
164
  globalSignalLoggers.setOwnNodeId(globalData.ownId);
165 166 167
  globalSignalLoggers.setOutputStream(signalLog);
#endif
  
168
  catchsigs(false);
169 170 171 172 173 174 175 176 177 178 179 180 181
   
  /**
   * 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:
joreland@mysql.com's avatar
joreland@mysql.com committed
182
    assert("Illegal state globalData.theRestartFlag" == 0);
183 184
  }

tomas@poseidon.bredbandsbolaget.se's avatar
tomas@poseidon.bredbandsbolaget.se committed
185 186
  SocketServer socket_server;

187 188
  globalTransporterRegistry.startSending();
  globalTransporterRegistry.startReceiving();
joreland@mysql.com's avatar
joreland@mysql.com committed
189 190 191 192
  if (!globalTransporterRegistry.start_service(socket_server)){
    ndbout_c("globalTransporterRegistry.start_service() failed");
    exit(-1);
  }
tomas@poseidon.bredbandsbolaget.se's avatar
tomas@poseidon.bredbandsbolaget.se committed
193

joreland@mysql.com's avatar
joreland@mysql.com committed
194 195 196 197
  if (!globalTransporterRegistry.start_clients()){
    ndbout_c("globalTransporterRegistry.start_clients() failed");
    exit(-1);
  }
tomas@poseidon.bredbandsbolaget.se's avatar
tomas@poseidon.bredbandsbolaget.se committed
198

199 200
  globalEmulatorData.theWatchDog->doStart();
  
tomas@poseidon.bredbandsbolaget.se's avatar
tomas@poseidon.bredbandsbolaget.se committed
201 202
  socket_server.startServer();

203 204
  //  theConfig->closeConfiguration();

205 206 207
  globalEmulatorData.theThreadConfig->ipControlLoop();
  
  NdbShutdown(NST_Normal);
tomas@poseidon.bredbandsbolaget.se's avatar
tomas@poseidon.bredbandsbolaget.se committed
208 209 210 211 212 213

  socket_server.stopServer();
  socket_server.stopSessions();

  globalTransporterRegistry.stop_clients();

214
  return NRT_Default;
215 216 217 218 219
}


void 
systemInfo(const Configuration & config, const LogLevel & logLevel){
220
#ifdef NDB_WIN32
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
  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);
  }
239
#elif defined NDB_SOLARIS // ok
240 241 242 243 244 245 246 247 248 249 250
  // 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){
251 252
    g_eventLogger.info("NDB Cluster -- DB node %d", globalData.ownId);
    g_eventLogger.info("%s --", NDB_VERSION_STRING);
253 254 255
    if (config.get_mgmd_host())
      g_eventLogger.info("Configuration fetched at %s port %d",
			 config.get_mgmd_host(), config.get_mgmd_port());
256
#ifdef NDB_SOLARIS // ok
257 258
    g_eventLogger.info("NDB is running on a machine with %d processor(s) at %d MHz",
		       processor, speed);
259 260 261 262
#endif
  }
  if(logLevel.getLogLevel(LogLevel::llStartUp) > 3){
    Uint32 t = config.timeBetweenWatchDogCheck();
263
    g_eventLogger.info("WatchDog timer is set to %d ms", t);
264 265 266 267
  }

}

268 269 270 271 272 273 274
#define handler_register(signum, handler, ignore)\
{\
  if (ignore) {\
    if(signum != SIGCHLD)\
      signal(signum, SIG_IGN);\
  } else\
    signal(signum, handler);\
275 276
}

277
void 
278 279
catchsigs(bool ignore){
#if ! defined NDB_SOFTOSE && !defined NDB_OSE 
280

281 282 283
  static const int signals_shutdown[] = {
#ifdef SIGBREAK
    SIGBREAK,
284
#endif
285 286 287 288 289 290
    SIGHUP,
    SIGINT,
#if defined SIGPWR
    SIGPWR,
#elif defined SIGINFO
    SIGINFO,
291
#endif
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311
    SIGQUIT,
    SIGTERM,
#ifdef SIGTSTP
    SIGTSTP,
#endif
    SIGTTIN,
    SIGTTOU
  };

  static const int signals_error[] = {
    SIGABRT,
    SIGALRM,
#ifdef SIGBUS
    SIGBUS,
#endif
    SIGCHLD,
    SIGFPE,
    SIGILL,
#ifdef SIGIO
    SIGIO,
312 313
#endif
#ifdef SIGPOLL
314
    SIGPOLL,
315
#endif
316 317 318
    SIGSEGV,
#ifdef SIGTRAP
    SIGTRAP
joreland@mysql.com's avatar
joreland@mysql.com committed
319
#endif
320 321 322 323 324 325 326
  };
#endif

  static const int signals_ignore[] = {
    SIGPIPE
  };

327 328
  size_t i;
  for(i = 0; i < sizeof(signals_shutdown)/sizeof(signals_shutdown[0]); i++)
329
    handler_register(signals_shutdown[i], handler_shutdown, ignore);
330
  for(i = 0; i < sizeof(signals_error)/sizeof(signals_error[0]); i++)
331
    handler_register(signals_error[i], handler_error, ignore);
332
  for(i = 0; i < sizeof(signals_ignore)/sizeof(signals_ignore[0]); i++)
333 334 335 336 337 338 339 340 341 342 343 344 345
    handler_register(signals_ignore[i], SIG_IGN, ignore);
}

extern "C"
void 
handler_shutdown(int signum){
  g_eventLogger.info("Received signal %d. Performing stop.", signum);
  globalData.theRestartFlag = perform_stop;
}

extern "C"
void 
handler_error(int signum){
346 347 348 349
  // only let one thread run shutdown
  static long thread_id= 0;

  if (thread_id != 0 && thread_id == my_thread_id())
tomas@poseidon.(none)'s avatar
tomas@poseidon.(none) committed
350 351 352 353 354 355 356
  {
    // Shutdown thread received signal
    signal(signum, SIG_DFL);
    kill(getpid(), signum);
    while(true)
      NdbSleep_MilliSleep(10);
  }
357 358 359 360
  if(theShutdownMutex && NdbMutex_Trylock(theShutdownMutex) != 0)
    while(true)
      NdbSleep_MilliSleep(10);
  thread_id= my_thread_id();
361 362 363
  g_eventLogger.info("Received signal %d. Running error handler.", signum);
  // restart the system
  char errorData[40];
364
  BaseString::snprintf(errorData, 40, "Signal %d received", signum);
tomas@poseidon.(none)'s avatar
tomas@poseidon.(none) committed
365
  ERROR_SET_SIGNAL(fatal, 0, errorData, __FILE__);
366
}