1 /*
2    Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
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 "my_alloc.h"
31 #include "ndbd.hpp"
32 #include "angel.hpp"
33 
34 #include "../common/util/parse_mask.hpp"
35 #include "OwnProcessInfo.hpp"
36 
37 #include <EventLogger.hpp>
38 
39 #define JAM_FILE_ID 485
40 
41 extern EventLogger * g_eventLogger;
42 
43 static int opt_daemon, opt_no_daemon, opt_foreground,
44   opt_initialstart, opt_verbose;
45 static const char* opt_nowait_nodes = 0;
46 static const char* opt_bind_address = 0;
47 static int opt_report_fd;
48 static int opt_initial;
49 static int opt_no_start;
50 static unsigned opt_allocated_nodeid;
51 static int opt_angel_pid;
52 static int opt_retries;
53 static int opt_delay;
54 static unsigned long opt_logbuffer_size;
55 
56 extern NdbNodeBitmask g_nowait_nodes;
57 
58 static struct my_option my_long_options[] =
59 {
60   NDB_STD_OPTS("ndbd"),
61   { "initial", NDB_OPT_NOSHORT,
62     "Perform initial start of ndbd, including cleaning the file system. "
63     "Consult documentation before using this",
64     (uchar**) &opt_initial, (uchar**) &opt_initial, 0,
65     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
66   { "nostart", 'n',
67     "Don't start ndbd immediately. Ndbd will await command from ndb_mgmd",
68     (uchar**) &opt_no_start, (uchar**) &opt_no_start, 0,
69     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
70   { "daemon", 'd', "Start ndbd as daemon (default)",
71     (uchar**) &opt_daemon, (uchar**) &opt_daemon, 0,
72     GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 },
73   { "nodaemon", NDB_OPT_NOSHORT,
74     "Do not start ndbd as daemon, provided for testing purposes",
75     (uchar**) &opt_no_daemon, (uchar**) &opt_no_daemon, 0,
76     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
77   { "foreground", NDB_OPT_NOSHORT,
78     "Run real ndbd in foreground, provided for debugging purposes"
79     " (implies --nodaemon)",
80     (uchar**) &opt_foreground, (uchar**) &opt_foreground, 0,
81     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
82   { "nowait-nodes", NDB_OPT_NOSHORT,
83     "Nodes that will not be waited for during start",
84     (uchar**) &opt_nowait_nodes, (uchar**) &opt_nowait_nodes, 0,
85     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
86   { "initial-start", NDB_OPT_NOSHORT,
87     "Perform a partial initial start of the cluster.  "
88     "Each node should be started with this option, as well as --nowait-nodes",
89     (uchar**) &opt_initialstart, (uchar**) &opt_initialstart, 0,
90     GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
91   { "bind-address", NDB_OPT_NOSHORT,
92     "Local bind address",
93     (uchar**) &opt_bind_address, (uchar**) &opt_bind_address, 0,
94     GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
95   { "verbose", 'v',
96     "Write more log messages",
97     (uchar**) &opt_verbose, (uchar**) &opt_verbose, 0,
98     GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0 },
99   { "report-fd", 256,
100     "INTERNAL: fd where to write extra shutdown status",
101     (uchar**) &opt_report_fd, (uchar**) &opt_report_fd, 0,
102     GET_UINT, REQUIRED_ARG, 0, 0, INT_MAX, 0, 0, 0 },
103   { "allocated-nodeid", 256,
104     "INTERNAL: nodeid allocated by angel process",
105     (uchar**) &opt_allocated_nodeid, (uchar**) &opt_allocated_nodeid, 0,
106     GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 0, 0 },
107   { "angel-pid", NDB_OPT_NOSHORT,
108     "INTERNAL: angel process id",
109     (uchar**) &opt_angel_pid, (uchar **) &opt_angel_pid, 0,
110     GET_UINT, REQUIRED_ARG, 0, 0, UINT_MAX, 0, 0, 0 },
111   { "connect-retries", 'r',
112     "Number of times mgmd is contacted at start. -1: eternal retries",
113     (uchar**) &opt_retries, (uchar**) &opt_retries, 0,
114     GET_INT, REQUIRED_ARG, 12, -1, 65535, 0, 0, 0 },
115   { "connect-delay", NDB_OPT_NOSHORT,
116     "Number of seconds between each connection attempt",
117     (uchar**) &opt_delay, (uchar**) &opt_delay, 0,
118     GET_INT, REQUIRED_ARG, 5, 0, 3600, 0, 0, 0 },
119   { "logbuffer-size", NDB_OPT_NOSHORT,
120     "Size of the log buffer for data node ndb_x_out.log",
121     (uchar**) &opt_logbuffer_size, (uchar**) &opt_logbuffer_size, 0,
122     GET_ULONG, REQUIRED_ARG, 32768, 2048, ULONG_MAX, 0, 0, 0
123   },
124   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
125 };
126 
127 const char *load_default_groups[]= { "mysql_cluster", "ndbd", 0 };
128 
129 
short_usage_sub(void)130 static void short_usage_sub(void)
131 {
132   ndb_short_usage_sub(NULL);
133   ndb_service_print_options("ndbd");
134 }
135 
136 /**
137  * C++ Standard 3.6.1/3:
138  *  The function main shall not be used (3.2) within a program.
139  *
140  * So call "main" "real_main" to avoid this rule...
141  */
142 int
real_main(int argc,char ** argv)143 real_main(int argc, char** argv)
144 {
145   NDB_INIT(argv[0]);
146   Ndb_opts::release();  // because ndbd can fork and call real_main() again
147   Ndb_opts opts(argc, argv, my_long_options, load_default_groups);
148 
149   // Print to stdout/console
150   g_eventLogger->createConsoleHandler();
151 
152 #ifdef _WIN32
153   /* Output to Windows event log */
154   g_eventLogger->createEventLogHandler("MySQL Cluster Data Node Daemon");
155 #endif
156 
157   g_eventLogger->setCategory("ndbd");
158 
159   // Turn on max loglevel for startup messages
160   g_eventLogger->m_logLevel.setLogLevel(LogLevel::llStartUp, 15);
161 
162   opts.set_usage_funcs(short_usage_sub);
163 
164 #ifndef DBUG_OFF
165   opt_debug= "d:t:O,/tmp/ndbd.trace";
166 #endif
167 
168   // Save the original program name and arguments for angel
169   const char* progname = argv[0];
170   Vector<BaseString> original_args;
171   for (int i = 0; i < argc; i++)
172   {
173     if (ndb_is_load_default_arg_separator(argv[i]))
174       continue;
175     original_args.push_back(argv[i]);
176   }
177 
178   int ho_error;
179   if ((ho_error=opts.handle_options()))
180     exit(ho_error);
181 
182   if (opt_no_daemon || opt_foreground) {
183     // --nodaemon or --forground implies --daemon=0
184     opt_daemon= 0;
185   }
186 
187   // Turn on debug printouts if --verbose
188   if (opt_verbose)
189     g_eventLogger->enable(Logger::LL_DEBUG);
190 
191   if (opt_nowait_nodes)
192   {
193     int res = parse_mask(opt_nowait_nodes, g_nowait_nodes);
194     if(res == -2 || (res > 0 && g_nowait_nodes.get(0)))
195     {
196       g_eventLogger->error("Invalid nodeid specified in nowait-nodes: %s",
197                            opt_nowait_nodes);
198       exit(-1);
199     }
200     else if (res < 0)
201     {
202       g_eventLogger->error("Unable to parse nowait-nodes argument: %s",
203                            opt_nowait_nodes);
204       exit(-1);
205     }
206   }
207 
208  if(opt_angel_pid)
209   {
210     setOwnProcessInfoAngelPid(opt_angel_pid);
211   }
212 
213   if (opt_foreground ||
214       opt_allocated_nodeid ||
215       opt_report_fd)
216   {
217     /**
218       This is where we start running the real data node process after
219       reading options. This function will never return.
220     */
221     ndbd_run(opt_foreground, opt_report_fd,
222              opt_ndb_connectstring, opt_ndb_nodeid, opt_bind_address,
223              opt_no_start, opt_initial, opt_initialstart,
224              opt_allocated_nodeid, opt_retries, opt_delay,
225              opt_logbuffer_size);
226   }
227 
228   /**
229     The angel process takes care of automatic restarts, by default this is
230     the default to have an angel process. When an angel process is used the
231     program will enter into angel_run from where we fork off the real data
232     node process, the real process will always have opt_allocated_nodeid
233     set since we don't want the nodeid to change between restarts.
234   */
235   angel_run(progname,
236             original_args,
237             opt_ndb_connectstring,
238             opt_ndb_nodeid,
239             opt_bind_address,
240             opt_initial,
241             opt_no_start,
242             opt_daemon,
243             opt_retries,
244             opt_delay);
245 
246   return 1; // Never reached
247 }
248 
249 int
main(int argc,char ** argv)250 main(int argc, char** argv)
251 {
252   return ndb_daemon_init(argc, argv, real_main, angel_stop,
253                          "ndbd", "MySQL Cluster Data Node Daemon");
254 }
255