]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
osd: Introduce functions required for EC OMAP support
authorMatty Williams <Matty.Williams@ibm.com>
Fri, 12 Dec 2025 11:21:10 +0000 (11:21 +0000)
committerMatty Williams <Matty.Williams@ibm.com>
Thu, 26 Feb 2026 09:39:15 +0000 (09:39 +0000)
Introduced wrappers around omap read operations in PGBackend to include updates from the journal in EC pools with optimisations enabled.
Introduced a function for encoding an EC_OMAP operation in the ObjectModDesc::Visitor class and a function for committing an operation in the Trimmer struct.

Signed-off-by: Matty Williams <Matty.Williams@ibm.com>
src/osd/ECBackend.cc
src/osd/ECBackend.h
src/osd/ECCommon.h
src/osd/ECSwitch.h
src/osd/PGBackend.cc
src/osd/PGBackend.h
src/osd/ReplicatedBackend.h
src/osd/osd_types.h
src/test/osd/TestPeeringState.cc

index 8e462f1a0617b0b089ef8b2c45b19464b8c8765b..1c6a35bc696413b1448f6e363b9a8a665a8b179c 100644 (file)
@@ -1375,3 +1375,230 @@ int ECBackend::be_deep_scrub(
   o.omap_digest_present = true;
   return 0;
 }
