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