1 /*
2 Copyright (c) 2003, 2013, 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 /* ***************************************************
26 FLEXHAMMER
27 Hammer ndb with read, insert, update and delete transactions.
28
29 Arguments:
30 -t Number of threads to start, default 1
31 -o Number of operations per hammering-round, default 500
32 -l Number of loops to run, default 1, 0=infinite
33 -a Number of attributes, default 25
34 -c Number of tables, default 1
35 -s Size of each attribute, default 1
36 -simple Use simple read to read from database
37 -dirty Use dirty read to read from database
38 -write Use writeTuple to write to db
39 -r Number of records to Hammer
40 -no_table_create Don't create tables in db
41 -regulate To be able to regulate the load flexHammer produces.
42 -stdtables Use standard table names
43 -sleep Sleep a number of seconds before running the test, this
44 can be used so that another flexProgram have tome to create tables
45
46 Returns:
47 0 - Test passed
48 -1 - Test failed
49 1 - Invalid arguments
50
51 Revision history:
52 1.7 020208 epesson: Adapted to use NDBT
53 1.10 020222 epesson: Finalised handling of thread results
54 1.11 020222 epesson: Bug in checking results during delete fixed
55
56 * *************************************************** */
57
58 #include <ndb_global.h>
59 #include <NdbApi.hpp>
60
61 #include <NdbMain.h>
62 #include <NdbThread.h>
63 #include <NdbSleep.h>
64 #include <NdbTick.h>
65 #include <NdbOut.hpp>
66 #include <NdbTimer.hpp>
67 #include <NdbTick.h>
68 #include <NdbTest.hpp>
69 #include <NDBT_Error.hpp>
70 #include <NdbSchemaCon.hpp>
71
72 ErrorData * flexHammerErrorData;
73
74
75 #define MAXSTRLEN 16
76 #define MAXATTR 64
77 #define MAXTABLES 64
78 #define NDB_MAXTHREADS 256
79 /*
80 NDB_MAXTHREADS used to be just MAXTHREADS, which collides with a
81 #define from <sys/thread.h> on AIX (IBM compiler). We explicitly
82 #undef it here lest someone use it by habit and get really funny
83 results. K&R says we may #undef non-existent symbols, so let's go.
84 */
85 #undef MAXTHREADS
86 #define MAXATTRSIZE 100
87 // Max number of retries if something fails
88 #define MaxNoOfAttemptsC 10
89
90 enum StartType {
91 stIdle,
92 stHammer,
93 stStop,
94 stLast};
95
96 enum MyOpType {
97 otInsert,
98 otRead,
99 otDelete,
100 otUpdate,
101 otLast};
102
103 struct ThreadNdb {
104 int threadNo;
105 NdbThread* threadLife;
106 int threadReady;
107 StartType threadStart;
108 int threadResult;};
109
110 extern "C" void* flexHammerThread(void*);
111 static int setAttrNames(void);
112 static int setTableNames(void);
113 static int readArguments(int, const char**);
114 static int createTables(Ndb*);
115 static int dropTables(Ndb*);
116 static void sleepBeforeStartingTest(int seconds);
117 static int checkThreadResults(ThreadNdb *threadArrayP, const char* phase);
118
119 //enum OperationType {
120 // otInsert,
121 // otRead,
122 // otUpdate,
123 // otDelete,
124 // otVerifyDelete,
125 // otLast };
126
127 enum ReadyType {
128 stReady,
129 stRunning
130 } ;
131 static int tNoOfThreads;
132 static int tNoOfAttributes;
133 static int tNoOfTables;
134 static int tNoOfBackups;
135 static int tAttributeSize;
136 static int tNoOfOperations;
137 static int tNoOfRecords;
138 static int tNoOfLoops;
139 static char tableName[MAXTABLES][MAXSTRLEN];
140 static char attrName[MAXATTR][MAXSTRLEN];
141 static int theSimpleFlag = 0;
142 static int theWriteFlag = 0;
143 static int theDirtyFlag = 0;
144 static int theTableCreateFlag = 0;
145 static int theStandardTableNameFlag = 0;
146 static unsigned int tSleepTime = 0;
147
148 #define START_TIMER { NdbTimer timer; timer.doStart();
149 #define STOP_TIMER timer.doStop();
150 #define PRINT_TIMER(text, trans, opertrans) timer.printTransactionStatistics(text, trans, opertrans); };
151
152
153 // Initialise thread data
154 void
resetThreads(ThreadNdb * threadArrayP)155 resetThreads(ThreadNdb *threadArrayP) {
156
157 for (int i = 0; i < tNoOfThreads ; i++)
158 {
159 threadArrayP[i].threadReady = 0;
160 threadArrayP[i].threadResult = 0;
161 threadArrayP[i].threadStart = stIdle;
162 }
163 } // resetThreads
164
165 void
waitForThreads(ThreadNdb * threadArrayP)166 waitForThreads(ThreadNdb *threadArrayP)
167 {
168 int cont = 1;
169
170 while (cont) {
171 NdbSleep_MilliSleep(100);
172 cont = 0;
173 for (int i = 0; i < tNoOfThreads ; i++) {
174 if (threadArrayP[i].threadReady == 0) {
175 // Found one thread not yet ready, continue waiting
176 cont = 1;
177 break;
178 } // if
179 } // for
180 } // while
181 } // waitForThreads
182
183 void
tellThreads(ThreadNdb * threadArrayP,const StartType what)184 tellThreads(ThreadNdb* threadArrayP, const StartType what)
185 {
186 for (int i = 0; i < tNoOfThreads ; i++)
187 {
188 threadArrayP[i].threadStart = what;
189 } // for
190 } // tellThreads
191
192 static Ndb_cluster_connection *g_cluster_connection= 0;
193
194 NDB_COMMAND(flexHammer, "flexHammer", "flexHammer", "flexHammer", 65535)
195 //main(int argc, const char** argv)
196 {
197 ndb_init();
198 ThreadNdb* pThreads = NULL; // Pointer to thread data array
199 Ndb* pMyNdb = NULL; // Pointer to Ndb object
200 int tLoops = 0;
201 int returnValue = 0;
202 int check = 0;
203
204 flexHammerErrorData = new ErrorData;
205
206 flexHammerErrorData->resetErrorCounters();
207
208 if (readArguments(argc, argv) != 0) {
209 ndbout << "Wrong arguments to flexHammer" << endl;
210 return NDBT_ProgramExit(NDBT_WRONGARGS);
211 } // if
212
213 /* print Setting */
214 flexHammerErrorData->printSettings(ndbout);
215
216 check = setAttrNames();
217 if (check == -1) {
218 ndbout << "Couldn't set attribute names" << endl;
219 return NDBT_ProgramExit(NDBT_FAILED);
220 } // if
221 check = setTableNames();
222 if (check == -1) {
223 ndbout << "Couldn't set table names" << endl;
224 return NDBT_ProgramExit(NDBT_FAILED);
225 } // if
226
227 // Create thread data array
228 pThreads = new ThreadNdb[tNoOfThreads];
229 // NdbThread_SetConcurrencyLevel(tNoOfThreads + 2);
230
231 // Create and init Ndb object
232 Ndb_cluster_connection con;
233 if(con.connect(12, 5, 1) != 0)
234 {
235 return NDBT_ProgramExit(NDBT_FAILED);
236 }
237 g_cluster_connection= &con;
238 pMyNdb = new Ndb(g_cluster_connection, "TEST_DB");
239 pMyNdb->init();
240
241 // Wait for Ndb to become ready
242 if (pMyNdb->waitUntilReady(10000) != 0) {
243 ndbout << "NDB is not ready" << endl << "Benchmark failed" << endl;
244 returnValue = NDBT_FAILED;
245 }
246
247 else {
248 check = createTables(pMyNdb);
249 if (check != 0) {
250 returnValue = NDBT_FAILED;
251 } // if
252 else {
253 sleepBeforeStartingTest(tSleepTime);
254
255 // Create threads. *
256 resetThreads(pThreads);
257 for (int i = 0; i < tNoOfThreads ; i++) {
258 pThreads[i].threadNo = i;
259 pThreads[i].threadLife = NdbThread_Create(flexHammerThread,
260 (void**)&pThreads[i],
261 65535,
262 "flexHammerThread",
263 NDB_THREAD_PRIO_LOW);
264 } // for
265
266 // And wait until they are ready
267 waitForThreads(pThreads);
268 if (checkThreadResults(pThreads, "init") != 0) {
269 returnValue = NDBT_FAILED;
270 } // if
271
272
273 if (returnValue == NDBT_OK) {
274 ndbout << endl << "All threads started" << endl << endl;
275
276 for(;;) {
277
278 // Check if it's time to exit program
279 if((tNoOfLoops != 0) && (tNoOfLoops <= tLoops))
280 break;
281
282 // Tell all threads to start hammer
283 ndbout << "Hammering..." << endl;
284
285 resetThreads(pThreads);
286
287 START_TIMER;
288 tellThreads(pThreads, stHammer);
289
290 waitForThreads(pThreads);
291 ndbout << "Threads ready to continue..." << endl;
292 STOP_TIMER;
293
294 // Check here if anything went wrong
295 if (checkThreadResults(pThreads, "hammer") != 0) {
296 ndbout << "Thread(s) failed." << endl;
297 returnValue = NDBT_FAILED;
298 } // if
299
300 PRINT_TIMER("hammer", tNoOfOperations*tNoOfThreads, tNoOfTables*6);
301
302 ndbout << endl;
303
304 tLoops++;
305
306 } // for
307 } // if
308
309 // Signaling threads to stop
310 resetThreads(pThreads);
311 tellThreads(pThreads, stStop);
312
313 // Wait for threads to stop
314 waitForThreads(pThreads);
315
316 ndbout << "----------------------------------------------" << endl << endl;
317 ndbout << "Benchmark completed" << endl;
318 } // else
319 } // else
320 // Clean up
321
322 flexHammerErrorData->printErrorCounters(ndbout);
323
324 // Kill them all!
325 void* tmp;
326 for(int i = 0; i < tNoOfThreads; i++){
327 NdbThread_WaitFor(pThreads[i].threadLife, &tmp);
328 NdbThread_Destroy(&pThreads[i].threadLife);
329 }
330
331 dropTables(pMyNdb);
332
333 delete flexHammerErrorData;
334 delete [] pThreads;
335 delete pMyNdb;
336
337 // Exit via NDBT
338 return NDBT_ProgramExit(returnValue);
339
340 } //main
341
342 extern "C"
343 void*
flexHammerThread(void * pArg)344 flexHammerThread(void* pArg)
345 {
346 ThreadNdb* pThreadData = (ThreadNdb*)pArg;
347 //unsigned int threadNo = pThreadData->threadNo;
348 Ndb* pMyNdb = NULL ;
349 NdbConnection *pMyTransaction = NULL ;
350 // NdbOperation* pMyOperation[MAXTABLES] = {NULL};
351 NdbOperation* pMyOperation[MAXTABLES];
352 int check = 0;
353 int loop_count_ops = 0;
354 int loop_count_tables = 0;
355 int loop_count_attributes = 0;
356 int count_round = 0;
357 int count = 0;
358 int count_tables = 0;
359 int count_attributes = 0;
360 int i = 0;
361 int tThreadResult = 0;
362 MyOpType tMyOpType = otLast;
363 int pkValue = 0;
364 int readValue[MAXATTR][MAXATTRSIZE]; bzero(readValue, sizeof(readValue));
365 int attrValue[MAXATTRSIZE];
366 NdbRecAttr* tTmp = NULL;
367 int tNoOfAttempts = 0;
368
369 for (i = 0; i < MAXATTRSIZE; i++)
370 attrValue[i] = 0;
371 // Ndb object for each thread
372 pMyNdb = new Ndb(g_cluster_connection, "TEST_DB" );
373 pMyNdb->init();
374 if (pMyNdb->waitUntilReady(10000) != 0) {
375 // Error, NDB is not ready
376 tThreadResult = 99;
377 // Go to idle directly
378 pThreadData->threadStart = stIdle;
379 } // if
380
381 for(;;) {
382 pThreadData->threadResult = tThreadResult;
383 pThreadData->threadReady = 1; // Signalling ready to main
384
385 // If Idle just wait to be stopped from main
386 while (pThreadData->threadStart == stIdle) {
387 NdbSleep_MilliSleep(100);
388 } // while
389
390 // Check if signal to exit is received
391 if (pThreadData->threadStart == stStop) {
392 pThreadData->threadReady = 1;
393 // break out of eternal loop
394 break;
395 } // if
396
397 // Set to Idle to prepare for possible error break
398 pThreadData->threadStart = stIdle;
399
400 // Prepare transaction
401 loop_count_ops = tNoOfOperations;
402 loop_count_tables = tNoOfTables;
403 loop_count_attributes = tNoOfAttributes;
404
405 for (count=0 ; count < loop_count_ops ; count++) {
406
407 //pkValue = (int)(count + thread_base);
408 // This limits the number of records used in this test
409 pkValue = count % tNoOfRecords;
410
411 for (count_round = 0; count_round < 5; ) {
412 switch (count_round) {
413 case 0: // Insert
414 tMyOpType = otInsert;
415 // Increase attrValues
416 for (i=0; i < MAXATTRSIZE; i ++) {
417 attrValue[i]++;
418 }
419 break;
420 case 1:
421 case 3: // Read and verify
422 tMyOpType = otRead;
423 break;
424 case 2: // Update
425 // Increase attrValues
426 for(i=0; i < MAXATTRSIZE; i ++) {
427 attrValue[i]++;
428 }
429 tMyOpType = otUpdate;
430 break;
431 case 4: // Delete
432 tMyOpType = otDelete;
433 break;
434 default:
435 require(false);
436 break;
437 } // switch
438
439 // Get transaction object
440 pMyTransaction = pMyNdb->startTransaction();
441 if (pMyTransaction == NULL) {
442 // Fatal error
443 tThreadResult = 1;
444 // break out of for count_round loop waiting to be stopped by main
445 break;
446 } // if
447
448 for (count_tables = 0; count_tables < loop_count_tables;
449 count_tables++) {
450 pMyOperation[count_tables] =
451 pMyTransaction->getNdbOperation(tableName[count_tables]);
452 if (pMyOperation[count_tables] == NULL) {
453 //Fatal error
454 tThreadResult = 2;
455 // break out of inner for count_tables loop
456 break;
457 } // if
458
459 switch (tMyOpType) {
460 case otInsert: // Insert case
461 if (theWriteFlag == 1 && theDirtyFlag == 1) {
462 check = pMyOperation[count_tables]->dirtyWrite();
463 } else if (theWriteFlag == 1) {
464 check = pMyOperation[count_tables]->writeTuple();
465 } else {
466 check = pMyOperation[count_tables]->insertTuple();
467 } // if else
468 break;
469 case otRead: // Read Case
470 if (theSimpleFlag == 1) {
471 check = pMyOperation[count_tables]->simpleRead();
472 } else if (theDirtyFlag == 1) {
473 check = pMyOperation[count_tables]->dirtyRead();
474 } else {
475 check = pMyOperation[count_tables]->readTuple();
476 } // if else
477 break;
478 case otUpdate: // Update Case
479 if (theWriteFlag == 1 && theDirtyFlag == 1) {
480 check = pMyOperation[count_tables]->dirtyWrite();
481 } else if (theWriteFlag == 1) {
482 check = pMyOperation[count_tables]->writeTuple();
483 } else if (theDirtyFlag == 1) {
484 check = pMyOperation[count_tables]->dirtyUpdate();
485 } else {
486 check = pMyOperation[count_tables]->updateTuple();
487 } // if else
488 break;
489 case otDelete: // Delete Case
490 check = pMyOperation[count_tables]->deleteTuple();
491 break;
492 default:
493 require(false);
494 break;
495 } // switch
496 if (check == -1) {
497 // Fatal error
498 tThreadResult = 3;
499 // break out of inner for count_tables loop
500 break;
501 } // if
502
503 check = pMyOperation[count_tables]->equal( (char*)attrName[0],
504 (char*)&pkValue );
505
506 if (check == -1) {
507 // Fatal error
508 tThreadResult = 4;
509 ndbout << "pMyOperation equal failed" << endl;
510 // break out of inner for count_tables loop
511 break;
512 } // if
513
514 check = -1;
515 tTmp = NULL;
516 switch (tMyOpType) {
517 case otInsert: // Insert case
518 case otUpdate: // Update Case
519 for (count_attributes = 1; count_attributes < loop_count_attributes;
520 count_attributes++) {
521 check =
522 pMyOperation[count_tables]->setValue((char*)attrName[count_attributes], (char*)&attrValue[0]);
523 } // for
524 break;
525 case otRead: // Read Case
526 for (count_attributes = 1; count_attributes < loop_count_attributes;
527 count_attributes++) {
528 tTmp = pMyOperation[count_tables]->
529 getValue( (char*)attrName[count_attributes],
530 (char*)&readValue[count_attributes][0] );
531 } // for
532 break;
533 case otDelete: // Delete Case
534 break;
535 default:
536 require(false);
537 break;
538 } // switch
539 if (check == -1 && tTmp == NULL && tMyOpType != otDelete) {
540 // Fatal error
541 tThreadResult = 5;
542 break;
543 } // if
544 } // for count_tables
545
546 // Only execute if everything is OK
547 if (tThreadResult != 0) {
548 // Close transaction (below)
549 // and continue with next count_round
550 count_round++;
551 tNoOfAttempts = 0;
552 } // if
553 else {
554 check = pMyTransaction->execute(Commit);
555 if (check == -1 ) {
556 const NdbError & err = pMyTransaction->getNdbError();
557
558 // Add complete error handling here
559
560 int retCode = flexHammerErrorData->handleErrorCommon(pMyTransaction->getNdbError());
561 if (retCode == 1) {
562 //if (strcmp(pMyTransaction->getNdbError().message, "Tuple did not exist") != 0 && strcmp(pMyTransaction->getNdbError().message,"Tuple already existed when attempting to insert") != 0) ndbout_c("execute: %s", pMyTransaction->getNdbError().message);
563
564 if (pMyTransaction->getNdbError().code != 626 && pMyTransaction->getNdbError().code != 630){
565 ndbout_c("Error code = %d", pMyTransaction->getNdbError().code);
566 ndbout_c("execute: %s", pMyTransaction->getNdbError().message);}
567
568 } else if (retCode == 2) {
569 ndbout << "4115 should not happen in flexHammer" << endl;
570 } else if (retCode == 3) {
571 // --------------------------------------------------------------------
572 // We are not certain if the transaction was successful or not.
573 // We must reexecute but might very well find that the transaction
574 // actually was updated. Updates and Reads are no problem here. Inserts
575 // will not cause a problem if error code 630 arrives. Deletes will
576 // not cause a problem if 626 arrives.
577 // --------------------------------------------------------------------
578 /* What can we do here? */
579 ndbout_c("execute: %s", pMyTransaction->getNdbError().message);
580 }//if(retCode == 3)
581 // End of adding complete error handling
582
583 switch( err.classification) {
584 case NdbError::ConstraintViolation: // Tuple already existed
585 count_round++;
586 tNoOfAttempts = 0;
587 break;
588 case NdbError::TimeoutExpired:
589 case NdbError::NodeRecoveryError:
590 case NdbError::TemporaryResourceError:
591 case NdbError::OverloadError:
592 if (tNoOfAttempts <= MaxNoOfAttemptsC) {
593 // Retry
594 tNoOfAttempts++;
595 } else {
596 // Too many retries, continue with next
597 count_round++;
598 tNoOfAttempts = 0;
599 } // else if
600 break;
601 // Fatal, just continue
602 default:
603 count_round++;
604 tNoOfAttempts = 0;
605 break;
606 } // switch
607 } // if
608 else {
609 // Execute commit was OK
610 // This is verifying read values
611 //switch (tMyOpType) {
612 //case otRead: // Read case
613 //for (j = 0; j < tNoOfAttributes; j++) {
614 //for(i = 1; i < tAttributeSize; i++) {
615 //if ( readValue[j][i] != attrValue[i]) {
616 //ndbout << "pkValue = " << pkValue << endl;
617 //ndbout << "readValue != attrValue" << endl;
618 //ndbout << readValue[j][i] << " != " << attrValue[i] << endl;
619 //} // if
620 // } // for
621 //} // for
622 //break;
623 //} // switch
624 count_round++;
625 tNoOfAttempts = 0;
626 } // else if
627 } // else if
628 pMyNdb->closeTransaction(pMyTransaction);
629 } // for count_round
630 } // for count
631 } // for (;;)
632
633 // Clean up
634 delete pMyNdb;
635 pMyNdb = NULL;
636
637 flexHammerErrorData->resetErrorCounters();
638
639 return NULL; // thread exits
640
641 } // flexHammerThread
642
643
644 int
readArguments(int argc,const char ** argv)645 readArguments (int argc, const char** argv)
646 {
647 int i = 1;
648
649 tNoOfThreads = 5; // Default Value
650 tNoOfOperations = 500; // Default Value
651 tNoOfRecords = 1; // Default Value
652 tNoOfLoops = 1; // Default Value
653 tNoOfAttributes = 25; // Default Value
654 tNoOfTables = 1; // Default Value
655 tNoOfBackups = 0; // Default Value
656 tAttributeSize = 1; // Default Value
657 theTableCreateFlag = 0;
658
659 while (argc > 1) {
660 if (strcmp(argv[i], "-t") == 0) {
661 tNoOfThreads = atoi(argv[i+1]);
662 if ((tNoOfThreads < 1) || (tNoOfThreads > NDB_MAXTHREADS))
663 return(1);
664 }
665 else if (strcmp(argv[i], "-o") == 0) {
666 tNoOfOperations = atoi(argv[i+1]);
667 if (tNoOfOperations < 1)
668 return(1);
669 }
670 else if (strcmp(argv[i], "-r") == 0) {
671 tNoOfRecords = atoi(argv[i+1]);
672 if (tNoOfRecords < 1)
673 return(1);
674 }
675 else if (strcmp(argv[i], "-a") == 0) {
676 tNoOfAttributes = atoi(argv[i+1]);
677 if ((tNoOfAttributes < 2) || (tNoOfAttributes > MAXATTR))
678 return(1);
679 }
680 else if (strcmp(argv[i], "-c") == 0) {
681 tNoOfTables = atoi(argv[i+1]);
682 if ((tNoOfTables < 1) || (tNoOfTables > MAXTABLES))
683 return(1);
684 }
685 else if (strcmp(argv[i], "-l") == 0) {
686 tNoOfLoops = atoi(argv[i+1]);
687 if ((tNoOfLoops < 0) || (tNoOfLoops > 100000))
688 return(1);
689 }
690 else if (strcmp(argv[i], "-s") == 0) {
691 tAttributeSize = atoi(argv[i+1]);
692 if ((tAttributeSize < 1) || (tAttributeSize > MAXATTRSIZE))
693 return(1);
694 }
695 else if (strcmp(argv[i], "-sleep") == 0) {
696 tSleepTime = atoi(argv[i+1]);
697 if ((tSleepTime < 1) || (tSleepTime > 3600))
698 exit(-1);
699 }
700 else if (strcmp(argv[i], "-simple") == 0) {
701 theSimpleFlag = 1;
702 argc++;
703 i--;
704 }
705 else if (strcmp(argv[i], "-write") == 0) {
706 theWriteFlag = 1;
707 argc++;
708 i--;
709 }
710 else if (strcmp(argv[i], "-dirty") == 0) {
711 theDirtyFlag = 1;
712 argc++;
713 i--;
714 }
715 else if (strcmp(argv[i], "-no_table_create") == 0) {
716 theTableCreateFlag = 1;
717 argc++;
718 i--;
719 }
720 else if (strcmp(argv[i], "-stdtables") == 0) {
721 theStandardTableNameFlag = 1;
722 argc++;
723 i--;
724 } // if
725 else {
726 return(1);
727 }
728
729 argc -= 2;
730 i = i + 2;
731 } // while
732
733 ndbout << endl << "FLEXHAMMER - Starting normal mode" << endl;
734 ndbout << "Hammer ndb with read, insert, update and delete transactions"<< endl << endl;
735
736 ndbout << " " << tNoOfThreads << " thread(s) " << endl;
737 ndbout << " " << tNoOfLoops << " iterations " << endl;
738 ndbout << " " << tNoOfTables << " table(s) and " << 1 << " operation(s) per transaction " << endl;
739 ndbout << " " << tNoOfRecords << " records to hammer(limit this with the -r option)" << endl;
740 ndbout << " " << tNoOfAttributes << " attributes per table " << endl;
741 ndbout << " " << tNoOfOperations << " transaction(s) per thread and round " << endl;
742 ndbout << " " << tAttributeSize << " is the number of 32 bit words per attribute " << endl << endl;
743 return 0;
744 } // readArguments
745
746
sleepBeforeStartingTest(int seconds)747 void sleepBeforeStartingTest(int seconds)
748 {
749 if (seconds > 0) {
750 ndbout << "Sleeping(" << seconds << ")...";
751 NdbSleep_SecSleep(seconds);
752 ndbout << " done!" << endl;
753 } // if
754 } // sleepBeforeStartingTest
755
756 static int
createTables(Ndb * pMyNdb)757 createTables(Ndb* pMyNdb)
758 {
759 int i = 0;
760 int j = 0;
761 int check = 0;
762 NdbSchemaCon *MySchemaTransaction = NULL;
763 NdbSchemaOp *MySchemaOp = NULL;
764
765 // Create Table and Attributes.
766 if (theTableCreateFlag == 0) {
767
768 for (i = 0; i < tNoOfTables; i++) {
769
770 ndbout << "Creating " << tableName[i] << "...";
771 // Check if table exists already
772 const void * p = pMyNdb->getDictionary()->getTable(tableName[i]);
773 if (p != 0) {
774 ndbout << " already exists." << endl;
775 // Continue with next table at once
776 continue;
777 } // if
778 ndbout << endl;
779
780 MySchemaTransaction = NdbSchemaCon::startSchemaTrans(pMyNdb);
781 if (MySchemaTransaction == NULL) {
782 return(-1);
783 } // if
784
785 MySchemaOp = MySchemaTransaction->getNdbSchemaOp();
786 if (MySchemaOp == NULL) {
787 // Clean up opened schema transaction
788 NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
789 return(-1);
790 } // if
791
792 // Create tables, rest of parameters are default right now
793 check = MySchemaOp->createTable(tableName[i],
794 8, // Table Size
795 TupleKey, // Key Type
796 40); // Nr of Pages
797
798 if (check == -1) {
799 // Clean up opened schema transaction
800 NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
801 return(-1);
802 } // if
803
804 // Primary key
805 //ndbout << " pk " << (char*)&attrName[0] << "..." << endl;
806 check = MySchemaOp->createAttribute( (char*)attrName[0], TupleKey, 32,
807 1, UnSigned, MMBased,
808 NotNullAttribute );
809 if (check == -1) {
810 // Clean up opened schema transaction
811 NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
812 return(-1);
813 } // if
814
815 // Rest of attributes
816 for (j = 1; j < tNoOfAttributes ; j++) {
817 //ndbout << " " << (char*)attrName[j] << "..." << endl;
818 check = MySchemaOp->createAttribute( (char*)attrName[j], NoKey, 32,
819 tAttributeSize, UnSigned, MMBased,
820 NotNullAttribute );
821 if (check == -1) {
822 // Clean up opened schema transaction
823 NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
824 return(-1);
825 } // if
826 } // for
827
828 // Execute creation
829 check = MySchemaTransaction->execute();
830 if (check == -1) {
831 // Clean up opened schema transaction
832 NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
833 return(-1);
834 } // if
835
836 NdbSchemaCon::closeSchemaTrans(MySchemaTransaction);
837 } // for
838 } // if
839
840 return(0);
841
842 } // createTables
843
844 static int
dropTables(Ndb * pMyNdb)845 dropTables(Ndb* pMyNdb)
846 {
847 int i = 0;
848
849 if (theTableCreateFlag == 0)
850 {
851 for (i = 0; i < tNoOfTables; i++)
852 {
853 ndbout << "Dropping " << tableName[i] << "...";
854 pMyNdb->getDictionary()->dropTable(tableName[i]);
855 ndbout << "done" << endl;
856 }
857 }
858
859 return(0);
860
861 } // createTables
862
863
setAttrNames()864 static int setAttrNames()
865 {
866 int i = 0;
867 int retVal = 0;
868
869 for (i = 0; i < MAXATTR ; i++) {
870 retVal = BaseString::snprintf(attrName[i], MAXSTRLEN, "COL%d", i);
871 if (retVal < 0) {
872 // Error in conversion
873 return(-1);
874 } // if
875 } // for
876
877 return (0);
878 } // setAttrNames
879
setTableNames()880 static int setTableNames()
881 {
882 // Note! Uses only uppercase letters in table name's
883 // so that we can look at the tables wits SQL
884 int i = 0;
885 int retVal = 0;
886
887 for (i = 0; i < MAXTABLES ; i++) {
888 if (theStandardTableNameFlag == 0) {
889 retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d_%u", i,
890 (Uint32)(NdbTick_CurrentMillisecond()/1000));
891 } // if
892 else {
893 retVal = BaseString::snprintf(tableName[i], MAXSTRLEN, "TAB%d", i);
894 } // else
895 if (retVal < 0) {
896 // Error in conversion
897 return(-1);
898 } // if
899 } // for
900
901 return(0);
902 } // setTableNames
903
checkThreadResults(ThreadNdb * threadArrayP,const char * phase)904 static int checkThreadResults(ThreadNdb *threadArrayP, const char* phase)
905 {
906 int i = 0;
907
908 for (i = 0; i < tNoOfThreads; i++) {
909 if (threadArrayP[i].threadResult != 0) {
910 ndbout << "Thread " << i << " reported fatal error "
911 << threadArrayP[i].threadResult << " during " << phase << endl;
912 return(-1);
913 } // if
914 } // for
915
916 return(0);
917 }
918
919