+
+bool ECBackend::remove_ec_omap_journal_entry(const hobject_t &hoid, const ECOmapJournalEntry &entry) {
+  return ec_omap_journal.remove_entry(hoid, entry);
+}
+
+std::pair<gen_t, bool> ECBackend::omap_get_generation(const hobject_t& hoid)
+{
+  return ec_omap_journal.get_generation(hoid);
+}
+
+void ECBackend::omap_trim_delete_from_journal(const hobject_t &hoid, const version_t version)
+{
+  return ec_omap_journal.trim_delete(hoid, version);
+}
+
+int ECBackend::omap_iterate (
+  ObjectStore::CollectionHandle &c_, ///< [in] collection
+  const ghobject_t &oid, ///< [in] object
+  const ObjectStore::omap_iter_seek_t &start_from,
+  ///^ [in] where the iterator should point to at the beginning
+  const OmapIterFunction &f, ///< [in] function to call for each key/value pair
+  ObjectStore *store
+) {
+  // Updates in update_map take priority over removed_ranges
+  auto [update_map, removed_ranges] = ec_omap_journal.get_value_updates(oid.hobj);
+
+  auto journal_it = update_map.begin();
+  if (!start_from.seek_position.empty()) {
+    journal_it = update_map.lower_bound(start_from.seek_position);
+  }
+
+  auto wrapper = [&](const std::string_view store_key, const std::string_view store_value) {
+    bool found_store_key_in_journal = false;
+    
+    while (journal_it != update_map.end() && journal_it->first <= store_key) {
+      if (journal_it->first == store_key) {
+        found_store_key_in_journal = true;
+      }
+      if (journal_it->second.value.has_value()) {
+        ObjectStore::omap_iter_ret_t r = f(
+          journal_it->first,
+          std::string_view(
+            journal_it->second.value->c_str(),
+            journal_it->second.value->length()
+          )
+        );
+        if (r == ObjectStore::omap_iter_ret_t::STOP) {
+          return r;
+        }
+      }
+      ++journal_it;
+    }
+
+    if (found_store_key_in_journal) {
+      return ObjectStore::omap_iter_ret_t::NEXT;
+    }
+
+    if (should_be_removed(removed_ranges, store_key)) {
+      return ObjectStore::omap_iter_ret_t::NEXT;
+    }
+
+    return f(store_key, store_value);
+  };
+
+  if (const auto result = store->omap_iterate(c_, oid, start_from, wrapper);
+    result < 0) {
+    return result;
+  } else if (result > 0) {
+    return 1;
+  }
+
+  auto ret = ObjectStore::omap_iter_ret_t::NEXT;
+  while (journal_it != update_map.end()) {
+    if (journal_it->second.value.has_value()) {
+      ret = f(journal_it->first, std::string_view(journal_it->second.value->c_str(), journal_it->second.value->length()));
+      if (ret == ObjectStore::omap_iter_ret_t::STOP) {
+        break;
+      }
+    }
+    ++journal_it;
+  }
+
+  return ret == ObjectStore::omap_iter_ret_t::STOP ? 1 : 0;
+}
+
+int ECBackend::omap_get_values(
+  ObjectStore::CollectionHandle &c_, ///< [in] collection
+  const ghobject_t &oid,              ///< [in] object
+  const std::set<std::string> &keys,  ///< [in] keys to get
+  std::map<std::string, ceph::buffer::list> *out, ///< [out] returned key/values
+  ObjectStore *store
+) {
+  auto [update_map, removed_ranges] = ec_omap_journal.get_value_updates(oid.hobj);
+  
+  set<string> keys_still_to_get;
+  for (auto &key : keys) {
+    if (auto it = update_map.find(key);
+      it != update_map.end()) {
+      if (!it->second.value.has_value()) {
+        continue;
+      }
+      (*out)[key] = *(it->second.value);
+    } else if (should_be_removed(removed_ranges, key)) {
+      continue;
+    } else {
+      keys_still_to_get.insert(key);
+    }
+  }
+  store->omap_get_values(c_, oid, keys_still_to_get, out);
+
+  return 0;
+}
+
+int ECBackend::omap_get_header(
+  ObjectStore::CollectionHandle &c_,    ///< [in] Collection containing oid
+  const ghobject_t &oid,   ///< [in] Object containing omap
+  ceph::buffer::list *header,      ///< [out] omap header
+  const bool allow_eio, ///< [in] don't assert on eio
+  ObjectStore *store
+) {
+  std::optional<ceph::buffer::list> header_from_journal = ec_omap_journal.get_updated_header(oid.hobj);
+  if (header_from_journal) {
+    *header = *header_from_journal;
+  } else {
+    store->omap_get_header(c_, oid, header, allow_eio);
+  }
+  return 0;
+}
+
+int ECBackend::omap_get(
+  ObjectStore::CollectionHandle &c_,    ///< [in] Collection containing oid
+  const ghobject_t &oid,   ///< [in] Object containing omap
+  ceph::buffer::list *header,      ///< [out] omap header
+  std::map<std::string, ceph::buffer::list> *out, /// < [out] Key to value map
+  ObjectStore *store
+) {
+  // Update map takes priority over removed_ranges
+  auto [update_map, removed_ranges] = ec_omap_journal.get_value_updates(oid.hobj);
+  const auto updated_header = ec_omap_journal.get_updated_header(oid.hobj);
+
+  if (const int r = store->omap_get(c_, oid, header, out);
+    r < 0) {
+    return r;
+  }
+
+  // Update header if present
+  if (updated_header) {
+    *header = *updated_header;
+  }
+
+  // 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);
+    }
+  }
+
+  // Apply updates in update_map
+  for (const auto &[key, val_opt] : update_map) {
+    if (val_opt.value.has_value()) {
+      (*out)[key] = *(val_opt.value);
+    } else {
+      out->erase(key);
+    }
+  }
+
+  return 0;
+}
+
+int ECBackend::omap_check_keys(
+  ObjectStore::CollectionHandle &c_,    ///< [in] Collection containing oid
+  const ghobject_t &oid,   ///< [in] Object containing omap
+  const std::set<std::string> &keys, ///< [in] Keys to check
+  std::set<std::string> *out,         ///< [out] Subset of keys defined on oid
+  ObjectStore *store
+) {
+  // Update map takes priority over removed_ranges
+  auto [update_map, removed_ranges] = ec_omap_journal.get_value_updates(oid.hobj);
+  auto updated_header = ec_omap_journal.get_updated_header(oid.hobj);
+
+  // First check keys in update_map and removed_ranges
+  set<string> keys_to_check_on_disk;
+  for (const auto &key : keys) {
+    if (auto it = update_map.find(key);
+      it != update_map.end()) {
+      if (it->second.value.has_value()) {
+        out->insert(key);
+      }
+    } else if (should_be_removed(removed_ranges, key)) {
+      continue;
+    } else {
+      keys_to_check_on_disk.insert(key);
+    }
+  }
+
+  const int r = store->omap_check_keys(c_, oid, keys_to_check_on_disk, out);
+
+  return r;
+}
+
+bool ECBackend::should_be_removed(
+  const std::map<std::string, std::optional<std::string>>& removed_ranges,
+  std::string_view key) 
+{
+  if (removed_ranges.empty()) {
+    return false;
+  }
+  
+  // Find range that comes after this key
+  auto it = removed_ranges.upper_bound(std::string(key));
+
+  // If all ranges start after the key, it can't be in any range
+  if (it == removed_ranges.begin()) {
+    return false;
+  }
+
+  // Go back to the previous range
+  --it;
+  // If this range contains the key, return true
+  const auto& end_opt = it->second;
+  if (!end_opt || key < *end_opt) {
+    return true;
+  }
+
+  // No ranges contain the key, return false
+  return false;
+}
index 0068dfec01c2ee67447dc806a137e4929f227b60..a5c83acde1c82e001754a0ba49e3fcfdb099581c 100644 (file)
@@ -397,4 +397,54 @@ public:
     }
     return object_size_to_shard_size(logical_size, shard_id);
   }
