1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include <ndb_global.h>
26 #include <ndb_opts.h>
27 #include <kernel/NodeBitmask.hpp>
28 #include <portlib/ndb_daemon.h>
29 
30 #include "ndbd.hpp"
31 #include "angel.hpp"
32 
33 #include "../common/util/parse_mask.hpp"
34 
35 #include <EventLogger.hpp>
36 
37 #define JAM_FILE_ID 485
38 
39 extern EventLogger * g_eventLogger;
40 
41 static int opt_daemon, opt_no_daemon, opt_foreground,
42   opt_initialstart, opt_verbose;
43 static const char* opt_nowait_nodes = 0;
44 static const char* opt_bind_address = 0;
45 static int opt_report_fd;
46 static int opt_initial;
47 static int opt_no_start;
48 static unsigned opt_allocated_nodeid;
49 static int opt_retries;
50 static int opt_delay;
51 
52 extern NdbNodeBitmask g_nowait_nodes;
53 
54 static struct my_option my_long_options[] =
55 {
56   NDB_STD_OPTS("ndbd"),
57   { "initial", NDB_OPT_NOSHORT,
58     "Perform initial start of ndbd, including cleaning the file system. "
59     "Consult documentation before using this",
60     (uchar**) &opt_initial, (uchar**) &opt_initial, 0,
61     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
62   { "nostart", 'n',
63     "Don't start ndbd immediately. Ndbd will await command from ndb_mgmd",
64     (uchar**) &opt_no_start, (uchar**) &opt_no_start, 0,
65     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
66   { "daemon", 'd', "Start ndbd as daemon (default)",
67     (uchar**) &opt_daemon, (uchar**) &opt_daemon, 0,
68     GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 },
69   { "nodaemon", NDB_OPT_NOSHORT,
70     "Do not start ndbd as daemon, provided for testing purposes",
71     (uchar**) &opt_no_daemon, (uchar**) &opt_no_daemon, 0,
72     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
73   { "foreground", NDB_OPT_NOSHORT,
74     "Run real ndbd in foreground, provided for debugging purposes"
75     " (implies --nodaemon)",
76     (uchar**) &opt_foreground, (uchar**) &opt_foreground, 0,
77     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
78   { "nowait-nodes", NDB_OPT_NOSHORT,
79     "Nodes that will not be waited for during start",
80     (uchar**) &opt_nowait_nodes, (uchar**) &opt_nowait_nodes, 0,
81     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
82   { "initial-start", NDB_OPT_NOSHORT,
83     "Perform a partial initial start of the cluster.  "
84     "Each node should be started with this option, as well as --nowait-nodes",
85     (uchar**) &opt_initialstart, (uchar**) &opt_initialstart, 0,
86     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
87   { "bind-address", NDB_OPT_NOSHORT,
88     "Local bind address",
89     (uchar**) &opt_bind_address, (uchar**) &opt_bind_address, 0,
90     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
91   { "verbose", 'v',
92     "Write more log messages",
93     (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
94     GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
95   { "report-fd", 256,
96     "INTERNAL: fd where to write extra shutdown status",
97     (uchar**) &opt_report_fd, (uchar**) &opt_report_fd, 0,
98     GET_UINT, REQUIRED_ARG, 0, 0, INT_MAX, 0, 0, 0 },
99   { "allocated-nodeid", 256,
100     "INTERNAL: nodeid allocated by angel process",
101     (uchar**) &opt_allocated_nodeid, (uchar**) &opt_allocated_nodeid, 0,
102     GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 0, 0 },
103   { "connect-retries", 'r',
104     "Number of times mgmd is contacted at start. -1: eternal retries",
105     (uchar**) &opt_retries, (uchar**) &opt_retries, 0,
106     GET_INT, REQUIRED_ARG, 12, -1, 65535, 0, 0, 0 },
107   { "connect-delay", NDB_OPT_NOSHORT,
108     "Number of seconds between each connection attempt",
109     (uchar**) &opt_delay, (uchar**) &opt_delay, 0,
110     GET_INT, REQUIRED_ARG, 5, 0, 3600, 0, 0, 0 },
111   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
112 };
113 
114 const char *load_default_groups[]= { "mysql_cluster", "ndbd", 0 };
115 
116 
short_usage_sub(void)117 static void short_usage_sub(void)
118 {
119   ndb_short_usage_sub(NULL);
120   ndb_service_print_options("ndbd");
121 }
122 
usage()123 static void usage()
124 {
125   ndb_usage(short_usage_sub, load_default_groups, my_long_options);
126 }
127 
128 /**
129  * C++ Standard 3.6.1/3:
130  *  The function main shall not be used (3.2) within a program.
131  *
132  * So call "main" "real_main" to avoid this rule...
133  */
134 int
real_main(int argc,char ** argv)135 real_main(int argc, char** argv)
136 {
137   NDB_INIT(argv[0]);
138 
139   // Print to stdout/console
140   g_eventLogger->createConsoleHandler();
141 
142 #ifdef _WIN32
143   /* Output to Windows event log */
144   g_eventLogger->createEventLogHandler("MySQL Cluster Data Node Daemon");
145 #endif
146 
147   g_eventLogger->setCategory("ndbd");
148 
149   // Turn on max loglevel for startup messages
150   g_eventLogger->m_logLevel.setLogLevel(LogLevel::llStartUp, 15);
151 
152   ndb_opt_set_usage_funcs(short_usage_sub, usage);
153   ndb_load_defaults(NULL,load_default_groups,&argc,&argv);
154 
155 #ifndef NDEBUG
156   opt_debug= "d:t:O,/tmp/ndbd.trace";
157 #endif
158 
159   // Save the original program name and arguments for angel
160   const char* progname = argv[0];
161   Vector<BaseString> original_args;
162   for (int i = 0; i < argc; i++)
163   {
164     if (ndb_is_load_default_arg_separator(argv[i]))
165       continue;
166     original_args.push_back(argv[i]);
167   }
168 
169   int ho_error;
170   if ((ho_error=handle_options(&argc, &argv, my_long_options,
171                                ndb_std_get_one_option)))
172     exit(ho_error);
173 
174   if (opt_no_daemon || opt_foreground) {
175     // --nodaemon or --forground implies --daemon=0
176     opt_daemon= 0;
177   }
178 
179   // Turn on debug printouts if --verbose
180   if (opt_verbose)
181     g_eventLogger->enable(Logger::LL_DEBUG);
182 
183   if (opt_nowait_nodes)
184   {
185     int res = parse_mask(opt_nowait_nodes, g_nowait_nodes);
186     if(res == -2 || (res > 0 && g_nowait_nodes.get(0)))
187     {
188       g_eventLogger->error("Invalid nodeid specified in nowait-nodes: %s",
189                            opt_nowait_nodes);
190       exit(-1);
191     }
192     else if (res < 0)
193     {
194       g_eventLogger->error("Unable to parse nowait-nodes argument: %s",
195                            opt_nowait_nodes);
196       exit(-1);
197     }
198   }
199 
200   if (opt_foreground ||
201       opt_allocated_nodeid ||
202       opt_report_fd)
203   {
204     /**
205       This is where we start running the real data node process after
206       reading options. This function will never return.
207     */
208     ndbd_run(opt_foreground, opt_report_fd,
209              opt_ndb_connectstring, opt_ndb_nodeid, opt_bind_address,
210              opt_no_start, opt_initial, opt_initialstart,
211              opt_allocated_nodeid, opt_retries, opt_delay);
212   }
213 
214   /**
215     The angel process takes care of automatic restarts, by default this is
216     the default to have an angel process. When an angel process is used the
217     program will enter into angel_run from where we fork off the real data
218     node process, the real process will always have opt_allocated_nodeid
219     set since we don't want the nodeid to change between restarts.
220   */
221   angel_run(progname,
222             original_args,
223             opt_ndb_connectstring,
224             opt_ndb_nodeid,
225             opt_bind_address,
226             opt_initial,
227             opt_no_start,
228             opt_daemon,
229             opt_retries,
230             opt_delay);
231 
232   return 1; // Never reached
233 }
234 
235 int
main(int argc,char ** argv)236 main(int argc, char** argv)
237 {
238   return ndb_daemon_init(argc, argv, real_main, angel_stop,
239                          "ndbd", "MySQL Cluster Data Node Daemon");
240 }
241