===== storage/ndb/include/util/Bitmask.hpp 1.23 vs edited =====
--- 1.23/storage/ndb/include/util/Bitmask.hpp	2008-01-23 07:09:24 +00:00
+++ edited/storage/ndb/include/util/Bitmask.hpp	2008-01-23 06:53:28 +00:00
@@ -139,6 +139,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);
@@ -146,6 +147,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[]);
@@ -936,7 +938,8 @@ BitmaskImpl::getField(unsigned size, con
 		      unsigned pos, unsigned len, Uint32 dst[])
 {
   assert(pos + len <= (size << 5));
-  
+  assert (len != 0);
+
   src += (pos >> 5);
   Uint32 offset = pos & 31;
   * dst = (* src >> offset) & (len >= 32 ? ~0 : (1 << len) - 1);
@@ -955,6 +958,7 @@ BitmaskImpl::setField(unsigned size, Uin
 		      unsigned pos, unsigned len, const Uint32 src[])
 {
   assert(pos + len <= (size << 5));
+  assert(len != 0);
 
   dst += (pos >> 5);
   Uint32 offset = pos & 31;
===== storage/ndb/src/common/util/Bitmask.cpp 1.12 vs edited =====
--- 1.12/storage/ndb/src/common/util/Bitmask.cpp	2008-01-23 07:09:24 +00:00
+++ edited/storage/ndb/src/common/util/Bitmask.cpp	2008-01-22 16:18:42 +00:00
@@ -20,28 +20,59 @@ 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;
+    }
   }
 }
 
@@ -64,370 +95,24 @@ 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 ;
   }
 }
-#ifdef __TEST_BITMASK__
-
-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);
-    }
-  }
-
-  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);
-    
-    for(Uint32 j = 0; j<sz; j++)
-    {
-      bool expect = (j >= start && j<stop);
-      if(expect)
-	BitmaskImpl::set(sz32, check.getBase(), j);
-    }
-    
-    BitmaskImpl::set(sz32, map.getBase(), start, stop);
-    if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
-    {
-      ndbout_c(" FAIL 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");
-      abort();
-    }
-
-    map.clear();
-    check.clear();
-
-    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(sz32, map.getBase(), start, stop);    
-    if (!BitmaskImpl::equal(sz32, map.getBase(), check.getBase()))
-    {
-      ndbout_c(" FAIL 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");
-      abort();
-    }
-  }
-#endif
-}
 
-template class Vector<Alloc>;
-template class Vector<Uint32>;
+/* Bitmask testcase code moved from here to 
+ * storage/ndb/test/ndbapi/testBitfield.cpp
+ * to get coverage from automated testing
+ */
 
-#endif
===== storage/ndb/test/ndbapi/testBitfield.cpp 1.12 vs edited =====
--- 1.12/storage/ndb/test/ndbapi/testBitfield.cpp	2008-01-23 07:09:25 +00:00
+++ edited/storage/ndb/test/ndbapi/testBitfield.cpp	2008-01-23 07:06:53 +00:00
@@ -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 Nd
 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,392 @@ system_restart(Ndb* pNdb, const NdbDicti
 {
   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);
+    }
+  }
+
+  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;
+    }
+  }
+
+  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>;
+
