1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2016 Red Hat
8 * This is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License version 2.1, as published by the Free Software
11 * Foundation. See file COPYING.
15 #include "ExtentCache.h"
17 void ExtentCache::extent::_link_pin_state(pin_state &pin_state)
19 assert(parent_extent_set);
20 assert(!parent_pin_state);
21 parent_pin_state = &pin_state;
22 pin_state.pin_list.push_back(*this);
25 void ExtentCache::extent::_unlink_pin_state()
27 assert(parent_extent_set);
28 assert(parent_pin_state);
29 auto liter = pin_state::list::s_iterator_to(*this);
30 parent_pin_state->pin_list.erase(liter);
31 parent_pin_state = nullptr;
34 void ExtentCache::extent::unlink()
36 assert(parent_extent_set);
37 assert(parent_pin_state);
41 // remove from extent set
43 auto siter = object_extent_set::set::s_iterator_to(*this);
44 auto &set = object_extent_set::set::container_from_iterator(siter);
45 assert(&set == &(parent_extent_set->extent_set));
49 parent_extent_set = nullptr;
50 assert(!parent_pin_state);
53 void ExtentCache::extent::link(
54 object_extent_set &extent_set,
57 assert(!parent_extent_set);
58 parent_extent_set = &extent_set;
59 extent_set.extent_set.insert(*this);
61 _link_pin_state(pin_state);
64 void ExtentCache::extent::move(
71 void ExtentCache::remove_and_destroy_if_empty(object_extent_set &eset)
73 if (eset.extent_set.empty()) {
74 auto siter = cache_set::s_iterator_to(eset);
75 auto &set = cache_set::container_from_iterator(siter);
76 assert(&set == &per_object_caches);
78 // per_object_caches owns eset
79 per_object_caches.erase(eset);
84 ExtentCache::object_extent_set &ExtentCache::get_or_create(
87 cache_set::insert_commit_data data;
88 auto p = per_object_caches.insert_check(oid, Cmp(), data);
90 auto *eset = new object_extent_set(oid);
91 per_object_caches.insert_commit(*eset, data);
98 ExtentCache::object_extent_set *ExtentCache::get_if_exists(
101 cache_set::insert_commit_data data;
102 auto p = per_object_caches.insert_check(oid, Cmp(), data);
111 ExtentCache::object_extent_set::set::iterator,
112 ExtentCache::object_extent_set::set::iterator
113 > ExtentCache::object_extent_set::get_containing_range(
114 uint64_t off, uint64_t len)
116 // fst is first iterator with end after off (may be end)
117 auto fst = extent_set.upper_bound(off, uint_cmp());
118 if (fst != extent_set.begin())
120 if (fst != extent_set.end() && off >= (fst->offset + fst->get_length()))
123 // lst is first iterator with start >= off + len (may be end)
124 auto lst = extent_set.lower_bound(off + len, uint_cmp());
125 return std::make_pair(fst, lst);
128 extent_set ExtentCache::reserve_extents_for_rmw(
129 const hobject_t &oid,
131 const extent_set &to_write,
132 const extent_set &to_read)
134 if (to_write.empty() && to_read.empty()) {
137 extent_set must_read;
138 auto &eset = get_or_create(oid);
140 for (auto &&res: to_write) {
141 eset.traverse_update(
145 [&](uint64_t off, uint64_t len,
146 extent *ext, object_extent_set::update_action *action) {
147 action->action = object_extent_set::update_action::UPDATE_PIN;
149 missing.insert(off, len);
153 must_read.intersection_of(
159 extent_map ExtentCache::get_remaining_extents_for_rmw(
160 const hobject_t &oid,
162 const extent_set &to_get)
164 if (to_get.empty()) {
168 auto &eset = get_or_create(oid);
169 for (auto &&res: to_get) {
171 uint64_t cur = res.first;
172 eset.traverse_update(
176 [&](uint64_t off, uint64_t len,
177 extent *ext, object_extent_set::update_action *action) {
180 action->action = object_extent_set::update_action::NONE;
181 assert(ext && ext->bl && ext->pinned_by_write());
186 ret.insert(off, len, bl);
192 void ExtentCache::present_rmw_update(
193 const hobject_t &oid,
195 const extent_map &extents)
197 if (extents.empty()) {
200 auto &eset = get_or_create(oid);
201 for (auto &&res: extents) {
202 eset.traverse_update(
206 [&](uint64_t off, uint64_t len,
207 extent *ext, object_extent_set::update_action *action) {
208 action->action = object_extent_set::update_action::NONE;
209 assert(ext && ext->pinned_by_write());
210 action->bl = bufferlist();
211 action->bl->substr_of(
219 ostream &ExtentCache::print(ostream &out) const
221 out << "ExtentCache(" << std::endl;
222 for (auto esiter = per_object_caches.begin();
223 esiter != per_object_caches.end();
225 out << " Extents(" << esiter->oid << ")[" << std::endl;
226 for (auto exiter = esiter->extent_set.begin();
227 exiter != esiter->extent_set.end();
229 out << " Extent(" << exiter->offset
230 << "~" << exiter->get_length()
231 << ":" << exiter->pin_tid()
235 return out << ")" << std::endl;
238 ostream &operator<<(ostream &lhs, const ExtentCache &cache)
240 return cache.print(lhs);