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