]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/events/EMetaBlob.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / mds / events / EMetaBlob.h
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#ifndef CEPH_MDS_EMETABLOB_H
16#define CEPH_MDS_EMETABLOB_H
17
11fdf7f2 18#include <string_view>
94b18763 19
7c673cae
FG
20#include <stdlib.h>
21
22#include "../CInode.h"
23#include "../CDir.h"
24#include "../CDentry.h"
25#include "../LogSegment.h"
26
27#include "include/interval_set.h"
28
29class MDSRank;
30class MDLog;
31class LogSegment;
32struct MDSlaveUpdate;
33
34/*
35 * a bunch of metadata in the journal
36 */
37
38/* notes:
39 *
40 * - make sure you adjust the inode.version for any modified inode you
41 * journal. CDir and CDentry maintain a projected_version, but CInode
11fdf7f2 42 * doesn't, since the journaled inode usually has to be modified
7c673cae
FG
43 * manually anyway (to delay the change in the MDS's cache until after
44 * it is journaled).
45 *
46 */
47
48
49class EMetaBlob {
50
51public:
52 /* fullbit - a regular dentry + inode
53 *
54 * We encode this one a bit weirdly, just because (also, it's marginally faster
55 * on multiple encodes, which I think can happen):
56 * Encode a bufferlist on struct creation with all data members, without a struct_v.
57 * When encode is called, encode struct_v and then append the bufferlist.
58 * Decode straight into the appropriate variables.
59 *
60 * So, if you add members, encode them in the constructor and then change
61 * the struct_v in the encode function!
62 */
63 struct fullbit {
64 static const int STATE_DIRTY = (1<<0);
65 static const int STATE_DIRTYPARENT = (1<<1);
66 static const int STATE_DIRTYPOOL = (1<<2);
67 static const int STATE_NEED_SNAPFLUSH = (1<<3);
94b18763 68 std::string dn; // dentry
7c673cae 69 snapid_t dnfirst, dnlast;
c07f9fc5 70 version_t dnv{0};
94b18763 71 CInode::mempool_inode inode; // if it's not XXX should not be part of mempool; wait for std::pmr to simplify
7c673cae 72 fragtree_t dirfragtree;
94b18763
FG
73 CInode::mempool_xattr_map xattrs;
74 std::string symlink;
7c673cae
FG
75 snapid_t oldest_snap;
76 bufferlist snapbl;
c07f9fc5 77 __u8 state{0};
94b18763 78 CInode::mempool_old_inode_map old_inodes; // XXX should not be part of mempool; wait for std::pmr to simplify
7c673cae 79
11fdf7f2 80 fullbit(std::string_view d, snapid_t df, snapid_t dl,
94b18763 81 version_t v, const CInode::mempool_inode& i, const fragtree_t &dft,
11fdf7f2 82 const CInode::mempool_xattr_map &xa, std::string_view sym,
7c673cae 83 snapid_t os, const bufferlist &sbl, __u8 st,
94b18763 84 const CInode::mempool_old_inode_map *oi = NULL) :
7c673cae
FG
85 dn(d), dnfirst(df), dnlast(dl), dnv(v), inode(i), xattrs(xa),
86 oldest_snap(os), state(st)
87 {
88 if (i.is_symlink())
11fdf7f2 89 symlink = sym;
7c673cae
FG
90 if (i.is_dir())
91 dirfragtree = dft;
92 if (oi)
93 old_inodes = *oi;
94 snapbl = sbl;
95 }
11fdf7f2 96 explicit fullbit(bufferlist::const_iterator &p) {
7c673cae
FG
97 decode(p);
98 }
99 fullbit() {}
11fdf7f2 100 fullbit(const fullbit&) = delete;
7c673cae 101 ~fullbit() {}
11fdf7f2 102 fullbit& operator=(const fullbit&) = delete;
7c673cae
FG
103
104 void encode(bufferlist& bl, uint64_t features) const;
11fdf7f2 105 void decode(bufferlist::const_iterator &bl);
7c673cae 106 void dump(Formatter *f) const;
9f95a23c 107 static void generate_test_instances(std::list<EMetaBlob::fullbit*>& ls);
7c673cae
FG
108
109 void update_inode(MDSRank *mds, CInode *in);
110 bool is_dirty() const { return (state & STATE_DIRTY); }
111 bool is_dirty_parent() const { return (state & STATE_DIRTYPARENT); }
112 bool is_dirty_pool() const { return (state & STATE_DIRTYPOOL); }
113 bool need_snapflush() const { return (state & STATE_NEED_SNAPFLUSH); }
114
115 void print(ostream& out) const {
116 out << " fullbit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv
117 << " inode " << inode.ino
118 << " state=" << state << std::endl;
119 }
120 string state_string() const {
121 string state_string;
122 bool marked_already = false;
123 if (is_dirty()) {
124 state_string.append("dirty");
125 marked_already = true;
126 }
127 if (is_dirty_parent()) {
128 state_string.append(marked_already ? "+dirty_parent" : "dirty_parent");
129 if (is_dirty_pool())
130 state_string.append("+dirty_pool");
131 }
132 return state_string;
133 }
134 };
135 WRITE_CLASS_ENCODER_FEATURES(fullbit)
136
137 /* remotebit - a dentry + remote inode link (i.e. just an ino)
138 */
139 struct remotebit {
94b18763 140 std::string dn;
7c673cae
FG
141 snapid_t dnfirst, dnlast;
142 version_t dnv;
143 inodeno_t ino;
144 unsigned char d_type;
145 bool dirty;
146
11fdf7f2 147 remotebit(std::string_view d, snapid_t df, snapid_t dl, version_t v, inodeno_t i, unsigned char dt, bool dr) :
7c673cae 148 dn(d), dnfirst(df), dnlast(dl), dnv(v), ino(i), d_type(dt), dirty(dr) { }
11fdf7f2 149 explicit remotebit(bufferlist::const_iterator &p) { decode(p); }
7c673cae
FG
150 remotebit(): dnfirst(0), dnlast(0), dnv(0), ino(0),
151 d_type('\0'), dirty(false) {}
152
153 void encode(bufferlist& bl) const;
11fdf7f2 154 void decode(bufferlist::const_iterator &bl);
7c673cae
FG
155 void print(ostream& out) const {
156 out << " remotebit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv
157 << " ino " << ino
158 << " dirty=" << dirty << std::endl;
159 }
160 void dump(Formatter *f) const;
9f95a23c 161 static void generate_test_instances(std::list<remotebit*>& ls);
7c673cae
FG
162 };
163 WRITE_CLASS_ENCODER(remotebit)
164
165 /*
166 * nullbit - a null dentry
167 */
168 struct nullbit {
94b18763 169 std::string dn;
7c673cae
FG
170 snapid_t dnfirst, dnlast;
171 version_t dnv;
172 bool dirty;
173
11fdf7f2 174 nullbit(std::string_view d, snapid_t df, snapid_t dl, version_t v, bool dr) :
7c673cae 175 dn(d), dnfirst(df), dnlast(dl), dnv(v), dirty(dr) { }
11fdf7f2 176 explicit nullbit(bufferlist::const_iterator &p) { decode(p); }
7c673cae
FG
177 nullbit(): dnfirst(0), dnlast(0), dnv(0), dirty(false) {}
178
179 void encode(bufferlist& bl) const;
11fdf7f2 180 void decode(bufferlist::const_iterator &bl);
7c673cae 181 void dump(Formatter *f) const;
9f95a23c 182 static void generate_test_instances(std::list<nullbit*>& ls);
11fdf7f2 183 void print(ostream& out) const {
7c673cae
FG
184 out << " nullbit dn " << dn << " [" << dnfirst << "," << dnlast << "] dnv " << dnv
185 << " dirty=" << dirty << std::endl;
186 }
187 };
188 WRITE_CLASS_ENCODER(nullbit)
189
190
191 /* dirlump - contains metadata for any dir we have contents for.
192 */
193public:
194 struct dirlump {
195 static const int STATE_COMPLETE = (1<<1);
196 static const int STATE_DIRTY = (1<<2); // dirty due to THIS journal item, that is!
197 static const int STATE_NEW = (1<<3); // new directory
198 static const int STATE_IMPORTING = (1<<4); // importing directory
199 static const int STATE_DIRTYDFT = (1<<5); // dirty dirfragtree
200
201 //version_t dirv;
202 fnode_t fnode;
203 __u32 state;
204 __u32 nfull, nremote, nnull;
205
206 private:
207 mutable bufferlist dnbl;
208 mutable bool dn_decoded;
11fdf7f2
TL
209 mutable list<fullbit> dfull;
210 mutable vector<remotebit> dremote;
211 mutable vector<nullbit> dnull;
7c673cae
FG
212
213 public:
214 dirlump() : state(0), nfull(0), nremote(0), nnull(0), dn_decoded(true) { }
11fdf7f2
TL
215 dirlump(const dirlump&) = delete;
216 dirlump& operator=(const dirlump&) = delete;
7c673cae
FG
217
218 bool is_complete() const { return state & STATE_COMPLETE; }
219 void mark_complete() { state |= STATE_COMPLETE; }
220 bool is_dirty() const { return state & STATE_DIRTY; }
221 void mark_dirty() { state |= STATE_DIRTY; }
222 bool is_new() const { return state & STATE_NEW; }
223 void mark_new() { state |= STATE_NEW; }
224 bool is_importing() { return state & STATE_IMPORTING; }
225 void mark_importing() { state |= STATE_IMPORTING; }
226 bool is_dirty_dft() { return state & STATE_DIRTYDFT; }
227 void mark_dirty_dft() { state |= STATE_DIRTYDFT; }
228
11fdf7f2
TL
229 const list<fullbit> &get_dfull() const { return dfull; }
230 list<fullbit> &_get_dfull() { return dfull; }
231 const vector<remotebit> &get_dremote() const { return dremote; }
232 const vector<nullbit> &get_dnull() const { return dnull; }
7c673cae 233
11fdf7f2
TL
234 template< class... Args>
235 void add_dfull(Args&&... args) {
236 dfull.emplace_back(std::forward<Args>(args)...);
237 }
238 template< class... Args>
239 void add_dremote(Args&&... args) {
240 dremote.emplace_back(std::forward<Args>(args)...);
241 }
242 template< class... Args>
243 void add_dnull(Args&&... args) {
244 dnull.emplace_back(std::forward<Args>(args)...);
245 }
7c673cae 246
11fdf7f2 247 void print(dirfrag_t dirfrag, ostream& out) const {
7c673cae
FG
248 out << "dirlump " << dirfrag << " v " << fnode.version
249 << " state " << state
250 << " num " << nfull << "/" << nremote << "/" << nnull
251 << std::endl;
252 _decode_bits();
11fdf7f2
TL
253 for (const auto& p : dfull)
254 p.print(out);
255 for (const auto& p : dremote)
256 p.print(out);
257 for (const auto& p : dnull)
258 p.print(out);
7c673cae
FG
259 }
260
261 string state_string() const {
262 string state_string;
263 bool marked_already = false;
264 if (is_complete()) {
265 state_string.append("complete");
266 marked_already = true;
267 }
268 if (is_dirty()) {
269 state_string.append(marked_already ? "+dirty" : "dirty");
270 marked_already = true;
271 }
272 if (is_new()) {
273 state_string.append(marked_already ? "+new" : "new");
274 }
275 return state_string;
276 }
277
278 // if this changes, update the versioning in encode for it!
279 void _encode_bits(uint64_t features) const {
11fdf7f2 280 using ceph::encode;
7c673cae 281 if (!dn_decoded) return;
11fdf7f2
TL
282 encode(dfull, dnbl, features);
283 encode(dremote, dnbl);
284 encode(dnull, dnbl);
7c673cae
FG
285 }
286 void _decode_bits() const {
11fdf7f2 287 using ceph::decode;
7c673cae 288 if (dn_decoded) return;
11fdf7f2
TL
289 auto p = dnbl.cbegin();
290 decode(dfull, p);
291 decode(dremote, p);
292 decode(dnull, p);
7c673cae
FG
293 dn_decoded = true;
294 }
295
296 void encode(bufferlist& bl, uint64_t features) const;
11fdf7f2 297 void decode(bufferlist::const_iterator &bl);
7c673cae 298 void dump(Formatter *f) const;
9f95a23c 299 static void generate_test_instances(std::list<dirlump*>& ls);
7c673cae
FG
300 };
301 WRITE_CLASS_ENCODER_FEATURES(dirlump)
302
303 // my lumps. preserve the order we added them in a list.
11fdf7f2 304 vector<dirfrag_t> lump_order;
7c673cae 305 map<dirfrag_t, dirlump> lump_map;
11fdf7f2 306 list<fullbit> roots;
7c673cae 307public:
11fdf7f2 308 vector<pair<__u8,version_t> > table_tids; // tableclient transactions
7c673cae
FG
309
310 inodeno_t opened_ino;
311public:
312 inodeno_t renamed_dirino;
11fdf7f2 313 vector<frag_t> renamed_dir_frags;
7c673cae
FG
314private:
315
316 // ino (pre)allocation. may involve both inotable AND session state.
317 version_t inotablev, sessionmapv;
318 inodeno_t allocated_ino; // inotable
319 interval_set<inodeno_t> preallocated_inos; // inotable + session
320 inodeno_t used_preallocated_ino; // session
321 entity_name_t client_name; // session
322
323 // inodes i've truncated
11fdf7f2 324 vector<inodeno_t> truncate_start; // start truncate
9f95a23c 325 map<inodeno_t, LogSegment::seq_t> truncate_finish; // finished truncate (started in segment blah)
7c673cae
FG
326
327public:
328 vector<inodeno_t> destroyed_inodes;
329private:
330
331 // idempotent op(s)
11fdf7f2
TL
332 vector<pair<metareqid_t,uint64_t> > client_reqs;
333 vector<pair<metareqid_t,uint64_t> > client_flushes;
7c673cae
FG
334
335 public:
336 void encode(bufferlist& bl, uint64_t features) const;
11fdf7f2 337 void decode(bufferlist::const_iterator& bl);
7c673cae
FG
338 void get_inodes(std::set<inodeno_t> &inodes) const;
339 void get_paths(std::vector<std::string> &paths) const;
340 void get_dentries(std::map<dirfrag_t, std::set<std::string> > &dentries) const;
341 entity_name_t get_client_name() const {return client_name;}
342
343 void dump(Formatter *f) const;
9f95a23c 344 static void generate_test_instances(std::list<EMetaBlob*>& ls);
7c673cae
FG
345 // soft stateadd
346 uint64_t last_subtree_map;
347 uint64_t event_seq;
348
349 // for replay, in certain cases
350 //LogSegment *_segment;
351
11fdf7f2
TL
352 EMetaBlob() : opened_ino(0), renamed_dirino(0),
353 inotablev(0), sessionmapv(0), allocated_ino(0),
354 last_subtree_map(0), event_seq(0)
355 {}
356 EMetaBlob(const EMetaBlob&) = delete;
7c673cae 357 ~EMetaBlob() { }
11fdf7f2 358 EMetaBlob& operator=(const EMetaBlob&) = delete;
7c673cae
FG
359
360 void print(ostream& out) {
11fdf7f2
TL
361 for (const auto &p : lump_order)
362 lump_map[p].print(p, out);
7c673cae
FG
363 }
364
365 void add_client_req(metareqid_t r, uint64_t tid=0) {
366 client_reqs.push_back(pair<metareqid_t,uint64_t>(r, tid));
367 }
368 void add_client_flush(metareqid_t r, uint64_t tid=0) {
369 client_flushes.push_back(pair<metareqid_t,uint64_t>(r, tid));
370 }
371
372 void add_table_transaction(int table, version_t tid) {
373 table_tids.push_back(pair<__u8, version_t>(table, tid));
374 }
375
376 void add_opened_ino(inodeno_t ino) {
11fdf7f2 377 ceph_assert(!opened_ino);
7c673cae
FG
378 opened_ino = ino;
379 }
380
381 void set_ino_alloc(inodeno_t alloc,
382 inodeno_t used_prealloc,
383 interval_set<inodeno_t>& prealloc,
384 entity_name_t client,
385 version_t sv, version_t iv) {
386 allocated_ino = alloc;
387 used_preallocated_ino = used_prealloc;
388 preallocated_inos = prealloc;
389 client_name = client;
390 sessionmapv = sv;
391 inotablev = iv;
392 }
393
394 void add_truncate_start(inodeno_t ino) {
395 truncate_start.push_back(ino);
396 }
397 void add_truncate_finish(inodeno_t ino, uint64_t segoff) {
398 truncate_finish[ino] = segoff;
399 }
400
401 bool rewrite_truncate_finish(MDSRank const *mds, std::map<uint64_t, uint64_t> const &old_to_new);
402
403 void add_destroyed_inode(inodeno_t ino) {
404 destroyed_inodes.push_back(ino);
405 }
406
407 void add_null_dentry(CDentry *dn, bool dirty) {
408 add_null_dentry(add_dir(dn->get_dir(), false), dn, dirty);
409 }
410 void add_null_dentry(dirlump& lump, CDentry *dn, bool dirty) {
411 // add the dir
412 lump.nnull++;
11fdf7f2
TL
413 lump.add_dnull(dn->get_name(), dn->first, dn->last,
414 dn->get_projected_version(), dirty);
7c673cae
FG
415 }
416
417 void add_remote_dentry(CDentry *dn, bool dirty) {
418 add_remote_dentry(add_dir(dn->get_dir(), false), dn, dirty, 0, 0);
419 }
420 void add_remote_dentry(CDentry *dn, bool dirty, inodeno_t rino, int rdt) {
421 add_remote_dentry(add_dir(dn->get_dir(), false), dn, dirty, rino, rdt);
422 }
423 void add_remote_dentry(dirlump& lump, CDentry *dn, bool dirty,
424 inodeno_t rino=0, unsigned char rdt=0) {
425 if (!rino) {
426 rino = dn->get_projected_linkage()->get_remote_ino();
427 rdt = dn->get_projected_linkage()->get_remote_d_type();
428 }
429 lump.nremote++;
11fdf7f2
TL
430 lump.add_dremote(dn->get_name(), dn->first, dn->last,
431 dn->get_projected_version(), rino, rdt, dirty);
7c673cae
FG
432 }
433
434 // return remote pointer to to-be-journaled inode
435 void add_primary_dentry(CDentry *dn, CInode *in, bool dirty,
436 bool dirty_parent=false, bool dirty_pool=false,
437 bool need_snapflush=false) {
438 __u8 state = 0;
439 if (dirty) state |= fullbit::STATE_DIRTY;
440 if (dirty_parent) state |= fullbit::STATE_DIRTYPARENT;
441 if (dirty_pool) state |= fullbit::STATE_DIRTYPOOL;
442 if (need_snapflush) state |= fullbit::STATE_NEED_SNAPFLUSH;
443 add_primary_dentry(add_dir(dn->get_dir(), false), dn, in, state);
444 }
445 void add_primary_dentry(dirlump& lump, CDentry *dn, CInode *in, __u8 state) {
446 if (!in)
447 in = dn->get_projected_linkage()->get_inode();
448
449 // make note of where this inode was last journaled
450 in->last_journaled = event_seq;
451 //cout << "journaling " << in->inode.ino << " at " << my_offset << std::endl;
452
94b18763 453 const auto pi = in->get_projected_inode();
7c673cae
FG
454 if ((state & fullbit::STATE_DIRTY) && pi->is_backtrace_updated())
455 state |= fullbit::STATE_DIRTYPARENT;
456
457 bufferlist snapbl;
458 const sr_t *sr = in->get_projected_srnode();
459 if (sr)
460 sr->encode(snapbl);
461
462 lump.nfull++;
11fdf7f2
TL
463 lump.add_dfull(dn->get_name(), dn->first, dn->last, dn->get_projected_version(),
464 *pi, in->dirfragtree, *in->get_projected_xattrs(), in->symlink,
465 in->oldest_snap, snapbl, state, &in->old_inodes);
7c673cae
FG
466 }
467
468 // convenience: primary or remote? figure it out.
469 void add_dentry(CDentry *dn, bool dirty) {
470 dirlump& lump = add_dir(dn->get_dir(), false);
471 add_dentry(lump, dn, dirty, false, false);
472 }
473 void add_import_dentry(CDentry *dn) {
474 bool dirty_parent = false;
475 bool dirty_pool = false;
476 if (dn->get_linkage()->is_primary()) {
477 dirty_parent = dn->get_linkage()->get_inode()->is_dirty_parent();
478 dirty_pool = dn->get_linkage()->get_inode()->is_dirty_pool();
479 }
480 dirlump& lump = add_dir(dn->get_dir(), false);
481 add_dentry(lump, dn, dn->is_dirty(), dirty_parent, dirty_pool);
482 }
483 void add_dentry(dirlump& lump, CDentry *dn, bool dirty, bool dirty_parent, bool dirty_pool) {
484 // primary or remote
485 if (dn->get_projected_linkage()->is_remote()) {
486 add_remote_dentry(dn, dirty);
487 return;
488 } else if (dn->get_projected_linkage()->is_null()) {
489 add_null_dentry(dn, dirty);
490 return;
491 }
11fdf7f2 492 ceph_assert(dn->get_projected_linkage()->is_primary());
7c673cae
FG
493 add_primary_dentry(dn, 0, dirty, dirty_parent, dirty_pool);
494 }
495
11fdf7f2 496 void add_root(bool dirty, CInode *in) {
7c673cae
FG
497 in->last_journaled = event_seq;
498 //cout << "journaling " << in->inode.ino << " at " << my_offset << std::endl;
499
11fdf7f2
TL
500 const auto& pi = *(in->get_projected_inode());
501 const auto& pdft = in->dirfragtree;
502 const auto& px = *(in->get_projected_xattrs());
7c673cae
FG
503
504 bufferlist snapbl;
11fdf7f2
TL
505 const sr_t *sr = in->get_projected_srnode();
506 if (sr)
507 sr->encode(snapbl);
7c673cae 508
11fdf7f2
TL
509 for (auto p = roots.begin(); p != roots.end(); ++p) {
510 if (p->inode.ino == in->ino()) {
7c673cae
FG
511 roots.erase(p);
512 break;
513 }
514 }
515
516 string empty;
11fdf7f2
TL
517 roots.emplace_back(empty, in->first, in->last, 0, pi, pdft, px, in->symlink,
518 in->oldest_snap, snapbl, (dirty ? fullbit::STATE_DIRTY : 0),
519 &in->old_inodes);
7c673cae
FG
520 }
521
522 dirlump& add_dir(CDir *dir, bool dirty, bool complete=false) {
523 return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(),
524 dirty, complete);
525 }
526 dirlump& add_new_dir(CDir *dir) {
527 return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(),
528 true, true, true); // dirty AND complete AND new
529 }
530 dirlump& add_import_dir(CDir *dir) {
531 // dirty=false would be okay in some cases
532 return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(),
533 dir->is_dirty(), dir->is_complete(), false, true, dir->is_dirty_dft());
534 }
535 dirlump& add_fragmented_dir(CDir *dir, bool dirty, bool dirtydft) {
536 return add_dir(dir->dirfrag(), dir->get_projected_fnode(), dir->get_projected_version(),
537 dirty, false, false, false, dirtydft);
538 }
539 dirlump& add_dir(dirfrag_t df, const fnode_t *pf, version_t pv, bool dirty,
540 bool complete=false, bool isnew=false,
541 bool importing=false, bool dirty_dft=false) {
542 if (lump_map.count(df) == 0)
543 lump_order.push_back(df);
544
545 dirlump& l = lump_map[df];
546 l.fnode = *pf;
547 l.fnode.version = pv;
548 if (complete) l.mark_complete();
549 if (dirty) l.mark_dirty();
550 if (isnew) l.mark_new();
551 if (importing) l.mark_importing();
552 if (dirty_dft) l.mark_dirty_dft();
553 return l;
554 }
555
556 static const int TO_AUTH_SUBTREE_ROOT = 0; // default.
557 static const int TO_ROOT = 1;
558
559 void add_dir_context(CDir *dir, int mode = TO_AUTH_SUBTREE_ROOT);
560
561 bool empty() {
562 return roots.empty() && lump_order.empty() && table_tids.empty() &&
563 truncate_start.empty() && truncate_finish.empty() &&
564 destroyed_inodes.empty() && client_reqs.empty() &&
565 opened_ino == 0 && inotablev == 0 && sessionmapv == 0;
566 }
567
568 void print(ostream& out) const {
569 out << "[metablob";
570 if (!lump_order.empty())
571 out << " " << lump_order.front() << ", " << lump_map.size() << " dirs";
572 if (!table_tids.empty())
573 out << " table_tids=" << table_tids;
574 if (allocated_ino || preallocated_inos.size()) {
575 if (allocated_ino)
576 out << " alloc_ino=" << allocated_ino;
577 if (preallocated_inos.size())
578 out << " prealloc_ino=" << preallocated_inos;
579 if (used_preallocated_ino)
580 out << " used_prealloc_ino=" << used_preallocated_ino;
581 out << " v" << inotablev;
582 }
583 out << "]";
584 }
585
586 void update_segment(LogSegment *ls);
587 void replay(MDSRank *mds, LogSegment *ls, MDSlaveUpdate *su=NULL);
588};
589WRITE_CLASS_ENCODER_FEATURES(EMetaBlob)
590WRITE_CLASS_ENCODER_FEATURES(EMetaBlob::fullbit)
591WRITE_CLASS_ENCODER(EMetaBlob::remotebit)
592WRITE_CLASS_ENCODER(EMetaBlob::nullbit)
593WRITE_CLASS_ENCODER_FEATURES(EMetaBlob::dirlump)
594
595inline ostream& operator<<(ostream& out, const EMetaBlob& t) {
596 t.print(out);
597 return out;
598}
599
600#endif