summaryrefslogtreecommitdiffstats
path: root/src/osd/ExtentCache.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/ExtentCache.cc')
-rw-r--r--src/osd/ExtentCache.cc245
1 files changed, 245 insertions, 0 deletions
diff --git a/src/osd/ExtentCache.cc b/src/osd/ExtentCache.cc
new file mode 100644
index 000000000..3a8bbf11b
--- /dev/null
+++ b/src/osd/ExtentCache.cc
@@ -0,0 +1,245 @@
+// -*- 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"
+
+using std::ostream;
+
+using ceph::bufferlist;
+
+void ExtentCache::extent::_link_pin_state(pin_state &pin_state)
+{
+ ceph_assert(parent_extent_set);
+ ceph_assert(!parent_pin_state);
+ parent_pin_state = &pin_state;
+ pin_state.pin_list.push_back(*this);
+}
+
+void ExtentCache::extent::_unlink_pin_state()
+{
+ ceph_assert(parent_extent_set);
+ ceph_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()
+{
+ ceph_assert(parent_extent_set);
+ ceph_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);
+ ceph_assert(&set == &(parent_extent_set->extent_set));
+ set.erase(siter);
+ }
+
+ parent_extent_set = nullptr;
+ ceph_assert(!parent_pin_state);
+}
+
+void ExtentCache::extent::link(
+ object_extent_set &extent_set,
+ pin_state &pin_state)
+{
+ ceph_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);
+ ceph_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) {
+ ceph_assert(off == cur);
+ cur = off + len;
+ action->action = object_extent_set::update_action::NONE;
+ ceph_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;
+ ceph_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);
+}