+
+  bool remove_ec_omap_journal_entry(const hobject_t &hoid, const ECOmapJournalEntry &entry);
+  std::pair<gen_t, bool> omap_get_generation(const hobject_t &hoid);
+  void omap_trim_delete_from_journal(const hobject_t &hoid, const version_t version);
+
+  using OmapIterFunction = std::function<ObjectStore::omap_iter_ret_t(std::string_view, std::string_view)>;
+  int omap_iterate (
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const ObjectStore::omap_iter_seek_t &start_from, ///< [in] where the iterator should point to at the beginning
+    const OmapIterFunction &f, ///< [in] function to call for each key/value pair
+    ObjectStore *store
+  );
+
+  int omap_get_values(
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid,              ///< [in] object
+    const std::set<std::string> &keys,  ///< [in] keys to get
+    std::map<std::string, ceph::buffer::list> *out, ///< [out] returned key/values
+    ObjectStore *store
+  );
+
+  int omap_get_header(
+    ObjectStore::CollectionHandle &c_,    ///< [in] Collection containing oid
+    const ghobject_t &oid,   ///< [in] Object containing omap
+    ceph::buffer::list *header,      ///< [out] omap header
+    bool allow_eio, ///< [in] don't assert on eio
+    ObjectStore *store
+  );
+
+  int omap_get(
+    ObjectStore::CollectionHandle &c_,    ///< [in] Collection containing oid
+    const ghobject_t &oid,   ///< [in] Object containing omap
+    ceph::buffer::list *header,      ///< [out] omap header
+    std::map<std::string, ceph::buffer::list> *out, /// < [out] Key to value map
+    ObjectStore *store
+  );
+
+  int omap_check_keys(
+    ObjectStore::CollectionHandle &c_,    ///< [in] Collection containing oid
+    const ghobject_t &oid,   ///< [in] Object containing omap
+    const std::set<std::string> &keys, ///< [in] Keys to check
+    std::set<std::string> *out,         ///< [out] Subset of keys defined on oid
+    ObjectStore *store
+  );
+
+  bool should_be_removed(
+    const std::map<std::string, std::optional<std::string>>& removed_ranges,
+    std::string_view key
+  );
 };
index 24f48e822ffdf410b3c4628520c0f23d953af629..0622835b872ebbd7eea6c948682804ed01f788ec 100644 (file)
@@ -24,6 +24,7 @@
 #include "ECTypes.h"
 #include "messages/MOSDPGPushReply.h"
 #include "msg/MessageRef.h"
+#include "osd/ECOmapJournal.h"
 #if WITH_CRIMSON
 #include "crimson/osd/object_context.h"
 #include "os/Transaction.h"
