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