diff options
Diffstat (limited to 'src/osd/ExtentCache.cc')
-rw-r--r-- | src/osd/ExtentCache.cc | 245 |
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); +} |