MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
angel.cpp
1 /* Copyright (c) 2009, 2010, 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 as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
15 
16 
17 #include <ndb_global.h>
18 #include <ndb_version.h>
19 
20 #include "angel.hpp"
21 #include "ndbd.hpp"
22 
23 #include <NdbConfig.h>
24 #include <NdbAutoPtr.hpp>
25 #include <portlib/ndb_daemon.h>
26 #include <portlib/NdbSleep.h>
27 #include <portlib/NdbDir.hpp>
28 
29 #include <ConfigRetriever.hpp>
30 
31 #include <EventLogger.hpp>
32 extern EventLogger * g_eventLogger;
33 
34 static void
35 angel_exit(int code)
36 {
37  ndb_daemon_exit(code);
38 }
39 
40 #include "../mgmapi/mgmapi_configuration.hpp"
41 
42 static void
43 reportShutdown(const ndb_mgm_configuration* config,
44  NodeId nodeid, int error_exit,
45  bool restart, bool nostart, bool initial,
46  Uint32 error, Uint32 signum, Uint32 sphase)
47 {
48  // Only allow "initial" and "nostart" to be set if "restart" is set
49  assert(restart ||
50  (!restart && !initial && !nostart));
51 
52  Uint32 length, theData[25];
53  EventReport *rep= CAST_PTR(EventReport, &theData[0]);
54 
55  rep->setNodeId(nodeid);
56  if (restart)
57  theData[1]=1 |
58  (nostart ? 2 : 0) |
59  (initial ? 4 : 0);
60  else
61  theData[1]=0;
62 
63  if (error_exit == 0)
64  {
65  rep->setEventType(NDB_LE_NDBStopCompleted);
66  theData[2]=signum;
67  length=3;
68  } else
69  {
70  rep->setEventType(NDB_LE_NDBStopForced);
71  theData[2]=signum;
72  theData[3]=error;
73  theData[4]=sphase;
74  theData[5]=0; // extra
75  length=6;
76  }
77 
78  // Log event locally
79  g_eventLogger->log(rep->getEventType(), theData, length,
80  rep->getNodeId(), 0);
81 
82  // Log event to cluster log
83  ndb_mgm_configuration_iterator iter(*config, CFG_SECTION_NODE);
84  for (iter.first(); iter.valid(); iter.next())
85  {
86  Uint32 type;
87  if (iter.get(CFG_TYPE_OF_SECTION, &type) ||
88  type != NODE_TYPE_MGM)
89  continue;
90 
91  Uint32 port;
92  if (iter.get(CFG_MGM_PORT, &port))
93  continue;
94 
95  const char* hostname;
96  if (iter.get(CFG_NODE_HOST, &hostname))
97  continue;
98 
99  BaseString connect_str;
100  connect_str.assfmt("%s:%d", hostname, port);
101 
102 
104  if (h == 0)
105  {
106  g_eventLogger->warning("Unable to report shutdown reason "
107  "to '%s'(failed to create mgm handle)",
108  connect_str.c_str());
109  continue;
110  }
111 
112  if (ndb_mgm_set_connectstring(h, connect_str.c_str()) ||
113  ndb_mgm_connect(h, 1, 0, 0) ||
114  ndb_mgm_report_event(h, theData, length))
115  {
116  g_eventLogger->warning("Unable to report shutdown reason "
117  "to '%s'(error: %s - %s)",
118  connect_str.c_str(),
121  }
122 
124  }
125 }
126 
127 
128 static void
129 ignore_signals(void)
130 {
131  static const int ignore_list[] = {
132 #ifdef SIGBREAK
133  SIGBREAK,
134 #endif
135 #ifdef SIGHUP
136  SIGHUP,
137 #endif
138  SIGINT,
139 #if defined SIGPWR
140  SIGPWR,
141 #elif defined SIGINFO
142  SIGINFO,
143 #endif
144  SIGQUIT,
145  SIGTERM,
146 #ifdef SIGTSTP
147  SIGTSTP,
148 #endif
149 #ifdef SIGTTIN
150  SIGTTIN,
151 #endif
152 #ifdef SIGTTOU
153  SIGTTOU,
154 #endif
155  SIGABRT,
156 #ifdef SIGALRM
157  SIGALRM,
158 #endif
159 #ifdef SIGBUS
160  SIGBUS,
161 #endif
162  SIGFPE,
163  SIGILL,
164 #ifdef SIGIO
165  SIGIO,
166 #endif
167 #ifdef SIGPOLL
168  SIGPOLL,
169 #endif
170  SIGSEGV,
171  SIGPIPE,
172 #ifdef SIGTRAP
173  SIGTRAP
174 #endif
175  };
176 
177  for(size_t i = 0; i < sizeof(ignore_list)/sizeof(ignore_list[0]); i++)
178  signal(ignore_list[i], SIG_IGN);
179 }
180 
181 #ifdef _WIN32
182 static inline
183 int pipe(int pipefd[2]){
184  const unsigned int buffer_size = 4096;
185  const int flags = 0;
186  return _pipe(pipefd, buffer_size, flags);
187 }
188 
189 #undef getpid
190 #include <process.h>
191 
192 typedef DWORD pid_t;
193 
194 static const int WNOHANG = 37;
195 
196 static inline
197 pid_t waitpid(pid_t pid, int *stat_loc, int options)
198 {
199  /* Only support waitpid(,,WNOHANG) */
200  assert(options == WNOHANG);
201  assert(stat_loc);
202 
203  HANDLE handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
204  if (handle == NULL)
205  {
206  g_eventLogger->error("waitpid: Could not open handle for pid %d, "
207  "error: %d", pid, GetLastError());
208  return -1;
209  }
210 
211  DWORD exit_code;
212  if (!GetExitCodeProcess(handle, &exit_code))
213  {
214  g_eventLogger->error("waitpid: GetExitCodeProcess failed, pid: %d, "
215  "error: %d", pid, GetLastError());
216  CloseHandle(handle);
217  return -1;
218  }
219  CloseHandle(handle);
220 
221  if (exit_code == STILL_ACTIVE)
222  {
223  /* Still alive */
224  return 0;
225  }
226 
227  *stat_loc = exit_code;
228 
229  return pid;
230 }
231 
232 static inline
233 bool WIFEXITED(int status)
234 {
235  return true;
236 }
237 
238 static inline
239 int WEXITSTATUS(int status)
240 {
241  return status;
242 }
243 
244 static inline
245 bool WIFSIGNALED(int status)
246 {
247  return false;
248 }
249 
250 static inline
251 int WTERMSIG(int status)
252 {
253  return 0;
254 }
255 
256 static int
257 kill(pid_t pid, int sig)
258 {
259  int retry_open_event = 10;
260 
261  char shutdown_event_name[32];
262  _snprintf(shutdown_event_name, sizeof(shutdown_event_name),
263  "ndbd_shutdown_%d", pid);
264 
265  /* Open the event to signal */
266  HANDLE shutdown_event;
267  while ((shutdown_event =
268  OpenEvent(EVENT_MODIFY_STATE, FALSE, shutdown_event_name)) == NULL)
269  {
270  /*
271  Check if the process is alive, otherwise there is really
272  no sense to retry the open of the event
273  */
274  DWORD exit_code;
275  HANDLE process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION,
276  FALSE, pid);
277  if (!process)
278  {
279  /* Already died */
280  return -1;
281  }
282 
283  if (!GetExitCodeProcess(process,&exit_code))
284  {
285  g_eventLogger->error("GetExitCodeProcess failed, pid: %d, error: %d",
286  pid, GetLastError());
287  CloseHandle(process);
288  return -1;
289  }
290  CloseHandle(process);
291 
292  if (exit_code != STILL_ACTIVE)
293  {
294  /* Already died */
295  return -1;
296  }
297 
298  if (retry_open_event--)
299  Sleep(100);
300  else
301  {
302  g_eventLogger->error("Failed to open shutdown_event '%s', error: %d",
303  shutdown_event_name, GetLastError());
304  return -1;
305  }
306  }
307 
308  if (SetEvent(shutdown_event) == 0)
309  {
310  g_eventLogger->error("Failed to signal shutdown_event '%s', error: %d",
311  shutdown_event_name, GetLastError());
312  }
313  CloseHandle(shutdown_event);
314  return pid;
315 }
316 #endif
317 
318 extern int real_main(int, char**);
319 
320 
321 static
322 char** create_argv(const Vector<BaseString>& args)
323 {
324  char **argv = (char **)malloc(sizeof(char*) * (args.size() + 1));
325  if(argv == NULL)
326  return NULL;
327 
328  for(unsigned i = 0; i < args.size(); i++)
329  argv[i] = strdup(args[i].c_str());
330  argv[args.size()] = NULL;
331  return argv;
332 }
333 
334 
335 static
336 void free_argv(char** argv)
337 {
338  char** argp = argv;
339  while(*argp)
340  {
341  free((void*)*argp);
342  argp++;
343  }
344  free((void*)argv);
345 }
346 
347 
348 static pid_t
349 spawn_process(const char* progname, const Vector<BaseString>& args)
350 {
351 #ifdef _WIN32
352  // Get full path name of this executeble
353  char path[MAX_PATH];
354  DWORD len = GetModuleFileName(NULL, path, sizeof(path));
355  if (len == 0 || len == sizeof(path))
356  {
357  g_eventLogger->warning("spawn_process: Could not extract full path, "
358  "len: %u, error: %u\n",
359  len, GetLastError());
360  // Fall through and try with progname as it was supplied
361  }
362  else
363  {
364  progname = path;
365  }
366 #endif
367 
368  char** argv = create_argv(args);
369  if (!argv)
370  {
371  g_eventLogger->error("spawn_process: Failed to create argv, errno: %d",
372  errno);
373  return -1;
374  }
375 
376 #ifdef _WIN32
377 
378  intptr_t spawn_handle = _spawnv(P_NOWAIT, progname, argv);
379  if (spawn_handle == -1)
380  {
381  g_eventLogger->error("spawn_process: Failed to spawn process, errno: %d",
382  errno);
383  // Print the _spawnv arguments to aid debugging
384  g_eventLogger->error(" progname: '%s'", progname);
385  char** argp = argv;
386  while(*argp)
387  g_eventLogger->error("argv: '%s'", *argp++);
388 
389  free_argv(argv);
390  return -1;
391  }
392  free_argv(argv);
393 
394  // Convert the handle returned from spawnv_ to a pid
395  DWORD pid = GetProcessId((HANDLE)spawn_handle);
396  if (pid == 0)
397  {
398  g_eventLogger->error("spawn_process: Failed to convert handle %d "
399  "to pid, error: %d", spawn_handle, GetLastError());
400  CloseHandle((HANDLE)spawn_handle);
401  return -1;
402  }
403  CloseHandle((HANDLE)spawn_handle);
404  return pid;
405 #else
406  pid_t pid = fork();
407  if (pid == -1)
408  {
409  g_eventLogger->error("Failed to fork, errno: %d", errno);
410  free_argv(argv);
411  return -1;
412  }
413 
414  if (pid)
415  {
416  free_argv(argv);
417  // Parent
418  return pid;
419  }
420 
421  // Count number of arguments
422  int argc = 0;
423  while(argv[argc])
424  argc++;
425 
426  // Calling 'main' to start program from beginning
427  // without loading (possibly new version) from disk
428  (void)real_main(argc, argv);
429  assert(false); // main should never return
430  exit(1);
431  return -1; // Never reached
432 #endif
433 }
434 
435 /*
436  retry failed spawn after sleep until fork suceeds or
437  max number of retries occurs
438 */
439 
440 static pid_t
441 retry_spawn_process(const char* progname, const Vector<BaseString>& args)
442 {
443  const unsigned max_retries = 10;
444  unsigned retry_counter = 0;
445  while(true)
446  {
447  pid_t pid = spawn_process(progname, args);
448  if (pid == -1)
449  {
450  if (retry_counter++ == max_retries)
451  {
452  g_eventLogger->error("Angel failed to spawn %d times, giving up",
453  retry_counter);
454  angel_exit(1);
455  }
456 
457  g_eventLogger->warning("Angel failed to spawn, sleep and retry");
458 
459  NdbSleep_SecSleep(1);
460  continue;
461  }
462  return pid;
463  }
464 }
465 
466 static Uint32 stop_on_error;
467 static Uint32 config_max_start_fail_retries;
468 static Uint32 config_restart_delay_secs;
469 
470 
471 /*
472  Extract the config parameters that concerns angel
473 */
474 
475 static bool
476 configure(const ndb_mgm_configuration* conf, NodeId nodeid)
477 {
478  Uint32 generation = 0;
479  ndb_mgm_configuration_iterator sys_iter(*conf, CFG_SECTION_SYSTEM);
480  if (sys_iter.get(CFG_SYS_CONFIG_GENERATION, &generation))
481  {
482  g_eventLogger->warning("Configuration didn't contain generation "
483  "(likely old ndb_mgmd");
484  }
485  g_eventLogger->debug("Using configuration with generation %u", generation);
486 
487  ndb_mgm_configuration_iterator iter(*conf, CFG_SECTION_NODE);
488  if (iter.find(CFG_NODE_ID, nodeid))
489  {
490  g_eventLogger->error("Invalid configuration fetched, could not "
491  "find own node id %d", nodeid);
492  return false;
493  }
494 
495  if (iter.get(CFG_DB_STOP_ON_ERROR, &stop_on_error))
496  {
497  g_eventLogger->error("Invalid configuration fetched, could not "
498  "find StopOnError");
499  return false;
500  }
501  g_eventLogger->debug("Using StopOnError: %u", stop_on_error);
502 
503  if (iter.get(CFG_DB_MAX_START_FAIL, &config_max_start_fail_retries))
504  {
505  /* Old Management node, use default value */
506  config_max_start_fail_retries = 3;
507  }
508 
509  if (iter.get(CFG_DB_START_FAIL_DELAY_SECS, &config_restart_delay_secs))
510  {
511  /* Old Management node, use default value */
512  config_restart_delay_secs = 0;
513  }
514 
515  const char * datadir;
516  if (iter.get(CFG_NODE_DATADIR, &datadir))
517  {
518  g_eventLogger->error("Invalid configuration fetched, could not "
519  "find DataDir");
520  return false;
521  }
522  g_eventLogger->debug("Using DataDir: %s", datadir);
523 
524  NdbConfig_SetPath(datadir);
525 
526  if (NdbDir::chdir(NdbConfig_get_path(NULL)) != 0)
527  {
528  g_eventLogger->warning("Cannot change directory to '%s', error: %d",
529  NdbConfig_get_path(NULL), errno);
530  // Ignore error
531  }
532 
533  return true;
534 }
535 
536 bool stop_child = false;
537 
538 void
539 angel_run(const char* progname,
540  const Vector<BaseString>& original_args,
541  const char* connect_str,
542  int force_nodeid,
543  const char* bind_address,
544  bool initial,
545  bool no_start,
546  bool daemon)
547 {
548  ConfigRetriever retriever(connect_str,
549  force_nodeid,
550  NDB_VERSION,
552  bind_address);
553  if (retriever.hasError())
554  {
555  g_eventLogger->error("Could not initialize connection to management "
556  "server, error: '%s'", retriever.getErrorString());
557  angel_exit(1);
558  }
559 
560  const int connnect_retries = 12;
561  const int connect_delay = 5;
562  const int verbose = 1;
563  if (retriever.do_connect(connnect_retries, connect_delay, verbose) != 0)
564  {
565  g_eventLogger->error("Could not connect to management server, "
566  "error: '%s'", retriever.getErrorString());
567  angel_exit(1);
568  }
569  g_eventLogger->info("Angel connected to '%s:%d'",
570  retriever.get_mgmd_host(),
571  retriever.get_mgmd_port());
572 
573  const int alloc_retries = 2;
574  const int alloc_delay = 3;
575  const Uint32 nodeid = retriever.allocNodeId(alloc_retries, alloc_delay);
576  if (nodeid == 0)
577  {
578  g_eventLogger->error("Failed to allocate nodeid, error: '%s'",
579  retriever.getErrorString());
580  angel_exit(1);
581  }
582  g_eventLogger->info("Angel allocated nodeid: %u", nodeid);
583 
584  ndb_mgm_configuration * config = retriever.getConfig(nodeid);
585  NdbAutoPtr<ndb_mgm_configuration> config_autoptr(config);
586  if (config == 0)
587  {
588  g_eventLogger->error("Could not fetch configuration/invalid "
589  "configuration, error: '%s'",
590  retriever.getErrorString());
591  angel_exit(1);
592  }
593 
594  if (!configure(config, nodeid))
595  {
596  // Failed to configure, error already printed
597  angel_exit(1);
598  }
599 
600  if (daemon)
601  {
602  // Become a daemon
603  char *lockfile = NdbConfig_PidFileName(nodeid);
604  char *logfile = NdbConfig_StdoutFileName(nodeid);
605  NdbAutoPtr<char> tmp_aptr1(lockfile), tmp_aptr2(logfile);
606 
607  if (ndb_daemonize(lockfile, logfile) != 0)
608  {
609  g_eventLogger->error("Couldn't start as daemon, error: '%s'",
610  ndb_daemon_error);
611  angel_exit(1);
612  }
613  }
614 
615  // Counter for consecutive failed startups
616  Uint32 failed_startups_counter = 0;
617  while (true)
618  {
619 
620  // Create pipe where ndbd process will report extra shutdown status
621  int fds[2];
622  if (pipe(fds))
623  {
624  g_eventLogger->error("Failed to create pipe, errno: %d (%s)",
625  errno, strerror(errno));
626  angel_exit(1);
627  }
628 
629  FILE *child_info_r;
630  if (!(child_info_r = fdopen(fds[0], "r")))
631  {
632  g_eventLogger->error("Failed to open stream for pipe, errno: %d (%s)",
633  errno, strerror(errno));
634  angel_exit(1);
635  }
636 
637  // Build the args used to start ndbd by appending
638  // the arguments that may have changed at the end
639  // of original argument list
640  BaseString one_arg;
641  Vector<BaseString> args;
642  args = original_args;
643 
644  // Pass fd number of the pipe which ndbd should use
645  // for sending extra status to angel
646  one_arg.assfmt("--report-fd=%d", fds[1]);
647  args.push_back(one_arg);
648 
649  // The nodeid which has been allocated by angel
650  one_arg.assfmt("--allocated-nodeid=%d", nodeid);
651  args.push_back(one_arg);
652 
653  one_arg.assfmt("--initial=%d", initial);
654  args.push_back(one_arg);
655 
656  one_arg.assfmt("--nostart=%d", no_start);
657  args.push_back(one_arg);
658 
659  pid_t child = retry_spawn_process(progname, args);
660  if (child <= 0)
661  {
662  // safety, retry_spawn_process returns valid child or give up
663  g_eventLogger->error("retry_spawn_process, child: %d", child);
664  angel_exit(1);
665  }
666 
670  g_eventLogger->info("Angel pid: %d started child: %d",
671  getpid(), child);
672 
673  ignore_signals();
674 
675  int status=0, error_exit=0;
676  while(true)
677  {
678  pid_t ret_pid = waitpid(child, &status, WNOHANG);
679  if (ret_pid == child)
680  {
681  g_eventLogger->debug("Angel got child %d", child);
682  break;
683  }
684  if (ret_pid > 0)
685  {
686  g_eventLogger->warning("Angel got unexpected pid %d "
687  "when waiting for %d",
688  ret_pid, child);
689  }
690 
691  if (stop_child)
692  {
693  g_eventLogger->info("Angel shutting down ndbd with pid %d", child);
694  kill(child, SIGINT);
695  }
696  NdbSleep_MilliSleep(100);
697  }
698 
699  // Close the write end of pipe
700  close(fds[1]);
701 
702  // Read info from the child's pipe
703  char buf[128];
704  Uint32 child_error = 0, child_signal = 0, child_sphase = 0;
705  while (fgets(buf, sizeof (buf), child_info_r))
706  {
707  int value;
708  if (sscanf(buf, "error=%d\n", &value) == 1)
709  child_error = value;
710  else if (sscanf(buf, "signal=%d\n", &value) == 1)
711  child_signal = value;
712  else if (sscanf(buf, "sphase=%d\n", &value) == 1)
713  child_sphase = value;
714  else if (strcmp(buf, "\n") != 0)
715  fprintf(stderr, "unknown info from child: '%s'\n", buf);
716  }
717  g_eventLogger->debug("error: %u, signal: %u, sphase: %u",
718  child_error, child_signal, child_sphase);
719  // Close read end of pipe in parent
720  fclose(child_info_r);
721 
722  if (WIFEXITED(status))
723  {
724  switch (WEXITSTATUS(status)) {
725  case NRT_Default:
726  g_eventLogger->info("Angel shutting down");
727  reportShutdown(config, nodeid, 0, 0, false, false,
728  child_error, child_signal, child_sphase);
729  angel_exit(0);
730  break;
731  case NRT_NoStart_Restart:
732  initial = false;
733  no_start = true;
734  break;
735  case NRT_NoStart_InitialStart:
736  initial = true;
737  no_start = true;
738  break;
739  case NRT_DoStart_InitialStart:
740  initial = true;
741  no_start = false;
742  break;
743  default:
744  error_exit=1;
745  if (stop_on_error)
746  {
750  reportShutdown(config, nodeid,
751  error_exit, 0, false, false,
752  child_error, child_signal, child_sphase);
753  angel_exit(0);
754  }
755  // Fall-through
756  case NRT_DoStart_Restart:
757  initial = false;
758  no_start = false;
759  break;
760  }
761  } else
762  {
763  error_exit=1;
764  if (WIFSIGNALED(status))
765  {
766  child_signal = WTERMSIG(status);
767  }
768  else
769  {
770  child_signal = 127;
771  g_eventLogger->info("Unknown exit reason. Stopped.");
772  }
773  if (stop_on_error)
774  {
778  reportShutdown(config, nodeid,
779  error_exit, 0, false, false,
780  child_error, child_signal, child_sphase);
781  angel_exit(0);
782  }
783  }
784 
785  // Check startup failure
786  const Uint32 STARTUP_FAILURE_SPHASE = 6;
787  Uint32 restart_delay_secs = 0;
788  if (error_exit && // Only check startup failure if ndbd exited uncontrolled
789  child_sphase <= STARTUP_FAILURE_SPHASE)
790  {
791  if (++failed_startups_counter >= config_max_start_fail_retries)
792  {
793  g_eventLogger->alert("Angel detected too many startup failures(%d), "
794  "not restarting again", failed_startups_counter);
795  reportShutdown(config, nodeid,
796  error_exit, 0, false, false,
797  child_error, child_signal, child_sphase);
798  angel_exit(0);
799  }
800  g_eventLogger->info("Angel detected startup failure, count: %u",
801  failed_startups_counter);
802 
803  restart_delay_secs = config_restart_delay_secs;
804  }
805  else
806  {
807  // Reset the counter for consecutive failed startups
808  failed_startups_counter = 0;
809  }
810 
811  reportShutdown(config, nodeid,
812  error_exit, 1,
813  no_start,
814  initial,
815  child_error, child_signal, child_sphase);
816  g_eventLogger->info("Ndb has terminated (pid %d) restarting", child);
817 
818  g_eventLogger->debug("Angel reconnecting to management server");
819  (void)retriever.disconnect();
820 
821  if (restart_delay_secs > 0)
822  {
823  g_eventLogger->info("Delaying Ndb restart for %u seconds.",
824  restart_delay_secs);
825  NdbSleep_SecSleep(restart_delay_secs);
826  };
827 
828  const int connnect_retries = 12;
829  const int connect_delay = 5;
830  const int verbose = 1;
831  if (retriever.do_connect(connnect_retries, connect_delay, verbose) != 0)
832  {
833  g_eventLogger->error("Could not connect to management server, "
834  "error: '%s'", retriever.getErrorString());
835  angel_exit(1);
836  }
837  g_eventLogger->info("Angel reconnected to '%s:%d'",
838  retriever.get_mgmd_host(),
839  retriever.get_mgmd_port());
840 
841  // Tell retriver to allocate the same nodeid again
842  retriever.setNodeId(nodeid);
843 
844  g_eventLogger->debug("Angel reallocating nodeid %d", nodeid);
845  const int alloc_retries = 10;
846  const int alloc_delay = 3;
847  const Uint32 realloced = retriever.allocNodeId(alloc_retries, alloc_delay);
848  if (realloced == 0)
849  {
850  g_eventLogger->error("Angel failed to allocate nodeid, error: '%s'",
851  retriever.getErrorString());
852  angel_exit(1);
853  }
854  if (realloced != nodeid)
855  {
856  g_eventLogger->error("Angel failed to reallocate nodeid %d, got %d",
857  nodeid, realloced);
858  angel_exit(1);
859  }
860  g_eventLogger->info("Angel reallocated nodeid: %u", nodeid);
861 
862  }
863 
864  abort(); // Never reached
865 }
866 
867 
868 /*
869  Order angel to shutdown it's ndbd
870 */
871 void angel_stop(void)
872 {
873  stop_child = true;
874 }