mirror of
https://github.com/ceph/ceph
synced 2026-08-02 07:03:18 +00:00
Merge pull request #70142 from sunyuechi/fix-ec-omap-iterator-invalidation
osd/ECBackend: fix iterator invalidation in omap_get
This commit is contained in:
commit
d2003750cd
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
);
|
||||
};
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user