1 /*
2 Copyright (c) 2004, 2014, 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 ndb_load_defaults(NULL, 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
141 // Table need as minimum a PK and an 'Update count' column
142 Uint32 cols = 2 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 2));
143 const Uint32 maxLength = 4090;
144 Uint32 length = maxLength;
145 Uint8 defbuf[(maxLength + 7)/8];
146
147 BaseString name;
148 name.assfmt("TAB_%d", rand() & 65535);
149 tab.setName(name.c_str());
150 for(Uint32 i = 0; i<cols && length > 2; i++)
151 {
152 NdbDictionary::Column col;
153 name.assfmt("COL_%d", i);
154 col.setName(name.c_str());
155 if(i == 0 || i == 1)
156 {
157 col.setType(NdbDictionary::Column::Unsigned);
158 col.setLength(1);
159 col.setNullable(false);
160 col.setPrimaryKey(i == 0);
161 tab.addColumn(col);
162 continue;
163 }
164
165 col.setType(NdbDictionary::Column::Bit);
166
167 Uint32 len = 1 + (rand() % (length - 1));
168 memset(defbuf, 0, (length + 7)/8);
169 for (Uint32 j = 0; j < len/8; j++)
170 defbuf[j] = 0x63;
171 col.setDefaultValue(defbuf, 4*((len + 31)/32));
172 col.setLength(len); length -= len;
173 int nullable = (rand() >> 16) & 1;
174 col.setNullable(nullable); length -= nullable;
175 col.setPrimaryKey(false);
176 tab.addColumn(col);
177 }
178
179 pNdb->getDictionary()->dropTable(tab.getName());
180 if(pNdb->getDictionary()->createTable(tab) == 0)
181 {
182 ndbout << (NDBT_Table&)tab << endl;
183 return pNdb->getDictionary()->getTable(tab.getName());
184 }
185 } while(0);
186 return 0;
187 }
188
189 static
190 int
transactions(Ndb * pNdb,const NdbDictionary::Table * tab)191 transactions(Ndb* pNdb, const NdbDictionary::Table* tab)
192 {
193 int i = 0;
194 HugoTransactions trans(* tab);
195 i |= trans.loadTable(pNdb, 1000);
196 i |= trans.pkReadRecords(pNdb, 1000, 13);
197 i |= trans.scanReadRecords(pNdb, 1000, 25);
198 i |= trans.pkUpdateRecords(pNdb, 1000, 37);
199 i |= trans.scanUpdateRecords(pNdb, 1000, 25);
200 i |= trans.pkDelRecords(pNdb, 500, 23);
201 i |= trans.clearTable(pNdb);
202 return i;
203 }
204
205 static
206 int
unique_indexes(Ndb * pNdb,const NdbDictionary::Table * tab)207 unique_indexes(Ndb* pNdb, const NdbDictionary::Table* tab)
208 {
209 return 0;
210 }
211
212 static
213 int
ordered_indexes(Ndb * pNdb,const NdbDictionary::Table * tab)214 ordered_indexes(Ndb* pNdb, const NdbDictionary::Table* tab)
215 {
216 return 0;
217 }
218
219 static
220 int
node_restart(Ndb * pNdb,const NdbDictionary::Table * tab)221 node_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
222 {
223 return 0;
224 }
225
226 static
227 int
system_restart(Ndb * pNdb,const NdbDictionary::Table * tab)228 system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
229 {
230 return 0;
231 }
232
233 /* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp
234 * and were originally defined there.
235 * Set BITMASK_DEBUG to 1 to get more test debugging info.
236 */
237 #define BITMASK_DEBUG 0
238
239 static
cmp(const Uint32 b1[],const Uint32 b2[],Uint32 len)240 bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
241 {
242 Uint32 sz32 = (len + 31) >> 5;
243 for(Uint32 i = 0; i<len; i++)
244 {
245 if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
246 return false;
247 }
248 return true;
249 }
250
251 static
print(const Uint32 src[],Uint32 len,Uint32 pos=0)252 void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
253 {
254 printf("b'");
255 for(unsigned i = 0; i<len; i++)
256 {
257 if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
258 printf("1");
259 else
260 printf("0");
261 if((i & 31) == 31)
262 printf(" ");
263 }
264 }
265
lrand()266 static int lrand()
267 {
268 return rand();
269 }
270
271 static
rand(Uint32 dst[],Uint32 len)272 void rand(Uint32 dst[], Uint32 len)
273 {
274 for(Uint32 i = 0; i<len; i++)
275 BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
276 }
277
278 static
checkCopyField(const Uint32 totalTests)279 int checkCopyField(const Uint32 totalTests)
280 {
281 ndbout << "Testing : Checking Bitmaskimpl::copyField"
282 << endl;
283
284 const Uint32 numWords= 95;
285 const Uint32 maxBitsToCopy= (numWords * 32);
286
287 Uint32 sourceBuf[numWords];
288 Uint32 targetTest[numWords];
289 Uint32 targetCopy[numWords];
290
291 rand(sourceBuf, maxBitsToCopy);
292
293 /* Set both target buffers to the same random values */
294 rand(targetTest, maxBitsToCopy);
295 for (Uint32 i=0; i<maxBitsToCopy; i++)
296 BitmaskImpl::set(numWords, targetCopy, i,
297 BitmaskImpl::get(numWords, targetTest, i));
298
299 if (!cmp(targetTest, targetCopy, maxBitsToCopy))
300 {
301 ndbout_c("copyField :: Initial setup mismatch");
302 return -1;
303 }
304
305 for (Uint32 test=0; test < totalTests; test++)
306 {
307 Uint32 len= rand() % maxBitsToCopy;
308 Uint32 slack= maxBitsToCopy - len;
309 Uint32 srcPos= slack ? rand() % slack : 0;
310 Uint32 dstPos= slack ? rand() % slack : 0;
311
312 if (BITMASK_DEBUG)
313 ndbout_c("copyField :: Running test with len=%u, srcPos=%u, dstPos=%u, "
314 "srcOff=%u, dstOff=%u",
315 len, srcPos, dstPos, srcPos & 31, dstPos & 31);
316
317 /* Run the copy */
318 BitmaskImpl::copyField(targetCopy, dstPos, sourceBuf, srcPos, len);
319
320 /* Do the equivalent action */
321 for (Uint32 i=0; i< len; i++)
322 BitmaskImpl::set(numWords, targetTest, dstPos + i,
323 BitmaskImpl::get(numWords, sourceBuf, srcPos+i));
324
325 bool fail= false;
326 /* Compare results */
327 for (Uint32 i=0; i<maxBitsToCopy; i++)
328 {
329 if (BitmaskImpl::get(numWords, targetCopy, i) !=
330 BitmaskImpl::get(numWords, targetTest, i))
331 {
332 ndbout_c("copyField :: Mismatch at bit %u, should be %u but is %u",
333 i,
334 BitmaskImpl::get(numWords, targetTest, i),
335 BitmaskImpl::get(numWords, targetCopy, i));
336 fail=true;
337 }
338 }
339
340 if (fail)
341 return -1;
342 }
343
344 return 0;
345 }
346
347 static
checkNoTramplingGetSetField(const Uint32 totalTests)348 int checkNoTramplingGetSetField(const Uint32 totalTests)
349 {
350 const Uint32 numWords= 67;
351 const Uint32 maxBitsToCopy= (numWords * 32);
352 Uint32 sourceBuf[numWords];
353 Uint32 targetBuf[numWords];
354
355 ndbout << "Testing : Bitmask NoTrampling"
356 << endl;
357
358 memset(sourceBuf, 0x00, (numWords*4));
359
360 for (Uint32 test=0; test<totalTests; test++)
361 {
362 /* Always copy at least 1 bit */
363 Uint32 srcStart= rand() % (maxBitsToCopy -1);
364 Uint32 length= (rand() % ((maxBitsToCopy -1) - srcStart)) + 1;
365
366 if (BITMASK_DEBUG)
367 ndbout << "Testing start %u, length %u \n"
368 << srcStart
369 << length;
370 // Set target to all ones.
371 memset(targetBuf, 0xff, (numWords*4));
372
373 BitmaskImpl::getField(numWords, sourceBuf, srcStart, length, targetBuf);
374
375 // Check that there is no trampling
376 Uint32 firstUntrampledWord= (length + 31)/32;
377
378 for (Uint32 word=0; word< numWords; word++)
379 {
380 Uint32 targetWord= targetBuf[word];
381 if (BITMASK_DEBUG)
382 ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
383 << word << targetWord << firstUntrampledWord;
384
385 if (! (word < firstUntrampledWord) ?
386 (targetWord == 0) :
387 (targetWord == 0xffffffff))
388 {
389 ndbout << "Notrampling getField failed for srcStart "
390 << srcStart
391 << " length " << length
392 << " at word " << word << "\n";
393 ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
394 << word << targetWord << firstUntrampledWord;
395 return -1;
396 }
397
398 }
399
400 /* Set target back to all ones. */
401 memset(targetBuf, 0xff, (numWords*4));
402
403 BitmaskImpl::setField(numWords, targetBuf, srcStart, length, sourceBuf);
404
405 /* Check we've got all ones, with zeros only where expected */
406 for (Uint32 word=0; word< numWords; word++)
407 {
408 Uint32 targetWord= targetBuf[word];
409
410 for (Uint32 bit=0; bit< 32; bit++)
411 {
412 Uint32 bitNum= (word << 5) + bit;
413 bool expectedValue= !((bitNum >= srcStart) &&
414 (bitNum < (srcStart + length)));
415 bool actualValue= (((targetWord >> bit) & 1) == 1);
416 if (BITMASK_DEBUG)
417 ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
418 << bitNum << expectedValue << actualValue;
419
420 if (actualValue != expectedValue)
421 {
422 ndbout << "Notrampling setField failed for srcStart "
423 << srcStart
424 << " length " << length
425 << " at word " << word << " bit " << bit << "\n";
426 ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
427 << bitNum << expectedValue << actualValue;
428 return -1;
429 }
430 }
431 }
432
433 }
434
435 return 0;
436 }
437
438 static
simple(int pos,int size)439 int simple(int pos, int size)
440 {
441 ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size
442 << endl;
443
444 Vector<Uint32> _mask;
445 Vector<Uint32> _src;
446 Vector<Uint32> _dst;
447 Uint32 sz32 = (size + pos + 32) >> 5;
448 const Uint32 sz = 4 * sz32;
449
450 Uint32 zero = 0;
451 _mask.fill(sz32+1, zero);
452 _src.fill(sz32+1, zero);
453 _dst.fill(sz32+1, zero);
454
455 Uint32 * src = _src.getBase();
456 Uint32 * dst = _dst.getBase();
457 Uint32 * mask = _mask.getBase();
458
459 memset(src, 0x0, sz);
460 memset(dst, 0x0, sz);
461 memset(mask, 0xFF, sz);
462 rand(src, size);
463 BitmaskImpl::setField(sz32, mask, pos, size, src);
464 BitmaskImpl::getField(sz32, mask, pos, size, dst);
465 if (BITMASK_DEBUG)
466 {
467 printf("src: "); print(src, size+31); printf("\n");
468 printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
469 printf("dst: "); print(dst, size+31); printf("\n");
470 }
471 return (cmp(src, dst, size+31)?0 : -1);
472 };
473
474 struct Alloc
475 {
476 Uint32 pos;
477 Uint32 size;
478 Vector<Uint32> data;
479 };
480
481 static
482 int
testRanges(Uint32 bitmask_size)483 testRanges(Uint32 bitmask_size)
484 {
485 Vector<Alloc> alloc_list;
486 bitmask_size = (bitmask_size + 31) & ~31;
487 Uint32 sz32 = (bitmask_size >> 5);
488 Vector<Uint32> alloc_mask;
489 Vector<Uint32> test_mask;
490
491 ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size);
492 Uint32 zero = 0;
493 alloc_mask.fill(sz32, zero);
494 test_mask.fill(sz32, zero);
495
496 /* Loop a number of times, setting and clearing bits in the mask
497 * and tracking the modifications in a separate structure.
498 * Check that both structures remain in sync
499 */
500 for(int i = 0; i<5000; i++)
501 {
502 Vector<Uint32> tmp;
503 tmp.fill(sz32, zero);
504
505 Uint32 pos = lrand() % (bitmask_size - 1);
506 Uint32 free = 0;
507 if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
508 {
509 // Bit was allocated
510 // 1) Look up allocation
511 // 2) Check data
512 // 3) free it
513 unsigned j;
514 Uint32 min, max;
515 for(j = 0; j<alloc_list.size(); j++)
516 {
517 min = alloc_list[j].pos;
518 max = min + alloc_list[j].size;
519 if(pos >= min && pos < max)
520 {
521 break;
522 }
523 }
524 if (! ((pos >= min) && (pos < max)))
525 {
526 printf("Failed with pos %u, min %u, max %u\n",
527 pos, min, max);
528 return -1;
529 }
530 BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
531 tmp.getBase());
532 if(BITMASK_DEBUG)
533 {
534 printf("freeing [ %d %d ]", min, max);
535 printf("- mask: ");
536 print(tmp.getBase(), max - min);
537
538 printf(" save: ");
539 unsigned k;
540 Alloc& a = alloc_list[j];
541 for(k = 0; k<a.data.size(); k++)
542 printf("%.8x ", a.data[k]);
543 printf("\n");
544 }
545 if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
546 {
547 return -1;
548 }
549 while(min < max)
550 BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
551 alloc_list.erase(j);
552 }
553 else
554 {
555 Vector<Uint32> tmp;
556 tmp.fill(sz32, zero);
557
558 // Bit was free
559 // 1) Check how much space is avaiable
560 // 2) Create new allocation of lrandom size
561 // 3) Fill data with lrandom data
562 // 4) Update alloc mask
563 while(pos+free < bitmask_size &&
564 !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
565 free++;
566
567 Uint32 sz =
568 (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
569 sz = sz ? sz : 1;
570 sz = pos + sz == bitmask_size ? sz - 1 : sz;
571 Alloc a;
572 a.pos = pos;
573 a.size = sz;
574 a.data.fill(((sz+31)>> 5)-1, zero);
575 if(BITMASK_DEBUG)
576 printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
577 for(Uint32 j = 0; j<sz; j++)
578 {
579 BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
580 if((lrand() % 1000) > 500)
581 BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
582 }
583 if(BITMASK_DEBUG)
584 {
585 printf("- mask: ");
586 print(a.data.getBase(), sz);
587 printf("\n");
588 }
589 BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
590 a.data.getBase());
591 alloc_list.push_back(a);
592 }
593 }
594
595 #define NDB_BM_SUPPORT_RANGE
596 #ifdef NDB_BM_SUPPORT_RANGE
597 for(Uint32 i = 0; i<1000; i++)
598 {
599 Uint32 sz32 = 10+rand() % 100;
600 Uint32 zero = 0;
601 Vector<Uint32> map;
602 map.fill(sz32, zero);
603
604 Uint32 sz = 32 * sz32;
605 Uint32 start = (rand() % sz);
606 Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
607
608 Vector<Uint32> check;
609 check.fill(sz32, zero);
610
611 /* Verify range setting method works correctly */
612 for(Uint32 j = 0; j<sz; j++)
613 {
614 bool expect = (j >= start && j<stop);
615 if(expect)
616 BitmaskImpl::set(sz32, check.getBase(), j);
617 }
618
619 BitmaskImpl::setRange(sz32, map.getBase(), start, stop - start + 1);
620 if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
621 {
622 ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz, start, stop);
623 printf("check: ");
624 for(Uint32 j = 0; j<sz32; j++)
625 printf("%.8x ", check[j]);
626 printf("\n");
627
628 printf("map : ");
629 for(Uint32 j = 0; j<sz32; j++)
630 printf("%.8x ", map[j]);
631 printf("\n");
632 return -1;
633 }
634
635 map.clear();
636 check.clear();
637
638 /* Verify range clearing method works correctly */
639 Uint32 one = ~(Uint32)0;
640 map.fill(sz32, one);
641 check.fill(sz32, one);
642
643 for(Uint32 j = 0; j<sz; j++)
644 {
645 bool expect = (j >= start && j<stop);
646 if(expect)
647 BitmaskImpl::clear(sz32, check.getBase(), j);
648 }
649
650 BitmaskImpl::clear_range(sz32, map.getBase(), start, stop);
651 if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
652 {
653 ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz, start, stop);
654 printf("check: ");
655 for(Uint32 j = 0; j<sz32; j++)
656 printf("%.8x ", check[j]);
657 printf("\n");
658
659 printf("map : ");
660 for(Uint32 j = 0; j<sz32; j++)
661 printf("%.8x ", map[j]);
662 printf("\n");
663 return -1;
664 }
665 }
666 #endif
667
668 return 0;
669 }
670
671 static
672 int
testBitmask()673 testBitmask()
674 {
675 /* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
676 int res= 0;
677
678 if ((res= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
679 return res;
680
681 if ((res= checkCopyField(1000)) != 0)
682 return res;
683
684 if ((res= simple(rand() % 33, // position
685 (rand() % 63)+1) // size
686 ) != 0)
687 return res;
688
689 if ((res= testRanges(1+(rand() % 1000) // bitmask size
690 )) != 0)
691 return res;
692
693 return 0;
694 }
695
696 template class Vector<Alloc>;
697