Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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 }