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