1 /*
2 Copyright (c) 2009, 2019, 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 = 0;
158 bool rows_may_increase = (strstr(table->getName(), "cpustat_") != nullptr);
159 for (int l = 0; l < ctx->getNumLoops(); l++)
160 {
161 if (ctx->isTestStopped())
162 return NDBT_OK;
163
164 int rows = 0;
165 if (!scan_table(ndbinfo, table, rows))
166 {
167 ctx->stopTest();
168 return NDBT_FAILED;
169 }
170 // Check if the number of rows is as expected:
171 // Expected scenario 1: Same number of rows as last round (or)
172 // Expected scenario 2: Same or increased number of rows for tables which
173 // might be still getting filled.
174 if (l > 0 &&
175 (rows != last_rows &&
176 !(rows_may_increase && rows > last_rows)))
177 {
178 g_err << "Got different number of rows this round, table: "
179 << table->getName() << ", expected: "
180 << ((rows_may_increase)?"equal to or more than ":"")
181 << last_rows << ", got: " << rows << endl;
182 ndbinfo.closeTable(table);
183 ctx->stopTest();
184 return NDBT_FAILED;
185 }
186 last_rows = rows;
187 }
188 ndbinfo.closeTable(table);
189 tableId++;
190 }
191
192 // Should never come here
193 require(false);
194 return NDBT_FAILED;
195 }
196
197
runScanStop(NDBT_Context * ctx,NDBT_Step * step)198 int runScanStop(NDBT_Context* ctx, NDBT_Step* step)
199 {
200 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
201 if (!ndbinfo.init())
202 {
203 g_err << "ndbinfo.init failed" << endl;
204 return NDBT_FAILED;
205 }
206
207 Uint32 tableId = 0;
208 while(true) {
209 const NdbInfo::Table* table;
210
211 int err = ndbinfo.openTable(tableId, &table);
212 if (err == NdbInfo::ERR_NoSuchTable)
213 {
214 // No more tables -> return
215 return NDBT_OK;
216 }
217 else if (err != 0)
218 {
219 // Unexpected return code
220 g_err << "Failed to openTable(" << tableId << "), err: " << err << endl;
221 return NDBT_FAILED;
222 }
223 ndbout << "table: " << table->getName() << endl;
224
225 for (int l = 0; l < ctx->getNumLoops()*10; l++)
226 {
227 NdbInfoScanOperation* scanOp = NULL;
228 if (ndbinfo.createScanOperation(table, &scanOp))
229 {
230 g_err << "No NdbInfoScanOperation" << endl;
231 return NDBT_FAILED;
232 }
233
234 if (scanOp->readTuples() != 0)
235 {
236 g_err << "scanOp->readTuples failed" << endl;
237 return NDBT_FAILED;
238 }
239
240 int columnId = 0;
241 while (scanOp->getValue(columnId))
242 columnId++;
243 // At least one column
244 require(columnId >= 1);
245
246 if(scanOp->execute() != 0)
247 {
248 g_err << "scanOp->execute failed" << endl;
249 return NDBT_FAILED;
250 }
251
252 int stopRow = rand() % 100;
253 int row = 0;
254 while(scanOp->nextResult() == 1)
255 {
256 row++;
257 if (row == stopRow)
258 {
259 ndbout_c("Aborting scan at row %d", stopRow);
260 break;
261 }
262 }
263 ndbinfo.releaseScanOperation(scanOp);
264 }
265 ndbinfo.closeTable(table);
266 tableId++;
267 }
268
269 // Should never come here
270 require(false);
271 return NDBT_FAILED;
272 }
273
274
runRatelimit(NDBT_Context * ctx,NDBT_Step * step)275 int runRatelimit(NDBT_Context* ctx, NDBT_Step* step)
276 {
277 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
278 if (!ndbinfo.init())
279 {
280 g_err << "ndbinfo.init failed" << endl;
281 return NDBT_FAILED;
282 }
283
284 Uint32 tableId = 0;
285 while(true) {
286
287 const NdbInfo::Table* table;
288
289 int err = ndbinfo.openTable(tableId, &table);
290 if (err == NdbInfo::ERR_NoSuchTable)
291 {
292 // No more tables -> return
293 return NDBT_OK;
294 }
295 else if (err != 0)
296 {
297 // Unexpected return code
298 g_err << "Failed to openTable(" << tableId << "), err: " << err << endl;
299 return NDBT_FAILED;
300 }
301 ndbout << "table: " << table->getName() << endl;
302
303
304 struct { Uint32 rows; Uint32 bytes; } limits[] = {
305 { 0, 0 },
306 { 1, 0 }, { 2, 0 }, { 10, 0 }, { 37, 0 }, { 1000, 0 },
307 { 0, 1 }, { 0, 2 }, { 0, 10 }, { 0, 37 }, { 0, 1000 },
308 { 1, 1 }, { 2, 2 }, { 10, 10 }, { 37, 37 }, { 1000, 1000 }
309 };
310
311 int lastRows = 0;
312 bool rows_may_increase = (strstr(table->getName(), "cpustat_") != nullptr);
313 for (int l = 0; l < (int)(sizeof(limits)/sizeof(limits[0])); l++)
314 {
315
316 Uint32 maxRows = limits[l].rows;
317 Uint32 maxBytes = limits[l].bytes;
318
319 NdbInfoScanOperation* scanOp = NULL;
320 if (ndbinfo.createScanOperation(table, &scanOp, maxRows, maxBytes))
321 {
322 g_err << "No NdbInfoScanOperation" << endl;
323 return NDBT_FAILED;
324 }
325
326 if (scanOp->readTuples() != 0)
327 {
328 g_err << "scanOp->readTuples failed" << endl;
329 return NDBT_FAILED;
330 }
331
332 int columnId = 0;
333 while (scanOp->getValue(columnId))
334 columnId++;
335 // At least one column
336 require(columnId >= 1);
337
338 if(scanOp->execute() != 0)
339 {
340 g_err << "scanOp->execute failed" << endl;
341 return NDBT_FAILED;
342 }
343
344 int row = 0;
345 while(scanOp->nextResult() == 1)
346 row++;
347 ndbinfo.releaseScanOperation(scanOp);
348
349 ndbout_c("[%u,%u] rows: %d", maxRows, maxBytes, row);
350 // Check if the number of rows is as expected:
351 // Expected scenario 1: Same number of rows as last round (or)
352 // Expected scenario 2: Same or increased number of rows for tables which
353 // might be still getting filled.
354 if (lastRows != 0 &&
355 (row != lastRows &&
356 !(rows_may_increase && row > lastRows)))
357 {
358 g_err << "Got different number of rows this round, table: "
359 << table->getName() << ", expected: "
360 << ((rows_may_increase)?"equal to or more than ":"")
361 << lastRows << ", got: " << row << endl;
362 ndbinfo.closeTable(table);
363 return NDBT_FAILED;
364 }
365 lastRows = row;
366 }
367 ndbinfo.closeTable(table);
368 tableId++;
369 }
370
371 // Should never come here
372 require(false);
373 return NDBT_FAILED;
374 }
375
runTestTable(NDBT_Context * ctx,NDBT_Step * step)376 int runTestTable(NDBT_Context* ctx, NDBT_Step* step)
377 {
378 NdbInfo ndbinfo(&ctx->m_cluster_connection, "ndbinfo/");
379 if (!ndbinfo.init())
380 {
381 g_err << "ndbinfo.init failed" << endl;
382 return NDBT_FAILED;
383 }
384
385 const NdbInfo::Table* table;
386 if (ndbinfo.openTable("ndbinfo/test", &table) != 0)
387 {
388 g_err << "Failed to openTable(test)" << endl;
389 return NDBT_FAILED;
390 }
391
392 for (int l = 0; l < ctx->getNumLoops(); l++)
393 {
394
395 NdbInfoScanOperation* scanOp = NULL;
396 if (ndbinfo.createScanOperation(table, &scanOp))
397 {
398 ndbinfo.closeTable(table);
399 g_err << "No NdbInfoScanOperation" << endl;
400 return NDBT_FAILED;
401 }
402
403 if (scanOp->readTuples() != 0)
404 {
405 ndbinfo.releaseScanOperation(scanOp);
406 ndbinfo.closeTable(table);
407 g_err << "scanOp->readTuples failed" << endl;
408 return NDBT_FAILED;
409 }
410
411 const NdbInfoRecAttr* nodeId= scanOp->getValue("node_id");
412 const NdbInfoRecAttr* blockNumber= scanOp->getValue("block_number");
413 const NdbInfoRecAttr* blockInstance= scanOp->getValue("block_instance");
414 const NdbInfoRecAttr* counter= scanOp->getValue("counter");
415 const NdbInfoRecAttr* counter2= scanOp->getValue("counter2");
416
417 if(scanOp->execute() != 0)
418 {
419 ndbinfo.releaseScanOperation(scanOp);
420 ndbinfo.closeTable(table);
421 g_err << "scanOp->execute failed" << endl;
422 return NDBT_FAILED;
423 }
424
425 int ret;
426 int rows = 0;
427 while((ret = scanOp->nextResult()) == 1)
428 {
429 rows++;
430 (void)nodeId->u_32_value();
431 (void)blockNumber->u_32_value();
432 (void)blockInstance->u_32_value();
433 (void)counter->u_32_value();
434 (void)counter2->u_64_value();
435 }
436 ndbinfo.releaseScanOperation(scanOp);
437 if (ret != 0)
438 {
439 ndbinfo.closeTable(table);
440 g_err << "scan failed, ret: " << ret << endl;
441 return NDBT_FAILED;
442 }
443 ndbout << "rows: " << rows << endl;
444
445 }
446
447 ndbinfo.closeTable(table);
448 return NDBT_OK;
449 }
450
451
runTestTableUntilStopped(NDBT_Context * ctx,NDBT_Step * step)452 int runTestTableUntilStopped(NDBT_Context* ctx, NDBT_Step* step){
453 int i = 0;
454 while (ctx->isTestStopped() == false) {
455 g_info << i << ": ";
456 (void)runTestTable(ctx, step);
457 i++;
458 }
459 return NDBT_OK;
460 }
461
462
runRestarter(NDBT_Context * ctx,NDBT_Step * step)463 int runRestarter(NDBT_Context* ctx, NDBT_Step* step){
464 int result = NDBT_OK;
465 int loops = ctx->getNumLoops();
466 int sync_threads = ctx->getProperty("SyncThreads", (unsigned)0);
467 int sleep0 = ctx->getProperty("Sleep0", (unsigned)0);
468 int sleep1 = ctx->getProperty("Sleep1", (unsigned)0);
469 int randnode = ctx->getProperty("RandNode", (unsigned)0);
470 NdbRestarter restarter;
471 int i = 0;
472 int lastId = 0;
473
474 if (restarter.getNumDbNodes() < 2){
475 ctx->stopTest();
476 return NDBT_OK;
477 }
478
479 if(restarter.waitClusterStarted() != 0){
480 g_err << "Cluster failed to start" << endl;
481 return NDBT_FAILED;
482 }
483
484 if (loops > restarter.getNumDbNodes())
485 loops = restarter.getNumDbNodes();
486
487 while(i<loops && result != NDBT_FAILED && !ctx->isTestStopped()){
488
489 int id = lastId % restarter.getNumDbNodes();
490 if (randnode == 1)
491 {
492 id = rand() % restarter.getNumDbNodes();
493 }
494 int nodeId = restarter.getDbNodeId(id);
495 ndbout << "Restart node " << nodeId << endl;
496 if(restarter.restartOneDbNode(nodeId, false, true, true) != 0){
497 g_err << "Failed to restartNextDbNode" << endl;
498 result = NDBT_FAILED;
499 break;
500 }
501
502 if (restarter.waitNodesNoStart(&nodeId, 1))
503 {
504 g_err << "Failed to waitNodesNoStart" << endl;
505 result = NDBT_FAILED;
506 break;
507 }
508
509 if (sleep1)
510 NdbSleep_MilliSleep(sleep1);
511
512 if (restarter.startNodes(&nodeId, 1))
513 {
514 g_err << "Failed to start node" << endl;
515 result = NDBT_FAILED;
516 break;
517 }
518
519 if(restarter.waitClusterStarted() != 0){
520 g_err << "Cluster failed to start" << endl;
521 result = NDBT_FAILED;
522 break;
523 }
524
525 if (sleep0)
526 NdbSleep_MilliSleep(sleep0);
527
528 ctx->sync_up_and_wait("PauseThreads", sync_threads);
529
530 lastId++;
531 i++;
532 }
533
534 ctx->stopTest();
535
536 return result;
537 }
538
539
540
541 NDBT_TESTSUITE(testNdbinfo);
542 TESTCASE("NodeRestart", "Scan NdbInfo tables while restarting nodes"){
543 STEP(runRestarter);
544 STEPS(runTestTableUntilStopped, 1);
545 }
546 TESTCASE("Ndbinfo",
547 "Test ndbapi interface to NDB$INFO"){
548 INITIALIZER(runTestNdbInfo);
549 }
550 TESTCASE("Ndbinfo10",
551 "Test ndbapi interface to NDB$INFO"){
552 STEPS(runTestNdbInfo, 10);
553 }
554 TESTCASE("ScanAll",
555 "Scan all colums of all table known to NdbInfo"
556 "check that number of rows returned are as expected."
557 "Either they should be same across multiple iterations or"
558 "should increasing if in case the table is still getting filled."){
559 STEPS(runScanAll, 1);
560 }
561 TESTCASE("ScanAll10",
562 "Scan all columns of all table known to NdbInfo from "
563 "10 parallel threads, check that number of rows returned are as"
564 "expected. Either they should be same across multiple iterations or"
565 "should increasing if in case the table is still getting filled."){
566 STEPS(runScanAll, 10);
567 }
568 TESTCASE("ScanStop",
569 "Randomly stop the scan"){
570 STEPS(runScanStop, 1);
571 }
572 TESTCASE("Ratelimit",
573 "Scan wit different combinations of ratelimit"){
574 STEPS(runRatelimit, 1);
575 }
576 TESTCASE("TestTable",
577 "Scan the test table and make sure it returns correct number "
578 "of rows which will depend on how many TUP blocks are configured"){
579 STEP(runTestTable);
580 }
NDBT_TESTSUITE_END(testNdbinfo)581 NDBT_TESTSUITE_END(testNdbinfo)
582
583
584 int main(int argc, const char** argv){
585 ndb_init();
586 NDBT_TESTSUITE_INSTANCE(testNdbinfo);
587 testNdbinfo.setCreateTable(false);
588 testNdbinfo.setRunAllTables(true);
589 return testNdbinfo.execute(argc, argv);
590 }
591