summaryrefslogtreecommitdiff
path: root/ndb
diff options
context:
space:
mode:
Diffstat (limited to 'ndb')
-rw-r--r--ndb/include/util/Bitmask.hpp10
-rw-r--r--ndb/src/common/transporter/TCP_Transporter.cpp22
-rw-r--r--ndb/src/common/util/Bitmask.cpp353
-rw-r--r--ndb/test/ndbapi/testBitfield.cpp407
4 files changed, 480 insertions, 312 deletions
diff --git a/ndb/include/util/Bitmask.hpp b/ndb/include/util/Bitmask.hpp
index 3b3fe721cca..0383841a666 100644
--- a/ndb/include/util/Bitmask.hpp
+++ b/ndb/include/util/Bitmask.hpp
@@ -126,6 +126,7 @@ public:
/**
* setField - Set bitfield at given position and length (max 32 bits)
+ * Note : length == 0 not supported.
*/
static void setField(unsigned size, Uint32 data[],
unsigned pos, unsigned len, Uint32 val);
@@ -133,6 +134,7 @@ public:
/**
* getField - Get bitfield at given position and length
+ * Note : length == 0 not supported.
*/
static void getField(unsigned size, const Uint32 data[],
unsigned pos, unsigned len, Uint32 dst[]);
@@ -814,7 +816,10 @@ BitmaskImpl::getField(unsigned size, const Uint32 src[],
unsigned pos, unsigned len, Uint32 dst[])
{
assert(pos + len <= (size << 5));
-
+ assert (len != 0);
+ if (len == 0)
+ return;
+
src += (pos >> 5);
Uint32 offset = pos & 31;
* dst = (* src >> offset) & (len >= 32 ? ~0 : (1 << len) - 1);
@@ -833,6 +838,9 @@ BitmaskImpl::setField(unsigned size, Uint32 dst[],
unsigned pos, unsigned len, const Uint32 src[])
{
assert(pos + len <= (size << 5));
+ assert(len != 0);
+ if (len == 0)
+ return;
dst += (pos >> 5);
Uint32 offset = pos & 31;
diff --git a/ndb/src/common/transporter/TCP_Transporter.cpp b/ndb/src/common/transporter/TCP_Transporter.cpp
index c8095defd86..ea9e0944915 100644
--- a/ndb/src/common/transporter/TCP_Transporter.cpp
+++ b/ndb/src/common/transporter/TCP_Transporter.cpp
@@ -337,22 +337,32 @@ TCP_Transporter::doSend() {
// Empty the SendBuffers
- const char * const sendPtr = m_sendBuffer.sendPtr;
- const Uint32 sizeToSend = m_sendBuffer.sendDataSize;
- if (sizeToSend > 0){
+ bool sent_any = true;
+ while (m_sendBuffer.dataSize > 0)
+ {
+ const char * const sendPtr = m_sendBuffer.sendPtr;
+ const Uint32 sizeToSend = m_sendBuffer.sendDataSize;
const int nBytesSent = inet_send(theSocket, sendPtr, sizeToSend, 0);
- if (nBytesSent > 0) {
+ if (nBytesSent > 0)
+ {
+ sent_any = true;
m_sendBuffer.bytesSent(nBytesSent);
sendCount ++;
sendSize += nBytesSent;
- if(sendCount == reportFreq){
+ if(sendCount == reportFreq)
+ {
reportSendLen(get_callback_obj(), remoteNodeId, sendCount, sendSize);
sendCount = 0;
sendSize = 0;
}
- } else {
+ }
+ else
+ {
+ if (nBytesSent < 0 && InetErrno == EAGAIN && sent_any)
+ break;
+
// Send failed
#if defined DEBUG_TRANSPORTER
ndbout_c("Send Failure(disconnect==%d) to node = %d nBytesSent = %d "
diff --git a/ndb/src/common/util/Bitmask.cpp b/ndb/src/common/util/Bitmask.cpp
index 4b90e5a01f4..22919fe585a 100644
--- a/ndb/src/common/util/Bitmask.cpp
+++ b/ndb/src/common/util/Bitmask.cpp
@@ -16,34 +16,63 @@
#include <Bitmask.hpp>
#include <NdbOut.hpp>
-#ifndef __TEST_BITMASK__
-
void
BitmaskImpl::getFieldImpl(const Uint32 src[],
unsigned shiftL, unsigned len, Uint32 dst[])
{
+ /* Copy whole words of src to dst, shifting src left
+ * by shiftL. Undefined bits of the last written dst word
+ * should be zeroed.
+ */
assert(shiftL < 32);
unsigned shiftR = 32 - shiftL;
unsigned undefined = shiftL ? ~0 : 0;
+ /* Merge first word with previously set bits if there's a shift */
* dst = shiftL ? * dst : 0;
-
- while(len >= 32)
- {
- * dst++ |= (* src) << shiftL;
- * dst = ((* src++) >> shiftR) & undefined;
- len -= 32;
- }
-
- if(len < shiftR)
+
+ /* Treat the zero-shift case separately to avoid
+ * trampling or reading past the end of src
+ */
+ if (shiftL == 0)
{
- * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
+ while(len >= 32)
+ {
+ * dst++ = * src++;
+ len -=32;
+ }
+
+ if (len != 0)
+ {
+ /* Last word has some bits set */
+ Uint32 mask= ((1 << len) -1); // 0000111
+ * dst = (* src) & mask;
+ }
}
- else
+ else // shiftL !=0, need to build each word from two words shifted
{
- * dst++ |= ((* src) << shiftL);
- * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
+ while(len >= 32)
+ {
+ * dst++ |= (* src) << shiftL;
+ * dst = ((* src++) >> shiftR) & undefined;
+ len -= 32;
+ }
+
+ /* Have space for shiftR more bits in the current dst word
+ * is that enough?
+ */
+ if(len <= shiftR)
+ {
+ /* Fit the remaining bits in the current dst word */
+ * dst |= ((* src) & ((1 << len) - 1)) << shiftL;
+ }
+ else
+ {
+ /* Need to write to two dst words */
+ * dst++ |= ((* src) << shiftL);
+ * dst = ((* src) >> shiftR) & ((1 << (len - shiftR)) - 1) & undefined;
+ }
}
}
@@ -66,301 +95,23 @@ BitmaskImpl::setFieldImpl(Uint32 dst[],
len -= 32;
}
+ /* Copy last bits */
Uint32 mask = ((1 << len) -1);
* dst = (* dst & ~mask);
- if(len < shiftR)
+ if(len <= shiftR)
{
+ /* Remaining bits fit in current word */
* dst |= ((* src++) >> shiftL) & mask;
}
else
{
+ /* Remaining bits update 2 words */
* dst |= ((* src++) >> shiftL);
* dst |= ((* src) & ((1 << (len - shiftR)) - 1)) << shiftR ;
}
}
-#else
-
-static
-void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
-{
- printf("b'");
- for(unsigned i = 0; i<len; i++)
- {
- if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
- printf("1");
- else
- printf("0");
- if((i & 31) == 31)
- printf(" ");
- }
-}
-
-#define DEBUG 0
-#include <Vector.hpp>
-static void do_test(int bitmask_size);
-
-int
-main(int argc, char** argv)
-{
- int loops = argc > 1 ? atoi(argv[1]) : 1000;
- int max_size = argc > 2 ? atoi(argv[2]) : 1000;
-
-
- for(int i = 0; i<loops; i++)
- do_test(1 + (rand() % max_size));
-}
-
-struct Alloc
-{
- Uint32 pos;
- Uint32 size;
- Vector<Uint32> data;
-};
-
-static void require(bool b)
-{
- if(!b) abort();
-}
-
-static
-bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
-{
- Uint32 sz32 = (len + 31) >> 5;
- for(int i = 0; i<len; i++)
- {
- if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
- return false;
- }
- return true;
-}
-
-
-static int val_pos = 0;
-static int val[] = { 384, 241, 32,
- 1,1,1,1, 0,0,0,0, 1,1,1,1, 0,0,0,0,
- 241 };
-
-static int lrand()
-{
-#if 0
- return val[val_pos++];
-#else
- return rand();
-#endif
-}
-
-static
-void rand(Uint32 dst[], Uint32 len)
-{
- for(int i = 0; i<len; i++)
- BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
-}
-
-static
-void simple(int pos, int size)
-{
- ndbout_c("simple pos: %d size: %d", pos, size);
- Vector<Uint32> _mask;
- Vector<Uint32> _src;
- Vector<Uint32> _dst;
- Uint32 sz32 = (size + pos + 32) >> 5;
- const Uint32 sz = 4 * sz32;
-
- Uint32 zero = 0;
- _mask.fill(sz32+1, zero);
- _src.fill(sz32+1, zero);
- _dst.fill(sz32+1, zero);
-
- Uint32 * src = _src.getBase();
- Uint32 * dst = _dst.getBase();
- Uint32 * mask = _mask.getBase();
-
- memset(src, 0x0, sz);
- memset(dst, 0x0, sz);
- memset(mask, 0xFF, sz);
- rand(src, size);
- BitmaskImpl::setField(sz32, mask, pos, size, src);
- BitmaskImpl::getField(sz32, mask, pos, size, dst);
- printf("src: "); print(src, size+31); printf("\n");
- printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
- printf("dst: "); print(dst, size+31); printf("\n");
- require(cmp(src, dst, size+31));
-};
-
-static
-void simple2(int size, int loops)
-{
- ndbout_c("simple2 %d - ", size);
- Vector<Uint32> _mask;
- Vector<Uint32> _src;
- Vector<Uint32> _dst;
-
- Uint32 sz32 = (size + 32) >> 5;
- Uint32 sz = sz32 << 2;
-
- Uint32 zero = 0;
- _mask.fill(sz32+1, zero);
- _src.fill(sz32+1, zero);
- _dst.fill(sz32+1, zero);
-
- Uint32 * src = _src.getBase();
- Uint32 * dst = _dst.getBase();
- Uint32 * mask = _mask.getBase();
-
- Vector<Uint32> save;
- for(int i = 0; i<loops; i++)
- {
- memset(mask, 0xFF, sz);
- memset(dst, 0xFF, sz);
- int len;
- int pos = 0;
- while(pos+1 < size)
- {
- memset(src, 0xFF, sz);
- while(!(len = rand() % (size - pos)));
- BitmaskImpl::setField(sz32, mask, pos, len, src);
- if(memcmp(dst, mask, sz))
- {
- ndbout_c("pos: %d len: %d", pos, len);
- print(mask, size);
- abort();
- }
- printf("[ %d %d ]", pos, len);
- save.push_back(pos);
- save.push_back(len);
- pos += len;
- }
-
- for(int j = 0; j<save.size(); )
- {
- pos = save[j++];
- len = save[j++];
- memset(src, 0xFF, sz);
- BitmaskImpl::getField(sz32, mask, pos, len, src);
- if(memcmp(dst, src, sz))
- {
- ndbout_c("pos: %d len: %d", pos, len);
- printf("src: "); print(src, size); printf("\n");
- printf("dst: "); print(dst, size); printf("\n");
- printf("msk: "); print(mask, size); printf("\n");
- abort();
- }
- }
- ndbout_c("");
- }
-}
-
-static void
-do_test(int bitmask_size)
-{
-#if 1
- simple(rand() % 33, (rand() % 63)+1);
-//#else
- Vector<Alloc> alloc_list;
- bitmask_size = (bitmask_size + 31) & ~31;
- Uint32 sz32 = (bitmask_size >> 5);
- Vector<Uint32> alloc_mask;
- Vector<Uint32> test_mask;
-
- ndbout_c("Testing bitmask of size %d", bitmask_size);
- Uint32 zero = 0;
- alloc_mask.fill(sz32, zero);
- test_mask.fill(sz32, zero);
-
- for(int i = 0; i<5000; i++)
- {
- Vector<Uint32> tmp;
- tmp.fill(sz32, zero);
-
- int pos = lrand() % (bitmask_size - 1);
- int free = 0;
- if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
- {
- // Bit was allocated
- // 1) Look up allocation
- // 2) Check data
- // 3) free it
- size_t j;
- int min, max;
- for(j = 0; j<alloc_list.size(); j++)
- {
- min = alloc_list[j].pos;
- max = min + alloc_list[j].size;
- if(pos >= min && pos < max)
- {
- break;
- }
- }
- require(pos >= min && pos < max);
- BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
- tmp.getBase());
- if(DEBUG)
- {
- printf("freeing [ %d %d ]", min, max);
- printf("- mask: ");
- print(tmp.getBase(), max - min);
-
- printf(" save: ");
- size_t k;
- Alloc& a = alloc_list[j];
- for(k = 0; k<a.data.size(); k++)
- printf("%.8x ", a.data[k]);
- printf("\n");
- }
- int bytes = (max - min + 7) >> 3;
- if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
- {
- abort();
- }
- while(min < max)
- BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
- alloc_list.erase(j);
- }
- else
- {
- Vector<Uint32> tmp;
- tmp.fill(sz32, zero);
-
- // Bit was free
- // 1) Check how much space is avaiable
- // 2) Create new allocation of lrandom size
- // 3) Fill data with lrandom data
- // 4) Update alloc mask
- while(pos+free < bitmask_size &&
- !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
- free++;
-
- Uint32 sz =
- (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
- sz = sz ? sz : 1;
- sz = pos + sz == bitmask_size ? sz - 1 : sz;
- Alloc a;
- a.pos = pos;
- a.size = sz;
- a.data.fill(((sz+31)>> 5)-1, zero);
- if(DEBUG)
- printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
- for(size_t j = 0; j<sz; j++)
- {
- BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
- if((lrand() % 1000) > 500)
- BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
- }
- if(DEBUG)
- {
- printf("- mask: ");
- print(a.data.getBase(), sz);
- printf("\n");
- }
- BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
- a.data.getBase());
- alloc_list.push_back(a);
- }
- }
-#endif
-}
-
-template class Vector<Alloc>;
-template class Vector<Uint32>;
-#endif
+/* Bitmask testcase code moved from here to
+ * storage/ndb/test/ndbapi/testBitfield.cpp
+ * to get coverage from automated testing
+ */
diff --git a/ndb/test/ndbapi/testBitfield.cpp b/ndb/test/ndbapi/testBitfield.cpp
index 8ba8f3d92ef..40a7a9d4557 100644
--- a/ndb/test/ndbapi/testBitfield.cpp
+++ b/ndb/test/ndbapi/testBitfield.cpp
@@ -4,6 +4,8 @@
#include <NDBT.hpp>
#include <NdbApi.hpp>
#include <HugoTransactions.hpp>
+#include <Bitmask.hpp>
+#include <Vector.hpp>
static const char* _dbname = "TEST_DB";
static int g_loops = 7;
@@ -37,6 +39,7 @@ static int unique_indexes(Ndb*, const NdbDictionary::Table* tab);
static int ordered_indexes(Ndb*, const NdbDictionary::Table* tab);
static int node_restart(Ndb*, const NdbDictionary::Table* tab);
static int system_restart(Ndb*, const NdbDictionary::Table* tab);
+static int testBitmask();
int
main(int argc, char** argv){
@@ -49,6 +52,15 @@ main(int argc, char** argv){
ndb_std_get_one_option)))
return NDBT_ProgramExit(NDBT_WRONGARGS);
+ int res = NDBT_FAILED;
+
+ /* Run cluster-independent tests */
+ for (int i=0; i<(10*g_loops); i++)
+ {
+ if (NDBT_OK != (res= testBitmask()))
+ return NDBT_ProgramExit(res);
+ }
+
Ndb_cluster_connection con(opt_connect_str);
if(con.connect(12, 5, 1))
{
@@ -60,7 +72,6 @@ main(int argc, char** argv){
pNdb = new Ndb(&con, _dbname);
pNdb->init();
while (pNdb->waitUntilReady() != 0);
- int res = NDBT_FAILED;
NdbDictionary::Dictionary * dict = pNdb->getDictionary();
@@ -121,14 +132,12 @@ create_random_table(Ndb* pNdb)
do {
NdbDictionary::Table tab;
Uint32 cols = 1 + (rand() % (NDB_MAX_ATTRIBUTES_IN_TABLE - 1));
- Uint32 keys = NDB_MAX_NO_OF_ATTRIBUTES_IN_KEY;
Uint32 length = 4090;
- Uint32 key_size = NDB_MAX_KEYSIZE_IN_WORDS;
BaseString name;
name.assfmt("TAB_%d", rand() & 65535);
tab.setName(name.c_str());
- for(int i = 0; i<cols && length > 2; i++)
+ for(Uint32 i = 0; i<cols && length > 2; i++)
{
NdbDictionary::Column col;
name.assfmt("COL_%d", i);
@@ -206,3 +215,393 @@ system_restart(Ndb* pNdb, const NdbDictionary::Table* tab)
{
return 0;
}
+
+/* Note : folowing classes test functionality of storage/ndb/src/common/util/Bitmask.cpp
+ * and were originally defined there.
+ * Set BITMASK_DEBUG to 1 to get more test debugging info.
+ */
+#define BITMASK_DEBUG 0
+
+static
+bool cmp(const Uint32 b1[], const Uint32 b2[], Uint32 len)
+{
+ Uint32 sz32 = (len + 31) >> 5;
+ for(Uint32 i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get(sz32, b1, i) ^ BitmaskImpl::get(sz32, b2, i))
+ return false;
+ }
+ return true;
+}
+
+static
+void print(const Uint32 src[], Uint32 len, Uint32 pos = 0)
+{
+ printf("b'");
+ for(unsigned i = 0; i<len; i++)
+ {
+ if(BitmaskImpl::get((pos + len + 31) >> 5, src, i+pos))
+ printf("1");
+ else
+ printf("0");
+ if((i & 31) == 31)
+ printf(" ");
+ }
+}
+
+static int lrand()
+{
+ return rand();
+}
+
+static
+void rand(Uint32 dst[], Uint32 len)
+{
+ for(Uint32 i = 0; i<len; i++)
+ BitmaskImpl::set((len + 31) >> 5, dst, i, (lrand() % 1000) > 500);
+}
+
+static
+int checkNoTramplingGetSetField(const Uint32 totalTests)
+{
+ const Uint32 numWords= 67;
+ const Uint32 maxBitsToCopy= (numWords * 32);
+ Uint32 sourceBuf[numWords];
+ Uint32 targetBuf[numWords];
+
+ ndbout << "Testing : Bitmask NoTrampling\n";
+
+ memset(sourceBuf, 0x00, (numWords*4));
+
+ for (Uint32 test=0; test<totalTests; test++)
+ {
+ /* Always copy at least 1 bit */
+ Uint32 srcStart= rand() % (maxBitsToCopy -1);
+ Uint32 length= (rand() % ((maxBitsToCopy -1) - srcStart)) + 1;
+
+ if (BITMASK_DEBUG)
+ ndbout << "Testing start %u, length %u \n"
+ << srcStart
+ << length;
+ // Set target to all ones.
+ memset(targetBuf, 0xff, (numWords*4));
+
+ BitmaskImpl::getField(numWords, sourceBuf, srcStart, length, targetBuf);
+
+ // Check that there is no trampling
+ Uint32 firstUntrampledWord= (length + 31)/32;
+
+ for (Uint32 word=0; word< numWords; word++)
+ {
+ Uint32 targetWord= targetBuf[word];
+ if (BITMASK_DEBUG)
+ ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
+ << word << targetWord << firstUntrampledWord;
+
+ if (! (word < firstUntrampledWord) ?
+ (targetWord == 0) :
+ (targetWord == 0xffffffff))
+ {
+ ndbout << "Notrampling getField failed for srcStart "
+ << srcStart
+ << " length " << length
+ << " at word " << word << "\n";
+ ndbout << "word=%d, targetWord=%u, firstUntrampledWord..=%u"
+ << word << targetWord << firstUntrampledWord;
+ return -1;
+ }
+
+ }
+
+ /* Set target back to all ones. */
+ memset(targetBuf, 0xff, (numWords*4));
+
+ BitmaskImpl::setField(numWords, targetBuf, srcStart, length, sourceBuf);
+
+ /* Check we've got all ones, with zeros only where expected */
+ for (Uint32 word=0; word< numWords; word++)
+ {
+ Uint32 targetWord= targetBuf[word];
+
+ for (Uint32 bit=0; bit< 32; bit++)
+ {
+ Uint32 bitNum= (word << 5) + bit;
+ bool expectedValue= !((bitNum >= srcStart) &&
+ (bitNum < (srcStart + length)));
+ bool actualValue= (((targetWord >> bit) & 1) == 1);
+ if (BITMASK_DEBUG)
+ ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
+ << bitNum << expectedValue << actualValue;
+
+ if (actualValue != expectedValue)
+ {
+ ndbout << "Notrampling setField failed for srcStart "
+ << srcStart
+ << " length " << length
+ << " at word " << word << " bit " << bit << "\n";
+ ndbout << "bitNum=%u expectedValue=%u, actual value=%u"
+ << bitNum << expectedValue << actualValue;
+ return -1;
+ }
+ }
+ }
+
+ }
+
+ return 0;
+}
+
+static
+int simple(int pos, int size)
+{
+ ndbout << "Testing : Bitmask simple pos: " << pos << " size: " << size << "\n";
+ Vector<Uint32> _mask;
+ Vector<Uint32> _src;
+ Vector<Uint32> _dst;
+ Uint32 sz32 = (size + pos + 32) >> 5;
+ const Uint32 sz = 4 * sz32;
+
+ Uint32 zero = 0;
+ _mask.fill(sz32+1, zero);
+ _src.fill(sz32+1, zero);
+ _dst.fill(sz32+1, zero);
+
+ Uint32 * src = _src.getBase();
+ Uint32 * dst = _dst.getBase();
+ Uint32 * mask = _mask.getBase();
+
+ memset(src, 0x0, sz);
+ memset(dst, 0x0, sz);
+ memset(mask, 0xFF, sz);
+ rand(src, size);
+ BitmaskImpl::setField(sz32, mask, pos, size, src);
+ BitmaskImpl::getField(sz32, mask, pos, size, dst);
+ if (BITMASK_DEBUG)
+ {
+ printf("src: "); print(src, size+31); printf("\n");
+ printf("msk: "); print(mask, (sz32 << 5) + 31); printf("\n");
+ printf("dst: "); print(dst, size+31); printf("\n");
+ }
+ return (cmp(src, dst, size+31)?0 : -1);
+};
+
+struct Alloc
+{
+ Uint32 pos;
+ Uint32 size;
+ Vector<Uint32> data;
+};
+
+static
+int
+testRanges(Uint32 bitmask_size)
+{
+ Vector<Alloc> alloc_list;
+ bitmask_size = (bitmask_size + 31) & ~31;
+ Uint32 sz32 = (bitmask_size >> 5);
+ Vector<Uint32> alloc_mask;
+ Vector<Uint32> test_mask;
+
+ ndbout_c("Testing : Bitmask ranges for bitmask of size %d", bitmask_size);
+ Uint32 zero = 0;
+ alloc_mask.fill(sz32, zero);
+ test_mask.fill(sz32, zero);
+
+ /* Loop a number of times, setting and clearing bits in the mask
+ * and tracking the modifications in a separate structure.
+ * Check that both structures remain in sync
+ */
+ for(int i = 0; i<5000; i++)
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ Uint32 pos = lrand() % (bitmask_size - 1);
+ Uint32 free = 0;
+ if(BitmaskImpl::get(sz32, alloc_mask.getBase(), pos))
+ {
+ // Bit was allocated
+ // 1) Look up allocation
+ // 2) Check data
+ // 3) free it
+ size_t j;
+ Uint32 min, max;
+ for(j = 0; j<alloc_list.size(); j++)
+ {
+ min = alloc_list[j].pos;
+ max = min + alloc_list[j].size;
+ if(pos >= min && pos < max)
+ {
+ break;
+ }
+ }
+ if (! ((pos >= min) && (pos < max)))
+ {
+ printf("Failed with pos %u, min %u, max %u\n",
+ pos, min, max);
+ return -1;
+ }
+ BitmaskImpl::getField(sz32, test_mask.getBase(), min, max-min,
+ tmp.getBase());
+ if(BITMASK_DEBUG)
+ {
+ printf("freeing [ %d %d ]", min, max);
+ printf("- mask: ");
+ print(tmp.getBase(), max - min);
+
+ printf(" save: ");
+ size_t k;
+ Alloc& a = alloc_list[j];
+ for(k = 0; k<a.data.size(); k++)
+ printf("%.8x ", a.data[k]);
+ printf("\n");
+ }
+ if(!cmp(tmp.getBase(), alloc_list[j].data.getBase(), max - min))
+ {
+ return -1;
+ }
+ while(min < max)
+ BitmaskImpl::clear(sz32, alloc_mask.getBase(), min++);
+ alloc_list.erase(j);
+ }
+ else
+ {
+ Vector<Uint32> tmp;
+ tmp.fill(sz32, zero);
+
+ // Bit was free
+ // 1) Check how much space is avaiable
+ // 2) Create new allocation of lrandom size
+ // 3) Fill data with lrandom data
+ // 4) Update alloc mask
+ while(pos+free < bitmask_size &&
+ !BitmaskImpl::get(sz32, alloc_mask.getBase(), pos+free))
+ free++;
+
+ Uint32 sz =
+ (free <= 64 && ((lrand() % 100) > 80)) ? free : (lrand() % free);
+ sz = sz ? sz : 1;
+ sz = pos + sz == bitmask_size ? sz - 1 : sz;
+ Alloc a;
+ a.pos = pos;
+ a.size = sz;
+ a.data.fill(((sz+31)>> 5)-1, zero);
+ if(BITMASK_DEBUG)
+ printf("pos %d -> alloc [ %d %d ]", pos, pos, pos+sz);
+ for(size_t j = 0; j<sz; j++)
+ {
+ BitmaskImpl::set(sz32, alloc_mask.getBase(), pos+j);
+ if((lrand() % 1000) > 500)
+ BitmaskImpl::set((sz + 31) >> 5, a.data.getBase(), j);
+ }
+ if(BITMASK_DEBUG)
+ {
+ printf("- mask: ");
+ print(a.data.getBase(), sz);
+ printf("\n");
+ }
+ BitmaskImpl::setField(sz32, test_mask.getBase(), pos, sz,
+ a.data.getBase());
+ alloc_list.push_back(a);
+ }
+ }
+
+#ifdef NDB_BM_SUPPORT_RANGE
+ for(Uint32 i = 0; i<1000; i++)
+ {
+ Uint32 sz32 = 10+rand() % 100;
+ Uint32 zero = 0;
+ Vector<Uint32> map;
+ map.fill(sz32, zero);
+
+ Uint32 sz = 32 * sz32;
+ Uint32 start = (rand() % sz);
+ Uint32 stop = start + ((rand() % (sz - start)) & 0xFFFFFFFF);
+
+ Vector<Uint32> check;
+ check.fill(sz32, zero);
+
+ /* Verify range setting method works correctly */
+ for(Uint32 j = 0; j<sz; j++)
+ {
+ bool expect = (j >= start && j<stop);
+ if(expect)
+ BitmaskImpl::set(sz32, check.getBase(), j);
+ }
+
+ BitmaskImpl::set_range(sz32, map.getBase(), start, stop);
+ if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
+ {
+ ndbout_c(" FAIL 1 sz: %d [ %d %d ]", sz, start, stop);
+ printf("check: ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", check[j]);
+ printf("\n");
+
+ printf("map : ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", map[j]);
+ printf("\n");
+ return -1;
+ }
+
+ map.clear();
+ check.clear();
+
+ /* Verify range clearing method works correctly */
+ Uint32 one = ~(Uint32)0;
+ map.fill(sz32, one);
+ check.fill(sz32, one);
+
+ for(Uint32 j = 0; j<sz; j++)
+ {
+ bool expect = (j >= start && j<stop);
+ if(expect)
+ BitmaskImpl::clear(sz32, check.getBase(), j);
+ }
+
+ BitmaskImpl::clear_range(sz32, map.getBase(), start, stop);
+ if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
+ {
+ ndbout_c(" FAIL 2 sz: %d [ %d %d ]", sz, start, stop);
+ printf("check: ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", check[j]);
+ printf("\n");
+
+ printf("map : ");
+ for(Uint32 j = 0; j<sz32; j++)
+ printf("%.8x ", map[j]);
+ printf("\n");
+ return -1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static
+int
+testBitmask()
+{
+ /* Some testcases from storage/ndb/src/common/util/Bitmask.cpp */
+ int res= 0;
+
+ if ((res= checkNoTramplingGetSetField(100 /* totalTests */)) != 0)
+ return res;
+
+ if ((res= simple(rand() % 33, // position
+ (rand() % 63)+1) // size
+ ) != 0)
+ return res;
+
+ if ((res= testRanges(1+(rand() % 1000) // bitmask size
+ )) != 0)
+ return res;
+
+ return 0;
+}
+
+template class Vector<Alloc>;
+template class Vector<Uint32>;