@@ -57,6 +58,8 @@ struct PGLog;
 struct RecoveryMessages;
 
 struct ECCommon {
+  ECOmapJournal ec_omap_journal;
+
   struct ec_extent_t {
     int err;
     extent_map emap;
index 641e939eddee619af4e0c322152d652abd75f7dc..ea7351269144b2bef082b180471d32ce9f7d2bfd 100644 (file)
@@ -437,4 +437,81 @@ public:
   bool get_is_ec_optimized() const final {
     return is_optimized();
   }
+  bool remove_ec_omap_journal_entry(const hobject_t &hoid, const ECOmapJournalEntry &entry) override {
+    ceph_assert(is_optimized());
+    return optimized.remove_ec_omap_journal_entry(hoid, entry);
+  }
+
+  std::pair<gen_t, bool> omap_get_generation(const hobject_t &hoid) override
+  {
+    ceph_assert(is_optimized());
+    return optimized.omap_get_generation(hoid);
+  }
+
+  void omap_trim_delete_from_journal(const hobject_t &hoid, const version_t version) override
+  {
+    ceph_assert(is_optimized());
+    optimized.omap_trim_delete_from_journal(hoid, version);
+  }
+
+  int omap_iterate (
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const ObjectStore::omap_iter_seek_t &start_from,
+    ///^ [in] where the iterator should point to at the beginning
+    const OmapIterFunction &f ///< [in] function to call for each key/value pair
+  ) override {
+    if (!is_optimized()) {
+      return store->omap_iterate(c_, oid, start_from, f);
+    }
+    return optimized.omap_iterate(c_, oid, start_from, f, store);
+  }
+
+  int omap_get_values(
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const std::set<std::string> &keys, ///< [in] keys to get
+    std::map<std::string, ceph::buffer::list> *out ///< [out] returned key/values
+  ) override {
+    if (!is_optimized()) {
+      return store->omap_get_values(c_, oid, keys, out);
+    }
+    return optimized.omap_get_values(c_, oid, keys, out, store);
+  }
+
+  int omap_get_header(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    ceph::buffer::list *header, ///< [out] omap header
+    bool allow_eio ///< [in] don't assert on eio
+  ) override {
+    if (!is_optimized()) {
+      return store->omap_get_header(c_, oid, header, allow_eio);
+    }
+    return optimized.omap_get_header(c_, oid, header, allow_eio, store);
+  }
+
+  int omap_get(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    ceph::buffer::list *header, ///< [out] omap header
+    std::map<std::string, ceph::buffer::list> *out /// < [out] Key to value map
+  ) override {
+    if (!is_optimized()) {
+      return store->omap_get(c_, oid, header, out);
+    }
+    return optimized.omap_get(c_, oid, header, out, store);
+  }
+
+  int omap_check_keys(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    const std::set<std::string> &keys, ///< [in] Keys to check
+    std::set<std::string> *out ///< [out] Subset of keys defined on oid
+  ) override {
+    if (!is_optimized()) {
+      return store->omap_check_keys(c_, oid, keys, out);
+    }
+    return optimized.omap_check_keys(c_, oid, keys, out, store);
+  }
 };
index e17f4f3909d442d25688f7a6a60b12bd59da1eb6..c8e361fa0adfddae1137fd6eb933df726bc21ab4 100644 (file)
@@ -341,11 +341,12 @@ struct Trimmer : public ObjectModDesc::Visitor {
   const hobject_t &soid;
   PGBackend *pg;
   ObjectStore::Transaction *t;
+  const pg_log_entry_t &entry;
   Trimmer(
-    const hobject_t &soid,
     PGBackend *pg,
-    ObjectStore::Transaction *t)
-    : soid(soid), pg(pg), t(t) {}
+    ObjectStore::Transaction *t,
+    const pg_log_entry_t &entry)
+    : soid(entry.soid), pg(pg), t(t), entry(entry) {}
   void rmobject(version_t old_version) override {
     pg->trim_rollback_object(
       soid,
@@ -377,6 +378,80 @@ struct Trimmer : public ObjectModDesc::Visitor {
       }
     }
   }
+
+  void ec_omap(bool clear_omap, std::optional<ceph::buffer::list> omap_header, 
+    std::vector<std::pair<OmapUpdateType, ceph::buffer::list>> &omap_updates) override {
+
+    auto shard = pg->get_parent()->whoami_shard().shard;
+    spg_t spg = pg->get_parent()->whoami_spg_t();
+    auto sinfo = pg->ec_get_sinfo();
+    const auto [gen, lost_delete] = pg->omap_get_generation(soid);
+
+    if (!sinfo.is_nonprimary_shard(shard)) {
+      // If lost_delete is true, check if the object exists before performing updates
+      bool should_update = true;
+      if (lost_delete) {
+        struct stat st;
+        int r = pg->store->stat(
+          pg->ch,
+          ghobject_t(soid, gen, shard),
+          &st,
+          true);
+        if (r != 0) {
+          // Object doesn't exist on this shard, skip the update
+          should_update = false;
+        }
+      }
+
+      if (should_update) {
+        if (omap_header) {
+          t->omap_setheader(
+            coll_t(spg),
+            ghobject_t(soid, gen, shard),
+            *(omap_header));
+        }
+
+        if (clear_omap) {
+          t->omap_clear(
+            coll_t(spg),
+            ghobject_t(soid, gen, shard));
+        }
+
+        for (auto &&up: omap_updates) {
+          switch (up.first) {
+            case OmapUpdateType::Remove:
+              t->omap_rmkeys(
+                coll_t(spg),
+                ghobject_t(soid, gen, shard),
+                up.second);
+              break;
+            case OmapUpdateType::Insert:
+              t->omap_setkeys(
+                coll_t(spg),
+                ghobject_t(soid, gen, shard),
+                up.second);
+              break;
+            case OmapUpdateType::RemoveRange:
+              t->omap_rmkeyrange(
+                coll_t(spg),
+                ghobject_t(soid, gen, shard),
+                up.second);
+              break;
+          }
+        }
+      }
+    }
+
+    // Only remove journal entry if generation is NO_GEN (object not deleted)
+    // If gen != NO_GEN, the object has been deleted and journal was already cleared
+    if (gen == ghobject_t::NO_GEN && pg->get_parent()->pgb_is_primary()) {
+      const ECOmapJournalEntry to_remove(
+        entry.version, clear_omap,
+        omap_header, omap_updates
+        );
+      pg->remove_ec_omap_journal_entry(soid, to_remove);
+    }
+  }
 };
 
 void PGBackend::rollforward(
@@ -387,7 +462,7 @@ void PGBackend::rollforward(
   ldpp_dout(dpp, 20) << __func__ << ": entry=" << entry << dendl;
   if (!entry.can_rollback())
     return;
-  Trimmer trimmer(entry.soid, this, t);
+  Trimmer trimmer(this, t, entry);
   entry.mod_desc.visit(&trimmer);
 }
 
@@ -397,7 +472,7 @@ void PGBackend::trim(
 {
   if (!entry.can_rollback())
     return;
-  Trimmer trimmer(entry.soid, this, t);
+  Trimmer trimmer(this, t, entry);
   entry.mod_desc.visit(&trimmer);
 }
 
index a3110b6fe559353ffe4a5e622e07a0faf161e49e..33b6510bb117869c6840ad3060be706ffaf14f1c 100644 (file)
 #ifndef PGBACKEND_H
 #define PGBACKEND_H
 
-#include "ECListener.h"
-#include "ECTypes.h"
-#include "ECExtentCache.h"
-#include "osd_types.h"
-#include "pg_features.h"
-#include "common/intrusive_timer.h"
+#include <string>
+
+#include "common/LogClient.h"
 #include "common/WorkQueue.h"
+#include "common/intrusive_timer.h"
+#include "common/ostream_temp.h"
 #include "include/Context.h"
 #include "os/ObjectStore.h"
 #include "osd/scrubber_common.h"
-#include "common/LogClient.h"
-#include <string>
+
+#include "ECExtentCache.h"
+#include "ECListener.h"
+#include "ECTypes.h"
 #include "PGTransaction.h"
-#include "common/ostream_temp.h"
+#include "osd_types.h"
+#include "pg_features.h"
+
+
+class ECOmapJournalEntry;
 
 namespace Scrub {
   class Store;
@@ -447,7 +452,45 @@ typedef std::shared_ptr<const OSDMap> OSDMapRef;
    virtual shard_id_map<bufferlist> ec_decode_acting_set(
        const shard_id_map<bufferlist> &shard_map, int chunk_size) const = 0;
    virtual ECUtil::stripe_info_t ec_get_sinfo() const = 0;
-
+   virtual bool remove_ec_omap_journal_entry(const hobject_t &hoid, const ECOmapJournalEntry &entry) {
+     return false; // Only EC uses ec_omap_journal
+   };
+   virtual std::pair<gen_t, bool> omap_get_generation(const hobject_t &hoid) {
+     return {0, false}; // Only EC uses ec_omap_journal
+   };
+   virtual void omap_trim_delete_from_journal(const hobject_t &hoid, const version_t version) {};
+   using OmapIterFunction = std::function<ObjectStore::omap_iter_ret_t(std::string_view, std::string_view)>;
+   virtual int omap_iterate(
+     ObjectStore::CollectionHandle &c_, ///< [in] collection
+     const ghobject_t &oid, ///< [in] object
+     const ObjectStore::omap_iter_seek_t &start_from,
+     ///^ [in] where the iterator should point to at the beginning
+     const OmapIterFunction &f ///< [in] function to call for each key/value pair
+   ) = 0;
+   virtual int omap_get_values(
+     ObjectStore::ObjectStore::CollectionHandle &c_, ///< [in] collection
+     const ghobject_t &oid, ///< [in] object
+     const std::set<std::string> &keys, ///< [in] keys to get
+     std::map<std::string, ceph::buffer::list> *out ///< [out] returned key/values
+   ) = 0;
+   virtual int omap_get_header(
+     ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+     const ghobject_t &oid, ///< [in] Object containing omap
+     ceph::buffer::list *header, ///< [out] omap header
+     bool allow_eio ///< [in] don't assert on eio
+   ) = 0;
+   virtual int omap_get(
+     ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+     const ghobject_t &oid, ///< [in] Object containing omap
+     ceph::buffer::list *header, ///< [out] omap header
+     std::map<std::string, ceph::buffer::list> *out /// < [out] Key to value map
+   ) = 0;
+   virtual int omap_check_keys(
+     ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+     const ghobject_t &oid, ///< [in] Object containing omap
+     const std::set<std::string> &keys, ///< [in] Keys to check
+     std::set<std::string> *out ///< [out] Subset of keys defined on oid
+   ) = 0;
  private:
    std::set<hobject_t> temp_contents;
  public:
index 4ce6c3aa34e13e18c626f80106b7e76fe6a65656..a40dc1b62823a5ae0281a171accffa5b3ca17a99 100644 (file)
@@ -134,6 +134,53 @@ public:
     }
   }
 
+  int omap_iterate(
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const ObjectStore::omap_iter_seek_t &start_from,
+    ///^ [in] where the iterator should point to at the beginning
+    const OmapIterFunction &f ///< [in] function to call for each key/value pair
+  ) override
+  {
+    return store->omap_iterate(c_, oid, start_from, f);
+  }
+  int omap_get_values(
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const std::set<std::string> &keys, ///< [in] keys to get
+    std::map<std::string, ceph::buffer::list> *out ///< [out] returned key/values
+  ) override
+  {
+    return store->omap_get_values(c_, oid, keys, out);
+  }
+  int omap_get_header(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    ceph::buffer::list *header, ///< [out] omap header
+    bool allow_eio ///< [in] don't assert on eio
+  ) override
+  {
+    return store->omap_get_header(c_, oid, header, allow_eio);
+  }
+  int omap_get(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    ceph::buffer::list *header, ///< [out] omap header
+    std::map<std::string, ceph::buffer::list> *out /// < [out] Key to value map
+  ) override
+  {
+    return store->omap_get(c_, oid, header, out);
+  }
+  int omap_check_keys(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    const std::set<std::string> &keys, ///< [in] Keys to check
+    std::set<std::string> *out ///< [out] Subset of keys defined on oid
+  ) override
+  {
+    return store->omap_check_keys(c_, oid, keys, out);
+  }
+
   int objects_read_sync(
     const hobject_t &hoid,
     uint64_t off,
index 09ddd2ae569e53313741009b4d14a43666ad9b26..dc2e5ae242ffaa00dfd3518e442de3e94fe7ca6d 100644 (file)
@@ -145,7 +145,7 @@ typedef interval_set<
 using shard_id_set = bitset_set<128, shard_id_t>;
 WRITE_CLASS_DENC(shard_id_set)
 
-enum class OmapUpdateType {Remove, Insert, RemoveRange};
+enum class OmapUpdateType : uint8_t {Remove, Insert, RemoveRange};
 
 /**
  * osd request identifier
@@ -4079,6 +4079,8 @@ public:
   public:
     virtual void append(uint64_t old_offset) {}
     virtual void setattrs(std::map<std::string, std::optional<ceph::buffer::list>> &attrs) {}
+    virtual void ec_omap(bool clear_omap, std::optional<ceph::buffer::list> omap_header, 
+      std::vector<std::pair<OmapUpdateType, ceph::buffer::list>> &omap_updates) {}
     virtual void rmobject(version_t old_version) {}
     /**
      * Used to support the unfound_lost_delete log event: if the stashed
@@ -4107,7 +4109,8 @@ public:
     CREATE = 4,
     UPDATE_SNAPS = 5,
     TRY_DELETE = 6,
-    ROLLBACK_EXTENTS = 7
+    ROLLBACK_EXTENTS = 7,
+    EC_OMAP = 8
   };
   ObjectModDesc() : can_local_rollback(true), rollback_info_completed(false) {
     bl.reassign_to_mempool(mempool::mempool_osd_pglog);
@@ -4159,6 +4162,18 @@ public:
     encode(old_attrs, bl);
     ENCODE_FINISH(bl);
   }
+  void ec_omap(bool clear_omap, std::optional<ceph::buffer::list> omap_header, 
+    std::vector<std::pair<OmapUpdateType, ceph::buffer::list>> &omap_updates) {
+    if(!can_local_rollback) {
+      return;
+    }
+    ENCODE_START(1, 1, bl);
+    append_id(EC_OMAP);
+    encode(clear_omap, bl);
+    encode(omap_header, bl);
+    encode(omap_updates, bl);
+    ENCODE_FINISH(bl);
+  }
   bool rmobject(version_t deletion_version) {
     if (!can_local_rollback || rollback_info_completed) {
       return false;
index 4153f956d44aa5b6648a20ba13f7a3313c89207b..d0a69655fab622967c5be3518a39ad81052c4539 100644 (file)
@@ -674,6 +674,48 @@ public:
     cb();
   }
 
+  int omap_iterate(
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const ObjectStore::omap_iter_seek_t &start_from,
+    ///^ [in] where the iterator should point to at the beginning
+    const OmapIterFunction &f ///< [in] function to call for each key/value pair
+  ) override {
+    return 0;
+  }
+  int omap_get_values(
+    ObjectStore::CollectionHandle &c_, ///< [in] collection
+    const ghobject_t &oid, ///< [in] object
+    const std::set<std::string> &keys, ///< [in] keys to get
+    std::map<std::string, ceph::buffer::list> *out ///< [out] returned key/values
+  ) override {
+    return 0;
+  }
+  int omap_get_header(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    ceph::buffer::list *header, ///< [out] omap header
+    bool allow_eio ///< [in] don't assert on eio
+  ) override {
+    return 0;
+  }
+  int omap_get(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    ceph::buffer::list *header, ///< [out] omap header
+    std::map<std::string, ceph::buffer::list> *out /// < [out] Key to value map
+  ) override {
+    return 0;
+  }
+  int omap_check_keys(
+    ObjectStore::CollectionHandle &c_, ///< [in] Collection containing oid
+    const ghobject_t &oid, ///< [in] Object containing omap
+    const std::set<std::string> &keys, ///< [in] Keys to check
+    std::set<std::string> *out ///< [out] Subset of keys defined on oid
+  ) override {
+    return 0;
+  }
+
   // Object operations
   int objects_read_sync(
     const hobject_t &hoid,