]> git.proxmox.com Git - ceph.git/blob - ceph/src/osd/ExtentCache.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / osd / ExtentCache.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2016 Red Hat
7 *
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.
12 *
13 */
14
15 #include "ExtentCache.h"
16
17 void ExtentCache::extent::_link_pin_state(pin_state &pin_state)
18 {
19 assert(parent_extent_set);
20 assert(!parent_pin_state);
21 parent_pin_state = &pin_state;
22 pin_state.pin_list.push_back(*this);
23 }
24
25 void ExtentCache::extent::_unlink_pin_state()
26 {
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;
32 }
33
34 void ExtentCache::extent::unlink()
35 {
36 assert(parent_extent_set);
37 assert(parent_pin_state);
38
39 _unlink_pin_state();
40
41 // remove from extent set
42 {
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));
46 set.erase(siter);
47 }
48
49 parent_extent_set = nullptr;
50 assert(!parent_pin_state);
51 }
52
53 void ExtentCache::extent::link(
54 object_extent_set &extent_set,
55 pin_state &pin_state)
56 {
57 assert(!parent_extent_set);
58 parent_extent_set = &extent_set;
59 extent_set.extent_set.insert(*this);
60
61 _link_pin_state(pin_state);
62 }
63
64 void ExtentCache::extent::move(
65 pin_state &to)
66 {
67 _unlink_pin_state();
68 _link_pin_state(to);
69 }
70
71 void ExtentCache::remove_and_destroy_if_empty(object_extent_set &eset)
72 {
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);
77
78 // per_object_caches owns eset
79 per_object_caches.erase(eset);
80 delete &eset;
81 }
82 }
83
84 ExtentCache::object_extent_set &ExtentCache::get_or_create(
85 const hobject_t &oid)
86 {
87 cache_set::insert_commit_data data;
88 auto p = per_object_caches.insert_check(oid, Cmp(), data);
89 if (p.second) {
90 auto *eset = new object_extent_set(oid);
91 per_object_caches.insert_commit(*eset, data);
92 return *eset;
93 } else {
94 return *(p.first);
95 }
96 }
97
98 ExtentCache::object_extent_set *ExtentCache::get_if_exists(
99 const hobject_t &oid)
100 {
101 cache_set::insert_commit_data data;
102 auto p = per_object_caches.insert_check(oid, Cmp(), data);
103 if (p.second) {
104 return nullptr;
105 } else {
106 return &*(p.first);
107 }
108 }
109
110 std::pair<
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)
115 {
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())
119 --fst;
120 if (fst != extent_set.end() && off >= (fst->offset + fst->get_length()))
121 ++fst;
122
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);
126 }
127
128 extent_set ExtentCache::reserve_extents_for_rmw(
129 const hobject_t &oid,
130 write_pin &pin,
131 const extent_set &to_write,
132 const extent_set &to_read)
133 {
134 if (to_write.empty() && to_read.empty()) {
135 return extent_set();
136 }
137 extent_set must_read;
138 auto &eset = get_or_create(oid);
139 extent_set missing;
140 for (auto &&res: to_write) {
141 eset.traverse_update(
142 pin,
143 res.first,
144 res.second,
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;
148 if (!ext) {
149 missing.insert(off, len);
150 }
151 });
152 }
153 must_read.intersection_of(
154 to_read,
155 missing);
156 return must_read;
157 }
158
159 extent_map ExtentCache::get_remaining_extents_for_rmw(
160 const hobject_t &oid,
161 write_pin &pin,
162 const extent_set &to_get)
163 {
164 if (to_get.empty()) {
165 return extent_map();
166 }
167 extent_map ret;
168 auto &eset = get_or_create(oid);
169 for (auto &&res: to_get) {
170 bufferlist bl;
171 uint64_t cur = res.first;
172 eset.traverse_update(
173 pin,
174 res.first,
175 res.second,
176 [&](uint64_t off, uint64_t len,
177 extent *ext, object_extent_set::update_action *action) {
178 assert(off == cur);
179 cur = off + len;
180 action->action = object_extent_set::update_action::NONE;
181 assert(ext && ext->bl && ext->pinned_by_write());
182 bl.substr_of(
183 *(ext->bl),
184 off - ext->offset,
185 len);
186 ret.insert(off, len, bl);
187 });
188 }
189 return ret;
190 }
191
192 void ExtentCache::present_rmw_update(
193 const hobject_t &oid,
194 write_pin &pin,
195 const extent_map &extents)
196 {
197 if (extents.empty()) {
198 return;
199 }
200 auto &eset = get_or_create(oid);
201 for (auto &&res: extents) {
202 eset.traverse_update(
203 pin,
204 res.get_off(),
205 res.get_len(),
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(
212 res.get_val(),
213 off - res.get_off(),
214 len);
215 });
216 }
217 }
218
219 ostream &ExtentCache::print(ostream &out) const
220 {
221 out << "ExtentCache(" << std::endl;
222 for (auto esiter = per_object_caches.begin();
223 esiter != per_object_caches.end();
224 ++esiter) {
225 out << " Extents(" << esiter->oid << ")[" << std::endl;
226 for (auto exiter = esiter->extent_set.begin();
227 exiter != esiter->extent_set.end();
228 ++exiter) {
229 out << " Extent(" << exiter->offset
230 << "~" << exiter->get_length()
231 << ":" << exiter->pin_tid()
232 << ")" << std::endl;
233 }
234 }
235 return out << ")" << std::endl;
236 }
237
238 ostream &operator<<(ostream &lhs, const ExtentCache &cache)
239 {
240 return cache.print(lhs);
241 }