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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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>;