]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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) 2004-2006 Sage Weil <sage@newdream.net> | |
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 "SnapRealm.h" | |
16 | #include "MDCache.h" | |
17 | #include "MDSRank.h" | |
11fdf7f2 | 18 | #include "SnapClient.h" |
7c673cae | 19 | |
11fdf7f2 | 20 | #include <string_view> |
7c673cae FG |
21 | |
22 | ||
23 | /* | |
24 | * SnapRealm | |
25 | */ | |
26 | ||
27 | #define dout_context g_ceph_context | |
28 | #define dout_subsys ceph_subsys_mds | |
29 | #undef dout_prefix | |
30 | #define dout_prefix _prefix(_dout, mdcache->mds->get_nodeid(), inode, srnode.seq, this) | |
20effc67 TL |
31 | |
32 | using namespace std; | |
33 | ||
34 | static std::ostream& _prefix(std::ostream *_dout, int whoami, const CInode *inode, | |
35 | uint64_t seq, const SnapRealm *realm) { | |
7c673cae FG |
36 | return *_dout << " mds." << whoami |
37 | << ".cache.snaprealm(" << inode->ino() | |
38 | << " seq " << seq << " " << realm << ") "; | |
39 | } | |
40 | ||
41 | ostream& operator<<(ostream& out, const SnapRealm& realm) | |
42 | { | |
43 | out << "snaprealm(" << realm.inode->ino() | |
44 | << " seq " << realm.srnode.seq | |
45 | << " lc " << realm.srnode.last_created | |
46 | << " cr " << realm.srnode.created; | |
47 | if (realm.srnode.created != realm.srnode.current_parent_since) | |
48 | out << " cps " << realm.srnode.current_parent_since; | |
49 | out << " snaps=" << realm.srnode.snaps; | |
11fdf7f2 TL |
50 | out << " past_parent_snaps=" << realm.srnode.past_parent_snaps; |
51 | ||
11fdf7f2 TL |
52 | if (realm.srnode.is_parent_global()) |
53 | out << " global "; | |
7c673cae FG |
54 | out << " " << &realm << ")"; |
55 | return out; | |
56 | } | |
57 | ||
11fdf7f2 | 58 | SnapRealm::SnapRealm(MDCache *c, CInode *in) : |
f67539c2 | 59 | mdcache(c), inode(in), inodes_with_caps(member_offset(CInode, item_caps)) |
11fdf7f2 | 60 | { |
b3b6e05e | 61 | global = (inode->ino() == CEPH_INO_GLOBAL_SNAPREALM); |
11fdf7f2 | 62 | } |
7c673cae | 63 | |
7c673cae FG |
64 | /* |
65 | * get list of snaps for this realm. we must include parents' snaps | |
66 | * for the intervals during which they were our parent. | |
67 | */ | |
11fdf7f2 | 68 | void SnapRealm::build_snap_set() const |
7c673cae | 69 | { |
11fdf7f2 | 70 | dout(10) << "build_snap_set on " << *this << dendl; |
7c673cae | 71 | |
11fdf7f2 | 72 | cached_snaps.clear(); |
7c673cae | 73 | |
11fdf7f2 TL |
74 | if (global) { |
75 | mdcache->mds->snapclient->get_snaps(cached_snaps); | |
76 | return; | |
77 | } | |
7c673cae | 78 | |
11fdf7f2 TL |
79 | // include my snaps |
80 | for (const auto& p : srnode.snaps) | |
81 | cached_snaps.insert(p.first); | |
82 | ||
83 | if (!srnode.past_parent_snaps.empty()) { | |
84 | set<snapid_t> snaps = mdcache->mds->snapclient->filter(srnode.past_parent_snaps); | |
85 | if (!snaps.empty()) { | |
86 | snapid_t last = *snaps.rbegin(); | |
87 | cached_seq = std::max(cached_seq, last); | |
88 | cached_last_created = std::max(cached_last_created, last); | |
89 | } | |
90 | cached_snaps.insert(snaps.begin(), snaps.end()); | |
7c673cae | 91 | } |
7c673cae | 92 | |
11fdf7f2 TL |
93 | snapid_t parent_seq = parent ? parent->get_newest_seq() : snapid_t(0); |
94 | if (parent_seq >= srnode.current_parent_since) { | |
95 | auto& snaps = parent->get_snaps(); | |
96 | auto p = snaps.lower_bound(srnode.current_parent_since); | |
97 | cached_snaps.insert(p, snaps.end()); | |
98 | cached_seq = std::max(cached_seq, parent_seq); | |
99 | cached_last_created = std::max(cached_last_created, parent->get_last_created()); | |
100 | } | |
101 | } | |
7c673cae FG |
102 | |
103 | void SnapRealm::check_cache() const | |
104 | { | |
11fdf7f2 TL |
105 | snapid_t seq; |
106 | snapid_t last_created; | |
107 | snapid_t last_destroyed = mdcache->mds->snapclient->get_last_destroyed(); | |
108 | if (global || srnode.is_parent_global()) { | |
109 | last_created = mdcache->mds->snapclient->get_last_created(); | |
110 | seq = std::max(last_created, last_destroyed); | |
111 | } else { | |
112 | last_created = srnode.last_created; | |
113 | seq = srnode.seq; | |
114 | } | |
115 | if (cached_seq >= seq && | |
116 | cached_last_destroyed == last_destroyed) | |
7c673cae FG |
117 | return; |
118 | ||
7c673cae FG |
119 | cached_snap_context.clear(); |
120 | ||
11fdf7f2 TL |
121 | cached_seq = seq; |
122 | cached_last_created = last_created; | |
123 | cached_last_destroyed = last_destroyed; | |
adb31ebb TL |
124 | |
125 | cached_subvolume_ino = 0; | |
126 | if (parent) | |
127 | cached_subvolume_ino = parent->get_subvolume_ino(); | |
128 | if (!cached_subvolume_ino && srnode.is_subvolume()) | |
129 | cached_subvolume_ino = inode->ino(); | |
130 | ||
11fdf7f2 | 131 | build_snap_set(); |
7c673cae | 132 | |
11fdf7f2 | 133 | build_snap_trace(); |
7c673cae FG |
134 | |
135 | dout(10) << "check_cache rebuilt " << cached_snaps | |
11fdf7f2 | 136 | << " seq " << seq |
7c673cae FG |
137 | << " cached_seq " << cached_seq |
138 | << " cached_last_created " << cached_last_created | |
139 | << " cached_last_destroyed " << cached_last_destroyed | |
140 | << ")" << dendl; | |
141 | } | |
142 | ||
143 | const set<snapid_t>& SnapRealm::get_snaps() const | |
144 | { | |
145 | check_cache(); | |
146 | dout(10) << "get_snaps " << cached_snaps | |
147 | << " (seq " << srnode.seq << " cached_seq " << cached_seq << ")" | |
148 | << dendl; | |
149 | return cached_snaps; | |
150 | } | |
151 | ||
152 | /* | |
153 | * build vector in reverse sorted order | |
154 | */ | |
155 | const SnapContext& SnapRealm::get_snap_context() const | |
156 | { | |
157 | check_cache(); | |
158 | ||
159 | if (!cached_snap_context.seq) { | |
160 | cached_snap_context.seq = cached_seq; | |
161 | cached_snap_context.snaps.resize(cached_snaps.size()); | |
162 | unsigned i = 0; | |
163 | for (set<snapid_t>::reverse_iterator p = cached_snaps.rbegin(); | |
164 | p != cached_snaps.rend(); | |
165 | ++p) | |
166 | cached_snap_context.snaps[i++] = *p; | |
167 | } | |
168 | ||
169 | return cached_snap_context; | |
170 | } | |
171 | ||
11fdf7f2 | 172 | void SnapRealm::get_snap_info(map<snapid_t, const SnapInfo*>& infomap, snapid_t first, snapid_t last) |
7c673cae FG |
173 | { |
174 | const set<snapid_t>& snaps = get_snaps(); | |
175 | dout(10) << "get_snap_info snaps " << snaps << dendl; | |
176 | ||
177 | // include my snaps within interval [first,last] | |
11fdf7f2 | 178 | for (auto p = srnode.snaps.lower_bound(first); // first element >= first |
7c673cae FG |
179 | p != srnode.snaps.end() && p->first <= last; |
180 | ++p) | |
181 | infomap[p->first] = &p->second; | |
182 | ||
11fdf7f2 TL |
183 | if (!srnode.past_parent_snaps.empty()) { |
184 | set<snapid_t> snaps; | |
185 | for (auto p = srnode.past_parent_snaps.lower_bound(first); // first element >= first | |
186 | p != srnode.past_parent_snaps.end() && *p <= last; | |
187 | ++p) { | |
188 | snaps.insert(*p); | |
189 | } | |
190 | ||
191 | map<snapid_t, const SnapInfo*> _infomap; | |
192 | mdcache->mds->snapclient->get_snap_infos(_infomap, snaps); | |
193 | infomap.insert(_infomap.begin(), _infomap.end()); | |
7c673cae | 194 | } |
11fdf7f2 | 195 | |
7c673cae | 196 | if (srnode.current_parent_since <= last && parent) |
11fdf7f2 | 197 | parent->get_snap_info(infomap, std::max(first, srnode.current_parent_since), last); |
7c673cae FG |
198 | } |
199 | ||
11fdf7f2 | 200 | std::string_view SnapRealm::get_snapname(snapid_t snapid, inodeno_t atino) |
7c673cae FG |
201 | { |
202 | auto srnode_snaps_entry = srnode.snaps.find(snapid); | |
203 | if (srnode_snaps_entry != srnode.snaps.end()) { | |
204 | if (atino == inode->ino()) | |
205 | return srnode_snaps_entry->second.name; | |
206 | else | |
207 | return srnode_snaps_entry->second.get_long_name(); | |
208 | } | |
209 | ||
11fdf7f2 TL |
210 | if (!srnode.past_parent_snaps.empty()) { |
211 | if (srnode.past_parent_snaps.count(snapid)) { | |
212 | const SnapInfo *sinfo = mdcache->mds->snapclient->get_snap_info(snapid); | |
213 | if (sinfo) { | |
214 | if (atino == sinfo->ino) | |
215 | return sinfo->name; | |
216 | else | |
217 | return sinfo->get_long_name(); | |
218 | } | |
219 | } | |
7c673cae FG |
220 | } |
221 | ||
11fdf7f2 TL |
222 | ceph_assert(srnode.current_parent_since <= snapid); |
223 | ceph_assert(parent); | |
7c673cae FG |
224 | return parent->get_snapname(snapid, atino); |
225 | } | |
226 | ||
11fdf7f2 | 227 | snapid_t SnapRealm::resolve_snapname(std::string_view n, inodeno_t atino, snapid_t first, snapid_t last) |
7c673cae FG |
228 | { |
229 | // first try me | |
230 | dout(10) << "resolve_snapname '" << n << "' in [" << first << "," << last << "]" << dendl; | |
231 | ||
7c673cae FG |
232 | bool actual = (atino == inode->ino()); |
233 | string pname; | |
234 | inodeno_t pino; | |
11fdf7f2 | 235 | if (n.length() && n[0] == '_') { |
81eedcae TL |
236 | size_t next_ = n.find_last_of('_'); |
237 | if (next_ > 1 && next_ + 1 < n.length()) { | |
11fdf7f2 TL |
238 | pname = n.substr(1, next_ - 1); |
239 | pino = atoll(n.data() + next_ + 1); | |
240 | dout(10) << " " << n << " parses to name '" << pname << "' dirino " << pino << dendl; | |
241 | } | |
7c673cae FG |
242 | } |
243 | ||
11fdf7f2 | 244 | for (auto p = srnode.snaps.lower_bound(first); // first element >= first |
7c673cae FG |
245 | p != srnode.snaps.end() && p->first <= last; |
246 | ++p) { | |
247 | dout(15) << " ? " << p->second << dendl; | |
248 | //if (num && p->second.snapid == num) | |
249 | //return p->first; | |
250 | if (actual && p->second.name == n) | |
251 | return p->first; | |
252 | if (!actual && p->second.name == pname && p->second.ino == pino) | |
253 | return p->first; | |
254 | } | |
255 | ||
11fdf7f2 TL |
256 | if (!srnode.past_parent_snaps.empty()) { |
257 | set<snapid_t> snaps; | |
258 | for (auto p = srnode.past_parent_snaps.lower_bound(first); // first element >= first | |
259 | p != srnode.past_parent_snaps.end() && *p <= last; | |
260 | ++p) | |
261 | snaps.insert(*p); | |
262 | ||
263 | map<snapid_t, const SnapInfo*> _infomap; | |
264 | mdcache->mds->snapclient->get_snap_infos(_infomap, snaps); | |
265 | ||
266 | for (auto& it : _infomap) { | |
267 | dout(15) << " ? " << *it.second << dendl; | |
268 | actual = (it.second->ino == atino); | |
269 | if (actual && it.second->name == n) | |
270 | return it.first; | |
271 | if (!actual && it.second->name == pname && it.second->ino == pino) | |
272 | return it.first; | |
273 | } | |
7c673cae | 274 | } |
11fdf7f2 | 275 | |
7c673cae | 276 | if (parent && srnode.current_parent_since <= last) |
11fdf7f2 | 277 | return parent->resolve_snapname(n, atino, std::max(first, srnode.current_parent_since), last); |
7c673cae FG |
278 | return 0; |
279 | } | |
280 | ||
281 | ||
282 | void SnapRealm::adjust_parent() | |
283 | { | |
11fdf7f2 TL |
284 | SnapRealm *newparent; |
285 | if (srnode.is_parent_global()) { | |
286 | newparent = mdcache->get_global_snaprealm(); | |
287 | } else { | |
288 | CDentry *pdn = inode->get_parent_dn(); | |
289 | newparent = pdn ? pdn->get_dir()->get_inode()->find_snaprealm() : NULL; | |
290 | } | |
7c673cae FG |
291 | if (newparent != parent) { |
292 | dout(10) << "adjust_parent " << parent << " -> " << newparent << dendl; | |
293 | if (parent) | |
294 | parent->open_children.erase(this); | |
295 | parent = newparent; | |
296 | if (parent) | |
297 | parent->open_children.insert(this); | |
298 | ||
299 | invalidate_cached_snaps(); | |
300 | } | |
301 | } | |
302 | ||
303 | void SnapRealm::split_at(SnapRealm *child) | |
304 | { | |
305 | dout(10) << "split_at " << *child | |
306 | << " on " << *child->inode << dendl; | |
307 | ||
308 | if (inode->is_mdsdir() || !child->inode->is_dir()) { | |
309 | // it's not a dir. | |
310 | if (child->inode->containing_realm) { | |
311 | // - no open children. | |
312 | // - only need to move this child's inode's caps. | |
313 | child->inode->move_to_realm(child); | |
314 | } else { | |
315 | // no caps, nothing to move/split. | |
316 | dout(20) << " split no-op, no caps to move on file " << *child->inode << dendl; | |
11fdf7f2 | 317 | ceph_assert(!child->inode->is_any_caps()); |
7c673cae FG |
318 | } |
319 | return; | |
320 | } | |
321 | ||
322 | // it's a dir. | |
323 | ||
324 | // split open_children | |
325 | dout(10) << " open_children are " << open_children << dendl; | |
326 | for (set<SnapRealm*>::iterator p = open_children.begin(); | |
327 | p != open_children.end(); ) { | |
328 | SnapRealm *realm = *p; | |
329 | if (realm != child && | |
11fdf7f2 | 330 | child->inode->is_ancestor_of(realm->inode)) { |
7c673cae FG |
331 | dout(20) << " child gets child realm " << *realm << " on " << *realm->inode << dendl; |
332 | realm->parent = child; | |
333 | child->open_children.insert(realm); | |
334 | open_children.erase(p++); | |
335 | } else { | |
336 | dout(20) << " keeping child realm " << *realm << " on " << *realm->inode << dendl; | |
337 | ++p; | |
338 | } | |
339 | } | |
340 | ||
341 | // split inodes_with_caps | |
f67539c2 | 342 | for (auto p = inodes_with_caps.begin(); !p.end(); ) { |
7c673cae FG |
343 | CInode *in = *p; |
344 | ++p; | |
7c673cae | 345 | // does inode fall within the child realm? |
11fdf7f2 | 346 | if (child->inode->is_ancestor_of(in)) { |
7c673cae FG |
347 | dout(20) << " child gets " << *in << dendl; |
348 | in->move_to_realm(child); | |
349 | } else { | |
350 | dout(20) << " keeping " << *in << dendl; | |
351 | } | |
352 | } | |
11fdf7f2 TL |
353 | } |
354 | ||
355 | void SnapRealm::merge_to(SnapRealm *newparent) | |
356 | { | |
357 | if (!newparent) | |
358 | newparent = parent; | |
359 | dout(10) << "merge to " << *newparent << " on " << *newparent->inode << dendl; | |
360 | ||
11fdf7f2 TL |
361 | dout(10) << " open_children are " << open_children << dendl; |
362 | for (auto realm : open_children) { | |
363 | dout(20) << " child realm " << *realm << " on " << *realm->inode << dendl; | |
364 | newparent->open_children.insert(realm); | |
365 | realm->parent = newparent; | |
366 | } | |
367 | open_children.clear(); | |
368 | ||
f67539c2 | 369 | for (auto p = inodes_with_caps.begin(); !p.end(); ) { |
11fdf7f2 TL |
370 | CInode *in = *p; |
371 | ++p; | |
372 | in->move_to_realm(newparent); | |
373 | } | |
374 | ceph_assert(inodes_with_caps.empty()); | |
7c673cae | 375 | |
11fdf7f2 TL |
376 | // delete this |
377 | inode->close_snaprealm(); | |
7c673cae FG |
378 | } |
379 | ||
11fdf7f2 | 380 | const bufferlist& SnapRealm::get_snap_trace() const |
7c673cae FG |
381 | { |
382 | check_cache(); | |
383 | return cached_snap_trace; | |
384 | } | |
385 | ||
11fdf7f2 | 386 | void SnapRealm::build_snap_trace() const |
7c673cae | 387 | { |
11fdf7f2 TL |
388 | cached_snap_trace.clear(); |
389 | ||
390 | if (global) { | |
391 | SnapRealmInfo info(inode->ino(), 0, cached_seq, 0); | |
392 | info.my_snaps.reserve(cached_snaps.size()); | |
393 | for (auto p = cached_snaps.rbegin(); p != cached_snaps.rend(); ++p) | |
394 | info.my_snaps.push_back(*p); | |
7c673cae | 395 | |
11fdf7f2 TL |
396 | dout(10) << "build_snap_trace my_snaps " << info.my_snaps << dendl; |
397 | encode(info, cached_snap_trace); | |
398 | return; | |
399 | } | |
400 | ||
401 | SnapRealmInfo info(inode->ino(), srnode.created, srnode.seq, srnode.current_parent_since); | |
7c673cae FG |
402 | if (parent) { |
403 | info.h.parent = parent->inode->ino(); | |
11fdf7f2 TL |
404 | |
405 | set<snapid_t> past; | |
406 | if (!srnode.past_parent_snaps.empty()) { | |
407 | past = mdcache->mds->snapclient->filter(srnode.past_parent_snaps); | |
408 | if (srnode.is_parent_global()) { | |
409 | auto p = past.lower_bound(srnode.current_parent_since); | |
410 | past.erase(p, past.end()); | |
411 | } | |
11fdf7f2 TL |
412 | } |
413 | ||
414 | if (!past.empty()) { | |
7c673cae FG |
415 | info.prior_parent_snaps.reserve(past.size()); |
416 | for (set<snapid_t>::reverse_iterator p = past.rbegin(); p != past.rend(); ++p) | |
417 | info.prior_parent_snaps.push_back(*p); | |
11fdf7f2 | 418 | dout(10) << "build_snap_trace prior_parent_snaps from [1," << *past.rbegin() << "] " |
7c673cae FG |
419 | << info.prior_parent_snaps << dendl; |
420 | } | |
11fdf7f2 | 421 | } |
7c673cae FG |
422 | |
423 | info.my_snaps.reserve(srnode.snaps.size()); | |
11fdf7f2 | 424 | for (auto p = srnode.snaps.rbegin(); |
7c673cae FG |
425 | p != srnode.snaps.rend(); |
426 | ++p) | |
427 | info.my_snaps.push_back(p->first); | |
428 | dout(10) << "build_snap_trace my_snaps " << info.my_snaps << dendl; | |
429 | ||
11fdf7f2 | 430 | encode(info, cached_snap_trace); |
7c673cae FG |
431 | |
432 | if (parent) | |
11fdf7f2 | 433 | cached_snap_trace.append(parent->get_snap_trace()); |
7c673cae FG |
434 | } |
435 | ||
f67539c2 | 436 | void SnapRealm::prune_past_parent_snaps() |
7c673cae | 437 | { |
f67539c2 | 438 | dout(10) << __func__ << dendl; |
7c673cae | 439 | check_cache(); |
11fdf7f2 | 440 | |
11fdf7f2 TL |
441 | for (auto p = srnode.past_parent_snaps.begin(); |
442 | p != srnode.past_parent_snaps.end(); ) { | |
443 | auto q = cached_snaps.find(*p); | |
444 | if (q == cached_snaps.end()) { | |
f67539c2 | 445 | dout(10) << __func__ << " pruning " << *p << dendl; |
11fdf7f2 | 446 | srnode.past_parent_snaps.erase(p++); |
7c673cae | 447 | } else { |
f67539c2 | 448 | dout(10) << __func__ << " keeping " << *p << dendl; |
7c673cae FG |
449 | ++p; |
450 | } | |
451 | } | |
452 | } | |
453 |