MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbMixRestarter.cpp
1 /*
2  Copyright (c) 2007, 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 "NdbMixRestarter.hpp"
19 
20 NdbMixRestarter::NdbMixRestarter(unsigned * _seed, const char* _addr) :
21  NdbRestarter(_addr),
22  m_mask(~(Uint32)0)
23 {
24  if (_seed == 0)
25  {
26  ownseed = (unsigned)NdbTick_CurrentMillisecond();
27  seed = &ownseed;
28  }
29  else
30  {
31  seed = _seed;
32  }
33 }
34 
35 NdbMixRestarter::~NdbMixRestarter()
36 {
37 
38 }
39 
40 #define CHECK(b) if (!(b)) { \
41  ndbout << "ERR: "<< step->getName() \
42  << " failed on line " << __LINE__ << endl; \
43  result = NDBT_FAILED; \
44  continue; }
45 
46 int
47 NdbMixRestarter::restart_cluster(NDBT_Context* ctx,
48  NDBT_Step* step,
49  bool stopabort)
50 {
51  int timeout = 180;
52  int result = NDBT_OK;
53 
54  do
55  {
56  ctx->setProperty(NMR_SR_THREADS_STOPPED, (Uint32)0);
57  ctx->setProperty(NMR_SR_VALIDATE_THREADS_DONE, (Uint32)0);
58 
59  ndbout << " -- Shutting down " << endl;
60  ctx->setProperty(NMR_SR, NdbMixRestarter::SR_STOPPING);
61  CHECK(restartAll(false, true, stopabort) == 0);
62  ctx->setProperty(NMR_SR, NdbMixRestarter::SR_STOPPED);
63  CHECK(waitClusterNoStart(timeout) == 0);
64 
65  Uint32 cnt = ctx->getProperty(NMR_SR_THREADS);
66  Uint32 curr= ctx->getProperty(NMR_SR_THREADS_STOPPED);
67  while(curr != cnt && !ctx->isTestStopped())
68  {
69  if (curr > cnt)
70  {
71  ndbout_c("stopping: curr: %d cnt: %d", curr, cnt);
72  abort();
73  }
74 
75  NdbSleep_MilliSleep(100);
76  curr= ctx->getProperty(NMR_SR_THREADS_STOPPED);
77  }
78 
79  CHECK(ctx->isTestStopped() == false);
80  CHECK(startAll() == 0);
81  CHECK(waitClusterStarted(timeout) == 0);
82 
83  cnt = ctx->getProperty(NMR_SR_VALIDATE_THREADS);
84  if (cnt)
85  {
86  ndbout << " -- Validating starts " << endl;
87  ctx->setProperty(NMR_SR_VALIDATE_THREADS_DONE, (Uint32)0);
88  ctx->setProperty(NMR_SR, NdbMixRestarter::SR_VALIDATING);
89  curr = ctx->getProperty(NMR_SR_VALIDATE_THREADS_DONE);
90  while (curr != cnt && !ctx->isTestStopped())
91  {
92  if (curr > cnt)
93  {
94  ndbout_c("validating: curr: %d cnt: %d", curr, cnt);
95  abort();
96  }
97 
98  NdbSleep_MilliSleep(100);
99  curr = ctx->getProperty(NMR_SR_VALIDATE_THREADS_DONE);
100  }
101  ndbout << " -- Validating complete " << endl;
102  }
103  CHECK(ctx->isTestStopped() == false);
104  ctx->setProperty(NMR_SR, NdbMixRestarter::SR_RUNNING);
105 
106  } while(0);
107 
108  return result;
109 }
110 
111 static
112 void
113 select_nodes_to_stop(Vector<ndb_mgm_node_state*>& victims,
115 {
116  Uint32 i, j;
117  Vector<ndb_mgm_node_state*> alive_nodes;
118  for(i = 0; i<nodes.size(); i++)
119  {
120  ndb_mgm_node_state* node = &nodes[i];
122  alive_nodes.push_back(node);
123  }
124 
125  // Remove those with one in node group
126  for(i = 0; i<alive_nodes.size(); i++)
127  {
128  int group = alive_nodes[i]->node_group;
129  for(j = 0; j<alive_nodes.size(); j++)
130  {
131  if (i != j && alive_nodes[j]->node_group == group)
132  {
133  victims.push_back(alive_nodes[i]);
134  break;
135  }
136  }
137  }
138 }
139 
140 static
142 select_node_to_stop(unsigned * seed, Vector<ndb_mgm_node_state>& nodes)
143 {
145  select_nodes_to_stop(victims, nodes);
146 
147  if (victims.size())
148  {
149  int victim = ndb_rand_r(seed) % victims.size();
150  return victims[victim];
151  }
152  else
153  {
154  return 0;
155  }
156 }
157 
158 static
159 void
160 select_nodes_to_start(Vector<ndb_mgm_node_state*>& victims,
162 {
163  Uint32 i;
164  for(i = 0; i<nodes.size(); i++)
165  {
166  ndb_mgm_node_state* node = &nodes[i];
168  victims.push_back(node);
169  }
170 }
171 
172 static
174 select_node_to_start(unsigned * seed,
176 {
178  select_nodes_to_start(victims, nodes);
179 
180  if (victims.size())
181  {
182  int victim = ndb_rand_r(seed) % victims.size();
183  return victims[victim];
184  }
185  else
186  {
187  return 0;
188  }
189 }
190 
191 void
192 NdbMixRestarter::setRestartTypeMask(Uint32 mask)
193 {
194  m_mask = mask;
195 }
196 
197 int
198 NdbMixRestarter::runUntilStopped(NDBT_Context* ctx,
199  NDBT_Step* step,
200  Uint32 freq)
201 {
202  if (init(ctx, step))
203  return NDBT_FAILED;
204 
205  while (!ctx->isTestStopped())
206  {
207  if (dostep(ctx, step))
208  return NDBT_FAILED;
209  NdbSleep_SecSleep(freq);
210  }
211 
212  if (!finish(ctx, step))
213  return NDBT_FAILED;
214 
215  return NDBT_OK;
216 }
217 
218 int
219 NdbMixRestarter::runPeriod(NDBT_Context* ctx,
220  NDBT_Step* step,
221  Uint32 period, Uint32 freq)
222 {
223  if (init(ctx, step))
224  return NDBT_FAILED;
225 
226  Uint32 stop = (Uint32)time(0) + period;
227  while (!ctx->isTestStopped() && (time(0) < stop))
228  {
229  if (dostep(ctx, step))
230  {
231  return NDBT_FAILED;
232  }
233  NdbSleep_SecSleep(freq);
234  }
235 
236  if (finish(ctx, step))
237  {
238  return NDBT_FAILED;
239  }
240 
241  ctx->stopTest();
242  return NDBT_OK;
243 }
244 
245 int
246 NdbMixRestarter::init(NDBT_Context* ctx, NDBT_Step* step)
247 {
248  waitClusterStarted();
249  m_nodes = ndbNodes;
250  return 0;
251 }
252 
253 int
254 NdbMixRestarter::dostep(NDBT_Context* ctx, NDBT_Step* step)
255 {
256  ndb_mgm_node_state* node = 0;
257  int action;
258 loop:
259  while(((action = (1 << (ndb_rand_r(seed) % RTM_COUNT))) & m_mask) == 0);
260  switch(action){
261  case RTM_RestartCluster:
262  if (restart_cluster(ctx, step))
263  return NDBT_FAILED;
264  for (Uint32 i = 0; i<m_nodes.size(); i++)
265  m_nodes[i].node_status = NDB_MGM_NODE_STATUS_STARTED;
266  break;
267  case RTM_RestartNode:
268  case RTM_RestartNodeInitial:
269  case RTM_StopNode:
270  case RTM_StopNodeInitial:
271  {
272  if ((node = select_node_to_stop(seed, m_nodes)) == 0)
273  goto loop;
274 
275  if (action == RTM_RestartNode || action == RTM_RestartNodeInitial)
276  ndbout << "Restarting " << node->node_id;
277  else
278  ndbout << "Stopping " << node->node_id;
279 
280  bool initial =
281  action == RTM_RestartNodeInitial || action == RTM_StopNodeInitial;
282 
283  if (initial)
284  ndbout << " inital";
285  ndbout << endl;
286 
287  if (restartOneDbNode(node->node_id, initial, true, true))
288  return NDBT_FAILED;
289 
290  if (waitNodesNoStart(&node->node_id, 1))
291  return NDBT_FAILED;
292 
294 
295  if (action == RTM_StopNode || action == RTM_StopNodeInitial)
296  break;
297  else
298  goto start;
299  }
300  case RTM_StartNode:
301  if ((node = select_node_to_start(seed, m_nodes)) == 0)
302  goto loop;
303 start:
304  ndbout << "Starting " << node->node_id << endl;
305  if (startNodes(&node->node_id, 1))
306  return NDBT_FAILED;
307  if (waitNodesStarted(&node->node_id, 1))
308  return NDBT_FAILED;
309 
311  break;
312  }
313  return NDBT_OK;
314 }
315 
316 int
317 NdbMixRestarter::finish(NDBT_Context* ctx, NDBT_Step* step)
318 {
319  Vector<int> not_started;
320  {
321  ndb_mgm_node_state* node = 0;
322  while((node = select_node_to_start(seed, m_nodes)))
323  {
324  not_started.push_back(node->node_id);
326  }
327  }
328 
329  if (not_started.size())
330  {
331  ndbout << "Starting stopped nodes " << endl;
332  if (startNodes(not_started.getBase(), not_started.size()))
333  return NDBT_FAILED;
334  if (waitClusterStarted())
335  return NDBT_FAILED;
336  }
337  return NDBT_OK;
338 }
339 
340 template class Vector<ndb_mgm_node_state*>;