]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/SnapRealm.cc
import 15.2.9
[ceph.git] / ceph / src / mds / SnapRealm.cc
CommitLineData
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)
31static ostream& _prefix(std::ostream *_dout, int whoami, const CInode *inode,
32 uint64_t seq, const SnapRealm *realm) {
33 return *_dout << " mds." << whoami
34 << ".cache.snaprealm(" << inode->ino()
35 << " seq " << seq << " " << realm << ") ";
36}
37
38ostream& operator<<(ostream& out, const SnapRealm& realm)
39{
40 out << "snaprealm(" << realm.inode->ino()
41 << " seq " << realm.srnode.seq
42 << " lc " << realm.srnode.last_created
43 << " cr " << realm.srnode.created;
44 if (realm.srnode.created != realm.srnode.current_parent_since)
45 out << " cps " << realm.srnode.current_parent_since;
46 out << " snaps=" << realm.srnode.snaps;
11fdf7f2
TL
47 out << " past_parent_snaps=" << realm.srnode.past_parent_snaps;
48
7c673cae
FG
49 if (realm.srnode.past_parents.size()) {
50 out << " past_parents=(";
51 for (map<snapid_t, snaplink_t>::const_iterator p = realm.srnode.past_parents.begin();
52 p != realm.srnode.past_parents.end();
53 ++p) {
54 if (p != realm.srnode.past_parents.begin()) out << ",";
55 out << p->second.first << "-" << p->first
56 << "=" << p->second.ino;
57 }
58 out << ")";
59 }
11fdf7f2
TL
60
61 if (realm.srnode.is_parent_global())
62 out << " global ";
7c673cae
FG
63 out << " " << &realm << ")";
64 return out;
65}
66
11fdf7f2 67SnapRealm::SnapRealm(MDCache *c, CInode *in) :
9f95a23c 68 mdcache(c), inode(in)
11fdf7f2
TL
69{
70 global = (inode->ino() == MDS_INO_GLOBAL_SNAPREALM);
71}
7c673cae
FG
72
73void SnapRealm::add_open_past_parent(SnapRealm *parent, snapid_t last)
74{
75 auto p = open_past_parents.find(parent->inode->ino());
76 if (p != open_past_parents.end()) {
11fdf7f2 77 ceph_assert(p->second.second.count(last) == 0);
7c673cae
FG
78 p->second.second.insert(last);
79 } else {
80 open_past_parents[parent->inode->ino()].first = parent;
81 open_past_parents[parent->inode->ino()].second.insert(last);
82 parent->open_past_children.insert(this);
83 parent->inode->get(CInode::PIN_PASTSNAPPARENT);
84 }
85 ++num_open_past_parents;
86}
87
88void SnapRealm::remove_open_past_parent(inodeno_t ino, snapid_t last)
89{
90 auto p = open_past_parents.find(ino);
11fdf7f2 91 ceph_assert(p != open_past_parents.end());
7c673cae 92 auto q = p->second.second.find(last);
11fdf7f2 93 ceph_assert(q != p->second.second.end());
7c673cae
FG
94 p->second.second.erase(q);
95 --num_open_past_parents;
96 if (p->second.second.empty()) {
97 SnapRealm *parent = p->second.first;
98 open_past_parents.erase(p);
99 parent->open_past_children.erase(this);
100 parent->inode->put(CInode::PIN_PASTSNAPPARENT);
101 }
102}
103
11fdf7f2 104struct C_SR_RetryOpenParents : public MDSContext {
7c673cae
FG
105 SnapRealm *sr;
106 snapid_t first, last, parent_last;
107 inodeno_t parent;
11fdf7f2 108 MDSContext* fin;
7c673cae 109 C_SR_RetryOpenParents(SnapRealm *s, snapid_t f, snapid_t l, snapid_t pl,
11fdf7f2 110 inodeno_t p, MDSContext *c) :
7c673cae
FG
111 sr(s), first(f), last(l), parent_last(pl), parent(p), fin(c) {
112 sr->inode->get(CInode::PIN_OPENINGSNAPPARENTS);
113 }
114 MDSRank *get_mds() override { return sr->mdcache->mds; }
115 void finish(int r) override {
116 if (r < 0)
117 sr->_remove_missing_parent(parent_last, parent, r);
11fdf7f2
TL
118 if (sr->_open_parents(fin, first, last)) {
119 if (fin)
120 fin->complete(0);
121 }
7c673cae
FG
122 sr->inode->put(CInode::PIN_OPENINGSNAPPARENTS);
123 }
124};
125
126void SnapRealm::_remove_missing_parent(snapid_t snapid, inodeno_t parent, int err)
127{
128 map<snapid_t, snaplink_t>::iterator p = srnode.past_parents.find(snapid);
129 if (p != srnode.past_parents.end()) {
130 dout(10) << __func__ << " " << parent << " [" << p->second.first << ","
131 << p->first << "] errno " << err << dendl;
132 srnode.past_parents.erase(p);
11fdf7f2 133 past_parents_dirty = true;
7c673cae
FG
134 } else {
135 dout(10) << __func__ << " " << parent << " not found" << dendl;
136 }
137}
138
11fdf7f2 139bool SnapRealm::_open_parents(MDSContext *finish, snapid_t first, snapid_t last)
7c673cae
FG
140{
141 dout(10) << "open_parents [" << first << "," << last << "]" << dendl;
142 if (open)
143 return true;
144
145 // make sure my current parents' parents are open...
146 if (parent) {
147 dout(10) << " current parent [" << srnode.current_parent_since << ",head] is " << *parent
148 << " on " << *parent->inode << dendl;
149 if (last >= srnode.current_parent_since &&
11fdf7f2 150 !parent->_open_parents(finish, std::max(first, srnode.current_parent_since), last))
7c673cae
FG
151 return false;
152 }
153
11fdf7f2
TL
154 if (!srnode.past_parent_snaps.empty())
155 ceph_assert(mdcache->mds->snapclient->get_cached_version() > 0);
156
157 if (!srnode.past_parents.empty() &&
158 mdcache->mds->allows_multimds_snaps()) {
159 dout(10) << " skip non-empty past_parents since multimds_snaps is allowed" << dendl;
160 open = true;
161 return true;
162 }
163
7c673cae 164 // and my past parents too!
11fdf7f2 165 ceph_assert(srnode.past_parents.size() >= num_open_past_parents);
7c673cae
FG
166 if (srnode.past_parents.size() > num_open_past_parents) {
167 for (map<snapid_t, snaplink_t>::iterator p = srnode.past_parents.begin();
168 p != srnode.past_parents.end(); ) {
169 dout(10) << " past_parent [" << p->second.first << "," << p->first << "] is "
170 << p->second.ino << dendl;
171 CInode *parent = mdcache->get_inode(p->second.ino);
172 if (!parent) {
173 C_SR_RetryOpenParents *fin = new C_SR_RetryOpenParents(this, first, last, p->first,
174 p->second.ino, finish);
175 mdcache->open_ino(p->second.ino, mdcache->mds->mdsmap->get_metadata_pool(), fin);
176 return false;
177 }
178 if (parent->state_test(CInode::STATE_PURGING)) {
179 dout(10) << " skip purging past_parent " << *parent << dendl;
180 srnode.past_parents.erase(p++);
11fdf7f2 181 past_parents_dirty = true;
7c673cae
FG
182 continue;
183 }
11fdf7f2 184 ceph_assert(parent->snaprealm); // hmm!
7c673cae
FG
185 if (!parent->snaprealm->_open_parents(finish, p->second.first, p->first))
186 return false;
187 auto q = open_past_parents.find(p->second.ino);
188 if (q == open_past_parents.end() ||
189 q->second.second.count(p->first) == 0) {
190 add_open_past_parent(parent->snaprealm, p->first);
191 }
192 ++p;
193 }
194 }
195
196 open = true;
197 return true;
198}
199
11fdf7f2 200bool SnapRealm::open_parents(MDSContext *retryorfinish) {
7c673cae
FG
201 if (!_open_parents(retryorfinish))
202 return false;
203 delete retryorfinish;
204 return true;
205}
206
11fdf7f2 207bool SnapRealm::have_past_parents_open(snapid_t first, snapid_t last) const
7c673cae
FG
208{
209 dout(10) << "have_past_parents_open [" << first << "," << last << "]" << dendl;
210 if (open)
211 return true;
212
11fdf7f2
TL
213 if (!srnode.past_parent_snaps.empty())
214 ceph_assert(mdcache->mds->snapclient->get_cached_version() > 0);
215
216 if (!srnode.past_parents.empty() &&
217 mdcache->mds->allows_multimds_snaps()) {
218 dout(10) << " skip non-empty past_parents since multimds_snaps is allowed" << dendl;
219 open = true;
220 return true;
221 }
222
223 for (auto p = srnode.past_parents.lower_bound(first);
7c673cae
FG
224 p != srnode.past_parents.end();
225 ++p) {
226 if (p->second.first > last)
227 break;
228 dout(10) << " past parent [" << p->second.first << "," << p->first << "] was "
229 << p->second.ino << dendl;
11fdf7f2
TL
230 auto q = open_past_parents.find(p->second.ino);
231 if (q == open_past_parents.end()) {
7c673cae
FG
232 dout(10) << " past parent " << p->second.ino << " is not open" << dendl;
233 return false;
234 }
11fdf7f2
TL
235 SnapRealm *parent_realm = q->second.first;
236 if (!parent_realm->have_past_parents_open(std::max(first, p->second.first),
237 std::min(last, p->first)))
7c673cae
FG
238 return false;
239 }
240
241 open = true;
242 return true;
243}
244
245void SnapRealm::close_parents()
246{
247 for (auto p = open_past_parents.begin(); p != open_past_parents.end(); ++p) {
248 num_open_past_parents -= p->second.second.size();
249 p->second.first->inode->put(CInode::PIN_PASTSNAPPARENT);
250 p->second.first->open_past_children.erase(this);
251 }
252 open_past_parents.clear();
253}
254
255
256/*
257 * get list of snaps for this realm. we must include parents' snaps
258 * for the intervals during which they were our parent.
259 */
11fdf7f2 260void SnapRealm::build_snap_set() const
7c673cae 261{
11fdf7f2 262 dout(10) << "build_snap_set on " << *this << dendl;
7c673cae 263
11fdf7f2 264 cached_snaps.clear();
7c673cae 265
11fdf7f2
TL
266 if (global) {
267 mdcache->mds->snapclient->get_snaps(cached_snaps);
268 return;
269 }
7c673cae 270
11fdf7f2
TL
271 // include my snaps
272 for (const auto& p : srnode.snaps)
273 cached_snaps.insert(p.first);
274
275 if (!srnode.past_parent_snaps.empty()) {
276 set<snapid_t> snaps = mdcache->mds->snapclient->filter(srnode.past_parent_snaps);
277 if (!snaps.empty()) {
278 snapid_t last = *snaps.rbegin();
279 cached_seq = std::max(cached_seq, last);
280 cached_last_created = std::max(cached_last_created, last);
281 }
282 cached_snaps.insert(snaps.begin(), snaps.end());
283 } else {
284 // include snaps for parents
285 for (const auto& p : srnode.past_parents) {
286 const CInode *oldparent = mdcache->get_inode(p.second.ino);
287 ceph_assert(oldparent); // call open_parents first!
288 ceph_assert(oldparent->snaprealm);
289
290 const set<snapid_t>& snaps = oldparent->snaprealm->get_snaps();
291 snapid_t last = 0;
292 for (auto q = snaps.lower_bound(p.second.first);
293 q != snaps.end() && *q <= p.first;
294 q++) {
295 cached_snaps.insert(*q);
296 last = *q;
297 }
298 cached_seq = std::max(cached_seq, last);
299 cached_last_created = std::max(cached_last_created, last);
300 }
7c673cae 301 }
7c673cae 302
11fdf7f2
TL
303 snapid_t parent_seq = parent ? parent->get_newest_seq() : snapid_t(0);
304 if (parent_seq >= srnode.current_parent_since) {
305 auto& snaps = parent->get_snaps();
306 auto p = snaps.lower_bound(srnode.current_parent_since);
307 cached_snaps.insert(p, snaps.end());
308 cached_seq = std::max(cached_seq, parent_seq);
309 cached_last_created = std::max(cached_last_created, parent->get_last_created());
310 }
311}
7c673cae
FG
312
313void SnapRealm::check_cache() const
314{
11fdf7f2
TL
315 ceph_assert(have_past_parents_open());
316 snapid_t seq;
317 snapid_t last_created;
318 snapid_t last_destroyed = mdcache->mds->snapclient->get_last_destroyed();
319 if (global || srnode.is_parent_global()) {
320 last_created = mdcache->mds->snapclient->get_last_created();
321 seq = std::max(last_created, last_destroyed);
322 } else {
323 last_created = srnode.last_created;
324 seq = srnode.seq;
325 }
326 if (cached_seq >= seq &&
327 cached_last_destroyed == last_destroyed)
7c673cae
FG
328 return;
329
7c673cae
FG
330 cached_snap_context.clear();
331
11fdf7f2
TL
332 cached_seq = seq;
333 cached_last_created = last_created;
334 cached_last_destroyed = last_destroyed;
adb31ebb
TL
335
336 cached_subvolume_ino = 0;
337 if (parent)
338 cached_subvolume_ino = parent->get_subvolume_ino();
339 if (!cached_subvolume_ino && srnode.is_subvolume())
340 cached_subvolume_ino = inode->ino();
341
11fdf7f2 342 build_snap_set();
7c673cae 343
11fdf7f2 344 build_snap_trace();
7c673cae
FG
345
346 dout(10) << "check_cache rebuilt " << cached_snaps
11fdf7f2 347 << " seq " << seq
7c673cae
FG
348 << " cached_seq " << cached_seq
349 << " cached_last_created " << cached_last_created
350 << " cached_last_destroyed " << cached_last_destroyed
351 << ")" << dendl;
352}
353
354const set<snapid_t>& SnapRealm::get_snaps() const
355{
356 check_cache();
357 dout(10) << "get_snaps " << cached_snaps
358 << " (seq " << srnode.seq << " cached_seq " << cached_seq << ")"
359 << dendl;
360 return cached_snaps;
361}
362
363/*
364 * build vector in reverse sorted order
365 */
366const SnapContext& SnapRealm::get_snap_context() const
367{
368 check_cache();
369
370 if (!cached_snap_context.seq) {
371 cached_snap_context.seq = cached_seq;
372 cached_snap_context.snaps.resize(cached_snaps.size());
373 unsigned i = 0;
374 for (set<snapid_t>::reverse_iterator p = cached_snaps.rbegin();
375 p != cached_snaps.rend();
376 ++p)
377 cached_snap_context.snaps[i++] = *p;
378 }
379
380 return cached_snap_context;
381}
382
11fdf7f2 383void SnapRealm::get_snap_info(map<snapid_t, const SnapInfo*>& infomap, snapid_t first, snapid_t last)
7c673cae
FG
384{
385 const set<snapid_t>& snaps = get_snaps();
386 dout(10) << "get_snap_info snaps " << snaps << dendl;
387
388 // include my snaps within interval [first,last]
11fdf7f2 389 for (auto p = srnode.snaps.lower_bound(first); // first element >= first
7c673cae
FG
390 p != srnode.snaps.end() && p->first <= last;
391 ++p)
392 infomap[p->first] = &p->second;
393
11fdf7f2
TL
394 if (!srnode.past_parent_snaps.empty()) {
395 set<snapid_t> snaps;
396 for (auto p = srnode.past_parent_snaps.lower_bound(first); // first element >= first
397 p != srnode.past_parent_snaps.end() && *p <= last;
398 ++p) {
399 snaps.insert(*p);
400 }
401
402 map<snapid_t, const SnapInfo*> _infomap;
403 mdcache->mds->snapclient->get_snap_infos(_infomap, snaps);
404 infomap.insert(_infomap.begin(), _infomap.end());
405 } else {
406 // include snaps for parents during intervals that intersect [first,last]
407 for (map<snapid_t, snaplink_t>::iterator p = srnode.past_parents.lower_bound(first);
408 p != srnode.past_parents.end() && p->first >= first && p->second.first <= last;
409 ++p) {
410 CInode *oldparent = mdcache->get_inode(p->second.ino);
411 ceph_assert(oldparent); // call open_parents first!
412 ceph_assert(oldparent->snaprealm);
413 oldparent->snaprealm->get_snap_info(infomap,
414 std::max(first, p->second.first),
415 std::min(last, p->first));
416 }
7c673cae 417 }
11fdf7f2 418
7c673cae 419 if (srnode.current_parent_since <= last && parent)
11fdf7f2 420 parent->get_snap_info(infomap, std::max(first, srnode.current_parent_since), last);
7c673cae
FG
421}
422
11fdf7f2 423std::string_view SnapRealm::get_snapname(snapid_t snapid, inodeno_t atino)
7c673cae
FG
424{
425 auto srnode_snaps_entry = srnode.snaps.find(snapid);
426 if (srnode_snaps_entry != srnode.snaps.end()) {
427 if (atino == inode->ino())
428 return srnode_snaps_entry->second.name;
429 else
430 return srnode_snaps_entry->second.get_long_name();
431 }
432
11fdf7f2
TL
433 if (!srnode.past_parent_snaps.empty()) {
434 if (srnode.past_parent_snaps.count(snapid)) {
435 const SnapInfo *sinfo = mdcache->mds->snapclient->get_snap_info(snapid);
436 if (sinfo) {
437 if (atino == sinfo->ino)
438 return sinfo->name;
439 else
440 return sinfo->get_long_name();
441 }
442 }
443 } else {
444 map<snapid_t,snaplink_t>::iterator p = srnode.past_parents.lower_bound(snapid);
445 if (p != srnode.past_parents.end() && p->second.first <= snapid) {
446 CInode *oldparent = mdcache->get_inode(p->second.ino);
447 ceph_assert(oldparent); // call open_parents first!
448 ceph_assert(oldparent->snaprealm);
449 return oldparent->snaprealm->get_snapname(snapid, atino);
450 }
7c673cae
FG
451 }
452
11fdf7f2
TL
453 ceph_assert(srnode.current_parent_since <= snapid);
454 ceph_assert(parent);
7c673cae
FG
455 return parent->get_snapname(snapid, atino);
456}
457
11fdf7f2 458snapid_t SnapRealm::resolve_snapname(std::string_view n, inodeno_t atino, snapid_t first, snapid_t last)
7c673cae
FG
459{
460 // first try me
461 dout(10) << "resolve_snapname '" << n << "' in [" << first << "," << last << "]" << dendl;
462
7c673cae
FG
463 bool actual = (atino == inode->ino());
464 string pname;
465 inodeno_t pino;
11fdf7f2 466 if (n.length() && n[0] == '_') {
81eedcae
TL
467 size_t next_ = n.find_last_of('_');
468 if (next_ > 1 && next_ + 1 < n.length()) {
11fdf7f2
TL
469 pname = n.substr(1, next_ - 1);
470 pino = atoll(n.data() + next_ + 1);
471 dout(10) << " " << n << " parses to name '" << pname << "' dirino " << pino << dendl;
472 }
7c673cae
FG
473 }
474
11fdf7f2 475 for (auto p = srnode.snaps.lower_bound(first); // first element >= first
7c673cae
FG
476 p != srnode.snaps.end() && p->first <= last;
477 ++p) {
478 dout(15) << " ? " << p->second << dendl;
479 //if (num && p->second.snapid == num)
480 //return p->first;
481 if (actual && p->second.name == n)
482 return p->first;
483 if (!actual && p->second.name == pname && p->second.ino == pino)
484 return p->first;
485 }
486
11fdf7f2
TL
487 if (!srnode.past_parent_snaps.empty()) {
488 set<snapid_t> snaps;
489 for (auto p = srnode.past_parent_snaps.lower_bound(first); // first element >= first
490 p != srnode.past_parent_snaps.end() && *p <= last;
491 ++p)
492 snaps.insert(*p);
493
494 map<snapid_t, const SnapInfo*> _infomap;
495 mdcache->mds->snapclient->get_snap_infos(_infomap, snaps);
496
497 for (auto& it : _infomap) {
498 dout(15) << " ? " << *it.second << dendl;
499 actual = (it.second->ino == atino);
500 if (actual && it.second->name == n)
501 return it.first;
502 if (!actual && it.second->name == pname && it.second->ino == pino)
503 return it.first;
504 }
505 } else {
7c673cae 506 // include snaps for parents during intervals that intersect [first,last]
11fdf7f2
TL
507 for (map<snapid_t, snaplink_t>::iterator p = srnode.past_parents.lower_bound(first);
508 p != srnode.past_parents.end() && p->first >= first && p->second.first <= last;
509 ++p) {
510 CInode *oldparent = mdcache->get_inode(p->second.ino);
511 ceph_assert(oldparent); // call open_parents first!
512 ceph_assert(oldparent->snaprealm);
513 snapid_t r = oldparent->snaprealm->resolve_snapname(n, atino,
514 std::max(first, p->second.first),
515 std::min(last, p->first));
516 if (r)
517 return r;
518 }
7c673cae 519 }
11fdf7f2 520
7c673cae 521 if (parent && srnode.current_parent_since <= last)
11fdf7f2 522 return parent->resolve_snapname(n, atino, std::max(first, srnode.current_parent_since), last);
7c673cae
FG
523 return 0;
524}
525
526
527void SnapRealm::adjust_parent()
528{
11fdf7f2
TL
529 SnapRealm *newparent;
530 if (srnode.is_parent_global()) {
531 newparent = mdcache->get_global_snaprealm();
532 } else {
533 CDentry *pdn = inode->get_parent_dn();
534 newparent = pdn ? pdn->get_dir()->get_inode()->find_snaprealm() : NULL;
535 }
7c673cae
FG
536 if (newparent != parent) {
537 dout(10) << "adjust_parent " << parent << " -> " << newparent << dendl;
538 if (parent)
539 parent->open_children.erase(this);
540 parent = newparent;
541 if (parent)
542 parent->open_children.insert(this);
543
544 invalidate_cached_snaps();
545 }
546}
547
548void SnapRealm::split_at(SnapRealm *child)
549{
550 dout(10) << "split_at " << *child
551 << " on " << *child->inode << dendl;
552
553 if (inode->is_mdsdir() || !child->inode->is_dir()) {
554 // it's not a dir.
555 if (child->inode->containing_realm) {
556 // - no open children.
557 // - only need to move this child's inode's caps.
558 child->inode->move_to_realm(child);
559 } else {
560 // no caps, nothing to move/split.
561 dout(20) << " split no-op, no caps to move on file " << *child->inode << dendl;
11fdf7f2 562 ceph_assert(!child->inode->is_any_caps());
7c673cae
FG
563 }
564 return;
565 }
566
567 // it's a dir.
568
569 // split open_children
570 dout(10) << " open_children are " << open_children << dendl;
571 for (set<SnapRealm*>::iterator p = open_children.begin();
572 p != open_children.end(); ) {
573 SnapRealm *realm = *p;
574 if (realm != child &&
11fdf7f2 575 child->inode->is_ancestor_of(realm->inode)) {
7c673cae
FG
576 dout(20) << " child gets child realm " << *realm << " on " << *realm->inode << dendl;
577 realm->parent = child;
578 child->open_children.insert(realm);
579 open_children.erase(p++);
580 } else {
581 dout(20) << " keeping child realm " << *realm << " on " << *realm->inode << dendl;
582 ++p;
583 }
584 }
585
586 // split inodes_with_caps
11fdf7f2
TL
587 for (elist<CInode*>::iterator p = inodes_with_caps.begin(member_offset(CInode, item_caps));
588 !p.end(); ) {
7c673cae
FG
589 CInode *in = *p;
590 ++p;
7c673cae 591 // does inode fall within the child realm?
11fdf7f2 592 if (child->inode->is_ancestor_of(in)) {
7c673cae
FG
593 dout(20) << " child gets " << *in << dendl;
594 in->move_to_realm(child);
595 } else {
596 dout(20) << " keeping " << *in << dendl;
597 }
598 }
11fdf7f2
TL
599}
600
601void SnapRealm::merge_to(SnapRealm *newparent)
602{
603 if (!newparent)
604 newparent = parent;
605 dout(10) << "merge to " << *newparent << " on " << *newparent->inode << dendl;
606
607 ceph_assert(open_past_children.empty());
608
609 dout(10) << " open_children are " << open_children << dendl;
610 for (auto realm : open_children) {
611 dout(20) << " child realm " << *realm << " on " << *realm->inode << dendl;
612 newparent->open_children.insert(realm);
613 realm->parent = newparent;
614 }
615 open_children.clear();
616
617 elist<CInode*>::iterator p = inodes_with_caps.begin(member_offset(CInode, item_caps));
618 while (!p.end()) {
619 CInode *in = *p;
620 ++p;
621 in->move_to_realm(newparent);
622 }
623 ceph_assert(inodes_with_caps.empty());
7c673cae 624
11fdf7f2
TL
625 // delete this
626 inode->close_snaprealm();
7c673cae
FG
627}
628
11fdf7f2 629const bufferlist& SnapRealm::get_snap_trace() const
7c673cae
FG
630{
631 check_cache();
632 return cached_snap_trace;
633}
634
11fdf7f2 635void SnapRealm::build_snap_trace() const
7c673cae 636{
11fdf7f2
TL
637 cached_snap_trace.clear();
638
639 if (global) {
640 SnapRealmInfo info(inode->ino(), 0, cached_seq, 0);
641 info.my_snaps.reserve(cached_snaps.size());
642 for (auto p = cached_snaps.rbegin(); p != cached_snaps.rend(); ++p)
643 info.my_snaps.push_back(*p);
7c673cae 644
11fdf7f2
TL
645 dout(10) << "build_snap_trace my_snaps " << info.my_snaps << dendl;
646 encode(info, cached_snap_trace);
647 return;
648 }
649
650 SnapRealmInfo info(inode->ino(), srnode.created, srnode.seq, srnode.current_parent_since);
7c673cae
FG
651 if (parent) {
652 info.h.parent = parent->inode->ino();
11fdf7f2
TL
653
654 set<snapid_t> past;
655 if (!srnode.past_parent_snaps.empty()) {
656 past = mdcache->mds->snapclient->filter(srnode.past_parent_snaps);
657 if (srnode.is_parent_global()) {
658 auto p = past.lower_bound(srnode.current_parent_since);
659 past.erase(p, past.end());
660 }
661 } else if (!srnode.past_parents.empty()) {
662 const set<snapid_t>& snaps = get_snaps();
663 for (const auto& p : srnode.past_parents) {
664 for (auto q = snaps.lower_bound(p.second.first);
665 q != snaps.end() && *q <= p.first;
666 q++) {
667 if (srnode.snaps.count(*q))
668 continue;
669 past.insert(*q);
670 }
671 }
672 }
673
674 if (!past.empty()) {
7c673cae
FG
675 info.prior_parent_snaps.reserve(past.size());
676 for (set<snapid_t>::reverse_iterator p = past.rbegin(); p != past.rend(); ++p)
677 info.prior_parent_snaps.push_back(*p);
11fdf7f2 678 dout(10) << "build_snap_trace prior_parent_snaps from [1," << *past.rbegin() << "] "
7c673cae
FG
679 << info.prior_parent_snaps << dendl;
680 }
11fdf7f2 681 }
7c673cae
FG
682
683 info.my_snaps.reserve(srnode.snaps.size());
11fdf7f2 684 for (auto p = srnode.snaps.rbegin();
7c673cae
FG
685 p != srnode.snaps.rend();
686 ++p)
687 info.my_snaps.push_back(p->first);
688 dout(10) << "build_snap_trace my_snaps " << info.my_snaps << dendl;
689
11fdf7f2 690 encode(info, cached_snap_trace);
7c673cae
FG
691
692 if (parent)
11fdf7f2 693 cached_snap_trace.append(parent->get_snap_trace());
7c673cae
FG
694}
695
7c673cae
FG
696void SnapRealm::prune_past_parents()
697{
698 dout(10) << "prune_past_parents" << dendl;
699 check_cache();
11fdf7f2
TL
700
701 // convert past_parents to past_parent_snaps
702 if (!srnode.past_parents.empty()) {
703 for (auto p = cached_snaps.begin();
704 p != cached_snaps.end() && *p < srnode.current_parent_since;
705 ++p) {
706 if (!srnode.snaps.count(*p))
707 srnode.past_parent_snaps.insert(*p);
708 }
709 srnode.past_parents.clear();
710 past_parents_dirty = true;
711 }
712
713 for (auto p = srnode.past_parent_snaps.begin();
714 p != srnode.past_parent_snaps.end(); ) {
715 auto q = cached_snaps.find(*p);
716 if (q == cached_snaps.end()) {
717 dout(10) << "prune_past_parents pruning " << *p << dendl;
718 srnode.past_parent_snaps.erase(p++);
7c673cae 719 } else {
11fdf7f2 720 dout(10) << "prune_past_parents keeping " << *p << dendl;
7c673cae
FG
721 ++p;
722 }
723 }
724}
725