1 /*
2 Copyright (c) 2009, 2015, 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 <NDBT.hpp>
26 #include <NDBT_Test.hpp>
27 #include "../../src/ndbapi/NdbInfo.hpp"
28
29 #include <NdbRestarter.hpp>
30
31
runTestNdbInfo(NDBT_Context * ctx,NDBT_Step * step)32 int runTestNdbInfo(NDBT_Context* ctx, NDBT_Step* step)
33 {
34 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
35 if (!ndbinfo.init())
36 {
37 g_err << "ndbinfo.init failed" << endl;
38 return NDBT_FAILED;
39 }
40
41 const NdbInfo::Table* table;
42 if (ndbinfo.openTable("ndbinfo/tables", &table) != 0)
43 {
44 g_err << "Failed to openTable(tables)" << endl;
45 return NDBT_FAILED;
46 }
47
48 for (int l = 0; l < ctx->getNumLoops(); l++)
49 {
50
51 NdbInfoScanOperation* scanOp = NULL;
52 if (ndbinfo.createScanOperation(table, &scanOp))
53 {
54 g_err << "No NdbInfoScanOperation" << endl;
55 return NDBT_FAILED;
56 }
57
58 if (scanOp->readTuples() != 0)
59 {
60 g_err << "scanOp->readTuples failed" << endl;
61 return NDBT_FAILED;
62 }
63
64 const NdbInfoRecAttr* tableName = scanOp->getValue("table_name");
65 const NdbInfoRecAttr* comment = scanOp->getValue("comment");
66
67 if(scanOp->execute() != 0)
68 {
69 g_err << "scanOp->execute failed" << endl;
70 return NDBT_FAILED;
71 }
72
73 while(scanOp->nextResult() == 1)
74 {
75 g_info << "NAME: " << tableName->c_str() << endl;
76 g_info << "COMMENT: " << comment->c_str() << endl;
77 }
78 ndbinfo.releaseScanOperation(scanOp);
79 }
80
81 ndbinfo.closeTable(table);
82 return NDBT_OK;
83 }
84
85 static bool
scan_table(NdbInfo & ndbinfo,const NdbInfo::Table * table,int & rows)86 scan_table(NdbInfo& ndbinfo, const NdbInfo::Table* table, int &rows)
87 {
88 NdbInfoScanOperation* scanOp = NULL;
89 if (ndbinfo.createScanOperation(table, &scanOp))
90 {
91 g_err << "No NdbInfoScanOperation" << endl;
92 return false;
93 }
94
95 if (scanOp->readTuples() != 0)
96 {
97 g_err << "scanOp->readTuples failed" << endl;
98 ndbinfo.releaseScanOperation(scanOp);
99 return false;
100 }
101
102 int columnId = 0;
103 while (scanOp->getValue(columnId))
104 columnId++;
105 // At least one column
106 require(columnId >= 1);
107 int ret;
108 if((ret = scanOp->execute()) != 0)
109 {
110 g_err << "scanOp->execute failed, ret: " << ret << endl;
111 ndbinfo.releaseScanOperation(scanOp);
112 return false;
113 }
114
115 while((ret = scanOp->nextResult()) == 1)
116 rows++;
117
118 ndbinfo.releaseScanOperation(scanOp);
119
120 if (ret != 0)
121 {
122 g_err << "scanOp->nextResult failed, ret: " << ret << endl;
123 return false;
124 }
125
126 return true;
127 }
128
129
runScanAll(NDBT_Context * ctx,NDBT_Step * step)130 int runScanAll(NDBT_Context* ctx, NDBT_Step* step)
131 {
132 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
133 if (!ndbinfo.init())
134 {
135 g_err << "ndbinfo.init failed" << endl;
136 return NDBT_FAILED;
137 }
138
139 Uint32 tableId = 0;
140 while(true) {
141 const NdbInfo::Table* table;
142
143 int err = ndbinfo.openTable(tableId, &table);
144 if (err == NdbInfo::ERR_NoSuchTable)
145 {
146 // No more tables -> return
147 return NDBT_OK;
148 }
149 else if (err != 0)
150 {
151 // Unexpected return code
152 g_err << "Failed to openTable(" << tableId << "), err: " << err << endl;
153 return NDBT_FAILED;
154 }
155 ndbout << "table("<<tableId<<"): " << table->getName() << endl;
156
157 int last_rows;
158 for (int l = 0; l < ctx->getNumLoops(); l++)
159 {
160 if (ctx->isTestStopped())
161 return NDBT_OK;
162
163 int rows = 0;
164 if (!scan_table(ndbinfo, table, rows))
165 {
166 ctx->stopTest();
167 return NDBT_FAILED;
168 }
169 // Check that the number of rows is same as last round on same table
170 if (l > 0 &&
171 last_rows != rows)
172 {
173 g_err << "Got different number of rows this round, expected: "
174 << last_rows << ", got: " << rows << endl;
175 ndbinfo.closeTable(table);
176 ctx->stopTest();
177 return NDBT_FAILED;
178 }
179 last_rows = rows;
180 }
181 ndbinfo.closeTable(table);
182 tableId++;
183 }
184
185 // Should never come here
186 require(false);
187 return NDBT_FAILED;
188 }
189
190
runScanAllUntilStopped(NDBT_Context * ctx,NDBT_Step * step)191 int runScanAllUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
192 int i = 0;
193 while (ctx->isTestStopped() == false) {
194 g_info << i << ": ";
195 if (runScanAll(ctx, step) != NDBT_OK){
196 return NDBT_FAILED;
197 }
198 i++;
199 }
200 return NDBT_OK;
201 }
202
203
runScanStop(NDBT_Context * ctx,NDBT_Step * step)204 int runScanStop(NDBT_Context* ctx, NDBT_Step* step)
205 {
206 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
207 if (!ndbinfo.init())
208 {
209 g_err << "ndbinfo.init failed" << endl;
210 return NDBT_FAILED;
211 }
212
213 Uint32 tableId = 0;
214 while(true) {
215 const NdbInfo::Table* table;
216
217 int err = ndbinfo.openTable(tableId, &table);
218 if (err == NdbInfo::ERR_NoSuchTable)
219 {
220 // No more tables -> return
221 return NDBT_OK;
222 }
223 else if (err != 0)
224 {
225 // Unexpected return code
226 g_err << "Failed to openTable(" << tableId << "), err: " << err << endl;
227 return NDBT_FAILED;
228 }
229 ndbout << "table: " << table->getName() << endl;
230
231 for (int l = 0; l < ctx->getNumLoops()*10; l++)
232 {
233 NdbInfoScanOperation* scanOp = NULL;
234 if (ndbinfo.createScanOperation(table, &scanOp))
235 {
236 g_err << "No NdbInfoScanOperation" << endl;
237 return NDBT_FAILED;
238 }
239
240 if (scanOp->readTuples() != 0)
241 {
242 g_err << "scanOp->readTuples failed" << endl;
243 return NDBT_FAILED;
244 }
245
246 int columnId = 0;
247 while (scanOp->getValue(columnId))
248 columnId++;
249 // At least one column
250 require(columnId >= 1);
251
252 if(scanOp->execute() != 0)
253 {
254 g_err << "scanOp->execute failed" << endl;
255 return NDBT_FAILED;
256 }
257
258 int stopRow = rand() % 100;
259 int row = 0;
260 while(scanOp->nextResult() == 1)
261 {
262 row++;
263 if (row == stopRow)
264 {
265 ndbout_c("Aborting scan at row %d", stopRow);
266 break;
267 }
268 }
269 ndbinfo.releaseScanOperation(scanOp);
270 }
271 ndbinfo.closeTable(table);
272 tableId++;
273 }
274
275 // Should never come here
276 require(false);
277 return NDBT_FAILED;
278 }
279
280
runRatelimit(NDBT_Context * ctx,NDBT_Step * step)281 int runRatelimit(NDBT_Context* ctx, NDBT_Step* step)
282 {
283 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
284 if (!ndbinfo.init())
285 {
286 g_err << "ndbinfo.init failed" << endl;
287 return NDBT_FAILED;
288 }
289
290 Uint32 tableId = 0;
291 while(true) {
292
293 const NdbInfo::Table* table;
294
295 int err = ndbinfo.openTable(tableId, &table);
296 if (err == NdbInfo::ERR_NoSuchTable)
297 {
298 // No more tables -> return
299 return NDBT_OK;
300 }
301 else if (err != 0)
302 {
303 // Unexpected return code
304 g_err << "Failed to openTable(" << tableId << "), err: " << err << endl;
305 return NDBT_FAILED;
306 }
307 ndbout << "table: " << table->getName() << endl;
308
309
310 struct { Uint32 rows; Uint32 bytes; } limits[] = {
311 { 0, 0 },
312 { 1, 0 }, { 2, 0 }, { 10, 0 }, { 37, 0 }, { 1000, 0 },
313 { 0, 1 }, { 0, 2 }, { 0, 10 }, { 0, 37 }, { 0, 1000 },
314 { 1, 1 }, { 2, 2 }, { 10, 10 }, { 37, 37 }, { 1000, 1000 }
315 };
316
317 int lastRows = 0;
318 for (int l = 0; l < (int)(sizeof(limits)/sizeof(limits[0])); l++)
319 {
320
321 Uint32 maxRows = limits[l].rows;
322 Uint32 maxBytes = limits[l].bytes;
323
324 NdbInfoScanOperation* scanOp = NULL;
325 if (ndbinfo.createScanOperation(table, &scanOp, maxRows, maxBytes))
326 {
327 g_err << "No NdbInfoScanOperation" << endl;
328 return NDBT_FAILED;
329 }
330
331 if (scanOp->readTuples() != 0)
332 {
333 g_err << "scanOp->readTuples failed" << endl;
334 return NDBT_FAILED;
335 }
336
337 int columnId = 0;
338 while (scanOp->getValue(columnId))
339 columnId++;
340 // At least one column
341 require(columnId >= 1);
342
343 if(scanOp->execute() != 0)
344 {
345 g_err << "scanOp->execute failed" << endl;
346 return NDBT_FAILED;
347 }
348
349 int row = 0;
350 while(scanOp->nextResult() == 1)
351 row++;
352 ndbinfo.releaseScanOperation(scanOp);
353
354 ndbout_c("[%u,%u] rows: %d", maxRows, maxBytes, row);
355 if (lastRows != 0)
356 {
357 // Check that the number of rows is same as last round on same table
358 if (lastRows != row)
359 {
360 g_err << "Got different number of rows this round, expected: "
361 << lastRows << ", got: " << row << endl;
362 ndbinfo.closeTable(table);
363 return NDBT_FAILED;
364 }
365 }
366 lastRows = row;
367 }
368 ndbinfo.closeTable(table);
369 tableId++;
370 }
371
372 // Should never come here
373 require(false);
374 return NDBT_FAILED;
375 }
376
runTestTable(NDBT_Context * ctx,NDBT_Step * step)377 int runTestTable(NDBT_Context* ctx, NDBT_Step* step)
378 {
379 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
380 if (!ndbinfo.init())
381 {
382 g_err << "ndbinfo.init failed" << endl;
383 return NDBT_FAILED;
384 }
385
386 const NdbInfo::Table* table;
387 if (ndbinfo.openTable("ndbinfo/test", &table) != 0)
388 {
389 g_err << "Failed to openTable(test)" << endl;
390 return NDBT_FAILED;
391 }
392
393 for (int l = 0; l < ctx->getNumLoops(); l++)
394 {
395
396 NdbInfoScanOperation* scanOp = NULL;
397 if (ndbinfo.createScanOperation(table, &scanOp))
398 {
399 ndbinfo.closeTable(table);
400 g_err << "No NdbInfoScanOperation" << endl;
401 return NDBT_FAILED;
402 }
403
404 if (scanOp->readTuples() != 0)
405 {
406 ndbinfo.releaseScanOperation(scanOp);
407 ndbinfo.closeTable(table);
408 g_err << "scanOp->readTuples failed" << endl;
409 return NDBT_FAILED;
410 }
411
412 const NdbInfoRecAttr* nodeId= scanOp->getValue("node_id");
413 const NdbInfoRecAttr* blockNumber= scanOp->getValue("block_number");
414 const NdbInfoRecAttr* blockInstance= scanOp->getValue("block_instance");
415 const NdbInfoRecAttr* counter= scanOp->getValue("counter");
416 const NdbInfoRecAttr* counter2= scanOp->getValue("counter2");
417
418 if(scanOp->execute() != 0)
419 {
420 ndbinfo.releaseScanOperation(scanOp);
421 ndbinfo.closeTable(table);
422 g_err << "scanOp->execute failed" << endl;
423 return NDBT_FAILED;
424 }
425
426 int ret;
427 int rows = 0;
428 while((ret = scanOp->nextResult()) == 1)
429 {
430 rows++;
431 (void)nodeId->u_32_value();
432 (void)blockNumber->u_32_value();
433 (void)blockInstance->u_32_value();
434 (void)counter->u_32_value();
435 (void)counter2->u_64_value();
436 }
437 ndbinfo.releaseScanOperation(scanOp);
438 if (ret != 0)
439 {
440 ndbinfo.closeTable(table);
441 g_err << "scan failed, ret: " << ret << endl;
442 return NDBT_FAILED;
443 }
444 ndbout << "rows: " << rows << endl;
445
446 }
447
448 ndbinfo.closeTable(table);
449 return NDBT_OK;
450 }
451
452
runTestTableUntilStopped(NDBT_Context * ctx,NDBT_Step * step)453 int runTestTableUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
454 int i = 0;
455 while (ctx->isTestStopped() == false) {
456 g_info << i << ": ";
457 (void)runTestTable(ctx, step);
458 i++;
459 }
460 return NDBT_OK;
461 }
462
463
runRestarter(NDBT_Context * ctx,NDBT_Step * step)464 int runRestarter(NDBT_Context* ctx, NDBT_Step* step){
465 int result = NDBT_OK;
466 int loops = ctx->getNumLoops();
467 int sync_threads = ctx->getProperty("SyncThreads", (unsigned)0);
468 int sleep0 = ctx->getProperty("Sleep0", (unsigned)0);
469 int sleep1 = ctx->getProperty("Sleep1", (unsigned)0);
470 int randnode = ctx->getProperty("RandNode", (unsigned)0);
471 NdbRestarter restarter;
472 int i = 0;
473 int lastId = 0;
474
475 if (restarter.getNumDbNodes() < 2){
476 ctx->stopTest();
477 return NDBT_OK;
478 }
479
480 if(restarter.waitClusterStarted() != 0){
481 g_err << "Cluster failed to start" << endl;
482 return NDBT_FAILED;
483 }
484
485 if (loops > restarter.getNumDbNodes())
486 loops = restarter.getNumDbNodes();
487
488 while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){
489
490 int id = lastId % restarter.getNumDbNodes();
491 if (randnode == 1)
492 {
493 id = rand() % restarter.getNumDbNodes();
494 }
495 int nodeId = restarter.getDbNodeId(id);
496 ndbout << "Restart node " << nodeId << endl;
497 if(restarter.restartOneDbNode(nodeId, false, true, true) != 0){
498 g_err << "Failed to restartNextDbNode" << endl;
499 result = NDBT_FAILED;
500 break;
501 }
502
503 if (restarter.waitNodesNoStart(&nodeId, 1))
504 {
505 g_err << "Failed to waitNodesNoStart" << endl;
506 result = NDBT_FAILED;
507 break;
508 }
509
510 if (sleep1)
511 NdbSleep_MilliSleep(sleep1);
512
513 if (restarter.startNodes(&nodeId, 1))
514 {
515 g_err << "Failed to start node" << endl;
516 result = NDBT_FAILED;
517 break;
518 }
519
520 if(restarter.waitClusterStarted() != 0){
521 g_err << "Cluster failed to start" << endl;
522 result = NDBT_FAILED;
523 break;
524 }
525
526 if (sleep0)
527 NdbSleep_MilliSleep(sleep0);
528
529 ctx->sync_up_and_wait("PauseThreads", sync_threads);
530
531 lastId++;
532 i++;
533 }
534
535 ctx->stopTest();
536
537 return result;
538 }
539
540
541
542 NDBT_TESTSUITE(testNdbinfo);
543 TESTCASE("NodeRestart", "Scan NdbInfo tables while restarting nodes"){
544 STEP(runRestarter);
545 STEPS(runTestTableUntilStopped, 1);
546 }
547 TESTCASE("Ndbinfo",
548 "Test ndbapi interface to NDB$INFO"){
549 INITIALIZER(runTestNdbInfo);
550 }
551 TESTCASE("Ndbinfo10",
552 "Test ndbapi interface to NDB$INFO"){
553 STEPS(runTestNdbInfo, 10);
554 }
555 TESTCASE("ScanAll",
556 "Scan all colums of all table known to NdbInfo"
557 "check that number of rows returned are constant"){
558 STEPS(runScanAll, 1);
559 }
560 TESTCASE("ScanAll10",
561 "Scan all columns of all table known to NdbInfo from "
562 "10 parallel threads, check that number of rows returned "
563 "are constant"){
564 STEPS(runScanAll, 10);
565 }
566 TESTCASE("ScanStop",
567 "Randomly stop the scan"){
568 STEPS(runScanStop, 1);
569 }
570 TESTCASE("Ratelimit",
571 "Scan wit different combinations of ratelimit"){
572 STEPS(runRatelimit, 1);
573 }
574 TESTCASE("TestTable",
575 "Scan the test table and make sure it returns correct number "
576 "of rows which will depend on how many TUP blocks are configured"){
577 STEP(runTestTable);
578 }
579 NDBT_TESTSUITE_END(testNdbinfo);
580
581
main(int argc,const char ** argv)582 int main(int argc, const char** argv){
583 ndb_init();
584 NDBT_TESTSUITE_INSTANCE(testNdbinfo);
585 testNdbinfo.setCreateTable(false);
586 testNdbinfo.setRunAllTables(true);
587 return testNdbinfo.execute(argc, argv);
588 }
589