Skip to content

Commit 5f7c445

Browse files
Merge pull request ceph#61900 from aclamk/wip-aclamk-bs-fix-get-unused-mask
os/bluestore: implemented bluestore_blob_t::get_unused_mask Reviewed-by: Chunmei Liu <[email protected]>
2 parents 388ef10 + 2e73c87 commit 5f7c445

File tree

4 files changed

+110
-10
lines changed

4 files changed

+110
-10
lines changed

src/os/bluestore/Writer.cc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ BlueStore::BlobRef BlueStore::Writer::_blob_create_with_data(
500500
_get_disk_space(blob_length - alloc_offset, blob_allocs);
501501
bblob.allocated(alloc_offset, blob_length - alloc_offset, blob_allocs);
502502
//^sets also logical_length = blob_length
503+
bblob.add_unused_all();
503504
dout(25) << __func__ << " @0x" << std::hex << in_blob_offset
504505
<< "~" << disk_data.length()
505506
<< " alloc_offset=" << alloc_offset
@@ -508,6 +509,7 @@ BlueStore::BlobRef BlueStore::Writer::_blob_create_with_data(
508509
_crop_allocs_to_io(disk_extents, in_blob_offset - alloc_offset,
509510
blob_length - in_blob_offset - disk_data.length());
510511
_schedule_io(disk_extents, disk_data);
512+
bblob.mark_used(in_blob_offset, data_length);
511513
return blob;
512514
}
513515

@@ -541,7 +543,7 @@ BlueStore::BlobRef BlueStore::Writer::_blob_create_full(
541543
_get_disk_space(blob_length, blob_allocs);
542544
_schedule_io(blob_allocs, disk_data); //have to do before move()
543545
bblob.allocated_full(blob_length, std::move(blob_allocs));
544-
bblob.mark_used(0, blob_length); //todo - optimize; this obviously clears it
546+
bblob.mark_used_all();
545547
return blob;
546548
}
547549

@@ -610,7 +612,7 @@ BlueStore::BlobRef BlueStore::Writer::_blob_create_full(
610612
inline void BlueStore::Writer::_schedule_io_masked(
611613
uint64_t disk_position,
612614
bufferlist data,
613-
bluestore_blob_t::unused_t mask,
615+
uint64_t mask,
614616
uint32_t chunk_size)
615617
{
616618
if (test_write_divertor == nullptr) {
@@ -771,7 +773,7 @@ void BlueStore::Writer::_try_reuse_allocated_l(
771773
uint32_t data_size = want_subau_end - want_subau_begin;
772774
bufferlist data_at_left = split_left(data, data_size);
773775
bd.real_length -= data_size;
774-
uint32_t mask = bb.get_unused_mask(in_blob_offset, data_size, chunk_size);
776+
uint64_t mask = bb.get_unused_mask(in_blob_offset, data_size, chunk_size);
775777
_blob_put_data_subau(b, in_blob_offset, data_at_left);
776778
// transfer do disk
777779
_schedule_io_masked(subau_disk_offset, data_at_left, mask, chunk_size);
@@ -844,9 +846,9 @@ void BlueStore::Writer::_try_reuse_allocated_r(
844846
uint32_t data_size = want_subau_end - want_subau_begin;
845847
bufferlist data_at_right = split_right(data, data.length() - data_size);
846848
bd.real_length -= data_size;
847-
uint32_t mask = bb.get_unused_mask(in_blob_offset, data_size, chunk_size);
849+
uint64_t mask = bb.get_unused_mask(in_blob_offset, data_size, chunk_size);
848850
_blob_put_data_subau(b, in_blob_offset, data_at_right);
849-
//transfer to disk
851+
// transfer to disk
850852
_schedule_io_masked(subau_disk_offset, data_at_right, mask, chunk_size);
851853

852854
uint32_t ref_end = std::min(ref_end_offset, want_subau_end);

src/os/bluestore/Writer.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ class BlueStore::Writer {
107107
inline void _schedule_io_masked(
108108
uint64_t disk_offset,
109109
bufferlist data,
110-
bluestore_blob_t::unused_t mask,
110+
uint64_t mask,
111111
uint32_t chunk_size);
112112

113113
inline void _schedule_io(

src/os/bluestore/bluestore_types.h

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,12 @@ struct bluestore_blob_t {
728728
}
729729
}
730730

731+
/// mark everything as unused
732+
void add_unused_all() {
733+
set_flag(FLAG_HAS_UNUSED);
734+
unused = ~0;
735+
}
736+
731737
/// indicate that a range has (now) been used.
732738
void mark_used(uint64_t offset, uint64_t length) {
733739
if (has_unused()) {
@@ -746,14 +752,58 @@ struct bluestore_blob_t {
746752
}
747753
}
748754
}
749-
/// todo implement me!
750-
unused_t get_unused_mask(uint32_t offset, uint32_t length, uint32_t chunk_size) {
755+
756+
///mark everything as used
757+
void mark_used_all() {
758+
clear_flag(FLAG_HAS_UNUSED);
759+
}
760+
761+
/// create bitmap mask, io_chunk_size per bit
762+
/// bit 0 is offset, bit 1 is offset + io_chunk_size, ....
763+
uint64_t get_unused_mask(uint32_t offset, uint32_t length, uint32_t io_chunk_size) {
751764
if (has_unused()) {
752-
return 0;
765+
uint32_t blob_len = get_logical_length();
766+
ceph_assert((blob_len % (sizeof(unused)*8)) == 0);
767+
ceph_assert(offset + length <= blob_len);
768+
ceph_assert((offset % io_chunk_size) == 0);
769+
ceph_assert((length % io_chunk_size) == 0);
770+
if (length / io_chunk_size > 64) {
771+
// the result cannot fit 64 bits, pretend all is used
772+
return 0;
773+
}
774+
uint32_t chunk_size = blob_len / (sizeof(unused)*8);
775+
uint16_t i = offset / chunk_size;
776+
uint16_t j = 0;
777+
uint64_t io_used = 0;
778+
uint64_t next_u = round_down_to(offset + chunk_size, chunk_size);
779+
uint64_t next_io = round_down_to(offset + io_chunk_size, io_chunk_size);
780+
// The algorithm here is iterating 2 sequences that have different "speeds":
781+
// unused bit speed (chunk_size) and output disk region speed (io_chunk_size)
782+
// unused_bits : aaaaabbbbbcccccdddddeeeeefffffggggghhhhh
783+
// disk_io_chnk: AAABBBCCCDDDEEEFFFGGGHHHIIIJJJ
784+
// But we operate on "used" logic, as it allows for easier summation, and return the inverse.
785+
// We apply restriction from i-th unused bit to j-th io_chunk.
786+
// The relative sizes of chunk_size and io_chunk_size determine
787+
// how fast we increase i and j respectively.
788+
for (; next_io < offset + length + io_chunk_size; ) {
789+
//produce io_mask bit, by copying state from unused bit
790+
(!(unused & (1 << i))) ? io_used |= uint64_t(1) << j : 0;
791+
auto le = next_u <= next_io;
792+
if (next_u >= next_io) {
793+
j++;
794+
next_io += io_chunk_size;
795+
}
796+
if (le) {
797+
i++;
798+
next_u += chunk_size;
799+
}
800+
}
801+
return ~io_used;
753802
} else {
754803
return 0;
755804
}
756805
}
806+
757807
// map_f_invoke templates intended to mask parameters which are not expected
758808
// by the provided callback
759809
template<class F, typename std::enable_if<std::is_invocable_r_v<

src/test/objectstore/test_bluestore_types.cc

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1864,7 +1864,7 @@ TEST_F(ExtentMapFixture, rain) {
18641864
X.push_back(create());
18651865
}
18661866
for (size_t i = 0; i < H - 1; i++) {
1867-
write(X[i], (rand() % W - 1) * au_size, au_size);
1867+
write(X[i], (rand() % (W - 1)) * au_size, au_size);
18681868
dup(X[i], X[i + 1], 0, W * au_size);
18691869
}
18701870
for (size_t i = 0; i < H; i++) {
@@ -3174,6 +3174,54 @@ TEST(bluestore_blob_t, wrong_map_bl_in_51682) {
31743174
ASSERT_EQ(expected_pos, num_expected_entries);
31753175
}
31763176
}
3177+
3178+
TEST(bluestore_blob_t, get_unused_mask) {
3179+
uint32_t disk_block = 4 * 1024;
3180+
for (uint32_t alloc = 4 * 1024; alloc <= 256 * 1024; alloc *= 2) {
3181+
for (uint32_t t = 0; t < 10000; t++) {
3182+
bluestore_blob_t b;
3183+
uint32_t size = (rand() % 10 + 1) * alloc;
3184+
b.allocated_test({uint64_t(rand() * 0x1000), size});
3185+
b.add_unused(0, size);
3186+
// sprinkle used
3187+
uint32_t regions = (rand() % 4) + 1;
3188+
for (uint32_t i = 0; i < regions; i++) {
3189+
uint32_t left = (rand() % 4) ?
3190+
rand() % (size / disk_block + 1) * disk_block : //aligned to disk block
3191+
(rand() * 1024 + rand()) % size; // completely free
3192+
uint32_t right = (rand() % 4) ?
3193+
rand() % (size / disk_block + 1) * disk_block : //aligned to disk block
3194+
(rand() * 1024 + rand()) % size; // completely free
3195+
if (left == right) continue;
3196+
if (left > right) swap(left, right);
3197+
b.mark_used(left, right - left);
3198+
}
3199+
3200+
for (uint32_t io_chunk_size = 1024; io_chunk_size <= 32 * 1024; io_chunk_size *= 2) {
3201+
if (size < io_chunk_size || (size % io_chunk_size) != 0) {
3202+
continue;
3203+
}
3204+
if (size / io_chunk_size > 64) continue;
3205+
uint32_t io_begin = rand() % (size / io_chunk_size + 1) * io_chunk_size;
3206+
uint32_t io_end = rand() % (size / io_chunk_size + 1) * io_chunk_size;
3207+
if (io_begin == io_end) continue;
3208+
if (io_begin > io_end) swap(io_begin, io_end);
3209+
3210+
uint64_t mask = 0;
3211+
uint64_t bit = 1;
3212+
for (uint32_t i = io_begin; i < io_end; i += io_chunk_size) {
3213+
mask = mask | (b.is_unused(i, io_chunk_size) ? bit : 0);
3214+
bit = bit << 1;
3215+
}
3216+
uint64_t result = b.get_unused_mask(io_begin, io_end - io_begin, io_chunk_size);
3217+
auto ref = std::bitset<64>(mask).to_string().substr(64 - (io_end - io_begin) / io_chunk_size);
3218+
auto uuu = std::bitset<64>(result).to_string().substr(64 - (io_end - io_begin) / io_chunk_size);
3219+
EXPECT_EQ(ref, uuu);
3220+
}
3221+
}
3222+
}
3223+
}
3224+
31773225
class bluestore_blob_t_test :
31783226
public ::testing::Test,
31793227
public ::testing::WithParamInterface<std::vector<int>>

0 commit comments

Comments
 (0)