]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
extent alloc functionality for stupid and bitmap allocator 10257/head
authorRamesh Chander <Ramesh.Chander@sandisk.com>
Tue, 7 Jun 2016 17:03:49 +0000 (10:03 -0700)
committerRamesh Chander <Ramesh.Chander@sandisk.com>
Mon, 18 Jul 2016 16:08:04 +0000 (09:08 -0700)
Signed-off-by: Ramesh Chander <Ramesh.Chander@sandisk.com>
17 files changed:
src/os/bluestore/Allocator.h
src/os/bluestore/BitAllocator.cc
src/os/bluestore/BitAllocator.h
src/os/bluestore/BitMapAllocator.cc
src/os/bluestore/BitMapAllocator.h
src/os/bluestore/BlueFS.cc
src/os/bluestore/BlueStore.cc
src/os/bluestore/StupidAllocator.cc
src/os/bluestore/StupidAllocator.h
src/os/bluestore/bluefs_types.cc
src/os/bluestore/bluefs_types.h
src/os/bluestore/bluestore_types.cc
src/os/bluestore/bluestore_types.h
src/test/Makefile-server.am
src/test/objectstore/Allocator_test.cc [new file with mode: 0644]
src/test/objectstore/BitAllocator_test.cc
src/test/objectstore/CMakeLists.txt

index d951142d9ce423404d197f3dd309066993263f48..774eb1196a678cabca6424324e3485f5dfd1d7de 100644 (file)
@@ -15,6 +15,7 @@
 #include "kv/KeyValueDB.h"
 #include <ostream>
 #include "include/assert.h"
+#include "os/bluestore/bluestore_types.h"
 
 class FreelistManager;
 
@@ -29,9 +30,39 @@ public:
     uint64_t need_size, uint64_t alloc_unit, int64_t hint,
     uint64_t *offset, uint32_t *length) = 0;
 
+  /*
+   * Allocate required number of blocks in n number of extents.
+   * Min and Max number of extents are limited by:
+   * a. alloc unit
+   * b. max_alloc_size.
+   * as no extent can be lesser than alloc_unit and greater than max_alloc size.
+   * Apart from that extents can vary between these lower and higher limits according
+   * to free block search algorithm and availability of contiguous space.
+   */
+  virtual int alloc_extents(uint64_t want_size, uint64_t alloc_unit,
+                            uint64_t max_alloc_size, int64_t hint,
+                            std::vector<AllocExtent> *extents, int *count) = 0;
+
+  virtual int alloc_extents(uint64_t want_size, uint64_t alloc_unit,
+                            int64_t hint, std::vector<AllocExtent> *extents,
+                           int *count) {
+    return alloc_extents(want_size, alloc_unit, want_size, hint, extents, count);
+  }
+
   virtual int release(
     uint64_t offset, uint64_t length) = 0;
 
+  virtual int release_extents(std::vector<AllocExtent> *extents, int count) {
+    int res = 0;
+      for (int i = 0; i < count; i++) {
+        res = release((*extents)[i].offset, (*extents)[i].length);
+        if (res != 0) {
+         break;
+        }
+      }
+    return res;
+  }
+
   virtual void commit_start() = 0;
   virtual void commit_finish() = 0;
 
