]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/MDSMap.h
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / mds / MDSMap.h
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
16 #ifndef CEPH_MDSMAP_H
17 #define CEPH_MDSMAP_H
18
19 #include <algorithm>
20 #include <map>
21 #include <set>
22 #include <string>
23 #include <string_view>
24
25 #include <errno.h>
26
27 #include "include/types.h"
28 #include "common/Clock.h"
29 #include "include/health.h"
30
31 #include "common/config.h"
32
33 #include "include/CompatSet.h"
34 #include "include/ceph_features.h"
35 #include "common/Formatter.h"
36 #include "mds/mdstypes.h"
37
38 class CephContext;
39 class health_check_map_t;
40
41 #define MDS_FEATURE_INCOMPAT_BASE CompatSet::Feature(1, "base v0.20")
42 #define MDS_FEATURE_INCOMPAT_CLIENTRANGES CompatSet::Feature(2, "client writeable ranges")
43 #define MDS_FEATURE_INCOMPAT_FILELAYOUT CompatSet::Feature(3, "default file layouts on dirs")
44 #define MDS_FEATURE_INCOMPAT_DIRINODE CompatSet::Feature(4, "dir inode in separate object")
45 #define MDS_FEATURE_INCOMPAT_ENCODING CompatSet::Feature(5, "mds uses versioned encoding")
46 #define MDS_FEATURE_INCOMPAT_OMAPDIRFRAG CompatSet::Feature(6, "dirfrag is stored in omap")
47 #define MDS_FEATURE_INCOMPAT_INLINE CompatSet::Feature(7, "mds uses inline data")
48 #define MDS_FEATURE_INCOMPAT_NOANCHOR CompatSet::Feature(8, "no anchor table")
49 #define MDS_FEATURE_INCOMPAT_FILE_LAYOUT_V2 CompatSet::Feature(9, "file layout v2")
50 #define MDS_FEATURE_INCOMPAT_SNAPREALM_V2 CompatSet::Feature(10, "snaprealm v2")
51
52 #define MDS_FS_NAME_DEFAULT "cephfs"
53
54 class MDSMap {
55 public:
56 /* These states are the union of the set of possible states of an MDS daemon,
57 * and the set of possible states of an MDS rank. See
58 * doc/cephfs/mds-states.rst for state descriptions,
59 * doc/cephfs/mds-state-diagram.svg for a visual state diagram, and
60 * doc/cephfs/mds-state-diagram.dot to update mds-state-diagram.svg.
61 */
62 typedef enum {
63 // States of an MDS daemon not currently holding a rank
64 // ====================================================
65 STATE_NULL = CEPH_MDS_STATE_NULL, // null value for fns returning this type.
66 STATE_BOOT = CEPH_MDS_STATE_BOOT, // up, boot announcement. destiny unknown.
67 STATE_STANDBY = CEPH_MDS_STATE_STANDBY, // up, idle. waiting for assignment by monitor.
68 STATE_STANDBY_REPLAY = CEPH_MDS_STATE_STANDBY_REPLAY, // up, replaying active node, ready to take over.
69
70 // States of an MDS rank, and of any MDS daemon holding that rank
71 // ==============================================================
72 STATE_STOPPED = CEPH_MDS_STATE_STOPPED, // down, once existed, but no subtrees. empty log. may not be held by a daemon.
73
74 STATE_CREATING = CEPH_MDS_STATE_CREATING, // up, creating MDS instance (new journal, idalloc..).
75 STATE_STARTING = CEPH_MDS_STATE_STARTING, // up, starting prior stopped MDS instance.
76
77 STATE_REPLAY = CEPH_MDS_STATE_REPLAY, // up, starting prior failed instance. scanning journal.
78 STATE_RESOLVE = CEPH_MDS_STATE_RESOLVE, // up, disambiguating distributed operations (import, rename, etc.)
79 STATE_RECONNECT = CEPH_MDS_STATE_RECONNECT, // up, reconnect to clients
80 STATE_REJOIN = CEPH_MDS_STATE_REJOIN, // up, replayed journal, rejoining distributed cache
81 STATE_CLIENTREPLAY = CEPH_MDS_STATE_CLIENTREPLAY, // up, active
82 STATE_ACTIVE = CEPH_MDS_STATE_ACTIVE, // up, active
83 STATE_STOPPING = CEPH_MDS_STATE_STOPPING, // up, exporting metadata (-> standby or out)
84 STATE_DNE = CEPH_MDS_STATE_DNE, // down, rank does not exist
85
86 // State which a daemon may send to MDSMonitor in its beacon
87 // to indicate that offline repair is required. Daemon must stop
88 // immediately after indicating this state.
89 STATE_DAMAGED = CEPH_MDS_STATE_DAMAGED
90
91 /*
92 * In addition to explicit states, an MDS rank implicitly in state:
93 * - STOPPED if it is not currently associated with an MDS daemon gid but it
94 * is in MDSMap::stopped
95 * - FAILED if it is not currently associated with an MDS daemon gid but it
96 * is in MDSMap::failed
97 * - DNE if it is not currently associated with an MDS daemon gid and it is
98 * missing from both MDSMap::failed and MDSMap::stopped
99 */
100 } DaemonState;
101
102 struct mds_info_t {
103 mds_gid_t global_id = MDS_GID_NONE;
104 std::string name;
105 mds_rank_t rank = MDS_RANK_NONE;
106 int32_t inc = 0;
107 MDSMap::DaemonState state = STATE_STANDBY;
108 version_t state_seq = 0;
109 entity_addrvec_t addrs;
110 utime_t laggy_since;
111 std::set<mds_rank_t> export_targets;
112 uint64_t mds_features = 0;
113 uint64_t flags = 0;
114 enum mds_flags : uint64_t {
115 FROZEN = 1 << 0,
116 };
117
118 mds_info_t() = default;
119
120 bool laggy() const { return !(laggy_since == utime_t()); }
121 void clear_laggy() { laggy_since = utime_t(); }
122
123 bool is_degraded() const {
124 return STATE_REPLAY <= state && state <= STATE_CLIENTREPLAY;
125 }
126
127 void freeze() { flags |= mds_flags::FROZEN; }
128 void unfreeze() { flags &= ~mds_flags::FROZEN; }
129 bool is_frozen() const { return flags&mds_flags::FROZEN; }
130
131 const entity_addrvec_t& get_addrs() const {
132 return addrs;
133 }
134
135 void encode(bufferlist& bl, uint64_t features) const {
136 if ((features & CEPH_FEATURE_MDSENC) == 0 ) encode_unversioned(bl);
137 else encode_versioned(bl, features);
138 }
139 void decode(bufferlist::const_iterator& p);
140 void dump(Formatter *f) const;
141 void print_summary(ostream &out) const;
142
143 // The long form name for use in cluster log messages`
144 std::string human_name() const;
145
146 static void generate_test_instances(list<mds_info_t*>& ls);
147 private:
148 void encode_versioned(bufferlist& bl, uint64_t features) const;
149 void encode_unversioned(bufferlist& bl) const;
150 };
151
152 static CompatSet get_compat_set_all();
153 static CompatSet get_compat_set_default();
154 static CompatSet get_compat_set_base(); // pre v0.20
155
156 protected:
157 // base map
158 epoch_t epoch = 0;
159 bool enabled = false;
160 std::string fs_name = MDS_FS_NAME_DEFAULT;
161 uint32_t flags = CEPH_MDSMAP_DEFAULTS; // flags
162 epoch_t last_failure = 0; // mds epoch of last failure
163 epoch_t last_failure_osd_epoch = 0; // osd epoch of last failure; any mds entering replay needs
164 // at least this osdmap to ensure the blacklist propagates.
165 utime_t created;
166 utime_t modified;
167
168 mds_rank_t tableserver = 0; // which MDS has snaptable
169 mds_rank_t root = 0; // which MDS has root directory
170
171 __u32 session_timeout = 60;
172 __u32 session_autoclose = 300;
173 uint64_t max_file_size = 1ULL<<40; /* 1TB */
174
175 int8_t min_compat_client = -1;
176
177 std::vector<int64_t> data_pools; // file data pools available to clients (via an ioctl). first is the default.
178 int64_t cas_pool = -1; // where CAS objects go
179 int64_t metadata_pool = -1; // where fs metadata objects go
180
181 /*
182 * in: the set of logical mds #'s that define the cluster. this is the set
183 * of mds's the metadata may be distributed over.
184 * up: map from logical mds #'s to the addrs filling those roles.
185 * failed: subset of @in that are failed.
186 * stopped: set of nodes that have been initialized, but are not active.
187 *
188 * @up + @failed = @in. @in * @stopped = {}.
189 */
190
191 mds_rank_t max_mds = 1; /* The maximum number of active MDSes. Also, the maximum rank. */
192 mds_rank_t old_max_mds = 0; /* Value to restore when MDS cluster is marked up */
193 mds_rank_t standby_count_wanted = -1;
194 string balancer; /* The name/version of the mantle balancer (i.e. the rados obj name) */
195
196 std::set<mds_rank_t> in; // currently defined cluster
197
198 // which ranks are failed, stopped, damaged (i.e. not held by a daemon)
199 std::set<mds_rank_t> failed, stopped, damaged;
200 std::map<mds_rank_t, mds_gid_t> up; // who is in those roles
201 std::map<mds_gid_t, mds_info_t> mds_info;
202
203 uint8_t ever_allowed_features = 0; //< bitmap of features the cluster has allowed
204 uint8_t explicitly_allowed_features = 0; //< bitmap of features explicitly enabled
205
206 bool inline_data_enabled = false;
207
208 uint64_t cached_up_features = 0;
209
210 public:
211 CompatSet compat;
212
213 friend class MDSMonitor;
214 friend class Filesystem;
215 friend class FSMap;
216
217 public:
218 bool get_inline_data_enabled() const { return inline_data_enabled; }
219 void set_inline_data_enabled(bool enabled) { inline_data_enabled = enabled; }
220
221 utime_t get_session_timeout() const {
222 return utime_t(session_timeout,0);
223 }
224 void set_session_timeout(uint32_t t) {
225 session_timeout = t;
226 }
227
228 utime_t get_session_autoclose() const {
229 return utime_t(session_autoclose, 0);
230 }
231 void set_session_autoclose(uint32_t t) {
232 session_autoclose = t;
233 }
234
235 uint64_t get_max_filesize() const { return max_file_size; }
236 void set_max_filesize(uint64_t m) { max_file_size = m; }
237
238 uint8_t get_min_compat_client() const { return min_compat_client; }
239 void set_min_compat_client(uint8_t version) { min_compat_client = version; }
240
241 int get_flags() const { return flags; }
242 bool test_flag(int f) const { return flags & f; }
243 void set_flag(int f) { flags |= f; }
244 void clear_flag(int f) { flags &= ~f; }
245
246 std::string_view get_fs_name() const {return fs_name;}
247
248 void set_snaps_allowed() {
249 set_flag(CEPH_MDSMAP_ALLOW_SNAPS);
250 ever_allowed_features |= CEPH_MDSMAP_ALLOW_SNAPS;
251 explicitly_allowed_features |= CEPH_MDSMAP_ALLOW_SNAPS;
252 }
253 void clear_snaps_allowed() { clear_flag(CEPH_MDSMAP_ALLOW_SNAPS); }
254 bool allows_snaps() const { return test_flag(CEPH_MDSMAP_ALLOW_SNAPS); }
255 bool was_snaps_ever_allowed() const { return ever_allowed_features & CEPH_MDSMAP_ALLOW_SNAPS; }
256
257 void set_standby_replay_allowed() {
258 set_flag(CEPH_MDSMAP_ALLOW_STANDBY_REPLAY);
259 ever_allowed_features |= CEPH_MDSMAP_ALLOW_STANDBY_REPLAY;
260 explicitly_allowed_features |= CEPH_MDSMAP_ALLOW_STANDBY_REPLAY;
261 }
262 void clear_standby_replay_allowed() { clear_flag(CEPH_MDSMAP_ALLOW_STANDBY_REPLAY); }
263 bool allows_standby_replay() const { return test_flag(CEPH_MDSMAP_ALLOW_STANDBY_REPLAY); }
264 bool was_standby_replay_ever_allowed() const { return ever_allowed_features & CEPH_MDSMAP_ALLOW_STANDBY_REPLAY; }
265
266 void set_multimds_snaps_allowed() {
267 set_flag(CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS);
268 ever_allowed_features |= CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS;
269 explicitly_allowed_features |= CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS;
270 }
271 void clear_multimds_snaps_allowed() { clear_flag(CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS); }
272 bool allows_multimds_snaps() const { return test_flag(CEPH_MDSMAP_ALLOW_MULTIMDS_SNAPS); }
273
274 epoch_t get_epoch() const { return epoch; }
275 void inc_epoch() { epoch++; }
276
277 bool get_enabled() const { return enabled; }
278
279 const utime_t& get_created() const { return created; }
280 void set_created(utime_t ct) { modified = created = ct; }
281 const utime_t& get_modified() const { return modified; }
282 void set_modified(utime_t mt) { modified = mt; }
283
284 epoch_t get_last_failure() const { return last_failure; }
285 epoch_t get_last_failure_osd_epoch() const { return last_failure_osd_epoch; }
286
287 mds_rank_t get_max_mds() const { return max_mds; }
288 void set_max_mds(mds_rank_t m) { max_mds = m; }
289 void set_old_max_mds() { old_max_mds = max_mds; }
290 mds_rank_t get_old_max_mds() const { return old_max_mds; }
291
292 mds_rank_t get_standby_count_wanted(mds_rank_t standby_daemon_count) const {
293 ceph_assert(standby_daemon_count >= 0);
294 std::set<mds_rank_t> s;
295 get_standby_replay_mds_set(s);
296 mds_rank_t standbys_avail = (mds_rank_t)s.size()+standby_daemon_count;
297 mds_rank_t wanted = std::max(0, standby_count_wanted);
298 return wanted > standbys_avail ? wanted - standbys_avail : 0;
299 }
300 void set_standby_count_wanted(mds_rank_t n) { standby_count_wanted = n; }
301 bool check_health(mds_rank_t standby_daemon_count);
302
303 const std::string get_balancer() const { return balancer; }
304 void set_balancer(std::string val) { balancer.assign(val); }
305
306 mds_rank_t get_tableserver() const { return tableserver; }
307 mds_rank_t get_root() const { return root; }
308
309 const std::vector<int64_t> &get_data_pools() const { return data_pools; }
310 int64_t get_first_data_pool() const { return *data_pools.begin(); }
311 int64_t get_metadata_pool() const { return metadata_pool; }
312 bool is_data_pool(int64_t poolid) const {
313 auto p = std::find(data_pools.begin(), data_pools.end(), poolid);
314 if (p == data_pools.end())
315 return false;
316 return true;
317 }
318
319 bool pool_in_use(int64_t poolid) const {
320 return get_enabled() && (is_data_pool(poolid) || metadata_pool == poolid);
321 }
322
323 const std::map<mds_gid_t,mds_info_t>& get_mds_info() const { return mds_info; }
324 const mds_info_t& get_mds_info_gid(mds_gid_t gid) const {
325 return mds_info.at(gid);
326 }
327 const mds_info_t& get_mds_info(mds_rank_t m) const {
328 ceph_assert(up.count(m) && mds_info.count(up.at(m)));
329 return mds_info.at(up.at(m));
330 }
331 mds_gid_t find_mds_gid_by_name(std::string_view s) const {
332 for (std::map<mds_gid_t,mds_info_t>::const_iterator p = mds_info.begin();
333 p != mds_info.end();
334 ++p) {
335 if (p->second.name == s) {
336 return p->first;
337 }
338 }
339 return MDS_GID_NONE;
340 }
341
342 // counts
343 unsigned get_num_in_mds() const {
344 return in.size();
345 }
346 unsigned get_num_up_mds() const {
347 return up.size();
348 }
349 mds_rank_t get_last_in_mds() const {
350 auto p = in.rbegin();
351 return p == in.rend() ? MDS_RANK_NONE : *p;
352 }
353 int get_num_failed_mds() const {
354 return failed.size();
355 }
356 unsigned get_num_mds(int state) const {
357 unsigned n = 0;
358 for (std::map<mds_gid_t,mds_info_t>::const_iterator p = mds_info.begin();
359 p != mds_info.end();
360 ++p)
361 if (p->second.state == state) ++n;
362 return n;
363 }
364
365 // data pools
366 void add_data_pool(int64_t poolid) {
367 data_pools.push_back(poolid);
368 }
369 int remove_data_pool(int64_t poolid) {
370 std::vector<int64_t>::iterator p = std::find(data_pools.begin(), data_pools.end(), poolid);
371 if (p == data_pools.end())
372 return -ENOENT;
373 data_pools.erase(p);
374 return 0;
375 }
376
377 // sets
378 void get_mds_set(std::set<mds_rank_t>& s) const {
379 s = in;
380 }
381 void get_up_mds_set(std::set<mds_rank_t>& s) const {
382 for (std::map<mds_rank_t, mds_gid_t>::const_iterator p = up.begin();
383 p != up.end();
384 ++p)
385 s.insert(p->first);
386 }
387 void get_active_mds_set(std::set<mds_rank_t>& s) const {
388 get_mds_set(s, MDSMap::STATE_ACTIVE);
389 }
390 void get_standby_replay_mds_set(std::set<mds_rank_t>& s) const {
391 get_mds_set(s, MDSMap::STATE_STANDBY_REPLAY);
392 }
393 void get_failed_mds_set(std::set<mds_rank_t>& s) const {
394 s = failed;
395 }
396
397 // features
398 uint64_t get_up_features() {
399 if (!cached_up_features) {
400 bool first = true;
401 for (std::map<mds_rank_t, mds_gid_t>::const_iterator p = up.begin();
402 p != up.end();
403 ++p) {
404 std::map<mds_gid_t, mds_info_t>::const_iterator q =
405 mds_info.find(p->second);
406 ceph_assert(q != mds_info.end());
407 if (first) {
408 cached_up_features = q->second.mds_features;
409 first = false;
410 } else {
411 cached_up_features &= q->second.mds_features;
412 }
413 }
414 }
415 return cached_up_features;
416 }
417
418 /**
419 * Get MDS ranks which are in but not up.
420 */
421 void get_down_mds_set(std::set<mds_rank_t> *s) const
422 {
423 ceph_assert(s != NULL);
424 s->insert(failed.begin(), failed.end());
425 s->insert(damaged.begin(), damaged.end());
426 }
427
428 int get_failed() const {
429 if (!failed.empty()) return *failed.begin();
430 return -1;
431 }
432 void get_stopped_mds_set(std::set<mds_rank_t>& s) const {
433 s = stopped;
434 }
435 void get_recovery_mds_set(std::set<mds_rank_t>& s) const {
436 s = failed;
437 for (const auto& p : damaged)
438 s.insert(p);
439 for (const auto& p : mds_info)
440 if (p.second.state >= STATE_REPLAY && p.second.state <= STATE_STOPPING)
441 s.insert(p.second.rank);
442 }
443
444 void get_mds_set_lower_bound(std::set<mds_rank_t>& s, DaemonState first) const {
445 for (std::map<mds_gid_t, mds_info_t>::const_iterator p = mds_info.begin();
446 p != mds_info.end();
447 ++p)
448 if (p->second.state >= first && p->second.state <= STATE_STOPPING)
449 s.insert(p->second.rank);
450 }
451 void get_mds_set(std::set<mds_rank_t>& s, DaemonState state) const {
452 for (std::map<mds_gid_t, mds_info_t>::const_iterator p = mds_info.begin();
453 p != mds_info.end();
454 ++p)
455 if (p->second.state == state)
456 s.insert(p->second.rank);
457 }
458
459 void get_health(list<pair<health_status_t,std::string> >& summary,
460 list<pair<health_status_t,std::string> > *detail) const;
461
462 void get_health_checks(health_check_map_t *checks) const;
463
464 typedef enum
465 {
466 AVAILABLE = 0,
467 TRANSIENT_UNAVAILABLE = 1,
468 STUCK_UNAVAILABLE = 2
469
470 } availability_t;
471
472 /**
473 * Return indication of whether cluster is available. This is a
474 * heuristic for clients to see if they should bother waiting to talk to
475 * MDSs, or whether they should error out at startup/mount.
476 *
477 * A TRANSIENT_UNAVAILABLE result indicates that the cluster is in a
478 * transition state like replaying, or is potentially about the fail over.
479 * Clients should wait for an updated map before making a final decision
480 * about whether the filesystem is mountable.
481 *
482 * A STUCK_UNAVAILABLE result indicates that we can't see a way that
483 * the cluster is about to recover on its own, so it'll probably require
484 * administrator intervention: clients should probably not bother trying
485 * to mount.
486 */
487 availability_t is_cluster_available() const;
488
489 /**
490 * Return whether this MDSMap is suitable for resizing based on the state
491 * of the ranks.
492 */
493 bool is_resizeable() const {
494 return !is_degraded() &&
495 get_num_mds(CEPH_MDS_STATE_CREATING) == 0 &&
496 get_num_mds(CEPH_MDS_STATE_STARTING) == 0 &&
497 get_num_mds(CEPH_MDS_STATE_STOPPING) == 0;
498 }
499
500 // mds states
501 bool is_down(mds_rank_t m) const { return up.count(m) == 0; }
502 bool is_up(mds_rank_t m) const { return up.count(m); }
503 bool is_in(mds_rank_t m) const { return up.count(m) || failed.count(m); }
504 bool is_out(mds_rank_t m) const { return !is_in(m); }
505
506 bool is_failed(mds_rank_t m) const { return failed.count(m); }
507 bool is_stopped(mds_rank_t m) const { return stopped.count(m); }
508
509 bool is_dne(mds_rank_t m) const { return in.count(m) == 0; }
510 bool is_dne_gid(mds_gid_t gid) const { return mds_info.count(gid) == 0; }
511
512 /**
513 * Get MDS rank state if the rank is up, else STATE_NULL
514 */
515 DaemonState get_state(mds_rank_t m) const {
516 std::map<mds_rank_t, mds_gid_t>::const_iterator u = up.find(m);
517 if (u == up.end())
518 return STATE_NULL;
519 return get_state_gid(u->second);
520 }
521
522 /**
523 * Get MDS daemon status by GID
524 */
525 DaemonState get_state_gid(mds_gid_t gid) const {
526 std::map<mds_gid_t,mds_info_t>::const_iterator i = mds_info.find(gid);
527 if (i == mds_info.end())
528 return STATE_NULL;
529 return i->second.state;
530 }
531
532 const mds_info_t& get_info(const mds_rank_t m) const {
533 return mds_info.at(up.at(m));
534 }
535 const mds_info_t& get_info_gid(const mds_gid_t gid) const {
536 return mds_info.at(gid);
537 }
538
539 bool is_boot(mds_rank_t m) const { return get_state(m) == STATE_BOOT; }
540 bool is_creating(mds_rank_t m) const { return get_state(m) == STATE_CREATING; }
541 bool is_starting(mds_rank_t m) const { return get_state(m) == STATE_STARTING; }
542 bool is_replay(mds_rank_t m) const { return get_state(m) == STATE_REPLAY; }
543 bool is_resolve(mds_rank_t m) const { return get_state(m) == STATE_RESOLVE; }
544 bool is_reconnect(mds_rank_t m) const { return get_state(m) == STATE_RECONNECT; }
545 bool is_rejoin(mds_rank_t m) const { return get_state(m) == STATE_REJOIN; }
546 bool is_clientreplay(mds_rank_t m) const { return get_state(m) == STATE_CLIENTREPLAY; }
547 bool is_active(mds_rank_t m) const { return get_state(m) == STATE_ACTIVE; }
548 bool is_stopping(mds_rank_t m) const { return get_state(m) == STATE_STOPPING; }
549 bool is_active_or_stopping(mds_rank_t m) const {
550 return is_active(m) || is_stopping(m);
551 }
552 bool is_clientreplay_or_active_or_stopping(mds_rank_t m) const {
553 return is_clientreplay(m) || is_active(m) || is_stopping(m);
554 }
555
556 mds_gid_t get_standby_replay(mds_rank_t r) const {
557 for (auto& [gid,info] : mds_info) {
558 if (info.rank == r && info.state == STATE_STANDBY_REPLAY) {
559 return gid;
560 }
561 }
562 return MDS_GID_NONE;
563 }
564 bool has_standby_replay(mds_rank_t r) const {
565 return get_standby_replay(r) != MDS_GID_NONE;
566 }
567
568 bool is_followable(mds_rank_t r) const {
569 if (auto it1 = up.find(r); it1 != up.end()) {
570 if (auto it2 = mds_info.find(it1->second); it2 != mds_info.end()) {
571 auto& info = it2->second;
572 if (!info.is_degraded() && !has_standby_replay(r)) {
573 return true;
574 }
575 }
576 }
577 return false;
578 }
579
580 bool is_laggy_gid(mds_gid_t gid) const {
581 auto it = mds_info.find(gid);
582 return it == mds_info.end() ? false : it->second.laggy();
583 }
584
585 // degraded = some recovery in process. fixes active membership and
586 // recovery_set.
587 bool is_degraded() const {
588 if (!failed.empty() || !damaged.empty())
589 return true;
590 for (const auto& p : mds_info) {
591 if (p.second.is_degraded())
592 return true;
593 }
594 return false;
595 }
596 bool is_any_failed() const {
597 return failed.size();
598 }
599 bool is_resolving() const {
600 return
601 get_num_mds(STATE_RESOLVE) > 0 &&
602 get_num_mds(STATE_REPLAY) == 0 &&
603 failed.empty() && damaged.empty();
604 }
605 bool is_rejoining() const {
606 // nodes are rejoining cache state
607 return
608 get_num_mds(STATE_REJOIN) > 0 &&
609 get_num_mds(STATE_REPLAY) == 0 &&
610 get_num_mds(STATE_RECONNECT) == 0 &&
611 get_num_mds(STATE_RESOLVE) == 0 &&
612 failed.empty() && damaged.empty();
613 }
614 bool is_stopped() const {
615 return up.empty();
616 }
617
618 /**
619 * Get whether a rank is 'up', i.e. has
620 * an MDS daemon's entity_inst_t associated
621 * with it.
622 */
623 bool have_inst(mds_rank_t m) const {
624 return up.count(m);
625 }
626
627 /**
628 * Get the MDS daemon entity_inst_t for a rank
629 * known to be up.
630 */
631 entity_addrvec_t get_addrs(mds_rank_t m) const {
632 return mds_info.at(up.at(m)).get_addrs();
633 }
634
635 mds_rank_t get_rank_gid(mds_gid_t gid) const {
636 if (mds_info.count(gid)) {
637 return mds_info.at(gid).rank;
638 } else {
639 return MDS_RANK_NONE;
640 }
641 }
642
643 /**
644 * Get MDS rank incarnation if the rank is up, else -1
645 */
646 mds_gid_t get_incarnation(mds_rank_t m) const {
647 std::map<mds_rank_t, mds_gid_t>::const_iterator u = up.find(m);
648 if (u == up.end())
649 return MDS_GID_NONE;
650 return (mds_gid_t)get_inc_gid(u->second);
651 }
652
653 int get_inc_gid(mds_gid_t gid) const {
654 auto mds_info_entry = mds_info.find(gid);
655 if (mds_info_entry != mds_info.end())
656 return mds_info_entry->second.inc;
657 return -1;
658 }
659 void encode(bufferlist& bl, uint64_t features) const;
660 void decode(bufferlist::const_iterator& p);
661 void decode(const bufferlist& bl) {
662 auto p = bl.cbegin();
663 decode(p);
664 }
665 void sanitize(const std::function<bool(int64_t pool)>& pool_exists);
666
667 void print(ostream& out) const;
668 void print_summary(Formatter *f, ostream *out) const;
669
670 void dump(Formatter *f) const;
671 static void generate_test_instances(list<MDSMap*>& ls);
672
673 static bool state_transition_valid(DaemonState prev, DaemonState next);
674 };
675 WRITE_CLASS_ENCODER_FEATURES(MDSMap::mds_info_t)
676 WRITE_CLASS_ENCODER_FEATURES(MDSMap)
677
678 inline ostream& operator<<(ostream &out, const MDSMap &m) {
679 m.print_summary(NULL, &out);
680 return out;
681 }
682
683 #endif