From: Adam Kupczyk Date: Thu, 9 Nov 2023 01:14:30 +0000 (+0000) Subject: os/bluestore: Add bluestore_blob_use_tracker_t::put_simple X-Git-Tag: v20.0.0~1280^2~31 X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=8e62d0c89a6a5dcb0898a136082ce64238d39754;p=ceph.git os/bluestore: Add bluestore_blob_use_tracker_t::put_simple New version of put(). It is simpler and faster, but does not allow for overprovisioning of used AUs. Signed-off-by: Adam Kupczyk --- diff --git a/src/os/bluestore/bluestore_types.cc b/src/os/bluestore/bluestore_types.cc index f7ee4a5467cfa..f8864157d9d3e 100644 --- a/src/os/bluestore/bluestore_types.cc +++ b/src/os/bluestore/bluestore_types.cc @@ -534,6 +534,62 @@ bool bluestore_blob_use_tracker_t::put( return empty; } + +std::pair 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; diff --git a/src/os/bluestore/bluestore_types.h b/src/os/bluestore/bluestore_types.h index 2d1540c3382bf..78293d8eaba83 100644 --- a/src/os/bluestore/bluestore_types.h +++ b/src/os/bluestore/bluestore_types.h @@ -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 put_simple( + uint32_t offset, + uint32_t length); + bool can_split() const; bool can_split_at(uint32_t blob_offset) const; void split( diff --git a/src/test/objectstore/test_bluestore_types.cc b/src/test/objectstore/test_bluestore_types.cc index fd761a2f836c5..b0a06fe80d4f9 100644 --- a/src/test/objectstore/test_bluestore_types.cc +++ b/src/test/objectstore/test_bluestore_types.cc @@ -2464,6 +2464,108 @@ INSTANTIATE_TEST_SUITE_P( ) ); +class bluestore_blob_use_tracker_t_test : + public ::testing::Test, + public ::testing::WithParamInterface> +{ +}; + +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 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> 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 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({4096, 10000, 50000, 100000, 2, 3}), + std::vector({4096, 10000, 40000, 80000, 1, 11}), + std::vector({8192, 30000, 80000, 160000, 2, 4}), + std::vector({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) {