initial code repo
[stor4nfv.git] / src / ceph / src / osd / ExtentCache.cc
diff --git a/src/ceph/src/osd/ExtentCache.cc b/src/ceph/src/osd/ExtentCache.cc
new file mode 100644 (file)
index 0000000..5368298
--- /dev/null
@@ -0,0 +1,241 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2016 Red Hat
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation.  See file COPYING.
+ *
+ */
+
+#include "ExtentCache.h"
+
+void ExtentCache::extent::_link_pin_state(pin_state &pin_state)
+{
+  assert(parent_extent_set);
+  assert(!parent_pin_state);
+  parent_pin_state = &pin_state;
+  pin_state.pin_list.push_back(*this);
+}
+
+void ExtentCache::extent::_unlink_pin_state()
+{
+  assert(parent_extent_set);
+  assert(parent_pin_state);
+  auto liter = pin_state::list::s_iterator_to(*this);
+  parent_pin_state->pin_list.erase(liter);
+  parent_pin_state = nullptr;
+}
+
+void ExtentCache::extent::unlink()
+{
+  assert(parent_extent_set);
+  assert(parent_pin_state);
+
+  _unlink_pin_state();
+
+  // remove from extent set
+  {
+    auto siter = object_extent_set::set::s_iterator_to(*this);
+    auto &set = object_extent_set::set::container_from_iterator(siter);
+    assert(&set == &(parent_extent_set->extent_set));
+    set.erase(siter);
+  }
+
+  parent_extent_set = nullptr;
+  assert(!parent_pin_state);
+}
+
+void ExtentCache::extent::link(
+  object_extent_set &extent_set,
+  pin_state &pin_state)
+{
+  assert(!parent_extent_set);
+  parent_extent_set = &extent_set;
+  extent_set.extent_set.insert(*this);
+
+  _link_pin_state(pin_state);
+}
+
+void ExtentCache::extent::move(
+  pin_state &to)
+{
+  _unlink_pin_state();
+  _link_pin_state(to);
+}
+
+void ExtentCache::remove_and_destroy_if_empty(object_extent_set &eset)
+{
+  if (eset.extent_set.empty()) {
+    auto siter = cache_set::s_iterator_to(eset);
+    auto &set = cache_set::container_from_iterator(siter);
+    assert(&set == &per_object_caches);
+
+    // per_object_caches owns eset
+    per_object_caches.erase(eset);
+    delete &eset;
+  }
+}
+
+ExtentCache::object_extent_set &ExtentCache::get_or_create(
+  const hobject_t &oid)
+{
+  cache_set::insert_commit_data data;
+  auto p = per_object_caches.insert_check(oid, Cmp(), data);
+  if (p.second) {
+    auto *eset = new object_extent_set(oid);
+    per_object_caches.insert_commit(*eset, data);
+    return *eset;
+  } else {
+    return *(p.first);
+  }
+}
+
+ExtentCache::object_extent_set *ExtentCache::get_if_exists(
+  const hobject_t &oid)
+{
+  cache_set::insert_commit_data data;
+  auto p = per_object_caches.insert_check(oid, Cmp(), data);
+  if (p.second) {
+    return nullptr;
+  } else {
+    return &*(p.first);
+  }
+}
+
+std::pair<
+  ExtentCache::object_extent_set::set::iterator,
+  ExtentCache::object_extent_set::set::iterator
+  > ExtentCache::object_extent_set::get_containing_range(
+    uint64_t off, uint64_t len)
+{
+  // fst is first iterator with end after off (may be end)
+  auto fst = extent_set.upper_bound(off, uint_cmp());
+  if (fst != extent_set.begin())
+    --fst;
+  if (fst != extent_set.end() && off >= (fst->offset + fst->get_length()))
+    ++fst;
+
+  // lst is first iterator with start >= off + len (may be end)
+  auto lst = extent_set.lower_bound(off + len, uint_cmp());
+  return std::make_pair(fst, lst);
+}
+
+extent_set ExtentCache::reserve_extents_for_rmw(
+  const hobject_t &oid,
+  write_pin &pin,
+  const extent_set &to_write,
+  const extent_set &to_read)
+{
+  if (to_write.empty() && to_read.empty()) {
+    return extent_set();
+  }
+  extent_set must_read;
+  auto &eset = get_or_create(oid);
+  extent_set missing;
+  for (auto &&res: to_write) {
+    eset.traverse_update(
+      pin,
+      res.first,
+      res.second,
+      [&](uint64_t off, uint64_t len,
+         extent *ext, object_extent_set::update_action *action) {
+       action->action = object_extent_set::update_action::UPDATE_PIN;
+       if (!ext) {
+         missing.insert(off, len);
+       }
+      });
+  }
+  must_read.intersection_of(
+    to_read,
+    missing);
+  return must_read;
+}
+
+extent_map ExtentCache::get_remaining_extents_for_rmw(
+  const hobject_t &oid,
+  write_pin &pin,
+  const extent_set &to_get)
+{
+  if (to_get.empty()) {
+    return extent_map();
+  }
+  extent_map ret;
+  auto &eset = get_or_create(oid);
+  for (auto &&res: to_get) {
+    bufferlist bl;
+    uint64_t cur = res.first;
+    eset.traverse_update(
+      pin,
+      res.first,
+      res.second,
+      [&](uint64_t off, uint64_t len,
+         extent *ext, object_extent_set::update_action *action) {
+       assert(off == cur);
+       cur = off + len;
+       action->action = object_extent_set::update_action::NONE;
+       assert(ext && ext->bl && ext->pinned_by_write());
+       bl.substr_of(
+         *(ext->bl),
+         off - ext->offset,
+         len);
+       ret.insert(off, len, bl);
+      });
+  }
+  return ret;
+}
+
+void ExtentCache::present_rmw_update(
+  const hobject_t &oid,
+  write_pin &pin,
+  const extent_map &extents)
+{
+  if (extents.empty()) {
+    return;
+  }
+  auto &eset = get_or_create(oid);
+  for (auto &&res: extents) {
+    eset.traverse_update(
+      pin,
+      res.get_off(),
+      res.get_len(),
+      [&](uint64_t off, uint64_t len,
+         extent *ext, object_extent_set::update_action *action) {
+       action->action = object_extent_set::update_action::NONE;
+       assert(ext && ext->pinned_by_write());
+       action->bl = bufferlist();
+       action->bl->substr_of(
+         res.get_val(),
+         off - res.get_off(),
+         len);
+      });
+  }
+}
+
+ostream &ExtentCache::print(ostream &out) const
+{
+  out << "ExtentCache(" << std::endl;
+  for (auto esiter = per_object_caches.begin();
+       esiter != per_object_caches.end();
+       ++esiter) {
+    out << "  Extents(" << esiter->oid << ")[" << std::endl;
+    for (auto exiter = esiter->extent_set.begin();
+        exiter != esiter->extent_set.end();
+        ++exiter) {
+      out << "    Extent(" << exiter->offset
+         << "~" << exiter->get_length()
+         << ":" << exiter->pin_tid()
+         << ")" << std::endl;
+    }
+  }
+  return out << ")" << std::endl;
+}
+
+ostream &operator<<(ostream &lhs, const ExtentCache &cache)
+{
+  return cache.print(lhs);
+}