1 /*
2 Copyright (c) 2004, 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, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25 #include <ndb_global.h>
26 #include <ndb_opts.h>
27 #include <NDBT.hpp>
28 #include <NdbApi.hpp>
29 #include <HugoTransactions.hpp>
30 #include <Bitmask.hpp>
31 #include <Vector.hpp>
32
33 static const char* _dbname = "TEST_DB";
34 static int g_loops = 7;
35
36 struct my_option my_long_options[] =
37 {
38 NDB_STD_OPTS("ndb_desc"),
39 { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
40 };
41
42 static const NdbDictionary::Table* create_random_table(Ndb*);
43 static int transactions(Ndb*, const NdbDictionary::Table* tab);
44 static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
45 static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab);
46 static int node_restart(Ndb*, const NdbDictionary::Table* tab);
47 static int system_restart(Ndb*, const NdbDictionary::Table* tab);
48 static int testBitmask();
49
50 int
main(int argc,char ** argv)51 main(int argc, char** argv){
52 NDB_INIT(argv[0]);
53 const char *load_default_groups[]= { "mysql_cluster",0 };
54 load_defaults("my",load_default_groups,&argc,&argv);
55 int ho_error;
56
57 if ((ho_error=handle_options(&argc, &argv, my_long_options,
58 ndb_std_get_one_option)))
59 return NDBT_ProgramExit(NDBT_WRONGARGS);
60
61 int res = NDBT_FAILED;
62
63 /* Run cluster-independent tests */
64 for (int i=0; i<(10*g_loops); i++)
65 {
66 if (NDBT_OK != (res= testBitmask()))
67 return NDBT_ProgramExit(res);
68 }
69
70 Ndb_cluster_connection con(opt_ndb_connectstring, opt_ndb_nodeid);
71 if(con.connect(12, 5, 1))
72 {
73 return NDBT_ProgramExit(NDBT_FAILED);
74 }
75
76
77 Ndb* pNdb;
78 pNdb = new Ndb(&con, _dbname);
79 pNdb->init();
80 while (pNdb->waitUntilReady() != 0) {};
81
82 NdbDictionary::Dictionary * dict = pNdb->getDictionary();
83
84 const NdbDictionary::Table* pTab = 0;
85 for (int i = 0; i < (argc ? argc : g_loops) ; i++)
86 {
87 res = NDBT_FAILED;
88 if(argc == 0)
89 {
90 pTab = create_random_table(pNdb);
91 }
92 else
93 {
94 dict->dropTable(argv[i]);
95 NDBT_Tables::createTable(pNdb, argv[i]);
96 pTab = dict->getTable(argv[i]);
97 }
98
99 if (pTab == 0)
100 {
101 ndbout << "Failed to create table" << endl;
102 ndbout << dict->getNdbError() << endl;
103 break;
104 }
105
106 if(transactions(pNdb, pTab))
107 break;
108
109 if(unique_indexes(pNdb, pTab))
110 break;
111
112 if(ordered_indexes(pNdb, pTab))
113 break;
114
115 if(node_restart(pNdb, pTab))
116 break;
117
118 if(system_restart(pNdb, pTab))
119 break;
120
121 dict->dropTable(pTab->getName());
122 res = NDBT_OK;
123 }
124
125 if(res != NDBT_OK && pTab)
126 {
127 dict->dropTable(pTab->getName());
128 }
129
130 delete pNdb;
131 return NDBT_ProgramExit(res);
132 }
133
134 static
135 const NdbDictionary::Table*
create_random_table(Ndb * pNdb)136 create_random_table(Ndb* pNdb)
137 {
138 do {
139 NdbDictionary::Table tab;
140 Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
141 const Uint32 maxLength = 4090;
142 Uint32 length = maxLength;
143 Uint8 defbuf[(maxLength + 7)/8];
144
145 BaseString name;
146 name.assfmt("TAB_%d", rand() & 65535);
147 tab.setName(name.c_str());
148 for(Uint32 i = 0; i<cols && length > 2; i++)
149 {
150 NdbDictionary::Column col;
151 name.assfmt("COL_%d", i);
152 col.setName(name.c_str());
153 if(i == 0 || i == 1)
154 {
155 col.setType(NdbDictionary::Column::Unsigned);
156 col.setLength(1);
157 col.setNullable(false);
158 col.setPrimaryKey(i == 0);
159 tab.addColumn(col);
160 continue;
161 }
162
163 col.setType(NdbDictionary::Column::Bit);
164
165 Uint32 len = 1 + (rand() % (length - 1));
166 memset(defbuf, 0, (length + 7)/8);
167 for (Uint32 j = 0; j < len/8; j++)
168 defbuf[j] = 0x63;
169 col.setDefaultValue(defbuf, (len + 7)/8);
170 col.setLength(len); length -= len;
171 int nullable = (rand() >> 16) & 1;
172 col.setNullable(nullable); length -= nullable;
173 col.setPrimaryKey(false);
174 tab.addColumn(col);
175 }
176
177 pNdb->getDictionary()->dropTable(tab.getName());
178 if(pNdb->getDictionary()->createTable(tab) == 0)
179 {
180 ndbout << (NDBT_Table&)tab << endl;
181 return pNdb->getDictionary()->getTable(tab.getName());
182 }
183 } while(0);
184 return 0;
185 }
186
187 static
188 int
transactions(Ndb * pNdb,const NdbDictionary::Table * tab)189 transactions(Ndb* pNdb, const NdbDictionary::Table* tab)
190 {
191 int i = 0;
192 HugoTransactions trans(* tab);
193 i |= trans.loadTable(pNdb, 1000);
194 i |= trans.pkReadRecords(pNdb, 1000, 13);
195 i |= trans.scanReadRecords(pNdb, 1000, 25);
196 i |= trans.pkUpdateRecords(pNdb, 1000, 37);
197 i |= trans.scanUpdateRecords(pNdb, 1000, 25);
198 i |= trans.pkDelRecords(pNdb, 500, 23);
199 i |= trans.clearTable(pNdb);
200 return i;
201 }
202
203 static
204 int
unique_indexes(Ndb * pNdb,const NdbDictionary::Table * tab)205 unique_indexes(Ndb* pNdb, const NdbDictionary::Table* tab)
206 {
207 return 0;
208 }
209
210 static
211 int
ordered_indexes(Ndb * pNdb,const NdbDictionary::Table * tab)212 ordered_indexes(Ndb* pNdb, const NdbDictionary::Table* tab)
213 {
214 return 0;
215 }
216
217 static
218 int
node_restart(Ndb * pNdb,const NdbDictionary::Table * tab)219 node_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
220 {
221 return 0;
222 }
223
224 static
225 int
system_restart(Ndb * pNdb,const NdbDictionary::Table * tab)226 system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
227 {
228 return 0;
229 }
230
231 /* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp
232 * and were originally defined there.
233 * Set BITMASK_DEBUG to 1 to get more test debugging info.
234 */
235 #define BITMASK_DEBUG 0
236
237 static
cmp(const Uint32 b1[],const Uint32 b2[],Uint32 len)238 bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
239 {
240 Uint32 sz32 = (len + 31) >> 5;
241 for(Uint32 i = 0; i<len; i++)
242 {
243 if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
244 return false;
245 }
246 return true;
247 }
248
249 static
print(const Uint32 src[],Uint32 len,Uint32 pos=0)250 void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
251 {
252 printf("b'");
253 for(unsigned i = 0; i<len; i++)
254 {
255 if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
256 printf("1");
257 else
258 printf("0");
259 if((i & 31) == 31)
260 printf(" ");
261 }
262 }
263
lrand()264 static int lrand()
265 {
266 return rand();
267 }
268
269 static
rand(Uint32 dst[],Uint32 len)270 void rand(Uint32 dst[], Uint32 len)
271 {
272 for(Uint32 i = 0; i<len; i++)
273 BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
274 }
275
276 static
checkCopyField(const Uint32 totalTests)277 int checkCopyField(const Uint32 totalTests)
278 {
279 ndbout << "Testing : Checking Bitmaskimpl::copyField";
280
281 const Uint32 numWords= 95;
282 const Uint32 maxBitsToCopy= (numWords * 32);
283
284 Uint32 sourceBuf[numWords];
285 Uint32 targetTest[numWords];
286 Uint32 targetCopy[numWords];
287
288 rand(sourceBuf, maxBitsToCopy);
289
290 /* Set both target buffers to the same random values */
291 rand(targetTest, maxBitsToCopy);
292 for (Uint32 i=0; i<maxBitsToCopy; i++)
293 BitmaskImpl::set(numWords, targetCopy, i,
294 BitmaskImpl::get(numWords, targetTest, i));
295
296 if (!cmp(targetTest, targetCopy, maxBitsToCopy))
297 {
298 ndbout_c("copyField :: Initial setup mismatch");
299 return -1;
300 }
301
302 for (Uint32 test=0; test < totalTests; test++)
303 {
304 Uint32 len= rand() % maxBitsToCopy;
305 Uint32 slack= maxBitsToCopy - len;
306 Uint32 srcPos= slack ? rand() % slack : 0;
307 Uint32 dstPos= slack ? rand() % slack : 0;
308
309 if (BITMASK_DEBUG)
310 ndbout_c("copyField :: Running test with len=%u, srcPos=%u, dstPos=%u, "
311 "srcOff=%u, dstOff=%u",
312 len, srcPos, dstPos, srcPos & 31, dstPos & 31);
313
314 /* Run the copy */
315 BitmaskImpl::copyField(targetCopy, dstPos, sourceBuf, srcPos, len);
316
317 /* Do the equivalent action */
318 for (Uint32 i=0; i< len; i++)
319 BitmaskImpl::set(numWords, targetTest, dstPos + i,
320 BitmaskImpl::get(numWords, sourceBuf, srcPos+i));
321
322 bool fail= false;
323 /* Compare results */
324 for (Uint32 i=0; i<maxBitsToCopy; i++)
325 {
326 if (BitmaskImpl::get(numWords, targetCopy, i) !=
327 BitmaskImpl::get(numWords, targetTest, i))
328 {
329 ndbout_c("copyField :: Mismatch at bit %u, should be %u but is %u",
330 i,
331 BitmaskImpl::get(numWords, targetTest, i),
332 BitmaskImpl::get(numWords, targetCopy, i));
333 fail=true;
334 }
335 }
336
337 if (fail)
338 return -1;
339 }
340
341 return 0;
342 }
343
344 static
checkNoTramplingGetSetField(const Uint32 totalTests)345 int checkNoTramplingGetSetField(const Uint32 totalTests)
346 {
347 const Uint32 numWords= 67;
348 const Uint32 maxBitsToCopy= (numWords * 32);
349 Uint32 sourceBuf[numWords];
350 Uint32 targetBuf[numWords];
351
352 ndbout << "Testing : Bitmask NoTrampling\n";
353
354 memset(sourceBuf, 0x00, (numWords*4));
355
356 for (Uint32 test=0; test<totalTests; test++)
357 {
358 /* Always copy at least 1 bit */
359 Uint32 srcStart= rand() % (maxBitsToCopy -1);
360 Uint32 length= (rand() % ((maxBitsToCopy -1) - srcStart)) + 1;
361
362 if (BITMASK_DEBUG)
363 ndbout << "Testing start %u, length %u \n"
364 << srcStart
365 << length;
366 // Set target to all ones.
367 memset(targetBuf, 0xff, (numWords*4));
368
369 BitmaskImpl::getField(numWords, sourceBuf, srcStart, length, targetBuf);
370
371 // Check that there is no trampling
372 Uint32 firstUntrampledWord= (length + 31)/32;
373
374 for (Uint32 word=0; word< numWords; word++)
375 {
376 Uint32 targetWord= targetBuf[word];
377 if (BITMASK_DEBUG)
378 ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
379 << word << targetWord << firstUntrampledWord;
380
381 if (! (word < firstUntrampledWord) ?
382 (targetWord == 0) :
383 (targetWord == 0xffffffff))
384 {
385 ndbout << "Notrampling getField failed for srcStart "
386 << srcStart
387 << " length " << length
388 << " at word " << word << "\n";
389 ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
390 << word << targetWord << firstUntrampledWord;
391 return -1;
392 }
393
394 }
395
396 /* Set target back to all ones. */
397 memset(targetBuf, 0xff, (numWords*4));
398
399 BitmaskImpl::setField(numWords, targetBuf, srcStart, length, sourceBuf);
400
401 /* Check we've got all ones, with zeros only where expected */
402 for (Uint32 word=0; word< numWords; word++)
403 {
404 Uint32 targetWord= targetBuf[word];
405
406 for (Uint32 bit=0; bit< 32; bit++)
407 {
408 Uint32 bitNum= (word << 5) + bit;
409 bool expectedValue= !((bitNum >= srcStart) &&
410 (bitNum < (srcStart + length)));
411 bool actualValue= (((targetWord >> bit) & 1) == 1);
412 if (BITMASK_DEBUG)
413 ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
414 << bitNum << expectedValue << actualValue;
415
416 if (actualValue != expectedValue)
417 {
418 ndbout << "Notrampling setField failed for srcStart "
419 << srcStart
420 << " length " << length
421 << " at word " << word << " bit " << bit << "\n";
422 ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
423 << bitNum << expectedValue << actualValue;
424 return -1;
425 }
426 }
427 }
428
429 }
430
431 return 0;
432 }
433
434 static
simple(int pos,int size)435 int simple(int pos, int size)
436 {
437 ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size << "\n";
438 Vector<Uint32> _mask;
439 Vector<Uint32> _src;
440 Vector<Uint32> _dst;
441 Uint32 sz32 = (size + pos + 32) >> 5;
442 const Uint32 sz = 4 * sz32;
443
444 Uint32 zero = 0;
445 _mask.fill(sz32+1, zero);
446 _src.fill(sz32+1, zero);
447 _dst.fill(sz32+1, zero);
448
449 Uint32 * src = _src.getBase();
450 Uint32 * dst = _dst.getBase();
451 Uint32 * mask = _mask.getBase();
452
453 memset(src, 0x0, sz);
454 memset(dst, 0x0, sz);
455 memset(mask, 0xFF, sz);
456 rand(src, size);
457 BitmaskImpl::setField(sz32, mask, pos, size, src);
458 BitmaskImpl::getField(sz32, mask, pos, size, dst);
459 if (BITMASK_DEBUG)
460 {
461 printf("src: "); print(src, size+31); printf("\n");
462 printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
463 printf("dst: "); print(dst, size+31); printf("\n");
464 }
465 return (cmp(src, dst, size+31)?0 : -1);
466 };
467
468 struct Alloc
469 {
470 Uint32 pos;
471 Uint32 size;
472 Vector<Uint32> data;
473 };
474
475 static
476 int
testRanges(Uint32 bitmask_size)477 testRanges(Uint32 bitmask_size)
478 {
479 Vector<Alloc> alloc_list;
480 bitmask_size = (bitmask_size + 31) & ~31;
481 Uint32 sz32 = (bitmask_size >> 5);
482 Vector<Uint32> alloc_mask;
483 Vector<Uint32> test_mask;
484
485 ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size);
486 Uint32 zero = 0;
487 alloc_mask.fill(sz32, zero);
488 test_mask.fill(sz32, zero);
489
490 /* Loop a number of times, setting and clearing bits in the mask
491 * and tracking the modifications in a separate structure.
492 * Check that both structures remain in sync
493 */
494 for(int i = 0; i<5000; i++)
495 {
496 Vector<Uint32> tmp;
497 tmp.fill(sz32, zero);
498
499 Uint32 pos = lrand() % (bitmask_size - 1);
500 Uint32 free = 0;
501 if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
502 {
503 // Bit was allocated
504 // 1) Look up allocation
505 // 2) Check data
506 // 3) free it
507 size_t j;
508 Uint32 min, max;
509 for(j = 0; j<alloc_list.size(); j++)
510 {
511 min = alloc_list[j].pos;
512 max = min + alloc_list[j].size;
513 if(pos >= min && pos < max)
514 {
515 break;
516 }
517 }
518 if (! ((pos >= min) && (pos < max)))
519 {
520 printf("Failed with pos %u, min %u, max %u\n",
521 pos, min, max);
522 return -1;
523 }
524 BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
525 tmp.getBase());
526 if(BITMASK_DEBUG)
527 {
528 printf("freeing [ %d %d ]", min, max);
529 printf("- mask: ");
530 print(tmp.getBase(), max - min);
531
532 printf(" save: ");
533 size_t k;
534 Alloc& a = alloc_list[j];
535 for(k = 0; k<a.data.size(); k++)
536 printf("%.8x ", a.data[k]);
537 printf("\n");
538 }
539 if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
540 {
541 return -1;
542 }
543 while(min < max)
544 BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
545 alloc_list.erase(j);
546 }
547 else
548 {
549 Vector<Uint32> tmp;
550 tmp.fill(sz32, zero);
551
552 // Bit was free
553 // 1) Check how much space is avaiable
554 // 2) Create new allocation of lrandom size
555 // 3) Fill data with lrandom data
556 // 4) Update alloc mask
557 while(pos+free < bitmask_size &&
558 !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
559 free++;
560
561 Uint32 sz =
562 (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
563 sz = sz ? sz : 1;
564 sz = pos + sz == bitmask_size ? sz - 1 : sz;
565 Alloc a;
566 a.pos = pos;
567 a.size = sz;
568 a.data.fill(((sz+31)>> 5)-1, zero);
569 if(BITMASK_DEBUG)
570 printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
571 for(size_t j = 0; j<sz; j++)
572 {
573 BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
574 if((lrand() % 1000) > 500)
575 BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
576 }
577 if(BITMASK_DEBUG)
578 {
579 printf("- mask: ");
580 print(a.data.getBase(), sz);
581 printf("\n");
582 }
583 BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
584 a.data.getBase());
585 alloc_list.push_back(a);
586 }
587 }
588
589 #define NDB_BM_SUPPORT_RANGE
590 #ifdef NDB_BM_SUPPORT_RANGE
591 for(Uint32 i = 0; i<1000; i++)
592 {
593 Uint32 sz32 = 10+rand() % 100;
594 Uint32 zero = 0;
595 Vector<Uint32> map;
596 map.fill(sz32, zero);
597
598 Uint32 sz = 32 * sz32;
599 Uint32 start = (rand() % sz);
600 Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
601
602 Vector<Uint32> check;
603 check.fill(sz32, zero);
604
605 /* Verify range setting method works correctly */
606 for(Uint32 j = 0; j<sz; j++)
607 {
608 bool expect = (j >= start && j<stop);
609 if(expect)
610 BitmaskImpl::set(sz32, check.getBase(), j);
611 }
612
613 BitmaskImpl::setRange(sz32, map.getBase(), start, stop - start + 1);
614 if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
615 {
616 ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz, start, stop);
617 printf("check: ");
618 for(Uint32 j = 0; j<sz32; j++)
619 printf("%.8x ", check[j]);
620 printf("\n");
621
622 printf("map : ");
623 for(Uint32 j = 0; j<sz32; j++)
624 printf("%.8x ", map[j]);
625 printf("\n");
626 return -1;
627 }
628
629 map.clear();
630 check.clear();
631
632 /* Verify range clearing method works correctly */
633 Uint32 one = ~(Uint32)0;
634 map.fill(sz32, one);
635 check.fill(sz32, one);
636
637 for(Uint32 j = 0; j<sz; j++)
638 {
639 bool expect = (j >= start && j<stop);
640 if(expect)
641 BitmaskImpl::clear(sz32, check.getBase(), j);
642 }
643
644 BitmaskImpl::clear_range(sz32, map.getBase(), start, stop);
645 if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
646 {
647 ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz, start, stop);
648 printf("check: ");
649 for(Uint32 j = 0; j<sz32; j++)
650 printf("%.8x ", check[j]);
651 printf("\n");
652
653 printf("map : ");
654 for(Uint32 j = 0; j<sz32; j++)
655 printf("%.8x ", map[j]);
656 printf("\n");
657 return -1;
658 }
659 }
660 #endif
661
662 return 0;
663 }
664
665 static
666 int
testBitmask()667 testBitmask()
668 {
669 /* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
670 int res= 0;
671
672 if ((res= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
673 return res;
674
675 if ((res= checkCopyField(1000)) != 0)
676 return res;
677
678 if ((res= simple(rand() % 33, // position
679 (rand() % 63)+1) // size
680 ) != 0)
681 return res;
682
683 if ((res= testRanges(1+(rand() % 1000) // bitmask size
684 )) != 0)
685 return res;
686
687 return 0;
688 }
689
690 template class Vector<Alloc>;
691