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