Merge pull request #70142 from sunyuechi/fix-ec-omap-iterator-invalidation

osd/ECBackend: fix iterator invalidation in omap_get
This commit is contained in:
SrinivasaBharathKanta 2026-07-22 04:41:04 +05:30 committed by GitHub
commit d2003750cd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 6 deletions

View File

@ -1808,11 +1808,7 @@ int ECBackend::omap_get(
}
// Remove keys in removed_ranges
for (auto out_it = out->begin(); out_it != out->end(); ++out_it) {
if (should_be_removed(removed_ranges, out_it->first)) {
out->erase(out_it->first);
}
}
remove_keys_in_ranges(removed_ranges, out);
// Apply updates in update_map
for (const auto &[key, val_opt] : update_map) {
@ -1887,3 +1883,12 @@ bool ECBackend::should_be_removed(
// No ranges contain the key, return false
return false;
}
void ECBackend::remove_keys_in_ranges(
const std::map<std::string, std::optional<std::string>>& removed_ranges,
std::map<std::string, ceph::buffer::list>* out) {
for (const auto& [start, end] : removed_ranges) {
out->erase(out->lower_bound(start),
end ? out->lower_bound(*end) : out->end());
}
}

View File

@ -456,4 +456,9 @@ public:
const std::map<std::string, std::optional<std::string>>& removed_ranges,
const std::string_view key
);
static void remove_keys_in_ranges(
const std::map<std::string, std::optional<std::string>>& removed_ranges,
std::map<std::string, ceph::buffer::list>* out
);
};

View File

@ -17,6 +17,7 @@
#include "test/unit.cc"
#include "osd/ECOmapJournal.h"
#include "osd/ECBackend.h"
#include "common/dout.h"
class MockDoutPrefixProvider : public DoutPrefixProvider {
@ -1450,4 +1451,30 @@ TEST(ecomapjournal, has_omap_updates_after_remove_entry)
// Should not have updates after removing all entries
ASSERT_FALSE(journal.has_omap_updates(test_hoid));
}
}
// A removed range spanning several adjacent keys erases all of them.
TEST(ecbackend_remove_keys_in_ranges, removes_contiguous_block)
{
std::map<std::string, ceph::buffer::list> out;
for (std::string_view k : {"k01", "k02", "k03", "k04", "k05", "k06"}) {
out[std::string(k)].append(k);
}
std::map<std::string, std::optional<std::string>> removed = {
{"k02", "k05"}, // -> erases k02, k03, k04
};
ECBackend::remove_keys_in_ranges(removed, &out);
std::vector<std::string> remaining;
for (const auto &[k, v] : out) {
remaining.push_back(k);
}
EXPECT_EQ((std::vector<std::string>{"k01", "k05", "k06"}), remaining);
// Surviving values must be untouched.
ASSERT_TRUE(out.contains("k05"));
ceph::buffer::list k05_bl;
k05_bl.append("k05");
EXPECT_TRUE(out["k05"].contents_equal(k05_bl));
}