MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
waiter.cpp
1 /*
2  Copyright (c) 2004, 2010, 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 as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <time.h>
19 #include <ndb_global.h>
20 #include <ndb_opts.h>
21 
22 #include <mgmapi.h>
23 #include <NdbMain.h>
24 #include <NdbOut.hpp>
25 #include <NdbSleep.h>
26 #include <NdbTick.h>
27 
28 #include <NDBT.hpp>
29 
30 #include <kernel/NodeBitmask.hpp>
31 
32 static int
33 waitClusterStatus(const char* _addr, ndb_mgm_node_status _status);
34 
35 static int _no_contact = 0;
36 static int _not_started = 0;
37 static int _single_user = 0;
38 static int _timeout = 120;
39 static const char* _wait_nodes = 0;
40 static const char* _nowait_nodes = 0;
41 static NdbNodeBitmask nowait_nodes_bitmask;
42 
43 const char *load_default_groups[]= { "mysql_cluster",0 };
44 
45 static struct my_option my_long_options[] =
46 {
47  NDB_STD_OPTS("ndb_waiter"),
48  { "no-contact", 'n', "Wait for cluster no contact",
49  (uchar**) &_no_contact, (uchar**) &_no_contact, 0,
50  GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
51  { "not-started", NDB_OPT_NOSHORT, "Wait for cluster not started",
52  (uchar**) &_not_started, (uchar**) &_not_started, 0,
53  GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
54  { "single-user", NDB_OPT_NOSHORT,
55  "Wait for cluster to enter single user mode",
56  (uchar**) &_single_user, (uchar**) &_single_user, 0,
57  GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
58  { "timeout", 't', "Timeout to wait in seconds",
59  (uchar**) &_timeout, (uchar**) &_timeout, 0,
60  GET_INT, REQUIRED_ARG, 120, 0, 0, 0, 0, 0 },
61  { "wait-nodes", 'w', "Node ids to wait on, e.g. '1,2-4'",
62  (uchar**) &_wait_nodes, (uchar**) &_wait_nodes, 0,
63  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
64  { "nowait-nodes", NDB_OPT_NOSHORT,
65  "Nodes that will not be waited for, e.g. '2,3,4-7'",
66  (uchar**) &_nowait_nodes, (uchar**) &_nowait_nodes, 0,
67  GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
68  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
69 };
70 
71 static void short_usage_sub(void)
72 {
73  ndb_short_usage_sub(NULL);
74 }
75 
76 static void usage()
77 {
78  ndb_usage(short_usage_sub, load_default_groups, my_long_options);
79 }
80 
81 extern "C"
82 void catch_signal(int signum)
83 {
84 }
85 
86 #include "../src/common/util/parse_mask.hpp"
87 
88 int main(int argc, char** argv){
89  NDB_INIT(argv[0]);
90  ndb_opt_set_usage_funcs(short_usage_sub, usage);
91  load_defaults("my",load_default_groups,&argc,&argv);
92 
93 #ifndef DBUG_OFF
94  opt_debug= "d:t:O,/tmp/ndb_waiter.trace";
95 #endif
96 
97 #ifndef _WIN32
98  // Catching signal to allow testing of EINTR safeness
99  // with "while killall -USR1 ndbwaiter; do true; done"
100  signal(SIGUSR1, catch_signal);
101 #endif
102 
103  if (handle_options(&argc, &argv, my_long_options,
104  ndb_std_get_one_option))
105  return NDBT_ProgramExit(NDBT_WRONGARGS);
106 
107  const char* connect_string = argv[0];
108  if (connect_string == 0)
109  connect_string = opt_ndb_connectstring;
110 
111  enum ndb_mgm_node_status wait_status;
112  if (_no_contact)
113  {
114  wait_status= NDB_MGM_NODE_STATUS_NO_CONTACT;
115  }
116  else if (_not_started)
117  {
118  wait_status= NDB_MGM_NODE_STATUS_NOT_STARTED;
119  }
120  else if (_single_user)
121  {
122  wait_status= NDB_MGM_NODE_STATUS_SINGLEUSER;
123  }
124  else
125  {
126  wait_status= NDB_MGM_NODE_STATUS_STARTED;
127  }
128 
129  if (_nowait_nodes)
130  {
131  int res = parse_mask(_nowait_nodes, nowait_nodes_bitmask);
132  if(res == -2 || (res > 0 && nowait_nodes_bitmask.get(0)))
133  {
134  ndbout_c("Invalid nodeid specified in nowait-nodes: %s",
135  _nowait_nodes);
136  exit(-1);
137  }
138  else if (res < 0)
139  {
140  ndbout_c("Unable to parse nowait-nodes argument: %s",
141  _nowait_nodes);
142  exit(-1);
143  }
144  }
145 
146  if (_wait_nodes)
147  {
148  if (_nowait_nodes)
149  {
150  ndbout_c("Can not set both wait-nodes and nowait-nodes.");
151  exit(-1);
152  }
153 
154  int res = parse_mask(_wait_nodes, nowait_nodes_bitmask);
155  if (res == -2 || (res > 0 && nowait_nodes_bitmask.get(0)))
156  {
157  ndbout_c("Invalid nodeid specified in wait-nodes: %s",
158  _wait_nodes);
159  exit(-1);
160  }
161  else if (res < 0)
162  {
163  ndbout_c("Unable to parse wait-nodes argument: %s",
164  _wait_nodes);
165  exit(-1);
166  }
167 
168  // Don't wait for any other nodes than the ones we have set explicitly
169  nowait_nodes_bitmask.bitNOT();
170  }
171 
172  if (waitClusterStatus(connect_string, wait_status) != 0)
173  return NDBT_ProgramExit(NDBT_FAILED);
174  return NDBT_ProgramExit(NDBT_OK);
175 }
176 
177 #define MGMERR(h) \
178  ndbout << "latest_error="<<ndb_mgm_get_latest_error(h) \
179  << ", line="<<ndb_mgm_get_latest_error_line(h) \
180  << endl;
181 
182 NdbMgmHandle handle= NULL;
183 
185 
186 int
187 getStatus(){
188  int retries = 0;
189  struct ndb_mgm_cluster_state * status;
190  struct ndb_mgm_node_state * node;
191 
192  ndbNodes.clear();
193 
194  while(retries < 10){
195  status = ndb_mgm_get_status(handle);
196  if (status == NULL){
197  ndbout << "status==NULL, retries="<<retries<<endl;
198  MGMERR(handle);
199  retries++;
200  ndb_mgm_disconnect(handle);
201  if (ndb_mgm_connect(handle,0,0,1)) {
202  MGMERR(handle);
203  g_err << "Reconnect failed" << endl;
204  break;
205  }
206  continue;
207  }
208  int count = status->no_of_nodes;
209  for (int i = 0; i < count; i++){
210  node = &status->node_states[i];
211  switch(node->node_type){
213  if (!nowait_nodes_bitmask.get(node->node_id))
214  ndbNodes.push_back(*node);
215  break;
217  /* Don't care about MGM nodes */
218  break;
220  /* Don't care about API nodes */
221  break;
222  default:
225  retries++;
226  ndbNodes.clear();
227  free(status);
228  status = NULL;
229  count = 0;
230 
231  ndbout << "kalle"<< endl;
232  break;
233  }
234  abort();
235  break;
236  }
237  }
238  if(status == 0){
239  ndbout << "status == 0" << endl;
240  continue;
241  }
242  free(status);
243  return 0;
244  }
245 
246  return -1;
247 }
248 
249 char*
250 getTimeAsString(char* pStr)
251 {
252  time_t now;
253  now= ::time((time_t*)NULL);
254 
255  struct tm* tm_now;
256 #ifdef NDB_WIN32
257  tm_now = localtime(&now);
258 #else
259  tm_now = ::localtime(&now); //uses the "current" timezone
260 #endif
261 
262  BaseString::snprintf(pStr, 9,
263  "%02d:%02d:%02d",
264  tm_now->tm_hour,
265  tm_now->tm_min,
266  tm_now->tm_sec);
267 
268  return pStr;
269 }
270 
271 static int
272 waitClusterStatus(const char* _addr,
273  ndb_mgm_node_status _status)
274 {
275  int _startphase = -1;
276 
277 #ifndef NDB_WIN
278  /* Ignore SIGPIPE */
279  signal(SIGPIPE, SIG_IGN);
280 #endif
281 
282  handle = ndb_mgm_create_handle();
283  if (handle == NULL){
284  g_err << "Could not create ndb_mgm handle" << endl;
285  return -1;
286  }
287  g_info << "Connecting to mgmsrv at " << _addr << endl;
288  if (ndb_mgm_set_connectstring(handle, _addr))
289  {
290  MGMERR(handle);
291  g_err << "Connectstring " << _addr << " invalid" << endl;
292  return -1;
293  }
294  if (ndb_mgm_connect(handle,0,0,1)) {
295  MGMERR(handle);
296  g_err << "Connection to " << _addr << " failed" << endl;
297  return -1;
298  }
299 
300  int attempts = 0;
301  int resetAttempts = 0;
302  const int MAX_RESET_ATTEMPTS = 10;
303  bool allInState = false;
304 
305  Uint64 time_now = NdbTick_CurrentMillisecond();
306  Uint64 timeout_time = time_now + 1000 * _timeout;
307 
308  while (allInState == false){
309  if (_timeout > 0 && time_now > timeout_time){
314  bool waitMore = false;
319  if(_status == NDB_MGM_NODE_STATUS_STARTED){
320  waitMore = true;
325  for (size_t n = 0; n < ndbNodes.size(); n++){
326  if (ndbNodes[n].node_status != NDB_MGM_NODE_STATUS_STARTED &&
327  ndbNodes[n].node_status != NDB_MGM_NODE_STATUS_STARTING)
328  waitMore = false;
329 
330  }
331  }
332 
333  if (!waitMore || resetAttempts > MAX_RESET_ATTEMPTS){
334  g_err << "waitNodeState("
336  <<", "<<_startphase<<")"
337  << " timeout after " << attempts << " attempts" << endl;
338  return -1;
339  }
340 
341  g_err << "waitNodeState("
343  <<", "<<_startphase<<")"
344  << " resetting timeout "
345  << resetAttempts << endl;
346 
347  timeout_time = time_now + 1000 * _timeout;
348 
349  resetAttempts++;
350  }
351 
352  if (attempts > 0)
353  NdbSleep_MilliSleep(100);
354  if (getStatus() != 0){
355  return -1;
356  }
357 
358  /* Assume all nodes are in state(if there is any) */
359  allInState = (ndbNodes.size() > 0);
360 
361  /* Loop through all nodes and check their state */
362  for (size_t n = 0; n < ndbNodes.size(); n++) {
363  ndb_mgm_node_state* ndbNode = &ndbNodes[n];
364 
365  assert(ndbNode != NULL);
366 
367  g_info << "Node " << ndbNode->node_id << ": "
368  << ndb_mgm_get_node_status_string(ndbNode->node_status)<< endl;
369 
370  if (ndbNode->node_status != _status)
371  allInState = false;
372  }
373 
374  if (!allInState) {
375  char time[9];
376  g_info << "[" << getTimeAsString(time) << "] "
377  << "Waiting for cluster enter state "
378  << ndb_mgm_get_node_status_string(_status) << endl;
379  }
380 
381  attempts++;
382 
383  time_now = NdbTick_CurrentMillisecond();
384  }
385  return 0;
386 }
387 
388 template class Vector<ndb_mgm_node_state>;