]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
os/bluestore: Add bluestore_blob_use_tracker_t::put_simple
authorAdam Kupczyk <akupczyk@ibm.com>
Thu, 9 Nov 2023 01:14:30 +0000 (01:14 +0000)
committerAdam Kupczyk <akupczyk@ibm.com>
Wed, 7 Aug 2024 10:55:45 +0000 (10:55 +0000)
New version of put().
It is simpler and faster, but does not allow for
overprovisioning of used AUs.

Signed-off-by: Adam Kupczyk <akupczyk@ibm.com>
src/os/bluestore/bluestore_types.cc
src/os/bluestore/bluestore_types.h
src/test/objectstore/test_bluestore_types.cc

index f7ee4a5467cfa4d64e90e848ea3029f4158c317a..f8864157d9d3e11c4daebe0fc5f8949ad5a277e2 100644 (file)
@@ -534,6 +534,62 @@ bool bluestore_blob_use_tracker_t::put(
   return empty;
 }
 
+
+std::pair<uint32_t, uint32_t> bluestore_blob_use_tracker_t::put_simple(
+  uint32_t offset, uint32_t length)
+{
+  if (num_au == 0) {
+    // single tracker for entire blob
+    ceph_assert(total_bytes >= length);
+    total_bytes -= length;
+    if (total_bytes == 0) {
+      return std::make_pair(0, au_size);
+    } else {
+      return std::make_pair(0, 0);
+    }
+  } else {
+    uint32_t clear_start = 0;
+    uint32_t clear_end = 0;
+    uint32_t pos = offset / au_size;
+    uint32_t remain = p2remain(offset, au_size);
+    if (length <= remain) {
+      // all in same block
+      ceph_assert(length <= bytes_per_au[pos]);
+      bytes_per_au[pos] -= length;
+      if (bytes_per_au[pos] == 0) {
+        clear_start = pos * au_size;
+        clear_end = clear_start + au_size;
+      }
+    } else {
+      // length > remain
+      ceph_assert(remain <= bytes_per_au[pos]);
+      bytes_per_au[pos] -= remain;
+      if (bytes_per_au[pos] == 0) {
+        clear_start = pos * au_size;
+      } else {
+        clear_start = (pos + 1) * au_size;
+      }
+      ++pos;
+      length -= remain;
+      while (length >= au_size) {
+        ceph_assert(au_size == bytes_per_au[pos]);
+        bytes_per_au[pos] = 0;
+        ++pos;
+        length -= au_size;
+      }
+      if (length > 0) {
+        ceph_assert(length <= bytes_per_au[pos]);
+        bytes_per_au[pos] -= length;
+        if (bytes_per_au[pos] == 0) {
+          ++pos;
+        }
+      }
+      clear_end = pos * au_size;
+    }
+    return std::make_pair(clear_start, clear_end - clear_start);
+  }
+}
+
 bool bluestore_blob_use_tracker_t::can_split() const
 {
   return num_au > 0;
index 2d1540c3382bf8129d6dcd85c8351e6d736c6551..78293d8eaba8313391aab96b62b733623b41ef5c 100644 (file)
@@ -403,6 +403,15 @@ struct bluestore_blob_use_tracker_t {
     uint32_t len,
     PExtentVector *release);
 
+  /// Puts back references in region [offset~length].
+  /// It is different, simpler version of put,
+  /// as it does not allow for overprovisioning.
+  /// Releasing off=0x500 len=0x2000 from {0x1000,0x1004,0x1000} will fail,
+  /// while the other one behaves properly
+  std::pair<uint32_t, uint32_t> put_simple(
+    uint32_t offset,
+    uint32_t length);
+
   bool can_split() const;
   bool can_split_at(uint32_t blob_offset) const;
   void split(
index fd761a2f836c56d63d331570f5f97ed424ffb4e1..b0a06fe80d4f9e0d5b138a5d8037425f526e4014 100644 (file)
@@ -2464,6 +2464,108 @@ INSTANTIATE_TEST_SUITE_P(
     )
 );
 
+class bluestore_blob_use_tracker_t_test :
+  public ::testing::Test,
+  public ::testing::WithParamInterface<std::vector<int>>
+{
+};
+
+TEST_P(bluestore_blob_use_tracker_t_test, put_simple)
+{
+  // generate offset / length
+  // get region [offset~length] in tracker
+  // choose randomly x points in range [offset~length]
+  // in random order
+  // put them into tracker
+  // check if all is cleared as it should
+
+  std::vector<int> param = GetParam();
+  ASSERT_EQ(param.size(), 6);
+  uint32_t alloc_unit =         param[0];
+  uint32_t test_size_range =    param[1];
+  uint32_t test_offset_range =  param[2];
+  uint32_t test_offset_length = param[3];
+  uint32_t test_aligned_nom =   param[4];
+  uint32_t test_aligned_denom = param[5];
+
+  auto rand_next = [&](uint32_t prev) -> uint32_t {
+    uint32_t next;
+    uint32_t len = rand() % test_size_range + 1;
+    if (rand() % test_aligned_denom < test_aligned_nom) {
+      // go for aligned
+      next = p2roundup(prev + len, alloc_unit);
+    } else {
+      // unaligned
+      next = prev + len;
+    }
+    return next;
+  };
+  auto rand_pos = [&](uint32_t range) -> uint32_t {
+    if (rand() % test_aligned_denom < test_aligned_nom) {
+      return p2align(rand() % range, alloc_unit);
+    } else {
+      return rand() % range;
+    }
+  };
+
+  for (int k = 0; k < 10000; k++) {
+    std::map<int, std::pair<int, int>> regions;
+    uint32_t offset = rand_pos(test_offset_range);
+    uint32_t length = 0;
+    while (length == 0) {
+      length = rand_pos(test_offset_length);
+    }
+    //std::cout << std::hex << "offset=" << offset
+    //          << " length=" << length << std::dec << std::endl;
+    uint32_t i = offset;
+    uint32_t j = offset;
+    while (i < offset + length) {
+      j = rand_next(i);
+      if (j > offset + length)
+        j = offset + length;
+      regions[rand() * 10000 + regions.size()] = std::make_pair(i, j - i);
+      i = j;
+    }
+    bluestore_blob_use_tracker_t t;
+    t.init(offset + length, alloc_unit);
+    t.get(offset, length);
+
+    interval_set<uint32_t> released;
+    for (auto r : regions) {
+      auto v = t.put_simple(r.second.first, r.second.second);
+      //std::cout << std::hex << "0x" << r.second.first << "~" << r.second.second
+      //          << "->0x" << v.first << "~" << v.second << std::dec << std::endl;
+      if (v.second > 0) {
+        released.insert(v.first, v.second);
+      }
+    }
+    ASSERT_FALSE(released.empty());
+    ASSERT_EQ(t.get_referenced_bytes(), 0);
+    ASSERT_EQ(released.begin().get_start(), p2align(offset, alloc_unit));
+    ASSERT_EQ(released.begin().get_end(), p2roundup(offset + length, alloc_unit));
+  }
+}
+
+/*
+  uint32_t alloc_unit = 4096;
+  uint32_t test_size_range = 10000;
+  uint32_t test_offset_range = 50000;
+  uint32_t test_offset_length = 100000;
+  uint32_t test_aligned_denom = 3;
+  uint32_t test_aligned_nom = 2;
+*/
+INSTANTIATE_TEST_SUITE_P(
+  BlueStore,
+  bluestore_blob_use_tracker_t_test,
+  ::testing::Values(
+    std::vector<int>({4096, 10000, 50000, 100000, 2, 3}),
+    std::vector<int>({4096, 10000, 40000, 80000, 1, 11}),
+    std::vector<int>({8192, 30000, 80000, 160000, 2, 4}),
+    std::vector<int>({32768, 40000, 80000, 160000, 5, 6})
+    )
+);
+
+
 //---------------------------------------------------------------------------------
 static int verify_extent(const extent_t &ext, const extent_t *ext_arr,
                          uint64_t ext_arr_size, uint64_t idx) {