1 /* Copyright (c) 2009, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22 
23 #include <ndb_global.h>
24 
25 #include <NdbEnv.h>
26 #include <NdbConfig.h>
27 #include <NdbSleep.h>
28 #include <portlib/NdbDir.hpp>
29 #include <NdbAutoPtr.hpp>
30 #include <portlib/NdbNuma.h>
31 
32 #include "vm/SimBlockList.hpp"
33 #include "vm/WatchDog.hpp"
34 #include "vm/ThreadConfig.hpp"
35 #include "vm/Configuration.hpp"
36 
37 #include "ndbd.hpp"
38 
39 #include <ConfigRetriever.hpp>
40 #include <LogLevel.hpp>
41 
42 #if defined NDB_SOLARIS
43 #include <sys/processor.h>
44 #endif
45 
46 #include <EventLogger.hpp>
47 extern EventLogger * g_eventLogger;
48 
49 static void
systemInfo(const Configuration & config,const LogLevel & logLevel)50 systemInfo(const Configuration & config, const LogLevel & logLevel)
51 {
52 #ifdef NDB_WIN32
53   int processors = 0;
54   int speed;
55   SYSTEM_INFO sinfo;
56   GetSystemInfo(&sinfo);
57   processors = sinfo.dwNumberOfProcessors;
58   HKEY hKey;
59   if(ERROR_SUCCESS==RegOpenKeyEx
60      (HKEY_LOCAL_MACHINE,
61       TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"),
62       0, KEY_READ, &hKey)) {
63     DWORD dwMHz;
64     DWORD cbData = sizeof(dwMHz);
65     if(ERROR_SUCCESS==RegQueryValueEx(hKey,
66 				      "~MHz", 0, 0, (LPBYTE)&dwMHz, &cbData)) {
67       speed = int(dwMHz);
68     }
69     RegCloseKey(hKey);
70   }
71 #elif defined NDB_SOLARIS
72   // Search for at max 16 processors among the first 256 processor ids
73   processor_info_t pinfo; memset(&pinfo, 0, sizeof(pinfo));
74   int pid = 0;
75   while(processors < 16 && pid < 256){
76     if(!processor_info(pid++, &pinfo))
77       processors++;
78   }
79   speed = pinfo.pi_clock;
80 #endif
81 
82   if(logLevel.getLogLevel(LogLevel::llStartUp) > 0){
83     g_eventLogger->info("NDB Cluster -- DB node %d", globalData.ownId);
84     g_eventLogger->info("%s --", NDB_VERSION_STRING);
85 #ifdef NDB_SOLARIS
86     g_eventLogger->info("NDB is running on a machine with %d processor(s) at %d MHz",
87                         processor, speed);
88 #endif
89   }
90   if(logLevel.getLogLevel(LogLevel::llStartUp) > 3){
91     Uint32 t = config.timeBetweenWatchDogCheck();
92     g_eventLogger->info("WatchDog timer is set to %d ms", t);
93   }
94 }
95 
96 
97 Uint32
compute_acc_32kpages(const ndb_mgm_configuration_iterator * p)98 compute_acc_32kpages(const ndb_mgm_configuration_iterator * p)
99 {
100   Uint64 accmem = 0;
101   ndb_mgm_get_int64_parameter(p, CFG_DB_INDEX_MEM, &accmem);
102   if (accmem)
103   {
104     accmem /= GLOBAL_PAGE_SIZE;
105 
106     Uint32 lqhInstances = 1;
107     if (globalData.isNdbMtLqh)
108     {
109       lqhInstances = globalData.ndbMtLqhWorkers;
110     }
111 
112     accmem += lqhInstances * (32 / 4); // Added as safty in Configuration.cpp
113   }
114   return Uint32(accmem);
115 }
116 
117 static int
init_global_memory_manager(EmulatorData & ed,Uint32 * watchCounter)118 init_global_memory_manager(EmulatorData &ed, Uint32 *watchCounter)
119 {
120   const ndb_mgm_configuration_iterator * p =
121     ed.theConfiguration->getOwnConfigIterator();
122   if (p == 0)
123   {
124     abort();
125   }
126 
127   Uint32 numa = 0;
128   ndb_mgm_get_int_parameter(p, CFG_DB_NUMA, &numa);
129   if (numa == 1)
130   {
131     int res = NdbNuma_setInterleaved();
132     g_eventLogger->info("numa_set_interleave_mask(numa_all_nodes) : %s",
133                         res == 0 ? "OK" : "no numa support");
134   }
135 
136   Uint64 shared_mem = 8*1024*1024;
137   ndb_mgm_get_int64_parameter(p, CFG_DB_SGA, &shared_mem);
138   Uint32 shared_pages = Uint32(shared_mem /= GLOBAL_PAGE_SIZE);
139 
140   Uint32 tupmem = 0;
141   if (ndb_mgm_get_int_parameter(p, CFG_TUP_PAGE, &tupmem))
142   {
143     g_eventLogger->alert("Failed to get CFG_TUP_PAGE parameter from "
144                         "config, exiting.");
145     return -1;
146   }
147 
148   {
149     /**
150      * IndexMemory
151      */
152     Uint32 accpages = compute_acc_32kpages(p);
153     tupmem += accpages; // Add to RG_DATAMEM
154   }
155 
156   Uint32 lqhInstances = 1;
157   if (globalData.isNdbMtLqh)
158   {
159     lqhInstances = globalData.ndbMtLqhWorkers;
160   }
161 
162   if (tupmem)
163   {
164     Resource_limit rl;
165     rl.m_min = tupmem;
166     rl.m_max = tupmem;
167     rl.m_resource_id = RG_DATAMEM;
168     ed.m_mem_manager->set_resource_limit(rl);
169   }
170 
171   Uint32 maxopen = 4 * 4; // 4 redo parts, max 4 files per part
172   Uint32 filebuffer = NDB_FILE_BUFFER_SIZE;
173   Uint32 filepages = (filebuffer / GLOBAL_PAGE_SIZE) * maxopen;
174 
175   {
176     /**
177      * RedoBuffer
178      */
179     Uint32 redomem = 0;
180     ndb_mgm_get_int_parameter(p, CFG_DB_REDO_BUFFER,
181                               &redomem);
182 
183     if (redomem)
184     {
185       redomem /= GLOBAL_PAGE_SIZE;
186       Uint32 tmp = redomem & 15;
187       if (tmp != 0)
188       {
189         redomem += (16 - tmp);
190       }
191 
192       filepages += lqhInstances * redomem; // Add to RG_FILE_BUFFERS
193     }
194   }
195 
196   if (filepages)
197   {
198     Resource_limit rl;
199     rl.m_min = filepages;
200     rl.m_max = filepages;
201     rl.m_resource_id = RG_FILE_BUFFERS;
202     ed.m_mem_manager->set_resource_limit(rl);
203   }
204 
205   Uint32 jbpages = compute_jb_pages(&ed);
206   if (jbpages)
207   {
208     Resource_limit rl;
209     rl.m_min = jbpages;
210     rl.m_max = jbpages;
211     rl.m_resource_id = RG_JOBBUFFER;
212     ed.m_mem_manager->set_resource_limit(rl);
213   }
214 
215   Uint32 sbpages = 0;
216   if (globalTransporterRegistry.get_using_default_send_buffer() == false)
217   {
218     Uint64 mem = globalTransporterRegistry.get_total_max_send_buffer();
219     sbpages = Uint32((mem + GLOBAL_PAGE_SIZE - 1) / GLOBAL_PAGE_SIZE);
220     Resource_limit rl;
221     rl.m_min = sbpages;
222     rl.m_max = sbpages;
223     rl.m_resource_id = RG_TRANSPORTER_BUFFERS;
224     ed.m_mem_manager->set_resource_limit(rl);
225   }
226 
227   Uint32 pgman_pages = 0;
228   {
229     /**
230      * Disk page buffer memory
231      */
232     Uint64 page_buffer = 64*1024*1024;
233     ndb_mgm_get_int64_parameter(p, CFG_DB_DISK_PAGE_BUFFER_MEMORY,&page_buffer);
234 
235     Uint32 pages = 0;
236     pages += Uint32(page_buffer / GLOBAL_PAGE_SIZE); // in pages
237     pages += LCP_RESTORE_BUFFER * lqhInstances;
238 
239     pgman_pages += pages;
240     pgman_pages += 64;
241 
242     Resource_limit rl;
243     rl.m_min = pgman_pages;
244     rl.m_max = pgman_pages;
245     rl.m_resource_id = RG_DISK_PAGE_BUFFER;  // Add to RG_DISK_PAGE_BUFFER
246     ed.m_mem_manager->set_resource_limit(rl);
247   }
248 
249   Uint32 sum = shared_pages + tupmem + filepages + jbpages + sbpages +
250     pgman_pages;
251 
252   if (sum)
253   {
254     Resource_limit rl;
255     rl.m_min = 0;
256     rl.m_max = sum;
257     rl.m_resource_id = 0;
258     ed.m_mem_manager->set_resource_limit(rl);
259   }
260 
261   if (!ed.m_mem_manager->init(watchCounter))
262   {
263     struct ndb_mgm_param_info dm;
264     struct ndb_mgm_param_info sga;
265     size_t size;
266 
267     size = sizeof(ndb_mgm_param_info);
268     ndb_mgm_get_db_parameter_info(CFG_DB_DATA_MEM, &dm, &size);
269     size = sizeof(ndb_mgm_param_info);
270     ndb_mgm_get_db_parameter_info(CFG_DB_SGA, &sga, &size);
271 
272     g_eventLogger->alert("Malloc (%lld bytes) for %s and %s failed, exiting",
273                          Uint64(shared_mem + tupmem) * GLOBAL_PAGE_SIZE,
274                          dm.m_name, sga.m_name);
275     return -1;
276   }
277 
278   Uint32 late_alloc = 0;
279   ndb_mgm_get_int_parameter(p, CFG_DB_LATE_ALLOC,
280                             &late_alloc);
281 
282   Uint32 memlock = 0;
283   ndb_mgm_get_int_parameter(p, CFG_DB_MEMLOCK, &memlock);
284 
285   if (late_alloc)
286   {
287     /**
288      * Only map these groups that are required for ndb to even "start"
289      */
290     Uint32 rg[] = { RG_JOBBUFFER, RG_FILE_BUFFERS, RG_TRANSPORTER_BUFFERS, 0 };
291     ed.m_mem_manager->map(watchCounter, memlock, rg);
292   }
293   else
294   {
295     ed.m_mem_manager->map(watchCounter, memlock); // Map all
296   }
297 
298   return 0;                     // Success
299 }
300 
301 
302 static int
get_multithreaded_config(EmulatorData & ed)303 get_multithreaded_config(EmulatorData& ed)
304 {
305   // multithreaded is compiled in ndbd/ndbmtd for now
306   globalData.isNdbMt = SimulatedBlock::isMultiThreaded();
307   if (!globalData.isNdbMt)
308   {
309     ndbout << "NDBMT: non-mt" << endl;
310     return 0;
311   }
312 
313   THRConfig & conf = ed.theConfiguration->m_thr_config;
314 
315   Uint32 threadcount = conf.getThreadCount();
316   ndbout << "NDBMT: MaxNoOfExecutionThreads=" << threadcount << endl;
317 
318   globalData.isNdbMtLqh = true;
319 
320   {
321     if (conf.getMtClassic())
322     {
323       globalData.isNdbMtLqh = false;
324     }
325   }
326 
327   if (!globalData.isNdbMtLqh)
328     return 0;
329 
330   Uint32 threads = conf.getThreadCount(THRConfig::T_LDM);
331   Uint32 workers = threads;
332   {
333     ndb_mgm_configuration * conf = ed.theConfiguration->getClusterConfig();
334     if (conf == 0)
335     {
336       abort();
337     }
338     ndb_mgm_configuration_iterator * p =
339       ndb_mgm_create_configuration_iterator(conf, CFG_SECTION_NODE);
340     if (ndb_mgm_find(p, CFG_NODE_ID, globalData.ownId))
341     {
342       abort();
343     }
344     ndb_mgm_get_int_parameter(p, CFG_NDBMT_LQH_WORKERS, &workers);
345   }
346 
347 #ifdef VM_TRACE
348   // testing
349   {
350     const char* p;
351     p = NdbEnv_GetEnv("NDBMT_LQH_WORKERS", (char*)0, 0);
352     if (p != 0)
353       workers = atoi(p);
354   }
355 #endif
356 
357   ndbout << "NDBMT: workers=" << workers
358          << " threads=" << threads << endl;
359 
360   assert(workers != 0 && workers <= MAX_NDBMT_LQH_WORKERS);
361   assert(threads != 0 && threads <= MAX_NDBMT_LQH_THREADS);
362   assert(workers % threads == 0);
363 
364   globalData.ndbMtLqhWorkers = workers;
365   globalData.ndbMtLqhThreads = threads;
366   return 0;
367 }
368 
369 
370 static void
ndbd_exit(int code)371 ndbd_exit(int code)
372 {
373   // Don't allow negative return code
374   if (code < 0)
375     code = 255;
376 
377 // gcov will not produce results when using _exit
378 #ifdef HAVE_gcov
379   exit(code);
380 #else
381   _exit(code);
382 #endif
383 }
384 
385 
386 static FILE *angel_info_w = NULL;
387 
388 static void
writeChildInfo(const char * token,int val)389 writeChildInfo(const char *token, int val)
390 {
391   fprintf(angel_info_w, "%s=%d\n", token, val);
392   fflush(angel_info_w);
393 }
394 
395 static void
childReportSignal(int signum)396 childReportSignal(int signum)
397 {
398   writeChildInfo("signal", signum);
399 }
400 
401 static void
childExit(int error_code,int exit_code,Uint32 currentStartPhase)402 childExit(int error_code, int exit_code, Uint32 currentStartPhase)
403 {
404   writeChildInfo("error", error_code);
405   writeChildInfo("sphase", currentStartPhase);
406   fprintf(angel_info_w, "\n");
407   fclose(angel_info_w);
408   ndbd_exit(exit_code);
409 }
410 
411 static void
childAbort(int error_code,int exit_code,Uint32 currentStartPhase)412 childAbort(int error_code, int exit_code, Uint32 currentStartPhase)
413 {
414   writeChildInfo("error", error_code);
415   writeChildInfo("sphase", currentStartPhase);
416   fprintf(angel_info_w, "\n");
417   fclose(angel_info_w);
418 
419 #ifdef _WIN32
420   // Don't use 'abort' on Windows since it returns
421   // exit code 3 which conflict with NRT_NoStart_InitialStart
422   ndbd_exit(exit_code);
423 #else
424   signal(SIGABRT, SIG_DFL);
425   abort();
426 #endif
427 }
428 
429 extern "C"
430 void
handler_shutdown(int signum)431 handler_shutdown(int signum){
432   g_eventLogger->info("Received signal %d. Performing stop.", signum);
433   childReportSignal(signum);
434   globalData.theRestartFlag = perform_stop;
435 }
436 
437 extern NdbMutex * theShutdownMutex;
438 
439 extern "C"
440 void
handler_error(int signum)441 handler_error(int signum){
442   // only let one thread run shutdown
443   static bool handling_error = false;
444   static pthread_t thread_id; // Valid when handling_error is true
445 
446   if (handling_error &&
447       pthread_equal(thread_id, pthread_self()))
448   {
449     // Shutdown thread received signal
450 #ifndef NDB_WIN32
451 	signal(signum, SIG_DFL);
452     kill(getpid(), signum);
453 #endif
454     while(true)
455       NdbSleep_MilliSleep(10);
456   }
457   if(theShutdownMutex && NdbMutex_Trylock(theShutdownMutex) != 0)
458     while(true)
459       NdbSleep_MilliSleep(10);
460 
461   thread_id = pthread_self();
462   handling_error = true;
463 
464   g_eventLogger->info("Received signal %d. Running error handler.", signum);
465   childReportSignal(signum);
466   // restart the system
467   char errorData[64], *info= 0;
468 #ifdef HAVE_STRSIGNAL
469   info= strsignal(signum);
470 #endif
471   BaseString::snprintf(errorData, sizeof(errorData), "Signal %d received; %s", signum,
472 		       info ? info : "No text for signal available");
473   ERROR_SET_SIGNAL(fatal, NDBD_EXIT_OS_SIGNAL_RECEIVED, errorData, __FILE__);
474 }
475 
476 
477 static void
catchsigs(bool foreground)478 catchsigs(bool foreground){
479   static const int signals_shutdown[] = {
480 #ifdef SIGBREAK
481     SIGBREAK,
482 #endif
483 #ifdef SIGHUP
484     SIGHUP,
485 #endif
486     SIGINT,
487 #if defined SIGPWR
488     SIGPWR,
489 #elif defined SIGINFO
490     SIGINFO,
491 #endif
492     SIGQUIT,
493     SIGTERM,
494 #ifdef SIGTSTP
495     SIGTSTP,
496 #endif
497 #ifdef SIGTTIN
498     SIGTTIN,
499 #endif
500 #ifdef SIGTTOU
501     SIGTTOU
502 #endif
503   };
504 
505   static const int signals_error[] = {
506     SIGABRT,
507 #ifdef SIGALRM
508     SIGALRM,
509 #endif
510 #ifdef SIGBUS
511     SIGBUS,
512 #endif
513 #ifdef SIGCHLD
514     SIGCHLD,
515 #endif
516     SIGFPE,
517     SIGILL,
518 #ifdef SIGIO
519     SIGIO,
520 #endif
521 #ifdef SIGPOLL
522     SIGPOLL,
523 #endif
524     SIGSEGV
525   };
526 
527   static const int signals_ignore[] = {
528     SIGPIPE
529   };
530 
531   size_t i;
532   for(i = 0; i < sizeof(signals_shutdown)/sizeof(signals_shutdown[0]); i++)
533     signal(signals_shutdown[i], handler_shutdown);
534   for(i = 0; i < sizeof(signals_error)/sizeof(signals_error[0]); i++)
535     signal(signals_error[i], handler_error);
536   for(i = 0; i < sizeof(signals_ignore)/sizeof(signals_ignore[0]); i++)
537     signal(signals_ignore[i], SIG_IGN);
538 
539 #ifdef SIGTRAP
540   if (!foreground)
541     signal(SIGTRAP, handler_error);
542 #endif
543 
544 }
545 
546 #ifdef _WIN32
547 static HANDLE g_shutdown_event;
548 
shutdown_thread(LPVOID)549 DWORD WINAPI shutdown_thread(LPVOID)
550 {
551   // Wait forever until the shutdown event is signaled
552   WaitForSingleObject(g_shutdown_event, INFINITE);
553 
554   g_eventLogger->info("Performing stop");
555   globalData.theRestartFlag = perform_stop;
556   return 0;
557 }
558 #endif
559 
560 
561 void
ndbd_run(bool foreground,int report_fd,const char * connect_str,int force_nodeid,const char * bind_address,bool no_start,bool initial,bool initialstart,unsigned allocated_nodeid)562 ndbd_run(bool foreground, int report_fd,
563          const char* connect_str, int force_nodeid, const char* bind_address,
564          bool no_start, bool initial, bool initialstart,
565          unsigned allocated_nodeid)
566 {
567 #ifdef _WIN32
568   {
569     char shutdown_event_name[32];
570     _snprintf(shutdown_event_name, sizeof(shutdown_event_name),
571               "ndbd_shutdown_%d", GetCurrentProcessId());
572 
573     g_shutdown_event = CreateEvent(NULL, TRUE, FALSE, shutdown_event_name);
574     if (g_shutdown_event == NULL)
575     {
576       g_eventLogger->error("Failed to create shutdown event, error: %d",
577                            GetLastError());
578      ndbd_exit(1);
579     }
580 
581     HANDLE thread = CreateThread(NULL, 0, &shutdown_thread, NULL, 0, NULL);
582     if (thread == NULL)
583     {
584       g_eventLogger->error("couldn't start shutdown thread, error: %d",
585                            GetLastError());
586       ndbd_exit(1);
587     }
588   }
589 #endif
590 
591   if (foreground)
592     g_eventLogger->info("Ndb started in foreground");
593 
594   if (report_fd)
595   {
596     g_eventLogger->debug("Opening report stream on fd: %d", report_fd);
597     // Open a stream for sending extra status to angel
598     if (!(angel_info_w = fdopen(report_fd, "w")))
599     {
600       g_eventLogger->error("Failed to open stream for reporting "
601                            "to angel, error: %d (%s)", errno, strerror(errno));
602       ndbd_exit(-1);
603     }
604   }
605   else
606   {
607     // No reporting requested, open /dev/null
608     const char* dev_null = IF_WIN("nul", "/dev/null");
609     if (!(angel_info_w = fopen(dev_null, "w")))
610     {
611       g_eventLogger->error("Failed to open stream for reporting to "
612                            "'%s', error: %d (%s)", dev_null, errno,
613                            strerror(errno));
614       ndbd_exit(-1);
615     }
616   }
617 
618   globalEmulatorData.create();
619 
620   Configuration* theConfig = globalEmulatorData.theConfiguration;
621   if(!theConfig->init(no_start, initial, initialstart))
622   {
623     g_eventLogger->error("Failed to init Configuration");
624     ndbd_exit(-1);
625   }
626 
627   theConfig->fetch_configuration(connect_str, force_nodeid, bind_address,
628                                  allocated_nodeid);
629 
630   if (NdbDir::chdir(NdbConfig_get_path(NULL)) != 0)
631   {
632     g_eventLogger->warning("Cannot change directory to '%s', error: %d",
633                            NdbConfig_get_path(NULL), errno);
634     // Ignore error
635   }
636 
637   theConfig->setupConfiguration();
638 
639   if (get_multithreaded_config(globalEmulatorData))
640     ndbd_exit(-1);
641 
642   systemInfo(* theConfig, * theConfig->m_logLevel);
643 
644   NdbThread* pWatchdog = globalEmulatorData.theWatchDog->doStart();
645 
646   {
647     /*
648      * Memory allocation can take a long time for large memory.
649      *
650      * So we want the watchdog to monitor the process of initial allocation.
651      */
652     Uint32 watchCounter;
653     watchCounter = 9;           //  Means "doing allocation"
654     globalEmulatorData.theWatchDog->registerWatchedThread(&watchCounter, 0);
655     if (init_global_memory_manager(globalEmulatorData, &watchCounter))
656       ndbd_exit(1);
657     globalEmulatorData.theWatchDog->unregisterWatchedThread(0);
658   }
659 
660   globalEmulatorData.theThreadConfig->init();
661 
662 #ifdef VM_TRACE
663   // Create a signal logger before block constructors
664   char *buf= NdbConfig_SignalLogFileName(globalData.ownId);
665   NdbAutoPtr<char> tmp_aptr(buf);
666   FILE * signalLog = fopen(buf, "a");
667   globalSignalLoggers.setOwnNodeId(globalData.ownId);
668   globalSignalLoggers.setOutputStream(signalLog);
669 #if 1 // to log startup
670   { const char* p = NdbEnv_GetEnv("NDB_SIGNAL_LOG", (char*)0, 0);
671     if (p != 0) {
672       char buf[200];
673       BaseString::snprintf(buf, sizeof(buf), "BLOCK=%s", p);
674       for (char* q = buf; *q != 0; q++) *q = toupper(toascii(*q));
675       globalSignalLoggers.log(SignalLoggerManager::LogInOut, buf);
676       globalData.testOn = 1;
677       assert(signalLog != 0);
678       fprintf(signalLog, "START\n");
679       fflush(signalLog);
680     }
681   }
682 #endif
683 #endif
684 
685   // Load blocks (both main and workers)
686   globalEmulatorData.theSimBlockList->load(globalEmulatorData);
687 
688   // Set thread concurrency for Solaris' light weight processes
689   int status;
690   status = NdbThread_SetConcurrencyLevel(30);
691   assert(status == 0);
692 
693   catchsigs(foreground);
694 
695   /**
696    * Do startup
697    */
698   switch(globalData.theRestartFlag){
699   case initial_state:
700     globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI);
701     break;
702   case perform_start:
703     globalEmulatorData.theThreadConfig->doStart(NodeState::SL_CMVMI);
704     globalEmulatorData.theThreadConfig->doStart(NodeState::SL_STARTING);
705     break;
706   default:
707     assert("Illegal state globalData.theRestartFlag" == 0);
708   }
709 
710   globalTransporterRegistry.startSending();
711   globalTransporterRegistry.startReceiving();
712   if (!globalTransporterRegistry.start_service(*globalEmulatorData.m_socket_server)){
713     ndbout_c("globalTransporterRegistry.start_service() failed");
714     ndbd_exit(-1);
715   }
716 
717   // Re-use the mgm handle as a transporter
718   if(!globalTransporterRegistry.connect_client(
719 		 theConfig->get_config_retriever()->get_mgmHandlePtr()))
720       ERROR_SET(fatal, NDBD_EXIT_CONNECTION_SETUP_FAILED,
721                 "Failed to convert mgm connection to a transporter",
722                 __FILE__);
723 
724   NdbThread* pTrp = globalTransporterRegistry.start_clients();
725   if (pTrp == 0)
726   {
727     ndbout_c("globalTransporterRegistry.start_clients() failed");
728     ndbd_exit(-1);
729   }
730 
731   NdbThread* pSockServ = globalEmulatorData.m_socket_server->startServer();
732 
733   globalEmulatorData.theConfiguration->addThread(pTrp, SocketClientThread);
734   globalEmulatorData.theConfiguration->addThread(pWatchdog, WatchDogThread);
735   globalEmulatorData.theConfiguration->addThread(pSockServ, SocketServerThread);
736 
737   //  theConfig->closeConfiguration();
738   {
739     NdbThread *pThis = NdbThread_CreateObject(0);
740     Uint32 inx = globalEmulatorData.theConfiguration->addThread(pThis,
741                                                                 MainThread);
742     globalEmulatorData.theThreadConfig->ipControlLoop(pThis, inx);
743     globalEmulatorData.theConfiguration->removeThreadId(inx);
744   }
745   NdbShutdown(0, NST_Normal);
746 
747   ndbd_exit(0);
748 }
749 
750 
751 extern "C" my_bool opt_core;
752 
753 // instantiated and updated in NdbcntrMain.cpp
754 extern Uint32 g_currentStartPhase;
755 
756 int simulate_error_during_shutdown= 0;
757 
758 void
NdbShutdown(int error_code,NdbShutdownType type,NdbRestartType restartType)759 NdbShutdown(int error_code,
760             NdbShutdownType type,
761 	    NdbRestartType restartType)
762 {
763   if(type == NST_ErrorInsert)
764   {
765     type = NST_Restart;
766     restartType = (NdbRestartType)
767       globalEmulatorData.theConfiguration->getRestartOnErrorInsert();
768     if(restartType == NRT_Default)
769     {
770       type = NST_ErrorHandler;
771       globalEmulatorData.theConfiguration->stopOnError(true);
772     }
773   }
774 
775   if((type == NST_ErrorHandlerSignal) || // Signal handler has already locked mutex
776      (NdbMutex_Trylock(theShutdownMutex) == 0)){
777     globalData.theRestartFlag = perform_stop;
778 
779     bool restart = false;
780 
781     if((type != NST_Normal &&
782 	globalEmulatorData.theConfiguration->stopOnError() == false) ||
783        type == NST_Restart)
784     {
785       restart  = true;
786     }
787 
788     const char * shutting = "shutting down";
789     if(restart)
790     {
791       shutting = "restarting";
792     }
793 
794     switch(type){
795     case NST_Normal:
796       g_eventLogger->info("Shutdown initiated");
797       break;
798     case NST_Watchdog:
799       g_eventLogger->info("Watchdog %s system", shutting);
800       break;
801     case NST_ErrorHandler:
802       g_eventLogger->info("Error handler %s system", shutting);
803       break;
804     case NST_ErrorHandlerSignal:
805       g_eventLogger->info("Error handler signal %s system", shutting);
806       break;
807     case NST_Restart:
808       g_eventLogger->info("Restarting system");
809       break;
810     default:
811       g_eventLogger->info("Error handler %s system (unknown type: %u)",
812                           shutting, (unsigned)type);
813       type = NST_ErrorHandler;
814       break;
815     }
816 
817     const char * exitAbort = 0;
818     if (opt_core)
819       exitAbort = "aborting";
820     else
821       exitAbort = "exiting";
822 
823     if(type == NST_Watchdog)
824     {
825       /**
826        * Very serious, don't attempt to free, just die!!
827        */
828       g_eventLogger->info("Watchdog shutdown completed - %s", exitAbort);
829       if (opt_core)
830       {
831 	childAbort(error_code, -1,g_currentStartPhase);
832       }
833       else
834       {
835 	childExit(error_code, -1,g_currentStartPhase);
836       }
837     }
838 
839 #ifndef NDB_WIN32
840     if (simulate_error_during_shutdown)
841     {
842       kill(getpid(), simulate_error_during_shutdown);
843       while(true)
844 	NdbSleep_MilliSleep(10);
845     }
846 #endif
847 
848     globalEmulatorData.theWatchDog->doStop();
849 
850 #ifdef VM_TRACE
851     FILE * outputStream = globalSignalLoggers.setOutputStream(0);
852     if(outputStream != 0)
853       fclose(outputStream);
854 #endif
855 
856     /**
857      * Don't touch transporter here (yet)
858      *   cause with ndbmtd, there are locks and nasty stuff
859      *   and we don't know which we are holding...
860      */
861 #if NOT_YET
862 
863     /**
864      * Stop all transporter connection attempts and accepts
865      */
866     globalEmulatorData.m_socket_server->stopServer();
867     globalEmulatorData.m_socket_server->stopSessions();
868     globalTransporterRegistry.stop_clients();
869 
870     /**
871      * Stop transporter communication with other nodes
872      */
873     globalTransporterRegistry.stopSending();
874     globalTransporterRegistry.stopReceiving();
875 
876     /**
877      * Remove all transporters
878      */
879     globalTransporterRegistry.removeAll();
880 #endif
881 
882     if(type == NST_ErrorInsert && opt_core)
883     {
884       // Unload some structures to reduce size of core
885       globalEmulatorData.theSimBlockList->unload();
886       NdbMutex_Unlock(theShutdownMutex);
887       globalEmulatorData.destroy();
888     }
889 
890     if(type != NST_Normal && type != NST_Restart)
891     {
892       g_eventLogger->info("Error handler shutdown completed - %s", exitAbort);
893       if (opt_core)
894       {
895 	childAbort(error_code, -1,g_currentStartPhase);
896       }
897       else
898       {
899 	childExit(error_code, -1,g_currentStartPhase);
900       }
901     }
902 
903     /**
904      * This is a normal restart, depend on angel
905      */
906     if(type == NST_Restart){
907       childExit(error_code, restartType,g_currentStartPhase);
908     }
909 
910     g_eventLogger->info("Shutdown completed - exiting");
911   }
912   else
913   {
914     /**
915      * Shutdown is already in progress
916      */
917 
918     /**
919      * If this is the watchdog, kill system the hard way
920      */
921     if (type== NST_Watchdog)
922     {
923       g_eventLogger->info("Watchdog is killing system the hard way");
924 #if defined VM_TRACE
925       childAbort(error_code, -1,g_currentStartPhase);
926 #else
927       childExit(error_code, -1, g_currentStartPhase);
928 #endif
929     }
930 
931     while(true)
932       NdbSleep_MilliSleep(10);
933   }
934 }
935