index 07047be65537b25280818a82698e4d630a953617..0c239efd244d2eb7b6a9641a8f9c8f2ee66f6d85 100644 (file)
@@ -312,8 +312,7 @@ BmapEntry::find_first_set_bits(int64_t required_blocks,
  * Find N number of free bits in bitmap. Need not be contiguous.
  */
 int BmapEntry::find_any_free_bits(int start_offset, int64_t num_blocks,
-            int64_t *allocated_blocks, int64_t block_offset,
-            int64_t *scanned)
+        ExtentList *allocated_blocks, int64_t block_offset, int64_t *scanned)
 {
   int allocated = 0;
   int required = num_blocks;
@@ -331,7 +330,7 @@ int BmapEntry::find_any_free_bits(int start_offset, int64_t num_blocks,
   for (i = start_offset; i < BmapEntry::size() &&
         allocated < required; i++) {
     if (check_n_set_bit(i)) {
-      allocated_blocks[allocated] = i + block_offset;
+      allocated_blocks->add_extents(i + block_offset, 1);
       allocated++;
     }
   }
@@ -601,7 +600,9 @@ void BitMapZone::free_blocks(int64_t start_block, int64_t num_blocks)
 /*
  * Allocate N blocks, dis-contiguous are fine
  */
-int64_t BitMapZone::alloc_blocks_dis(int64_t num_blocks, int64_t zone_blk_off, int64_t *alloc_blocks)
+int64_t BitMapZone::alloc_blocks_dis(int64_t num_blocks,
+                                   int64_t zone_blk_off, 
+                                   ExtentList *alloc_blocks)
 {
   int64_t bmap_idx = 0;
   int bit = 0;
@@ -617,8 +618,11 @@ int64_t BitMapZone::alloc_blocks_dis(int64_t num_blocks, int64_t zone_blk_off, i
     int64_t scanned = 0;
     blk_off = (iter.index() - 1) * BmapEntry::size() + zone_blk_off;
     allocated += bmap->find_any_free_bits(bit, num_blocks - allocated,
-            &alloc_blocks[allocated], blk_off, &scanned);
+            alloc_blocks, blk_off, &scanned);
 
+    if (allocated == num_blocks) {
+      break;
+    }
   }
 
   add_used_blocks(allocated);
@@ -868,17 +872,6 @@ bool BitMapAreaIN::is_allocated(int64_t start_block, int64_t num_blocks)
   return true;
 }
 
-bool BitMapAreaIN::is_allocated(int64_t *alloc_blocks, int64_t num_blocks, int64_t blk_off)
-{
-  for (int64_t i = 0; i < num_blocks; i++) {
-    if (!is_allocated(alloc_blocks[i] - blk_off, 1)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
 int64_t BitMapAreaIN::alloc_blocks_int(bool wait, bool wrap,
                          int64_t num_blocks, int64_t *start_block)
 {
@@ -931,7 +924,7 @@ exit:
 }
 
 int64_t BitMapAreaIN::alloc_blocks_dis_int(bool wait, int64_t num_blocks,
-           int64_t area_blk_off, int64_t *block_list)
+           int64_t area_blk_off, ExtentList *block_list)
 {
   BitMapArea *child = NULL;
   int64_t allocated = 0;
@@ -947,7 +940,7 @@ int64_t BitMapAreaIN::alloc_blocks_dis_int(bool wait, int64_t num_blocks,
 
     blk_off = child->get_index() * m_child_size_blocks + area_blk_off;
     allocated += child->alloc_blocks_dis(wait, num_blocks - allocated,
-                            blk_off, &block_list[allocated]);
+                            blk_off, block_list);
     child_unlock(child);
     if (allocated == num_blocks) {
       break;
@@ -958,14 +951,13 @@ int64_t BitMapAreaIN::alloc_blocks_dis_int(bool wait, int64_t num_blocks,
 }
 
 int64_t BitMapAreaIN::alloc_blocks_dis(bool wait, int64_t num_blocks,
-           int64_t blk_off, int64_t *block_list)
+           int64_t blk_off, ExtentList *block_list)
 {
   int64_t allocated = 0;
 
   lock_shared();
-  allocated += alloc_blocks_dis_int(wait, num_blocks, blk_off, &block_list[allocated]);
+  allocated += alloc_blocks_dis_int(wait, num_blocks, blk_off, block_list);
   add_used_blocks(allocated);
-  debug_assert(is_allocated(block_list, allocated, blk_off));
 
   unlock();
   return allocated;
@@ -1159,7 +1151,7 @@ int64_t BitMapAreaLeaf::alloc_blocks_int(bool wait, bool wrap,
 }
 
 int64_t BitMapAreaLeaf::alloc_blocks_dis_int(bool wait, int64_t num_blocks,
-                                 int64_t area_blk_off, int64_t *block_list)
+                                 int64_t area_blk_off, ExtentList *block_list)
 {
   BitMapArea *child = NULL;
   int64_t allocated = 0;
@@ -1174,8 +1166,7 @@ int64_t BitMapAreaLeaf::alloc_blocks_dis_int(bool wait, int64_t num_blocks,
     }
 
     blk_off = child->get_index() * m_child_size_blocks + area_blk_off;
-    allocated += child->alloc_blocks_dis(num_blocks - allocated,
-      blk_off, &block_list[allocated]);
+    allocated += child->alloc_blocks_dis(num_blocks - allocated, blk_off, block_list);
     child_unlock(child);
     if (allocated == num_blocks) {
       break;
@@ -1266,6 +1257,7 @@ void BitAllocator::init_check(int64_t total_blocks, int64_t zone_size_block,
         BmapEntry::size();
 
   unaligned_blocks = total_blocks % zone_size_block;
+  m_extra_blocks = unaligned_blocks? zone_size_block - unaligned_blocks: 0;
   total_blocks = ROUND_UP_TO(total_blocks, zone_size_block);
 
   m_alloc_mode = mode;
@@ -1280,8 +1272,7 @@ void BitAllocator::init_check(int64_t total_blocks, int64_t zone_size_block,
     /*
      * Mark extra padded blocks used from begning.
      */
-    set_blocks_used(total_blocks - (zone_size_block - unaligned_blocks),
-                 (zone_size_block - unaligned_blocks));
+    set_blocks_used(total_blocks - m_extra_blocks, m_extra_blocks);
   }
 }
 
@@ -1451,6 +1442,7 @@ int64_t BitAllocator::alloc_blocks(int64_t num_blocks, int64_t *start_block)
   if (!reserve_blocks(num_blocks)) {
     goto exit;
   }
+
   if (is_stats_on()) {
     m_stats->add_alloc_calls(1);
     m_stats->add_allocated(num_blocks);
@@ -1535,7 +1527,17 @@ void BitAllocator::set_blocks_used(int64_t start_block, int64_t num_blocks)
 /*
  * Allocate N dis-contiguous blocks.
  */
-int64_t BitAllocator::alloc_blocks_dis(int64_t num_blocks, int64_t *block_list)
+int64_t BitAllocator::alloc_blocks_dis(int64_t num_blocks, ExtentList *block_list)
+{
+  return alloc_blocks_dis_work(num_blocks, block_list, false);
+}
+
+int64_t BitAllocator::alloc_blocks_dis_res(int64_t num_blocks, ExtentList *block_list)
+{
+  return alloc_blocks_dis_work(num_blocks, block_list, true);
+}
+
+int64_t BitAllocator::alloc_blocks_dis_work(int64_t num_blocks, ExtentList *block_list, bool reserved)
 {
   int scans = 1;
   int64_t allocated = 0;
@@ -1555,7 +1557,7 @@ int64_t BitAllocator::alloc_blocks_dis(int64_t num_blocks, int64_t *block_list)
 
   lock_shared();
   serial_lock();
-  if (!reserve_blocks(num_blocks)) {
+  if (!reserved && !reserve_blocks(num_blocks)) {
     goto exit;
   }
 
@@ -1564,8 +1566,7 @@ int64_t BitAllocator::alloc_blocks_dis(int64_t num_blocks, int64_t *block_list)
   }
 
   while (scans && allocated < num_blocks) {
-    allocated += alloc_blocks_dis_int(false, num_blocks - allocated,
-      blk_off, &block_list[allocated]);
+    allocated += alloc_blocks_dis_int(false, num_blocks - allocated, blk_off, block_list);
     scans--;
   }
 
@@ -1579,15 +1580,14 @@ int64_t BitAllocator::alloc_blocks_dis(int64_t num_blocks, int64_t *block_list)
     unlock();
     lock_excl();
     serial_lock();
-    allocated += alloc_blocks_dis_int(false, num_blocks - allocated,
-      blk_off, &block_list[allocated]);
+    allocated += alloc_blocks_dis_int(false, num_blocks - allocated, blk_off, block_list);
     if (is_stats_on()) {
       m_stats->add_serial_scans(1);
     }
   }
 
   unreserve(num_blocks, allocated);
-  debug_assert(is_allocated(block_list, allocated, 0));
+  debug_assert(is_allocated_dis(block_list, allocated));
 
 exit:
   serial_unlock();
@@ -1596,18 +1596,37 @@ exit:
   return allocated;
 }
 
-void BitAllocator::free_blocks_dis(int64_t num_blocks, int64_t *block_list)
+bool BitAllocator::is_allocated_dis(ExtentList *blocks, int64_t num_blocks)
+{
+  int64_t count = 0;
+  for (int64_t j = 0; j < blocks->get_extent_count(); j++) {
+    auto p = blocks->get_nth_extent(j);
+    count += p.second;
+    if (!is_allocated(p.first, p.second)) {
+      return false;
+    }
+  }
+
+  debug_assert(count == num_blocks);
+  return true;
+}
+
+void BitAllocator::free_blocks_dis(int64_t num_blocks, ExtentList *block_list)
 {
+  int64_t freed = 0;
   lock_shared();
   if (is_stats_on()) {
     m_stats->add_free_calls(1);
     m_stats->add_freed(num_blocks);
   }
 
-  for (int64_t i = 0; i < num_blocks; i++) {
-    free_blocks_int(block_list[i], 1);
+  for (int64_t i = 0; i < block_list->get_extent_count(); i++) {
+    free_blocks_int(block_list->get_nth_extent(i).first,
+                    block_list->get_nth_extent(i).second);
+    freed += block_list->get_nth_extent(i).second;
   }
 
+  debug_assert(num_blocks == freed);
   sub_used_blocks(num_blocks);
   debug_assert(get_used_blocks() >= 0);
   unlock();
index 0804234a8b8553b9c2b26446c25791e14c4aee5c..18212ed989c0863ee80acfee0bdf245253f5fb5d 100644 (file)
@@ -17,6 +17,8 @@
 #include <atomic>
 #include <vector>
 #include "include/intarith.h"
+#include "os/bluestore/bluestore_types.h"
+
 
 class BitAllocatorStats {
 public:
@@ -166,7 +168,7 @@ public:
           int *start_offset, int64_t *scanned);
 
   int find_any_free_bits(int start_offset, int64_t num_blocks,
-        int64_t *alloc_list, int64_t block_offset,
+        ExtentList *alloc_list, int64_t block_offset,
         int64_t *scanned);
 
   ~BmapEntry();
@@ -192,6 +194,10 @@ public:
   static int get_level(int64_t total_blocks);
   static int64_t get_level_factor(int level);
   virtual bool is_allocated(int64_t start_block, int64_t num_blocks) = 0;
+  virtual bool is_allocated(ExtentList *blocks, int64_t num_blocks, int blk_off) {
+    debug_assert(0);
+    return true;
+  }
   virtual bool is_exhausted() = 0;
   virtual bool child_check_n_lock(BitMapArea *child, int64_t required) {
       debug_assert(0);
@@ -234,12 +240,12 @@ public:
   }
 
   virtual int64_t alloc_blocks_dis(bool wait, int64_t num_blocks,
-             int64_t blk_off, int64_t *block_list) {
+             int64_t blk_off, ExtentList *block_list) {
     debug_assert(0);
     return 0;
   }
   virtual int64_t alloc_blocks_dis(int64_t num_blocks,
-                         int64_t blk_offset, int64_t *block_list) {
+             int64_t blk_off, ExtentList *block_list) {
     debug_assert(0);
     return 0;
   }
@@ -358,7 +364,8 @@ public:
   }
 
   int64_t alloc_blocks(int64_t num_blocks, int64_t *start_block);
-  int64_t alloc_blocks_dis(int64_t num_blocks, int64_t blk_off, int64_t *block_list);
+  int64_t alloc_blocks_dis(int64_t num_blocks,
+        int64_t blk_off, ExtentList *block_list);  
   void set_blocks_used(int64_t start_block, int64_t num_blocks);
 
   void free_blocks(int64_t start_block, int64_t num_blocks);
@@ -377,8 +384,7 @@ protected:
   std::mutex m_blocks_lock;
   BitMapAreaList *m_child_list;
 
-  bool is_allocated(int64_t start_block, int64_t num_blocks);
-  virtual bool is_allocated(int64_t *blocks, int64_t num_blocks, int64_t blk_off);
+  virtual bool is_allocated(int64_t start_block, int64_t num_blocks);
   virtual bool is_exhausted();
   
   bool child_check_n_lock(BitMapArea *child, int64_t required, bool lock) {
@@ -425,9 +431,9 @@ public:
   using BitMapArea::alloc_blocks_dis; //non-wait version
   virtual int64_t alloc_blocks(bool wait, int64_t num_blocks, int64_t *start_block);
   virtual int64_t alloc_blocks_dis_int(bool wait, int64_t num_blocks,
-               int64_t blk_off, int64_t *block_list);
+        int64_t blk_off, ExtentList *block_list);  
   virtual int64_t alloc_blocks_dis(bool wait, int64_t num_blocks,
-             int64_t blk_off, int64_t *block_list);
+        int64_t blk_off, ExtentList *block_list);  
   virtual void set_blocks_used_int(int64_t start_block, int64_t num_blocks);
   virtual void set_blocks_used(int64_t start_block, int64_t num_blocks);
 
@@ -459,7 +465,7 @@ public:
   int64_t alloc_blocks_int(bool wait, bool wrap,
                          int64_t num_blocks, int64_t *start_block);
   int64_t alloc_blocks_dis_int(bool wait, int64_t num_blocks,
-                               int64_t blk_off, int64_t *block_list);
+        int64_t blk_off, ExtentList *block_list);  
   void free_blocks_int(int64_t start_block, int64_t num_blocks);
 
   virtual ~BitMapAreaLeaf();
@@ -478,8 +484,7 @@ private:
   pthread_rwlock_t m_rw_lock;
   BitAllocatorStats *m_stats;
   bool m_is_stats_on;
-
-  int64_t truncated_blocks; //see init_check
+  int64_t m_extra_blocks;
 
   bool is_stats_on() {
     return m_is_stats_on;
@@ -499,6 +504,7 @@ private:
   bool check_input_dis(int64_t num_blocks);
   void init_check(int64_t total_blocks, int64_t zone_size_block,
                  bmap_alloc_mode_t mode, bool def, bool stats_on);
+  int64_t alloc_blocks_dis_work(int64_t num_blocks, ExtentList *block_list, bool reserved);
 
 public:
 
@@ -517,10 +523,19 @@ public:
   void set_blocks_used(int64_t start_block, int64_t num_blocks);
   void unreserve_blocks(int64_t blocks);
 
-  int64_t alloc_blocks_dis(int64_t num_blocks, int64_t *block_list);
-  void free_blocks_dis(int64_t num_blocks, int64_t *block_list);
+  int64_t alloc_blocks_dis(int64_t num_blocks, ExtentList *block_list);
+  int64_t alloc_blocks_dis_res(int64_t num_blocks, ExtentList *block_list);
+
+  void free_blocks_dis(int64_t num_blocks, ExtentList *block_list);
+  bool is_allocated_dis(ExtentList *blocks, int64_t num_blocks);
+
+  int64_t size() {
+    return m_total_blocks - m_extra_blocks;
+  }
+  int64_t get_used_blocks() {
+    return BitMapAreaIN::get_used_blocks() - (m_extra_blocks + m_reserved_blocks);
+  }
 
-  int64_t get_truncated_blocks() { return truncated_blocks; }
   BitAllocatorStats *get_stats() {
       return m_stats;
   }
index 1695e21162964f0ca6b357090b725ca959e7663e..054ad472db8902551a4881496cc3954c9f1c687b 100644 (file)
@@ -148,6 +148,88 @@ int BitMapAllocator::allocate(
   return 0;
 }
 
+int BitMapAllocator::alloc_extents(
+  uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+  int64_t hint, std::vector<AllocExtent> *extents, int *count)
+{
+  assert(!(alloc_unit % m_block_size));
+  assert(alloc_unit);
+
+  assert(!max_alloc_size || max_alloc_size >= alloc_unit);
+
+  dout(10) << __func__ <<" instance "<< (uint64_t) this
+     << " want_size " << want_size
+     << " alloc_unit " << alloc_unit
+     << " hint " << hint
+     << dendl;
+
+  if (alloc_unit > (uint64_t) m_block_size) {
+    return alloc_extents_cont(want_size, alloc_unit, max_alloc_size, hint, extents, count);     
+  } else {
+    return alloc_extents_dis(want_size, alloc_unit, max_alloc_size, hint, extents, count); 
+  }
+}
+
+/*
+ * Allocator extents with min alloc unit > bitmap block size.
+ */
+int BitMapAllocator::alloc_extents_cont(
+  uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size, int64_t hint,
+  std::vector<AllocExtent> *extents, int *count)
+{
+  *count = 0;
+  assert(alloc_unit);
+  assert(!(alloc_unit % m_block_size));
+  assert(!(max_alloc_size % m_block_size));
+
+  int64_t nblks = (want_size + m_block_size - 1) / m_block_size;
+  int64_t start_blk = 0;
+  int64_t need_blks = nblks;
+  int64_t max_blks = max_alloc_size / m_block_size;
+
+  ExtentList block_list = ExtentList(extents, m_block_size, max_alloc_size);
+
+  while (need_blks > 0) {
+    int64_t count = 0;
+    count = m_bit_alloc->alloc_blocks_res(need_blks > max_blks? max_blks: need_blks,
+                                          &start_blk);
+    if (count == 0) {
+      break;
+    }
+    dout(30) << __func__ <<" instance "<< (uint64_t) this
+      << " offset " << start_blk << " length " << count << dendl;
+    need_blks -= count;
+    block_list.add_extents(start_blk, count);
+  }
+
+  if (need_blks > 0) {
+    m_bit_alloc->free_blocks_dis(nblks - need_blks, &block_list);
+    return -ENOSPC;
+  }
+  *count = block_list.get_extent_count();
+
+  return 0;
+}
+
+int BitMapAllocator::alloc_extents_dis(
+  uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+  int64_t hint, std::vector<AllocExtent> *extents, int *count)
+{
+  ExtentList block_list = ExtentList(extents, m_block_size, max_alloc_size);
+  int64_t nblks = (want_size + m_block_size - 1) / m_block_size;
+  int64_t num = 0;
+  *count = 0;
+
+  num = m_bit_alloc->alloc_blocks_dis_res(nblks, &block_list);
+  if (num < nblks) {
+    m_bit_alloc->free_blocks_dis(num, &block_list);
+    return -ENOSPC;
+  }
+  *count = block_list.get_extent_count();
+
+  return 0;
+}
+
 int BitMapAllocator::release(
   uint64_t offset, uint64_t length)
 {
index cb6002527b46272004235f0c8372416a8b908373..a478d176835a2e101917259ddd4cf2f8aadf4b2e 100644 (file)
@@ -24,6 +24,12 @@ class BitMapAllocator : public Allocator {
 
   void insert_free(uint64_t offset, uint64_t len);
 
+  int alloc_extents_cont(uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+                         int64_t hint, std::vector<AllocExtent> *extents, int *count);
+
+  int alloc_extents_dis(uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+                        int64_t hint, std::vector<AllocExtent> *extents, int *count);
+
 public:
   BitMapAllocator();
   BitMapAllocator(int64_t device_size, int64_t block_size);
@@ -36,6 +42,10 @@ public:
     uint64_t want_size, uint64_t alloc_unit, int64_t hint,
     uint64_t *offset, uint32_t *length);
 
+  int alloc_extents(
+    uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+    int64_t hint, std::vector<AllocExtent> *extents, int *count);
+
   int release(
     uint64_t offset, uint64_t length);
 
index dbfd59bdbac0d324912732908e5b258f82c56ca1..b4db22b0cf69cc29e56f71b2f2126a18b54978f8 100644 (file)
@@ -1362,8 +1362,9 @@ int BlueFS::_allocate(unsigned id, uint64_t len, vector<bluefs_extent_t> *ev)
   dout(10) << __func__ << " len 0x" << std::hex << len << std::dec
            << " from " << id << dendl;
   assert(id < alloc.size());
+  uint64_t min_alloc_size = g_conf->bluefs_alloc_size;
 
-  uint64_t left = ROUND_UP_TO(len, g_conf->bluefs_alloc_size);
+  uint64_t left = ROUND_UP_TO(len, min_alloc_size);
   int r = -ENOSPC;
   if (alloc[id]) {
     r = alloc[id]->reserve(left);
@@ -1389,24 +1390,27 @@ int BlueFS::_allocate(unsigned id, uint64_t len, vector<bluefs_extent_t> *ev)
   if (!ev->empty()) {
     hint = ev->back().end();
   }
-  while (left > 0) {
-    bluefs_extent_t e;
-    e.bdev = id;
-    int r = alloc[id]->allocate(left, g_conf->bluefs_alloc_size, hint,
-                               &e.offset, &e.length);
+
+  int count = 0;
+  std::vector<AllocExtent> extents = 
+        std::vector<AllocExtent>(left / min_alloc_size);
+
+  r = alloc[id]->alloc_extents(left, min_alloc_size,
+                               hint, &extents, &count);
+  assert(r == 0);
+  for (int i = 0; i < count; i++) {
+    bluefs_extent_t e = bluefs_extent_t(id, extents[i].offset, extents[i].length);
     if (r < 0) {
       assert(0 == "allocate failed... wtf");
       return r;
     }
-    if (!ev->empty() && ev->back().end() == e.offset)
+    if (!ev->empty() && ev->back().end() == (uint64_t) e.offset) {
       ev->back().length += e.length;
-    else
+    } else {
       ev->push_back(e);
-    if (e.length >= left)
-      break;
-    left -= e.length;
-    hint = e.end();
+    }
   }
+   
   return 0;
 }
 
index c4ba07b251af50f52d98df5c919c8388634b5ee9..ed4571e9bc32557bbe9b741f80496047452cc756 100644 (file)
@@ -6043,21 +6043,24 @@ int BlueStore::_do_alloc_write(
        csum_order = std::min(wctx->csum_order, ctz(l->length()));
       }
     }
-    while (final_length > 0) {
-      bluestore_pextent_t e;
-      uint32_t l;
-      uint64_t want = max_alloc_size ? MIN(final_length, max_alloc_size) : final_length;
-      int r = alloc->allocate(want, min_alloc_size, hint,
-                             &e.offset, &l);
-      assert(r == 0);
-      need -= l;
-      e.length = l;
+
+    int count = 0;
+    std::vector<AllocExtent> extents = 
+                std::vector<AllocExtent>(final_length / min_alloc_size);
+
+    int r = alloc->alloc_extents(final_length, min_alloc_size, max_alloc_size,
+                                 hint, &extents, &count);
+
+    need -= final_length;
+    assert(r == 0);
+    for (int i = 0; i < count; i++) {
+      bluestore_pextent_t e = bluestore_pextent_t(extents[i]);
       txc->allocated.insert(e.offset, e.length);
       txc->statfs_delta.allocated() += e.length;
       b->blob.extents.push_back(e);
-      final_length -= e.length;
       hint = e.end();
     }
+
     dout(20) << __func__ << " blob " << *b
             << " csum_order " << csum_order
             << " csum_length 0x" << std::hex << csum_length << std::dec
index 6b54b4f547cca4db6a0fb63784ed76bb0b722c4f..f2eabfd076b392528f16dddfed610765cf2aa1e8 100644 (file)
@@ -148,7 +148,6 @@ int StupidAllocator::allocate(
     }
   }
 
-  assert(0 == "caller didn't reserve?");
   return -ENOSPC;
 
  found:
@@ -198,6 +197,44 @@ int StupidAllocator::allocate(
   return 0;
 }
 
+int StupidAllocator::alloc_extents(
+  uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+  int64_t hint, std::vector<AllocExtent> *extents, int *count)
+{
+  uint64_t allocated_size = 0;
+  uint64_t offset = 0;
+  uint32_t length = 0;
+  int res = 0;
+
+  if (max_alloc_size == 0) {
+    max_alloc_size = want_size;
+  }
+
+  ExtentList block_list = ExtentList(extents, 1, max_alloc_size);
+
+  while (allocated_size < want_size) {
+    res = allocate(MIN(max_alloc_size, (want_size - allocated_size)),
+       alloc_unit, hint, &offset, &length);
+    if (res != 0) {
+      /*
+       * Allocation failed.
+       */
+      break;
+    }
+    block_list.add_extents(offset, length);
+    allocated_size += length;
+    hint = offset + length;
+  }
+
+  *count = block_list.get_extent_count();
+  if (want_size - allocated_size > 0) {
+    release_extents(extents, *count);
+    return -ENOSPC;
+  }
+
+  return 0;
+}
+
 int StupidAllocator::release(
   uint64_t offset, uint64_t length)
 {
index fa10c5d7473cde95becf7c6667b8ef1a90e3bd65..59ffdcefc811cfa629dc416b94d29a6b16dddabc 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "Allocator.h"
 #include "include/btree_interval_set.h"
+#include "os/bluestore/bluestore_types.h"
 
 class StupidAllocator : public Allocator {
   std::mutex lock;
@@ -33,6 +34,10 @@ public:
   int reserve(uint64_t need);
   void unreserve(uint64_t unused);
 
+  int alloc_extents(
+    uint64_t want_size, uint64_t alloc_unit, uint64_t max_alloc_size,
+    int64_t hint, std::vector<AllocExtent> *extents, int *count);
+
   int allocate(
     uint64_t want_size, uint64_t alloc_unit, int64_t hint,
     uint64_t *offset, uint32_t *length);
index a1eda9115d3968312113b026221e57f9c113fc98..39a1eb5d89875628e3daf1b23a56eb1d319b2a6d 100644 (file)
@@ -105,7 +105,7 @@ vector<bluefs_extent_t>::iterator bluefs_fnode_t::seek(
 {
   vector<bluefs_extent_t>::iterator p = extents.begin();
   while (p != extents.end()) {
-    if (offset >= p->length) {
+    if ((int64_t) offset >= p->length) {
       offset -= p->length;
       ++p;
     } else {
index eef6b3e702769cdd310f9896170386d39325478b..ac32aeec3af79ee15e1aa85052dec4052f1cb84e 100644 (file)
@@ -7,17 +7,12 @@
 #include "include/utime.h"
 #include "include/encoding.h"
 
-struct bluefs_extent_t {
-  uint64_t offset;
-  uint32_t length;
+class bluefs_extent_t : public AllocExtent{
+public:
   uint16_t bdev;
 
   bluefs_extent_t(uint16_t b = 0, uint64_t o = 0, uint32_t l = 0)
-    : offset(o), length(l), bdev(b) {}
-
-  uint64_t end() const {
-    return offset + length;
-  }
+    : AllocExtent(o, l), bdev(b) {}
 
   void encode(bufferlist&) const;
   void decode(bufferlist::iterator&);
index 0c8808ae7d3ef8215cf47bcb2fcdb3de5c245537..8723d92f0217e6df095181370cb2268af5e07e08 100644 (file)
 #include "common/Checksummer.h"
 #include "include/stringify.h"
 
+void ExtentList::add_extents(int64_t start, int64_t count) {
+  AllocExtent *last_extent = NULL;
+  bool can_merge = false;
+
+  if (m_num_extents > 0) {
+    last_extent = &((*m_extents)[m_num_extents - 1]);
+    uint64_t last_offset = (last_extent->offset + last_extent->length) / 
+                       m_block_size; 
+    uint32_t last_length = last_extent->length / m_block_size; 
+    int64_t max_blocks = m_max_alloc_size / m_block_size;
+    if ((last_offset == (uint64_t) start) &&
+        (!max_blocks || (last_length + count) <= max_blocks)) {
+      can_merge = true;
+    }
+  }
+
+  if (can_merge) {
+    last_extent->length += (count * m_block_size);
+  } else {
+    (*m_extents)[m_num_extents].offset = start * m_block_size;
+    (*m_extents)[m_num_extents].length = count * m_block_size;
+    m_num_extents++;
+  }
+  assert((int64_t) m_extents->size() >= m_num_extents);
+}
+
 // bluestore_bdev_label_t
 
 void bluestore_bdev_label_t::encode(bufferlist& bl) const
index 9c079297c44d41febe148f556a71e853f107826f..e8c4654654ba0c1e4bb7aff17b5184d354df9012 100644 (file)
@@ -56,18 +56,73 @@ struct bluestore_cnode_t {
 };
 WRITE_CLASS_ENCODER(bluestore_cnode_t)
 
-/// pextent: physical extent
-struct bluestore_pextent_t {
-  const static uint64_t INVALID_OFFSET = ~0ull;
+class AllocExtent {
+public:
+  uint64_t offset;
+  uint32_t length;
 
-  uint64_t offset, length;    ///< location on device
-
-  bluestore_pextent_t() : offset(0), length(0) {}
-  bluestore_pextent_t(uint64_t o, uint64_t l) : offset(o), length(l) {}
+  AllocExtent() { 
+    offset = 0;
+    length = 0;
+  }
 
+  AllocExtent(int64_t off, int32_t len) : offset(off), length(len) { }
   uint64_t end() const {
     return offset + length;
   }
+};
+
+class ExtentList {
+  std::vector<AllocExtent> *m_extents;
+  int64_t m_num_extents;
+  int64_t m_block_size;
+  uint64_t m_max_alloc_size;
+
+public:
+  void init(std::vector<AllocExtent> *extents, int64_t block_size, uint64_t max_alloc_size) {
+    m_extents = extents;
+    m_num_extents = 0;
+    m_block_size = block_size;
+    m_max_alloc_size = max_alloc_size;
+  }
+
+  ExtentList(std::vector<AllocExtent> *extents, int64_t block_size) {
+    init(extents, block_size, 0);
+  }
+
+  ExtentList(std::vector<AllocExtent> *extents, int64_t block_size, uint64_t max_alloc_size) {
+    init(extents, block_size, max_alloc_size);
+  }
+
+  void reset() {
+    m_num_extents = 0;
+  }
+
+  void add_extents(int64_t start, int64_t count);
+
+  std::vector<AllocExtent> *get_extents() {
+    return m_extents;
+  }
+
+  std::pair<int64_t, int64_t> get_nth_extent(int index) {
+      return std::make_pair
+            ((*m_extents)[index].offset / m_block_size,
+             (*m_extents)[index].length / m_block_size);
+  }
+
+  int64_t get_extent_count() {
+    return m_num_extents;
+  }
+};
+
+
+/// pextent: physical extent
+struct bluestore_pextent_t : public AllocExtent{
+  const static uint64_t INVALID_OFFSET = ~0ull;
+
+  bluestore_pextent_t() : AllocExtent() {}
+  bluestore_pextent_t(uint64_t o, uint64_t l) : AllocExtent(o, l) {}
+  bluestore_pextent_t(AllocExtent &ext) : AllocExtent(ext.offset, ext.length) { }
 
   bool is_valid() const {
     return offset != INVALID_OFFSET;
index a575e76ba9b709a8c93f88b9734ff7481bb63cf8..29c09da349f941cbfec4d0117a91f187dd341a1c 100644 (file)
@@ -71,6 +71,11 @@ unittest_bit_alloc_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL)
 unittest_bit_alloc_CXXFLAGS = $(UNITTEST_CXXFLAGS)
 check_TESTPROGRAMS += unittest_bit_alloc
 
+unittest_alloc_SOURCES = test/objectstore/Allocator_test.cc
+unittest_alloc_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL)
+unittest_alloc_CXXFLAGS = $(UNITTEST_CXXFLAGS)
+check_TESTPROGRAMS += unittest_alloc
+
 unittest_bluestore_types_SOURCES = test/objectstore/test_bluestore_types.cc
 unittest_bluestore_types_LDADD = $(LIBOS) $(UNITTEST_LDADD) $(CEPH_GLOBAL)
 unittest_bluestore_types_CXXFLAGS = $(UNITTEST_CXXFLAGS)
diff --git a/src/test/objectstore/Allocator_test.cc b/src/test/objectstore/Allocator_test.cc
new file mode 100644 (file)
index 0000000..89f3c54
--- /dev/null
@@ -0,0 +1,210 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * In memory space allocator test cases.
+ * Author: Ramesh Chander, Ramesh.Chander@sandisk.com
+ */
+#include "os/bluestore/Allocator.h"
+#include "global/global_init.h"
+#include <iostream>
+#include "include/Context.h"
+#include "common/ceph_argparse.h"
+#include "global/global_init.h"
+#include "common/Mutex.h"
+#include "common/Cond.h"
+#include "common/errno.h"
+#include "include/stringify.h"
+#include <gtest/gtest.h>
+#include <os/bluestore/BitAllocator.h>
+
+#if GTEST_HAS_PARAM_TEST
+
+class AllocTest : public ::testing::TestWithParam<const char*> {
+public:
+    boost::scoped_ptr<Allocator> alloc;
+    AllocTest(): alloc(0) { }
+    void init_alloc(int64_t size, uint64_t min_alloc_size) {
+      std::cout << "Creating alloc type " << string(GetParam()) << " \n";
+      alloc.reset(Allocator::create(string(GetParam()), size, min_alloc_size));
+    }
+
+    void init_close() {
+      alloc.reset(0);
+    }
+};
+
+TEST_P(AllocTest, test_alloc_init)
+{
+  int64_t blocks = BmapEntry::size();
+  init_alloc(blocks, 1);
+  ASSERT_EQ(alloc->get_free(), 0);
+  alloc->shutdown(); 
+  blocks = BitMapZone::get_total_blocks() * 2 + 16;
+  init_alloc(blocks, 1);
+  ASSERT_EQ(alloc->get_free(), 0);
+  alloc->shutdown(); 
+  blocks = BitMapZone::get_total_blocks() * 2;
+  init_alloc(blocks, 1);
+  ASSERT_EQ(alloc->get_free(), 0);
+}
+
+TEST_P(AllocTest, test_alloc_min_alloc)
+{
+  int64_t block_size = 1024;
+  int64_t blocks = BitMapZone::get_total_blocks() * 2 * block_size;
+  uint64_t offset = 0;
+  uint32_t length = 0;
+  int count = 0;
+
+  init_alloc(blocks, block_size);
+  alloc->init_add_free(block_size, block_size);
+  EXPECT_EQ(alloc->reserve(block_size), 0);
+  EXPECT_EQ(alloc->allocate(block_size, block_size, 0, &offset, &length), 0);
+
+  /*
+   * Allocate extent and make sure all comes in single extent.
+   */   
+  {
+    alloc->init_add_free(0, block_size * 4);
+    EXPECT_EQ(alloc->reserve(block_size * 4), 0);
+    std::vector<AllocExtent> extents = std::vector<AllocExtent> 
+                        (4, AllocExtent(0, 0));
+  
+    EXPECT_EQ(alloc->alloc_extents(4 * (uint64_t)block_size, (uint64_t) block_size, 
+                                   0, (int64_t) 0, &extents, &count), 0);
+    EXPECT_EQ(extents[0].length, 4 * block_size);
+    EXPECT_EQ(extents[1].length, 0);
+    EXPECT_EQ(count, 1);
+  }
+
+  /*
+   * Allocate extent and make sure we get two different extents.
+   */
+  {
+    alloc->init_add_free(0, block_size * 2);
+    alloc->init_add_free(3 * block_size, block_size * 2);
+    EXPECT_EQ(alloc->reserve(block_size * 4), 0);
+    std::vector<AllocExtent> extents = std::vector<AllocExtent> 
+                        (4, AllocExtent(0, 0));
+  
+    EXPECT_EQ(alloc->alloc_extents(4 * (uint64_t)block_size, (uint64_t) block_size, 
+                                   0, (int64_t) 0, &extents, &count), 0);
+    EXPECT_EQ(extents[0].length, 2 * block_size);
+    EXPECT_EQ(extents[1].length, 2 * block_size);
+    EXPECT_EQ(extents[2].length, 0);
+    EXPECT_EQ(count, 2);
+  }
+  alloc->shutdown();
+}
+
+TEST_P(AllocTest, test_alloc_min_max_alloc)
+{
+  int64_t block_size = 1024;
+  int64_t blocks = BitMapZone::get_total_blocks() * 2 * block_size;
+  int count = 0;
+
+  init_alloc(blocks, block_size);
+
+  /*
+   * Make sure we get all extents different when
+   * min_alloc_size == max_alloc_size
+   */
+  {
+    alloc->init_add_free(0, block_size * 4);
+    EXPECT_EQ(alloc->reserve(block_size * 4), 0);
+    std::vector<AllocExtent> extents = std::vector<AllocExtent> 
+                        (4, AllocExtent(0, 0));
+  
+    EXPECT_EQ(alloc->alloc_extents(4 * (uint64_t)block_size, (uint64_t) block_size, 
+                                   block_size, (int64_t) 0, &extents, &count), 0);
+    for (int i = 0; i < 4; i++) {
+      EXPECT_EQ(extents[i].length, block_size);
+    }
+    EXPECT_EQ(count, 4);
+  }
+
+
+  /*
+   * Make sure we get extents of length max_alloc size
+   * when max alloc size > min_alloc size
+   */
+  {
+    alloc->init_add_free(0, block_size * 4);
+    EXPECT_EQ(alloc->reserve(block_size * 4), 0);
+    std::vector<AllocExtent> extents = std::vector<AllocExtent> 
+                        (2, AllocExtent(0, 0));
+  
+    EXPECT_EQ(alloc->alloc_extents(4 * (uint64_t)block_size, (uint64_t) block_size, 
+                                   2 * block_size, (int64_t) 0, &extents, &count), 0);
+    for (int i = 0; i < 2; i++) {
+      EXPECT_EQ(extents[i].length, block_size * 2);
+    }
+    EXPECT_EQ(count, 2);
+  }
+
+  /*
+   * Allocate and free.
+   */
+  {
+    alloc->init_add_free(0, block_size * 16);
+    EXPECT_EQ(alloc->reserve(block_size * 16), 0);
+    std::vector<AllocExtent> extents = std::vector<AllocExtent> 
+                        (8, AllocExtent(0, 0));
+  
+    EXPECT_EQ(alloc->alloc_extents(16 * (uint64_t)block_size, (uint64_t) block_size, 
+                                   2 * block_size, (int64_t) 0, &extents, &count), 0);
+
+    EXPECT_EQ(count, 8);
+    for (int i = 0; i < 8; i++) {
+      EXPECT_EQ(extents[i].length, 2 * block_size);
+    }
+    EXPECT_EQ(alloc->release_extents(&extents, count), 0);
+  }
+}
+
+TEST_P(AllocTest, test_alloc_failure)
+{
+  int64_t block_size = 1024;
+  int64_t blocks = BitMapZone::get_total_blocks() * block_size;
+  int count = 0;
+
+  init_alloc(blocks, block_size);
+  {
+    alloc->init_add_free(0, block_size * 256);
+    alloc->init_add_free(block_size * 512, block_size * 256);
+
+    EXPECT_EQ(alloc->reserve(block_size * 512), 0);
+    std::vector<AllocExtent> extents = std::vector<AllocExtent> 
+                        (4, AllocExtent(0, 0));
+  
+    EXPECT_EQ(alloc->alloc_extents(512 * (uint64_t)block_size, (uint64_t) block_size * 256, 
+                                   block_size * 256, (int64_t) 0, &extents, &count), 0);
+    alloc->init_add_free(0, block_size * 256);
+    alloc->init_add_free(block_size * 512, block_size * 256);
+    EXPECT_EQ(alloc->reserve(block_size * 512), 0);
+    EXPECT_EQ(alloc->alloc_extents(512 * (uint64_t)block_size, (uint64_t) block_size * 512,
+                                   block_size * 512, (int64_t) 0, &extents, &count), -ENOSPC);
+  }
+}
+
+INSTANTIATE_TEST_CASE_P(
+  Allocator,
+  AllocTest,
+  ::testing::Values("stupid", "bitmap"));
+
+#else
+
+TEST(DummyTest, ValueParameterizedTestsAreNotSupportedOnThisPlatform) {}
+#endif
+
+int main(int argc, char **argv)
+{
+  vector<const char*> args;
+  argv_to_vec(argc, (const char **)argv, args);
+  env_to_vec(args);
+
+  global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, CODE_ENVIRONMENT_UTILITY, 0);
+
+  ::testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
index 44898775d389a5f76402e2392a5dc4f315de1c72..71eac0d4ad8bc375689b2c79d4c421c80af0fa1e 100644 (file)
@@ -15,7 +15,7 @@
 #include <sstream>
 #include <gtest/gtest.h>
 
-#define bmap_test_assert(x) EXPECT_EQ(true, (x))
+#define bmap_test_assert(x) ASSERT_EQ(true, (x))
 #define NUM_THREADS 16
 #define MAX_BLOCKS (1024 * 1024 * 1)
 
@@ -53,7 +53,6 @@ TEST(BitAllocator, test_bmap_iter)
   for (i = 0; i < num_items; i++) {
     (*arr)[i].init(i);
   }
-  //BitMapList<BmapEntityTmp> *list = new BitMapList<BmapEntityTmp>(arr, num_items, 0);
   BitMapEntityIter<BmapEntityTmp> iter = BitMapEntityIter<BmapEntityTmp>(arr, off, false);
 
   i = off;
@@ -330,7 +329,6 @@ TEST(BitAllocator, test_zone_alloc)
   zone = new BitMapZone(total_blocks, 0);
   lock = zone->lock_excl_try();
   bmap_test_assert(lock);
-  int64_t blocks[1024] = {0};
   for (int i = 0; i < zone->size(); i++) {
     allocated = zone->alloc_blocks(1, &start_block);
     bmap_test_assert(allocated == 1);
@@ -339,7 +337,12 @@ TEST(BitAllocator, test_zone_alloc)
     zone->free_blocks(i, 1);
   }
 
-  allocated = zone->alloc_blocks_dis(zone->size() / 2, 0, blocks);
+  int64_t blk_size = 1024;
+  std::vector<AllocExtent> extents = std::vector<AllocExtent>
+        (zone->size() / 2, AllocExtent(-1, -1));
+
+  ExtentList *block_list = new ExtentList(&extents, blk_size);
+  allocated = zone->alloc_blocks_dis(zone->size() / 2, 0, block_list);
   bmap_test_assert(allocated == zone->size() / 2);
 }
 
@@ -417,22 +420,28 @@ TEST(BitAllocator, test_bmap_alloc)
       alloc->free_blocks(i, 1);
     }
 
-    int64_t blocks[alloc->size() / 2];
-    memset(blocks, 0, sizeof(blocks));
-    allocated = alloc->alloc_blocks_dis(alloc->size()/2, blocks);
-    bmap_test_assert(allocated == alloc->size() / 2);
+               int64_t blk_size = 1024;
+               std::vector<AllocExtent> extents = std::vector<AllocExtent>
+                                       (alloc->size(), AllocExtent(-1, -1));
 
-    allocated = alloc->alloc_blocks_dis(1, blocks);
-    bmap_test_assert(allocated == 0);
+               ExtentList *block_list = new ExtentList(&extents, blk_size);
 
-    alloc->free_blocks(alloc->size()/2, 1);
-    allocated = alloc->alloc_blocks_dis(1, blocks);
+               allocated = alloc->alloc_blocks_dis(alloc->size()/2, block_list);
+               bmap_test_assert(allocated == alloc->size() / 2);
 
-    bmap_test_assert(allocated == 1);
-    bmap_test_assert(blocks[0] == alloc->size()/2);
+               block_list->reset();
+               allocated = alloc->alloc_blocks_dis(1, block_list);
+               bmap_test_assert(allocated == 0);
 
-    alloc->free_blocks(0, alloc->size());
-    delete alloc;
+               alloc->free_blocks(alloc->size()/2, 1);
+
+               block_list->reset();
+               allocated = alloc->alloc_blocks_dis(1, block_list);
+               bmap_test_assert(allocated == 1);
+
+               bmap_test_assert((int64_t) extents[0].offset == alloc->size()/2 * blk_size);
+
+               delete alloc;
 
     // unaligned zones
     total_blocks = zone_size * 2 + 11;
@@ -502,6 +511,49 @@ TEST(BitAllocator, test_bmap_alloc)
   g_ceph_context->_conf->apply_changes(NULL);
 }
 
+bool alloc_extents_max_block(BitAllocator *alloc,
+           int64_t max_alloc,
+           int64_t total_alloc)
+{
+  int64_t blk_size = 1;
+  int64_t allocated = 0;
+  int64_t verified = 0;
+  int64_t count = 0;
+  std::vector<AllocExtent> extents = std::vector<AllocExtent>
+        (total_alloc, AllocExtent(-1, -1));
+
+  ExtentList *block_list = new ExtentList(&extents, blk_size, max_alloc);
+
+  allocated = alloc->alloc_blocks_dis(total_alloc, block_list);
+  EXPECT_EQ(allocated, total_alloc);
+
+  max_alloc = total_alloc > max_alloc? max_alloc: total_alloc;
+
+  for (auto &p: extents) {
+    count++;
+    EXPECT_EQ(p.length,  max_alloc);
+    verified += p.length;
+    if (verified >= total_alloc) {
+      break;
+    }
+  }
+
+  EXPECT_EQ(total_alloc / max_alloc, count);
+  return true;
+}
+
+TEST(BitAllocator2, test_bmap_alloc)
+{
+  int64_t total_blocks = 1024 * 4;
+  int64_t zone_size = 1024;
+  BitAllocator *alloc = new BitAllocator(total_blocks, zone_size, CONCURRENT);
+
+  alloc_extents_max_block(alloc, 1, 16);
+  alloc_extents_max_block(alloc, 4, 16);
+  alloc_extents_max_block(alloc, 16, 16);
+  alloc_extents_max_block(alloc, 32, 16);
+}
+
 void
 verify_blocks(int64_t num_blocks, int64_t *blocks)
 {
@@ -529,8 +581,9 @@ do_work(BitAllocator *alloc)
 
   while (num_iters--) {
     printf("Allocating in tid %d.\n", my_tid);
+    debug_assert(alloc->reserve_blocks(num_blocks));
     for (int i = 0; i < num_blocks; i++) {
-      alloced = alloc->alloc_blocks(1, &start_block);
+      alloced = alloc->alloc_blocks_res(1, &start_block);
       bmap_test_assert(alloced == 1);
       total_alloced++;
       allocated_blocks[i] = start_block;
@@ -546,14 +599,43 @@ do_work(BitAllocator *alloc)
   }
 }
 
+void
+do_work_dis(BitAllocator *alloc)
+{
+  int num_iters = 10;
+  int64_t alloced = 0;
+  int64_t num_blocks = alloc->size() / NUM_THREADS;
+
+  std::vector<AllocExtent> extents = std::vector<AllocExtent>
+        (num_blocks, AllocExtent(-1, -1));
+  ExtentList *block_list = new ExtentList(&extents, 4096);
+
+  while (num_iters--) {
+      debug_assert(alloc->reserve_blocks(num_blocks));
+      alloced = alloc->alloc_blocks_dis_res(num_blocks, block_list);
+      debug_assert(alloced == num_blocks);
+
+      debug_assert(alloc->is_allocated_dis(block_list, num_blocks));
+      alloc->free_blocks_dis(num_blocks, block_list);
+      block_list->reset();
+  }
+}
+
 int tid = 0;
+static bool cont = true;
+
 void *
 worker(void *args)
 {
   my_tid = __sync_fetch_and_add(&tid, 1);
   BitAllocator *alloc = (BitAllocator *) args;
   printf("Starting thread %d", my_tid);
-  do_work(alloc);
+  if (cont) {
+    do_work(alloc);
+  } else {
+    do_work_dis(alloc);
+  }
+
   return NULL;
 }
 
@@ -566,23 +648,22 @@ TEST(BitAllocator, test_bmap_alloc_concurrent)
   bmap_test_assert(total_blocks <= MAX_BLOCKS);
 
   BitAllocator *alloc = new BitAllocator(total_blocks, zone_size, CONCURRENT);
-  printf("Spawning %d threads for parallel test.....\n", NUM_THREADS);
 
-  for (int j = 0; j < NUM_THREADS; j++) {
-    if (pthread_create(&pthreads[j], NULL, worker, alloc)) {
-      printf("Unable to create worker thread.\n");
-      exit(0);
+  for (int k = 0; k < 2; k++) {
+    cont = k;
+    printf("Spawning %d threads for parallel test. Mode Cont = %d.....\n", NUM_THREADS, cont);
+    for (int j = 0; j < NUM_THREADS; j++) {
+      if (pthread_create(&pthreads[j], NULL, worker, alloc)) {
+        printf("Unable to create worker thread.\n");
+        exit(0);
+      }
     }
-  }
 
-  for (int j = 0; j < NUM_THREADS; j++) {
-    pthread_join(pthreads[j], NULL);
+    for (int j = 0; j < NUM_THREADS; j++) {
+      pthread_join(pthreads[j], NULL);
+    }
   }
 
-  // max_blks / num threads and free those. Make sure threads
-  // always gets blocks
-  // Do this with dis-contiguous and contiguous allocations
-  // do multithreaded allocation and check allocations are unique
 }
 
 int main(int argc, char **argv)
index 9bff68144c43448edba9fb22132c58e19f3feec7..b41d0e985bbc6b150f03cd3f75d4926b26b3af24 100644 (file)
@@ -109,6 +109,12 @@ add_executable(unittest_bit_alloc
 add_ceph_unittest(unittest_bit_alloc ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest_bit_alloc)
 target_link_libraries(unittest_bit_alloc os global)
 
+add_executable(unittest_alloc
+  Allocator_test.cc
+  )
+add_ceph_unittest(unittest_alloc ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/unittest_alloc)
+target_link_libraries(unittest_alloc os global)
+
 # unittest_bluefs
 add_executable(unittest_bluefs
   test_bluefs.cc