MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
NdbRepStress.cpp
1 /*
2  Copyright (C) 2008 MySQL AB
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <NDBT_Test.hpp>
20 #include <NDBT_ReturnCodes.h>
21 #include <HugoTransactions.hpp>
22 #include <UtilTransactions.hpp>
23 #include <DbUtil.hpp>
24 #include <mysql.h>
25 
26 /*
27 Will include restart testing in future phases
28 #include <NdbRestarter.hpp>
29 #include <NdbRestarts.hpp>
30 */
31 
32 /**** TOOL SECTION ****/
33 
34 static uint
35 urandom()
36 {
37  uint r = (uint)random();
38  return r;
39 }
40 
41 static uint
42 urandom(uint m)
43 {
44  if (m == 0)
45  return NDBT_OK;
46  uint r = urandom();
47  r = r % m;
48  return r;
49 }
50 
51 bool
52 syncSlaveWithMaster()
53 {
54  /*
55  We need to look at the MAX epoch of the
56  mysql.ndb_binlog_index table so we will
57  know when the slave has caught up
58  */
59 
60  SqlResultSet result;
61  unsigned long long masterEpoch = 0;
62  unsigned long long slaveEpoch = 0;
63  unsigned long long slaveEpochOld = 0;
64  int maxLoops = 100;
65  int loopCnt = 0;
66 
67  //Create a DbUtil object for the master
68  DbUtil master("mysql");
69 
70  //Login to Master
71  if (!master.connect())
72  {
73  g_err << "sync connect to master failed" << endl;
74  return false;
75  }
76 
77  //Get max epoch from master
78  if(!master.doQuery("SELECT MAX(epoch) FROM mysql.ndb_binlog_index", result))
79  {
80  g_err << "Select max(epoch) SQL failed" << endl;
81  return false;
82  }
83  masterEpoch = result.columnAsLong("epoch");
84 
85  /*
86  Now we will pull current epoch from slave. If not the
87  same as master, we will continue to retrieve the epoch
88  and compare until it matches or we reach the max loops
89  allowed.
90  */
91 
92  //Create a dbutil object for the slave
93  DbUtil slave("mysql", ".1.slave");
94 
95  //Login to slave
96  if (!slave.connect())
97  {
98  g_err << "sync connect to slave failed" << endl;
99  return false;
100  }
101 
102  while(slaveEpoch != masterEpoch && loopCnt < maxLoops)
103  {
104  if(!slave.doQuery("SELECT epoch FROM mysql.ndb_apply_status",result))
105  {
106  g_err << "Select epoch SQL on slave failed" << endl;
107  return false;
108  }
109  result.print();
110  if (result.numRows() > 0)
111  slaveEpoch = result.columnAsLong("epoch");
112 
113  if(slaveEpoch != slaveEpochOld)
114  {
115  slaveEpochOld = slaveEpoch;
116  if(loopCnt > 0)
117  loopCnt--;
118  sleep(3);
119  }
120  else
121  {
122  sleep(1);
123  loopCnt++;
124  }
125  }
126 
127  if(slaveEpoch != masterEpoch)
128  {
129  g_err << "Slave not in sync with master!" << endl;
130  return false;
131  }
132  return true;
133 }
134 
135 bool
136 verifySlaveLoad(BaseString &table)
137 {
138  //BaseString sqlStm;
139  BaseString db;
140  unsigned int masterCount = 0;
141  unsigned int slaveCount = 0;
142 
143  db.assign("TEST_DB");
144  //sqlStm.assfmt("SELECT COUNT(*) FROM %s", table);
145 
146  //First thing to do is sync slave
147  printf("Calling syncSlave\n");
148  if(!syncSlaveWithMaster())
149  {
150  g_err << "Verify Load -> Syncing with slave failed" << endl;
151  return false;
152  }
153 
154  //Now that slave is sync we can verify load
155  DbUtil master(db.c_str());
156 
157  //Login to Master
158  if (!master.connect())
159  {
160  g_err << "Verify Load -> connect to master failed" << endl;
161  return false;
162  }
163 
164  if((masterCount = master.selectCountTable(table.c_str())) == 0 )
165  {
166  g_err << "Verify Load -> masterCount == ZERO!" << endl;
167  return false;
168  }
169 
170  //Create a DB Object for slave
171  DbUtil slave(db.c_str(), ".1.slave");
172 
173  //Login to slave
174  if (!slave.connect())
175  {
176  g_err << "Verify Load -> connect to master failed" << endl;
177  return false;
178  }
179 
180  if((slaveCount = slave.selectCountTable(table.c_str())) == 0 )
181  {
182  g_err << "Verify Load -> slaveCount == ZERO" << endl;
183  return false;
184  }
185 
186  if(slaveCount != masterCount)
187  {
188  g_err << "Verify Load -> Slave Count != Master Count "
189  << endl;
190  return false;
191  }
192  return true;
193 }
194 
195 int
196 createTEST_DB(NDBT_Context* ctx, NDBT_Step* step)
197 {
198  BaseString cdb;
199  cdb.assign("TEST_DB");
200 
201  //Create a dbutil object
202  DbUtil master("mysql");
203 
204  if (!master.connect())
205  {
206  g_err << "Create DB -> Connect to master failed"
207  << endl;
208  return NDBT_FAILED;
209  }
210 
211  if (!master.createDb(cdb))
212  {
213  return NDBT_FAILED;
214  }
215  return NDBT_OK;
216 }
217 
218 int
219 dropTEST_DB(NDBT_Context* ctx, NDBT_Step* step)
220 {
221  //Create an SQL Object
222  DbUtil master("mysql");
223 
224  //Login to Master
225  if (!master.connect())
226  {
227  g_err << "Drop DB -> Connect to master failed"
228  << endl;
229  return NDBT_FAILED;
230  }
231 
232  if(!master.doQuery("DROP DATABASE TEST_DB"))
233  {
234  g_err << "Drop DB -> SQL failed"
235  << endl;
236  return NDBT_FAILED;
237  }
238 
239  if(!syncSlaveWithMaster())
240  {
241  g_err << "Drop DB -> Syncing with slave failed"
242  << endl;
243  return NDBT_FAILED;
244  }
245  return NDBT_OK;
246 }
247 
248 int
249 verifySlave(BaseString& sqlStm, BaseString& db, BaseString& column)
250 {
251  SqlResultSet result;
252  float masterSum;
253  float slaveSum;
254 
255  //Create SQL Objects
256  DbUtil master(db.c_str());
257  DbUtil slave(db.c_str(), ".1.slave");
258 
259  if(!syncSlaveWithMaster())
260  {
261  g_err << "Verify Slave -> Syncing with slave failed"
262  << endl;
263  return NDBT_FAILED;
264  }
265 
266  //Login to Master
267  if (!master.connect())
268  {
269  g_err << "Verify Slave -> connect master failed"
270  << endl;
271  return NDBT_FAILED;
272  }
273 
274  if(!master.doQuery(sqlStm.c_str(),result))
275  {
276  return NDBT_FAILED;
277  }
278  masterSum = result.columnAsInt(column.c_str());
279 
280  //Login to slave
281  if (!slave.connect())
282  {
283  return NDBT_FAILED;
284  }
285 
286  if(!slave.doQuery(sqlStm.c_str(),result))
287  {
288  return NDBT_FAILED;
289  }
290  slaveSum = result.columnAsInt(column.c_str());
291 
292  if(masterSum != slaveSum)
293  {
294  g_err << "VerifySlave -> masterSum != slaveSum..." << endl;
295  return NDBT_FAILED;
296  }
297  return NDBT_OK;
298 }
299 
300 
301 /**** Test Section ****/
302 
303 int
304 createTable_rep1(NDBT_Context* ctx, NDBT_Step* step)
305 {
307  BaseString db;
308 
309  table.assign("rep1");
310  db.assign("TEST_DB");
311 
312  //Ensure slave is up and ready
313  if(!syncSlaveWithMaster())
314  {
315  g_err << "Create Table -> Syncing with slave failed"
316  << endl;
317  return NDBT_FAILED;
318  }
319 
320  //Create an SQL Object
321  DbUtil master(db.c_str());
322 
323  //Login to Master
324  if (!master.connect())
325  {
326  g_err << "Create Table -> Connect to Master failed"
327  << endl;
328  return NDBT_FAILED;
329  }
330 
331  if (!master.doQuery("CREATE TABLE rep1 (c1 MEDIUMINT NOT NULL AUTO_INCREMENT,"
332  " c2 FLOAT, c3 CHAR(5), c4 TEXT(8), c5 FLOAT, c6 INT,"
333  " c7 INT, PRIMARY KEY (c1))ENGINE=NDB"))
334  {
335  g_err << "Create Table -> Create table SQL failed"
336  << endl;
337  return NDBT_FAILED;
338  }
339 
340  /* Not happy with the data hugo generated
341 
342  Ndb* ndb=GETNDB(step);
343  NdbDictionary::Dictionary* myDict = ndb->getDictionary();
344  const NdbDictionary::Table *ndbTab = myDict->getTable(table.c_str());
345  HugoTransactions hugoTrans(*ndbTab);
346 
347  if (hugoTrans.loadTable(GETNDB(step), ctx->getNumRecords(), 1, true, 0)
348  == NDBT_FAILED)
349  {
350  g_err << "Create Table -> Hudo Load failed!" << endl;
351  return NDBT_FAILED;
352  }
353 
354  */
355 
356  for(int i = 0; i < ctx->getNumRecords(); i++)
357  {
358  if (!master.doQuery("INSERT INTO rep1 VALUES(NULL, 0, 'TEXAS', 'works', 0, 2, 1)"))
359  {
360  g_err << "Create Table -> Insert SQL failed"
361  << endl;
362  return NDBT_FAILED;
363  }
364  }
365 
366  if(!verifySlaveLoad(table))
367  {
368  g_err << "Create Table -> Failed on verify slave load!"
369  << endl;
370  return NDBT_FAILED;
371  }
372  //else everything is okay
373  return NDBT_OK;
374 }
375 
376 int
377 stressNDB_rep1(NDBT_Context* ctx, NDBT_Step* step)
378 {
379  Ndb* ndb=GETNDB(step);
380  NdbDictionary::Dictionary* myDict = ndb->getDictionary();
381  const NdbDictionary::Table * table = myDict->getTable("rep1");
382  HugoTransactions hugoTrans(* table);
383  while(!ctx->isTestStopped())
384  {
385  if (hugoTrans.pkUpdateRecords(GETNDB(step), ctx->getNumRecords(), 1, 30)
386  == NDBT_FAILED)
387  {
388  g_err << "pkUpdate Failed!" << endl;
389  return NDBT_FAILED;
390  }
391  if (hugoTrans.scanUpdateRecords(GETNDB(step), ctx->getNumRecords(), 1, 30)
392  == NDBT_FAILED)
393  {
394  g_err << "scanUpdate Failed!" << endl;
395  return NDBT_FAILED;
396  }
397  }
398  return NDBT_OK;
399 }
400 
401 int
402 stressSQL_rep1(NDBT_Context* ctx, NDBT_Step* step)
403 {
404  BaseString sqlStm;
405 
406  DbUtil master("TEST_DB");
407  int loops = ctx->getNumLoops();
408  uint record = 0;
409 
410  //Login to Master
411  if (!master.connect())
412  {
413  ctx->stopTest();
414  return NDBT_FAILED;
415  }
416 
417  for (int j= 0; loops == 0 || j < loops; j++)
418  {
419  record = urandom(ctx->getNumRecords());
420  sqlStm.assfmt("UPDATE TEST_DB.rep1 SET c2 = 33.3221 where c1 = %u", record);
421  if(!master.doQuery(sqlStm.c_str()))
422  {
423  return NDBT_FAILED;
424  }
425  }
426  ctx->stopTest();
427  return NDBT_OK;
428 }
429 
430 int
431 verifySlave_rep1(NDBT_Context* ctx, NDBT_Step* step)
432 {
433  BaseString sql;
434  BaseString db;
435  BaseString column;
436 
437  sql.assign("SELECT SUM(c3) FROM rep1");
438  db.assign("TEST_DB");
439  column.assign("c3");
440 
441  if (!verifySlave(sql,db,column))
442  return NDBT_FAILED;
443  return NDBT_OK;
444 }
445 
446 /* TOOLS LIST
447 
448  syncSlaveWithMaster()
449  {ensures slave is at same epoch as master}
450 
451  verifySlaveLoad(BaseString *table)
452  {ensures slave table has same record count as master}
453 
454  createTEST_DB()
455  {Creates TEST_DB database on master}
456 
457  dropTEST_DB()
458  {Drops TEST_DB database on master}
459 
460  verifySlave(BaseString& sql, BaseSting& db, BaseSting& column)
461  {The SQL statement must sum a column and will verify
462  that the sum of the column is equal on master & slave}
463 */
464 
465 
466 NDBT_TESTSUITE(NdbRepStress);
467 TESTCASE("PHASE_I_Stress","Basic Replication Stressing")
468 {
469  INITIALIZER(createTEST_DB);
470  INITIALIZER(createTable_rep1);
471  //STEP(stressNDB_rep1);
472  STEP(stressSQL_rep1);
473  FINALIZER(verifySlave_rep1);
474  FINALIZER(dropTEST_DB);
475 }
476 NDBT_TESTSUITE_END(NdbRepStress);
477 
478 int main(int argc, const char** argv){
479  ndb_init();
480  NDBT_TESTSUITE_INSTANCE(NdbRepStress);
481  NdbRepStress.setCreateAllTables(true);
482  return NdbRepStress.execute(argc, argv);
483 }
484