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