]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/SnapRealm.cc
import quincy beta 17.1.0
[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)
20effc67
TL
31
32using namespace std;
33
34static 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
41ostream& 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 58SnapRealm::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 68void 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
103void 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
143const 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 */
155const 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 172void 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 200std::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 227snapid_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
282void 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
303void 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
355void 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 380const bufferlist& SnapRealm::get_snap_trace() const
7c673cae
FG
381{
382 check_cache();
383 return cached_snap_trace;
384}
385
11fdf7f2 386void 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 436void 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