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