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