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