1 /* Copyright (C) 2004, 2008 MySQL AB
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 of the License.
7 This program is distributed in the hope that it will be useful,
8 but WITHOUT ANY WARRANTY; without even the implied warranty of
9 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 GNU General Public License for more details.
12 You should have received a copy of the GNU General Public License
13 along with this program; if not, write to the Free Software
14 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
16 #include <ndb_global.h>
20 #include <HugoTransactions.hpp>
21 #include <Bitmask.hpp>
24 static const char* _dbname
= "TEST_DB";
25 static int g_loops
= 7;
30 static struct my_option my_long_options
[] =
32 NDB_STD_OPTS("ndb_desc"),
33 { 0, 0, 0, 0, 0, 0, GET_NO_ARG
, NO_ARG
, 0, 0, 0, 0, 0, 0}
38 ndb_std_print_version();
42 get_one_option(int optid
, const struct my_option
*opt
__attribute__((unused
)),
45 return ndb_std_get_one_option(optid
, opt
, argument
? argument
:
46 "d:t:O,/tmp/testBitfield.trace");
50 static const NdbDictionary::Table
* create_random_table(Ndb
*);
51 static int transactions(Ndb
*, const NdbDictionary::Table
* tab
);
52 static int unique_indexes(Ndb
*, const NdbDictionary::Table
* tab
);
53 static int ordered_indexes(Ndb
*, const NdbDictionary::Table
* tab
);
54 static int node_restart(Ndb
*, const NdbDictionary::Table
* tab
);
55 static int system_restart(Ndb
*, const NdbDictionary::Table
* tab
);
56 static int testBitmask();
59 main(int argc
, char** argv
){
61 const char *load_default_groups
[]= { "mysql_cluster",0 };
62 load_defaults("my",load_default_groups
,&argc
,&argv
);
65 if ((ho_error
=handle_options(&argc
, &argv
, my_long_options
,
66 ndb_std_get_one_option
)))
67 return NDBT_ProgramExit(NDBT_WRONGARGS
);
69 int res
= NDBT_FAILED
;
71 /* Run cluster-independent tests */
72 for (int i
=0; i
<(10*g_loops
); i
++)
74 if (NDBT_OK
!= (res
= testBitmask()))
75 return NDBT_ProgramExit(res
);
78 Ndb_cluster_connection
con(opt_connect_str
);
79 if(con
.connect(12, 5, 1))
81 return NDBT_ProgramExit(NDBT_FAILED
);
86 pNdb
= new Ndb(&con
, _dbname
);
88 while (pNdb
->waitUntilReady() != 0);
90 NdbDictionary::Dictionary
* dict
= pNdb
->getDictionary();
92 const NdbDictionary::Table
* pTab
= 0;
93 for (int i
= 0; i
< (argc
? argc
: g_loops
) ; i
++)
98 pTab
= create_random_table(pNdb
);
102 dict
->dropTable(argv
[i
]);
103 NDBT_Tables::createTable(pNdb
, argv
[i
]);
104 pTab
= dict
->getTable(argv
[i
]);
109 ndbout
<< "Failed to create table" << endl
;
110 ndbout
<< dict
->getNdbError() << endl
;
114 if(transactions(pNdb
, pTab
))
117 if(unique_indexes(pNdb
, pTab
))
120 if(ordered_indexes(pNdb
, pTab
))
123 if(node_restart(pNdb
, pTab
))
126 if(system_restart(pNdb
, pTab
))
129 dict
->dropTable(pTab
->getName());
133 if(res
!= NDBT_OK
&& pTab
)
135 dict
->dropTable(pTab
->getName());
139 return NDBT_ProgramExit(res
);
143 const NdbDictionary::Table
*
144 create_random_table(Ndb
* pNdb
)
147 NdbDictionary::Table tab
;
148 Uint32 cols
= 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE
- 1));
149 Uint32 length
= 4090;
152 name
.assfmt("TAB_%d", rand() & 65535);
153 tab
.setName(name
.c_str());
154 for(Uint32 i
= 0; i
<cols
&& length
> 2; i
++)
156 NdbDictionary::Column col
;
157 name
.assfmt("COL_%d", i
);
158 col
.setName(name
.c_str());
161 col
.setType(NdbDictionary::Column::Unsigned
);
163 col
.setNullable(false);
164 col
.setPrimaryKey(i
== 0);
169 col
.setType(NdbDictionary::Column::Bit
);
171 Uint32 len
= 1 + (rand() % (length
- 1));
172 col
.setLength(len
); length
-= len
;
173 int nullable
= (rand() >> 16) & 1;
174 col
.setNullable(nullable
); length
-= nullable
;
175 col
.setPrimaryKey(false);
179 pNdb
->getDictionary()->dropTable(tab
.getName());
180 if(pNdb
->getDictionary()->createTable(tab
) == 0)
182 ndbout
<< (NDBT_Table
&)tab
<< endl
;
183 return pNdb
->getDictionary()->getTable(tab
.getName());
191 transactions(Ndb
* pNdb
, const NdbDictionary::Table
* tab
)
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
);
207 unique_indexes(Ndb
* pNdb
, const NdbDictionary::Table
* tab
)
214 ordered_indexes(Ndb
* pNdb
, const NdbDictionary::Table
* tab
)
221 node_restart(Ndb
* pNdb
, const NdbDictionary::Table
* tab
)
228 system_restart(Ndb
* pNdb
, const NdbDictionary::Table
* tab
)
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.
237 #define BITMASK_DEBUG 0
240 bool cmp(const Uint32 b1
[], const Uint32 b2
[], Uint32 len
)
242 Uint32 sz32
= (len
+ 31) >> 5;
243 for(Uint32 i
= 0; i
<len
; i
++)
245 if(BitmaskImpl::get(sz32
, b1
, i
) ^ BitmaskImpl::get(sz32
, b2
, i
))
252 void print(const Uint32 src
[], Uint32 len
, Uint32 pos
= 0)
255 for(unsigned i
= 0; i
<len
; i
++)
257 if(BitmaskImpl::get((pos
+ len
+ 31) >> 5, src
, i
+pos
))
272 void rand(Uint32 dst
[], Uint32 len
)
274 for(Uint32 i
= 0; i
<len
; i
++)
275 BitmaskImpl::set((len
+ 31) >> 5, dst
, i
, (lrand() % 1000) > 500);
279 int checkNoTramplingGetSetField(const Uint32 totalTests
)
281 const Uint32 numWords
= 67;
282 const Uint32 maxBitsToCopy
= (numWords
* 32);
283 Uint32 sourceBuf
[numWords
];
284 Uint32 targetBuf
[numWords
];
286 ndbout
<< "Testing : Bitmask NoTrampling\n";
288 memset(sourceBuf
, 0x00, (numWords
*4));
290 for (Uint32 test
=0; test
<totalTests
; test
++)
292 /* Always copy at least 1 bit */
293 Uint32 srcStart
= rand() % (maxBitsToCopy
-1);
294 Uint32 length
= (rand() % ((maxBitsToCopy
-1) - srcStart
)) + 1;
297 ndbout
<< "Testing start %u, length %u \n"
300 // Set target to all ones.
301 memset(targetBuf
, 0xff, (numWords
*4));
303 BitmaskImpl::getField(numWords
, sourceBuf
, srcStart
, length
, targetBuf
);
305 // Check that there is no trampling
306 Uint32 firstUntrampledWord
= (length
+ 31)/32;
308 for (Uint32 word
=0; word
< numWords
; word
++)
310 Uint32 targetWord
= targetBuf
[word
];
312 ndbout
<< "word=%d, targetWord=%u, firstUntrampledWord..=%u"
313 << word
<< targetWord
<< firstUntrampledWord
;
315 if (! (word
< firstUntrampledWord
) ?
317 (targetWord
== 0xffffffff))
319 ndbout
<< "Notrampling getField failed for srcStart "
321 << " length " << length
322 << " at word " << word
<< "\n";
323 ndbout
<< "word=%d, targetWord=%u, firstUntrampledWord..=%u"
324 << word
<< targetWord
<< firstUntrampledWord
;
330 /* Set target back to all ones. */
331 memset(targetBuf
, 0xff, (numWords
*4));
333 BitmaskImpl::setField(numWords
, targetBuf
, srcStart
, length
, sourceBuf
);
335 /* Check we've got all ones, with zeros only where expected */
336 for (Uint32 word
=0; word
< numWords
; word
++)
338 Uint32 targetWord
= targetBuf
[word
];
340 for (Uint32 bit
=0; bit
< 32; bit
++)
342 Uint32 bitNum
= (word
<< 5) + bit
;
343 bool expectedValue
= !((bitNum
>= srcStart
) &&
344 (bitNum
< (srcStart
+ length
)));
345 bool actualValue
= (((targetWord
>> bit
) & 1) == 1);
347 ndbout
<< "bitNum=%u expectedValue=%u, actual value=%u"
348 << bitNum
<< expectedValue
<< actualValue
;
350 if (actualValue
!= expectedValue
)
352 ndbout
<< "Notrampling setField failed for srcStart "
354 << " length " << length
355 << " at word " << word
<< " bit " << bit
<< "\n";
356 ndbout
<< "bitNum=%u expectedValue=%u, actual value=%u"
357 << bitNum
<< expectedValue
<< actualValue
;
369 int simple(int pos
, int size
)
371 ndbout
<< "Testing : Bitmask simple pos: " << pos
<< " size: " << size
<< "\n";
372 Vector
<Uint32
> _mask
;
375 Uint32 sz32
= (size
+ pos
+ 32) >> 5;
376 const Uint32 sz
= 4 * sz32
;
379 _mask
.fill(sz32
+1, zero
);
380 _src
.fill(sz32
+1, zero
);
381 _dst
.fill(sz32
+1, zero
);
383 Uint32
* src
= _src
.getBase();
384 Uint32
* dst
= _dst
.getBase();
385 Uint32
* mask
= _mask
.getBase();
387 memset(src
, 0x0, sz
);
388 memset(dst
, 0x0, sz
);
389 memset(mask
, 0xFF, sz
);
391 BitmaskImpl::setField(sz32
, mask
, pos
, size
, src
);
392 BitmaskImpl::getField(sz32
, mask
, pos
, size
, dst
);
395 printf("src: "); print(src
, size
+31); printf("\n");
396 printf("msk: "); print(mask
, (sz32
<< 5) + 31); printf("\n");
397 printf("dst: "); print(dst
, size
+31); printf("\n");
399 return (cmp(src
, dst
, size
+31)?0 : -1);
411 testRanges(Uint32 bitmask_size
)
413 Vector
<Alloc
> alloc_list
;
414 bitmask_size
= (bitmask_size
+ 31) & ~31;
415 Uint32 sz32
= (bitmask_size
>> 5);
416 Vector
<Uint32
> alloc_mask
;
417 Vector
<Uint32
> test_mask
;
419 ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size
);
421 alloc_mask
.fill(sz32
, zero
);
422 test_mask
.fill(sz32
, zero
);
424 /* Loop a number of times, setting and clearing bits in the mask
425 * and tracking the modifications in a separate structure.
426 * Check that both structures remain in sync
428 for(int i
= 0; i
<5000; i
++)
431 tmp
.fill(sz32
, zero
);
433 Uint32 pos
= lrand() % (bitmask_size
- 1);
435 if(BitmaskImpl::get(sz32
, alloc_mask
.getBase(), pos
))
438 // 1) Look up allocation
443 for(j
= 0; j
<alloc_list
.size(); j
++)
445 min
= alloc_list
[j
].pos
;
446 max
= min
+ alloc_list
[j
].size
;
447 if(pos
>= min
&& pos
< max
)
452 if (! ((pos
>= min
) && (pos
< max
)))
454 printf("Failed with pos %u, min %u, max %u\n",
458 BitmaskImpl::getField(sz32
, test_mask
.getBase(), min
, max
-min
,
462 printf("freeing [ %d %d ]", min
, max
);
464 print(tmp
.getBase(), max
- min
);
468 Alloc
& a
= alloc_list
[j
];
469 for(k
= 0; k
<a
.data
.size(); k
++)
470 printf("%.8x ", a
.data
[k
]);
473 if(!cmp(tmp
.getBase(), alloc_list
[j
].data
.getBase(), max
- min
))
478 BitmaskImpl::clear(sz32
, alloc_mask
.getBase(), min
++);
484 tmp
.fill(sz32
, zero
);
487 // 1) Check how much space is avaiable
488 // 2) Create new allocation of lrandom size
489 // 3) Fill data with lrandom data
490 // 4) Update alloc mask
491 while(pos
+free
< bitmask_size
&&
492 !BitmaskImpl::get(sz32
, alloc_mask
.getBase(), pos
+free
))
496 (free
<= 64 && ((lrand() % 100) > 80)) ? free
: (lrand() % free
);
498 sz
= pos
+ sz
== bitmask_size
? sz
- 1 : sz
;
502 a
.data
.fill(((sz
+31)>> 5)-1, zero
);
504 printf("pos %d -> alloc [ %d %d ]", pos
, pos
, pos
+sz
);
505 for(size_t j
= 0; j
<sz
; j
++)
507 BitmaskImpl::set(sz32
, alloc_mask
.getBase(), pos
+j
);
508 if((lrand() % 1000) > 500)
509 BitmaskImpl::set((sz
+ 31) >> 5, a
.data
.getBase(), j
);
514 print(a
.data
.getBase(), sz
);
517 BitmaskImpl::setField(sz32
, test_mask
.getBase(), pos
, sz
,
519 alloc_list
.push_back(a
);
523 #define NDB_BM_SUPPORT_RANGE
524 #ifdef NDB_BM_SUPPORT_RANGE
525 for(Uint32 i
= 0; i
<1000; i
++)
527 Uint32 sz32
= 10+rand() % 100;
530 map
.fill(sz32
, zero
);
532 Uint32 sz
= 32 * sz32
;
533 Uint32 start
= (rand() % sz
);
534 Uint32 stop
= start
+ ((rand() % (sz
- start
)) & 0xFFFFFFFF);
536 Vector
<Uint32
> check
;
537 check
.fill(sz32
, zero
);
539 /* Verify range setting method works correctly */
540 for(Uint32 j
= 0; j
<sz
; j
++)
542 bool expect
= (j
>= start
&& j
<stop
);
544 BitmaskImpl::set(sz32
, check
.getBase(), j
);
547 BitmaskImpl::set_range(sz32
, map
.getBase(), start
, stop
);
548 if (!BitmaskImpl::equal(sz32
, map
.getBase(), check
.getBase()))
550 ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz
, start
, stop
);
552 for(Uint32 j
= 0; j
<sz32
; j
++)
553 printf("%.8x ", check
[j
]);
557 for(Uint32 j
= 0; j
<sz32
; j
++)
558 printf("%.8x ", map
[j
]);
566 /* Verify range clearing method works correctly */
567 Uint32 one
= ~(Uint32
)0;
569 check
.fill(sz32
, one
);
571 for(Uint32 j
= 0; j
<sz
; j
++)
573 bool expect
= (j
>= start
&& j
<stop
);
575 BitmaskImpl::clear(sz32
, check
.getBase(), j
);
578 BitmaskImpl::clear_range(sz32
, map
.getBase(), start
, stop
);
579 if (!BitmaskImpl::equal(sz32
, map
.getBase(), check
.getBase()))
581 ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz
, start
, stop
);
583 for(Uint32 j
= 0; j
<sz32
; j
++)
584 printf("%.8x ", check
[j
]);
588 for(Uint32 j
= 0; j
<sz32
; j
++)
589 printf("%.8x ", map
[j
]);
603 /* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
606 if ((res
= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
609 if ((res
= simple(rand() % 33, // position
610 (rand() % 63)+1) // size
614 if ((res
= testRanges(1+(rand() % 1000) // bitmask size
621 template class Vector
<Alloc
>;
622 template class Vector
<Uint32
>;