1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #include "SnapRealm.h"
18 #include "SnapClient.h"
20 #include <string_view>
27 #define dout_context g_ceph_context
28 #define dout_subsys ceph_subsys_mds
30 #define dout_prefix _prefix(_dout, mdcache->mds->get_nodeid(), inode, srnode.seq, this)
34 static std::ostream
& _prefix(std::ostream
*_dout
, int whoami
, const CInode
*inode
,
35 uint64_t seq
, const SnapRealm
*realm
) {
36 return *_dout
<< " mds." << whoami
37 << ".cache.snaprealm(" << inode
->ino()
38 << " seq " << seq
<< " " << realm
<< ") ";
41 ostream
& operator<<(ostream
& out
, const SnapRealm
& realm
)
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
;
50 if (realm
.srnode
.past_parent_snaps
.size() > 0) {
51 out
<< " past_parent_snaps=" << realm
.srnode
.past_parent_snaps
;
54 if (realm
.srnode
.is_parent_global())
56 out
<< " last_modified " << realm
.srnode
.last_modified
57 << " change_attr " << realm
.srnode
.change_attr
;
58 out
<< " " << &realm
<< ")";
62 SnapRealm::SnapRealm(MDCache
*c
, CInode
*in
) :
63 mdcache(c
), inode(in
), inodes_with_caps(member_offset(CInode
, item_caps
))
65 global
= (inode
->ino() == CEPH_INO_GLOBAL_SNAPREALM
);
66 if (inode
->ino() == CEPH_INO_ROOT
) {
67 srnode
.last_modified
= in
->get_inode()->mtime
;
72 * get list of snaps for this realm. we must include parents' snaps
73 * for the intervals during which they were our parent.
75 void SnapRealm::build_snap_set() const
77 dout(10) << "build_snap_set on " << *this << dendl
;
82 mdcache
->mds
->snapclient
->get_snaps(cached_snaps
);
87 for (const auto& p
: srnode
.snaps
)
88 cached_snaps
.insert(p
.first
);
90 if (!srnode
.past_parent_snaps
.empty()) {
91 set
<snapid_t
> snaps
= mdcache
->mds
->snapclient
->filter(srnode
.past_parent_snaps
);
93 snapid_t last
= *snaps
.rbegin();
94 cached_seq
= std::max(cached_seq
, last
);
95 cached_last_created
= std::max(cached_last_created
, last
);
97 cached_snaps
.insert(snaps
.begin(), snaps
.end());
100 snapid_t parent_seq
= parent
? parent
->get_newest_seq() : snapid_t(0);
101 if (parent_seq
>= srnode
.current_parent_since
) {
102 auto& snaps
= parent
->get_snaps();
103 auto p
= snaps
.lower_bound(srnode
.current_parent_since
);
104 cached_snaps
.insert(p
, snaps
.end());
105 cached_seq
= std::max(cached_seq
, parent_seq
);
106 cached_last_created
= std::max(cached_last_created
, parent
->get_last_created());
110 void SnapRealm::check_cache() const
113 snapid_t last_created
;
114 snapid_t last_destroyed
= mdcache
->mds
->snapclient
->get_last_destroyed();
115 if (global
|| srnode
.is_parent_global()) {
116 last_created
= mdcache
->mds
->snapclient
->get_last_created();
117 seq
= std::max(last_created
, last_destroyed
);
119 last_created
= srnode
.last_created
;
122 if (cached_seq
>= seq
&&
123 cached_last_destroyed
== last_destroyed
)
126 cached_snap_context
.clear();
129 cached_last_created
= last_created
;
130 cached_last_destroyed
= last_destroyed
;
132 cached_subvolume_ino
= 0;
134 cached_subvolume_ino
= parent
->get_subvolume_ino();
135 if (!cached_subvolume_ino
&& srnode
.is_subvolume())
136 cached_subvolume_ino
= inode
->ino();
142 dout(10) << "check_cache rebuilt " << cached_snaps
144 << " cached_seq " << cached_seq
145 << " cached_last_created " << cached_last_created
146 << " cached_last_destroyed " << cached_last_destroyed
150 const set
<snapid_t
>& SnapRealm::get_snaps() const
153 dout(10) << "get_snaps " << cached_snaps
154 << " (seq " << srnode
.seq
<< " cached_seq " << cached_seq
<< ")"
160 * build vector in reverse sorted order
162 const SnapContext
& SnapRealm::get_snap_context() const
166 if (!cached_snap_context
.seq
) {
167 cached_snap_context
.seq
= cached_seq
;
168 cached_snap_context
.snaps
.resize(cached_snaps
.size());
170 for (set
<snapid_t
>::reverse_iterator p
= cached_snaps
.rbegin();
171 p
!= cached_snaps
.rend();
173 cached_snap_context
.snaps
[i
++] = *p
;
176 return cached_snap_context
;
179 void SnapRealm::get_snap_info(map
<snapid_t
, const SnapInfo
*>& infomap
, snapid_t first
, snapid_t last
)
181 const set
<snapid_t
>& snaps
= get_snaps();
182 dout(10) << "get_snap_info snaps " << snaps
<< dendl
;
184 // include my snaps within interval [first,last]
185 for (auto p
= srnode
.snaps
.lower_bound(first
); // first element >= first
186 p
!= srnode
.snaps
.end() && p
->first
<= last
;
188 infomap
[p
->first
] = &p
->second
;
190 if (!srnode
.past_parent_snaps
.empty()) {
192 for (auto p
= srnode
.past_parent_snaps
.lower_bound(first
); // first element >= first
193 p
!= srnode
.past_parent_snaps
.end() && *p
<= last
;
198 map
<snapid_t
, const SnapInfo
*> _infomap
;
199 mdcache
->mds
->snapclient
->get_snap_infos(_infomap
, snaps
);
200 infomap
.insert(_infomap
.begin(), _infomap
.end());
203 if (srnode
.current_parent_since
<= last
&& parent
)
204 parent
->get_snap_info(infomap
, std::max(first
, srnode
.current_parent_since
), last
);
207 std::string_view
SnapRealm::get_snapname(snapid_t snapid
, inodeno_t atino
)
209 auto srnode_snaps_entry
= srnode
.snaps
.find(snapid
);
210 if (srnode_snaps_entry
!= srnode
.snaps
.end()) {
211 if (atino
== inode
->ino())
212 return srnode_snaps_entry
->second
.name
;
214 return srnode_snaps_entry
->second
.get_long_name();
217 if (!srnode
.past_parent_snaps
.empty()) {
218 if (srnode
.past_parent_snaps
.count(snapid
)) {
219 const SnapInfo
*sinfo
= mdcache
->mds
->snapclient
->get_snap_info(snapid
);
221 if (atino
== sinfo
->ino
)
224 return sinfo
->get_long_name();
229 ceph_assert(srnode
.current_parent_since
<= snapid
);
231 return parent
->get_snapname(snapid
, atino
);
234 snapid_t
SnapRealm::resolve_snapname(std::string_view n
, inodeno_t atino
, snapid_t first
, snapid_t last
)
237 dout(10) << "resolve_snapname '" << n
<< "' in [" << first
<< "," << last
<< "]" << dendl
;
239 bool actual
= (atino
== inode
->ino());
242 if (n
.length() && n
[0] == '_') {
243 size_t next_
= n
.find_last_of('_');
244 if (next_
> 1 && next_
+ 1 < n
.length()) {
245 pname
= n
.substr(1, next_
- 1);
246 pino
= atoll(n
.data() + next_
+ 1);
247 dout(10) << " " << n
<< " parses to name '" << pname
<< "' dirino " << pino
<< dendl
;
251 for (auto p
= srnode
.snaps
.lower_bound(first
); // first element >= first
252 p
!= srnode
.snaps
.end() && p
->first
<= last
;
254 dout(15) << " ? " << p
->second
<< dendl
;
255 //if (num && p->second.snapid == num)
257 if (actual
&& p
->second
.name
== n
)
259 if (!actual
&& p
->second
.name
== pname
&& p
->second
.ino
== pino
)
263 if (!srnode
.past_parent_snaps
.empty()) {
265 for (auto p
= srnode
.past_parent_snaps
.lower_bound(first
); // first element >= first
266 p
!= srnode
.past_parent_snaps
.end() && *p
<= last
;
270 map
<snapid_t
, const SnapInfo
*> _infomap
;
271 mdcache
->mds
->snapclient
->get_snap_infos(_infomap
, snaps
);
273 for (auto& it
: _infomap
) {
274 dout(15) << " ? " << *it
.second
<< dendl
;
275 actual
= (it
.second
->ino
== atino
);
276 if (actual
&& it
.second
->name
== n
)
278 if (!actual
&& it
.second
->name
== pname
&& it
.second
->ino
== pino
)
283 if (parent
&& srnode
.current_parent_since
<= last
)
284 return parent
->resolve_snapname(n
, atino
, std::max(first
, srnode
.current_parent_since
), last
);
289 void SnapRealm::adjust_parent()
291 SnapRealm
*newparent
;
292 if (srnode
.is_parent_global()) {
293 newparent
= mdcache
->get_global_snaprealm();
295 CDentry
*pdn
= inode
->get_parent_dn();
296 newparent
= pdn
? pdn
->get_dir()->get_inode()->find_snaprealm() : NULL
;
298 if (newparent
!= parent
) {
299 dout(10) << "adjust_parent " << parent
<< " -> " << newparent
<< dendl
;
301 parent
->open_children
.erase(this);
304 parent
->open_children
.insert(this);
306 invalidate_cached_snaps();
310 void SnapRealm::split_at(SnapRealm
*child
)
312 dout(10) << "split_at " << *child
313 << " on " << *child
->inode
<< dendl
;
315 if (inode
->is_mdsdir() || !child
->inode
->is_dir()) {
317 if (child
->inode
->containing_realm
) {
318 // - no open children.
319 // - only need to move this child's inode's caps.
320 child
->inode
->move_to_realm(child
);
322 // no caps, nothing to move/split.
323 dout(20) << " split no-op, no caps to move on file " << *child
->inode
<< dendl
;
324 ceph_assert(!child
->inode
->is_any_caps());
331 // split open_children
332 dout(10) << " open_children are " << open_children
<< dendl
;
333 for (set
<SnapRealm
*>::iterator p
= open_children
.begin();
334 p
!= open_children
.end(); ) {
335 SnapRealm
*realm
= *p
;
336 if (realm
!= child
&&
337 child
->inode
->is_ancestor_of(realm
->inode
)) {
338 dout(20) << " child gets child realm " << *realm
<< " on " << *realm
->inode
<< dendl
;
339 realm
->parent
= child
;
340 child
->open_children
.insert(realm
);
341 open_children
.erase(p
++);
343 dout(20) << " keeping child realm " << *realm
<< " on " << *realm
->inode
<< dendl
;
348 // split inodes_with_caps
349 for (auto p
= inodes_with_caps
.begin(); !p
.end(); ) {
352 // does inode fall within the child realm?
353 if (child
->inode
->is_ancestor_of(in
)) {
354 dout(20) << " child gets " << *in
<< dendl
;
355 in
->move_to_realm(child
);
357 dout(20) << " keeping " << *in
<< dendl
;
362 void SnapRealm::merge_to(SnapRealm
*newparent
)
366 dout(10) << "merge to " << *newparent
<< " on " << *newparent
->inode
<< dendl
;
368 dout(10) << " open_children are " << open_children
<< dendl
;
369 for (auto realm
: open_children
) {
370 dout(20) << " child realm " << *realm
<< " on " << *realm
->inode
<< dendl
;
371 newparent
->open_children
.insert(realm
);
372 realm
->parent
= newparent
;
374 open_children
.clear();
376 for (auto p
= inodes_with_caps
.begin(); !p
.end(); ) {
379 in
->move_to_realm(newparent
);
381 ceph_assert(inodes_with_caps
.empty());
384 inode
->close_snaprealm();
387 const bufferlist
& SnapRealm::get_snap_trace() const
390 return cached_snap_trace
;
393 const bufferlist
& SnapRealm::get_snap_trace_new() const
396 return cached_snap_trace_new
;
399 void SnapRealm::build_snap_trace() const
401 cached_snap_trace
.clear();
402 cached_snap_trace_new
.clear();
405 SnapRealmInfo
info(inode
->ino(), 0, cached_seq
, 0);
406 info
.my_snaps
.reserve(cached_snaps
.size());
407 for (auto p
= cached_snaps
.rbegin(); p
!= cached_snaps
.rend(); ++p
)
408 info
.my_snaps
.push_back(*p
);
410 dout(10) << "build_snap_trace my_snaps " << info
.my_snaps
<< dendl
;
412 SnapRealmInfoNew
ninfo(info
, srnode
.last_modified
, srnode
.change_attr
);
413 encode(info
, cached_snap_trace
);
414 encode(ninfo
, cached_snap_trace_new
);
418 SnapRealmInfo
info(inode
->ino(), srnode
.created
, srnode
.seq
, srnode
.current_parent_since
);
420 info
.h
.parent
= parent
->inode
->ino();
423 if (!srnode
.past_parent_snaps
.empty()) {
424 past
= mdcache
->mds
->snapclient
->filter(srnode
.past_parent_snaps
);
425 if (srnode
.is_parent_global()) {
426 auto p
= past
.lower_bound(srnode
.current_parent_since
);
427 past
.erase(p
, past
.end());
432 info
.prior_parent_snaps
.reserve(past
.size());
433 for (set
<snapid_t
>::reverse_iterator p
= past
.rbegin(); p
!= past
.rend(); ++p
)
434 info
.prior_parent_snaps
.push_back(*p
);
435 dout(10) << "build_snap_trace prior_parent_snaps from [1," << *past
.rbegin() << "] "
436 << info
.prior_parent_snaps
<< dendl
;
440 info
.my_snaps
.reserve(srnode
.snaps
.size());
441 for (auto p
= srnode
.snaps
.rbegin();
442 p
!= srnode
.snaps
.rend();
444 info
.my_snaps
.push_back(p
->first
);
445 dout(10) << "build_snap_trace my_snaps " << info
.my_snaps
<< dendl
;
447 SnapRealmInfoNew
ninfo(info
, srnode
.last_modified
, srnode
.change_attr
);
449 encode(info
, cached_snap_trace
);
450 encode(ninfo
, cached_snap_trace_new
);
453 cached_snap_trace
.append(parent
->get_snap_trace());
454 cached_snap_trace_new
.append(parent
->get_snap_trace_new());
458 void SnapRealm::prune_past_parent_snaps()
460 dout(10) << __func__
<< dendl
;
463 for (auto p
= srnode
.past_parent_snaps
.begin();
464 p
!= srnode
.past_parent_snaps
.end(); ) {
465 auto q
= cached_snaps
.find(*p
);
466 if (q
== cached_snaps
.end()) {
467 dout(10) << __func__
<< " pruning " << *p
<< dendl
;
468 srnode
.past_parent_snaps
.erase(p
++);
470 dout(10) << __func__
<< " keeping " << *p
<< dendl
;