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 "common/debug.h"
16 #include "mon/health_check.h"
21 using std::stringstream;
23 #define dout_context g_ceph_context
24 #define dout_subsys ceph_subsys_
27 CompatSet get_mdsmap_compat_set_all() {
28 CompatSet::FeatureSet feature_compat;
29 CompatSet::FeatureSet feature_ro_compat;
30 CompatSet::FeatureSet feature_incompat;
31 feature_incompat.insert(MDS_FEATURE_INCOMPAT_BASE);
32 feature_incompat.insert(MDS_FEATURE_INCOMPAT_CLIENTRANGES);
33 feature_incompat.insert(MDS_FEATURE_INCOMPAT_FILELAYOUT);
34 feature_incompat.insert(MDS_FEATURE_INCOMPAT_DIRINODE);
35 feature_incompat.insert(MDS_FEATURE_INCOMPAT_ENCODING);
36 feature_incompat.insert(MDS_FEATURE_INCOMPAT_OMAPDIRFRAG);
37 feature_incompat.insert(MDS_FEATURE_INCOMPAT_INLINE);
38 feature_incompat.insert(MDS_FEATURE_INCOMPAT_NOANCHOR);
39 feature_incompat.insert(MDS_FEATURE_INCOMPAT_FILE_LAYOUT_V2);
41 return CompatSet(feature_compat, feature_ro_compat, feature_incompat);
44 CompatSet get_mdsmap_compat_set_default() {
45 CompatSet::FeatureSet feature_compat;
46 CompatSet::FeatureSet feature_ro_compat;
47 CompatSet::FeatureSet feature_incompat;
48 feature_incompat.insert(MDS_FEATURE_INCOMPAT_BASE);
49 feature_incompat.insert(MDS_FEATURE_INCOMPAT_CLIENTRANGES);
50 feature_incompat.insert(MDS_FEATURE_INCOMPAT_FILELAYOUT);
51 feature_incompat.insert(MDS_FEATURE_INCOMPAT_DIRINODE);
52 feature_incompat.insert(MDS_FEATURE_INCOMPAT_ENCODING);
53 feature_incompat.insert(MDS_FEATURE_INCOMPAT_OMAPDIRFRAG);
54 feature_incompat.insert(MDS_FEATURE_INCOMPAT_NOANCHOR);
55 feature_incompat.insert(MDS_FEATURE_INCOMPAT_FILE_LAYOUT_V2);
57 return CompatSet(feature_compat, feature_ro_compat, feature_incompat);
61 CompatSet get_mdsmap_compat_set_base() {
62 CompatSet::FeatureSet feature_compat_base;
63 CompatSet::FeatureSet feature_incompat_base;
64 feature_incompat_base.insert(MDS_FEATURE_INCOMPAT_BASE);
65 CompatSet::FeatureSet feature_ro_compat_base;
67 return CompatSet(feature_compat_base, feature_ro_compat_base, feature_incompat_base);
70 void MDSMap::mds_info_t::dump(Formatter *f) const
72 f->dump_unsigned("gid", global_id);
73 f->dump_string("name", name);
74 f->dump_int("rank", rank);
75 f->dump_int("incarnation", inc);
76 f->dump_stream("state") << ceph_mds_state_name(state);
77 f->dump_int("state_seq", state_seq);
78 f->dump_stream("addr") << addr;
79 if (laggy_since != utime_t())
80 f->dump_stream("laggy_since") << laggy_since;
82 f->dump_int("standby_for_rank", standby_for_rank);
83 f->dump_int("standby_for_fscid", standby_for_fscid);
84 f->dump_string("standby_for_name", standby_for_name);
85 f->dump_bool("standby_replay", standby_replay);
86 f->open_array_section("export_targets");
87 for (set<mds_rank_t>::iterator p = export_targets.begin();
88 p != export_targets.end(); ++p) {
89 f->dump_int("mds", *p);
92 f->dump_unsigned("features", mds_features);
95 void MDSMap::mds_info_t::print_summary(ostream &out) const
97 out << global_id << ":\t"
99 << " '" << name << "'"
102 << " " << ceph_mds_state_name(state)
103 << " seq " << state_seq;
105 out << " laggy since " << laggy_since;
107 if (standby_for_rank != -1 ||
108 !standby_for_name.empty()) {
109 out << " (standby for";
110 //if (standby_for_rank >= 0)
111 out << " rank " << standby_for_rank;
112 if (!standby_for_name.empty()) {
113 out << " '" << standby_for_name << "'";
117 if (!export_targets.empty()) {
118 out << " export_targets=" << export_targets;
122 void MDSMap::mds_info_t::generate_test_instances(list<mds_info_t*>& ls)
124 mds_info_t *sample = new mds_info_t();
125 ls.push_back(sample);
126 sample = new mds_info_t();
127 sample->global_id = 1;
128 sample->name = "test_instance";
130 ls.push_back(sample);
133 void MDSMap::dump(Formatter *f) const
135 f->dump_int("epoch", epoch);
136 f->dump_unsigned("flags", flags);
137 f->dump_unsigned("ever_allowed_features", ever_allowed_features);
138 f->dump_unsigned("explicitly_allowed_features", explicitly_allowed_features);
139 f->dump_stream("created") << created;
140 f->dump_stream("modified") << modified;
141 f->dump_int("tableserver", tableserver);
142 f->dump_int("root", root);
143 f->dump_int("session_timeout", session_timeout);
144 f->dump_int("session_autoclose", session_autoclose);
145 f->dump_int("max_file_size", max_file_size);
146 f->dump_int("last_failure", last_failure);
147 f->dump_int("last_failure_osd_epoch", last_failure_osd_epoch);
148 f->open_object_section("compat");
151 f->dump_int("max_mds", max_mds);
152 f->open_array_section("in");
153 for (set<mds_rank_t>::const_iterator p = in.begin(); p != in.end(); ++p)
154 f->dump_int("mds", *p);
156 f->open_object_section("up");
157 for (map<mds_rank_t,mds_gid_t>::const_iterator p = up.begin(); p != up.end(); ++p) {
159 sprintf(s, "mds_%d", int(p->first));
160 f->dump_int(s, p->second);
163 f->open_array_section("failed");
164 for (set<mds_rank_t>::const_iterator p = failed.begin(); p != failed.end(); ++p)
165 f->dump_int("mds", *p);
167 f->open_array_section("damaged");
168 for (set<mds_rank_t>::const_iterator p = damaged.begin(); p != damaged.end(); ++p)
169 f->dump_int("mds", *p);
171 f->open_array_section("stopped");
172 for (set<mds_rank_t>::const_iterator p = stopped.begin(); p != stopped.end(); ++p)
173 f->dump_int("mds", *p);
175 f->open_object_section("info");
176 for (map<mds_gid_t,mds_info_t>::const_iterator p = mds_info.begin(); p != mds_info.end(); ++p) {
177 char s[25]; // 'gid_' + len(str(ULLONG_MAX)) + '\0'
178 sprintf(s, "gid_%llu", (long long unsigned)p->first);
179 f->open_object_section(s);
184 f->open_array_section("data_pools");
185 for (const auto p: data_pools)
186 f->dump_int("pool", p);
188 f->dump_int("metadata_pool", metadata_pool);
189 f->dump_bool("enabled", enabled);
190 f->dump_string("fs_name", fs_name);
191 f->dump_string("balancer", balancer);
192 f->dump_int("standby_count_wanted", std::max(0, standby_count_wanted));
195 void MDSMap::generate_test_instances(list<MDSMap*>& ls)
197 MDSMap *m = new MDSMap();
199 m->data_pools.push_back(0);
200 m->metadata_pool = 1;
202 m->compat = get_mdsmap_compat_set_all();
204 // these aren't the defaults, just in case anybody gets confused
205 m->session_timeout = 61;
206 m->session_autoclose = 301;
207 m->max_file_size = 1<<24;
211 void MDSMap::print(ostream& out) const
213 out << "fs_name\t" << fs_name << "\n";
214 out << "epoch\t" << epoch << "\n";
215 out << "flags\t" << hex << flags << dec << "\n";
216 out << "created\t" << created << "\n";
217 out << "modified\t" << modified << "\n";
218 out << "tableserver\t" << tableserver << "\n";
219 out << "root\t" << root << "\n";
220 out << "session_timeout\t" << session_timeout << "\n"
221 << "session_autoclose\t" << session_autoclose << "\n";
222 out << "max_file_size\t" << max_file_size << "\n";
223 out << "last_failure\t" << last_failure << "\n"
224 << "last_failure_osd_epoch\t" << last_failure_osd_epoch << "\n";
225 out << "compat\t" << compat << "\n";
226 out << "max_mds\t" << max_mds << "\n";
227 out << "in\t" << in << "\n"
228 << "up\t" << up << "\n"
229 << "failed\t" << failed << "\n"
230 << "damaged\t" << damaged << "\n"
231 << "stopped\t" << stopped << "\n";
232 out << "data_pools\t" << data_pools << "\n";
233 out << "metadata_pool\t" << metadata_pool << "\n";
234 out << "inline_data\t" << (inline_data_enabled ? "enabled" : "disabled") << "\n";
235 out << "balancer\t" << balancer << "\n";
236 out << "standby_count_wanted\t" << std::max(0, standby_count_wanted) << "\n";
238 multimap< pair<mds_rank_t, unsigned>, mds_gid_t > foo;
239 for (const auto &p : mds_info) {
240 foo.insert(std::make_pair(
241 std::make_pair(p.second.rank, p.second.inc-1), p.first));
244 for (const auto &p : foo) {
245 const mds_info_t& info = mds_info.at(p.second);
246 info.print_summary(out);
253 void MDSMap::print_summary(Formatter *f, ostream *out) const
255 map<mds_rank_t,string> by_rank;
256 map<string,int> by_state;
259 f->dump_unsigned("epoch", get_epoch());
260 f->dump_unsigned("up", up.size());
261 f->dump_unsigned("in", in.size());
262 f->dump_unsigned("max", max_mds);
264 *out << "e" << get_epoch() << ": " << up.size() << "/" << in.size() << "/" << max_mds << " up";
268 f->open_array_section("by_rank");
269 for (const auto &p : mds_info) {
270 string s = ceph_mds_state_name(p.second.state);
271 if (p.second.laggy())
272 s += "(laggy or crashed)";
274 if (p.second.rank >= 0 && p.second.state != MDSMap::STATE_STANDBY_REPLAY) {
276 f->open_object_section("mds");
277 f->dump_unsigned("rank", p.second.rank);
278 f->dump_string("name", p.second.name);
279 f->dump_string("status", s);
282 by_rank[p.second.rank] = p.second.name + "=" + s;
291 if (!by_rank.empty())
292 *out << " " << by_rank;
295 for (map<string,int>::reverse_iterator p = by_state.rbegin(); p != by_state.rend(); ++p) {
297 f->dump_unsigned(p->first.c_str(), p->second);
299 *out << ", " << p->second << " " << p->first;
303 if (!failed.empty()) {
305 f->dump_unsigned("failed", failed.size());
307 *out << ", " << failed.size() << " failed";
311 if (!damaged.empty()) {
313 f->dump_unsigned("damaged", damaged.size());
315 *out << ", " << damaged.size() << " damaged";
318 //if (stopped.size())
319 //out << ", " << stopped.size() << " stopped";
322 void MDSMap::get_health(list<pair<health_status_t,string> >& summary,
323 list<pair<health_status_t,string> > *detail) const
325 if (!failed.empty()) {
326 std::ostringstream oss;
328 << ((failed.size() > 1) ? "s ":" ")
330 << ((failed.size() > 1) ? " have":" has")
332 summary.push_back(make_pair(HEALTH_ERR, oss.str()));
334 for (set<mds_rank_t>::const_iterator p = failed.begin(); p != failed.end(); ++p) {
335 std::ostringstream oss;
336 oss << "mds." << *p << " has failed";
337 detail->push_back(make_pair(HEALTH_ERR, oss.str()));
342 if (!damaged.empty()) {
343 std::ostringstream oss;
345 << ((damaged.size() > 1) ? "s ":" ")
347 << ((damaged.size() > 1) ? " are":" is")
349 summary.push_back(make_pair(HEALTH_ERR, oss.str()));
351 for (set<mds_rank_t>::const_iterator p = damaged.begin(); p != damaged.end(); ++p) {
352 std::ostringstream oss;
353 oss << "mds." << *p << " is damaged";
354 detail->push_back(make_pair(HEALTH_ERR, oss.str()));
360 summary.push_back(make_pair(HEALTH_WARN, "mds cluster is degraded"));
362 detail->push_back(make_pair(HEALTH_WARN, "mds cluster is degraded"));
363 for (mds_rank_t i = mds_rank_t(0); i< get_max_mds(); i++) {
366 mds_gid_t gid = up.find(i)->second;
367 map<mds_gid_t,mds_info_t>::const_iterator info = mds_info.find(gid);
370 ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is resolving";
372 ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is replaying journal";
374 ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is rejoining";
376 ss << "mds." << info->second.name << " at " << info->second.addr << " rank " << i << " is reconnecting to clients";
377 if (ss.str().length())
378 detail->push_back(make_pair(HEALTH_WARN, ss.str()));
383 map<mds_gid_t, mds_info_t>::const_iterator m_end = mds_info.end();
385 for (const auto &u : up) {
386 map<mds_gid_t, mds_info_t>::const_iterator m = mds_info.find(u.second);
388 std::cerr << "Up rank " << u.first << " GID " << u.second << " not found!" << std::endl;
391 const mds_info_t &mds_info(m->second);
392 if (mds_info.laggy()) {
393 laggy.insert(mds_info.name);
395 std::ostringstream oss;
396 oss << "mds." << mds_info.name << " at " << mds_info.addr << " is laggy/unresponsive";
397 detail->push_back(make_pair(HEALTH_WARN, oss.str()));
402 if (!laggy.empty()) {
403 std::ostringstream oss;
404 oss << "mds " << laggy
405 << ((laggy.size() > 1) ? " are":" is")
407 summary.push_back(make_pair(HEALTH_WARN, oss.str()));
411 void MDSMap::get_health_checks(health_check_map_t *checks) const
414 if (!damaged.empty()) {
415 health_check_t& check = checks->get_or_add("MDS_DAMAGE", HEALTH_ERR,
416 "%num% mds daemon%plurals% damaged");
417 for (auto p : damaged) {
418 std::ostringstream oss;
419 oss << "fs " << fs_name << " mds." << p << " is damaged";
420 check.detail.push_back(oss.str());
426 health_check_t& fscheck = checks->get_or_add(
427 "FS_DEGRADED", HEALTH_WARN,
428 "%num% filesystem%plurals% %isorare% degraded");
430 ss << "fs " << fs_name << " is degraded";
431 fscheck.detail.push_back(ss.str());
434 for (mds_rank_t i = mds_rank_t(0); i< get_max_mds(); i++) {
437 mds_gid_t gid = up.find(i)->second;
438 map<mds_gid_t,mds_info_t>::const_iterator info = mds_info.find(gid);
440 ss << "fs " << fs_name << " mds." << info->second.name << " at "
441 << info->second.addr << " rank " << i;
443 ss << " is resolving";
445 ss << " is replaying journal";
447 ss << " is rejoining";
449 ss << " is reconnecting to clients";
450 if (ss.str().length())
451 detail.push_back(ss.str());
456 void MDSMap::mds_info_t::encode_versioned(bufferlist& bl, uint64_t features) const
458 ENCODE_START(7, 4, bl);
459 ::encode(global_id, bl);
463 ::encode((int32_t)state, bl);
464 ::encode(state_seq, bl);
465 ::encode(addr, bl, features);
466 ::encode(laggy_since, bl);
467 ::encode(standby_for_rank, bl);
468 ::encode(standby_for_name, bl);
469 ::encode(export_targets, bl);
470 ::encode(mds_features, bl);
471 ::encode(standby_for_fscid, bl);
472 ::encode(standby_replay, bl);
476 void MDSMap::mds_info_t::encode_unversioned(bufferlist& bl) const
479 ::encode(struct_v, bl);
480 ::encode(global_id, bl);
484 ::encode((int32_t)state, bl);
485 ::encode(state_seq, bl);
486 ::encode(addr, bl, 0);
487 ::encode(laggy_since, bl);
488 ::encode(standby_for_rank, bl);
489 ::encode(standby_for_name, bl);
490 ::encode(export_targets, bl);
493 void MDSMap::mds_info_t::decode(bufferlist::iterator& bl)
495 DECODE_START_LEGACY_COMPAT_LEN(7, 4, 4, bl);
496 ::decode(global_id, bl);
500 ::decode((int32_t&)(state), bl);
501 ::decode(state_seq, bl);
503 ::decode(laggy_since, bl);
504 ::decode(standby_for_rank, bl);
505 ::decode(standby_for_name, bl);
507 ::decode(export_targets, bl);
509 ::decode(mds_features, bl);
511 ::decode(standby_for_fscid, bl);
514 ::decode(standby_replay, bl);
519 std::string MDSMap::mds_info_t::human_name() const
521 // Like "daemon mds.myhost restarted", "Activating daemon mds.myhost"
522 std::ostringstream out;
523 out << "daemon mds." << name;
527 void MDSMap::encode(bufferlist& bl, uint64_t features) const
529 std::map<mds_rank_t,int32_t> inc; // Legacy field, fake it so that
530 // old-mon peers have something sane
532 for (const auto rank : in) {
533 inc.insert(std::make_pair(rank, epoch));
536 if ((features & CEPH_FEATURE_PGID64) == 0) {
541 ::encode(last_failure, bl);
543 ::encode(session_timeout, bl);
544 ::encode(session_autoclose, bl);
545 ::encode(max_file_size, bl);
546 ::encode(max_mds, bl);
547 __u32 n = mds_info.size();
549 for (map<mds_gid_t, mds_info_t>::const_iterator i = mds_info.begin();
550 i != mds_info.end(); ++i) {
551 ::encode(i->first, bl);
552 ::encode(i->second, bl, features);
554 n = data_pools.size();
556 for (const auto p: data_pools) {
561 int32_t m = cas_pool;
564 } else if ((features & CEPH_FEATURE_MDSENC) == 0) {
569 ::encode(last_failure, bl);
571 ::encode(session_timeout, bl);
572 ::encode(session_autoclose, bl);
573 ::encode(max_file_size, bl);
574 ::encode(max_mds, bl);
575 __u32 n = mds_info.size();
577 for (map<mds_gid_t, mds_info_t>::const_iterator i = mds_info.begin();
578 i != mds_info.end(); ++i) {
579 ::encode(i->first, bl);
580 ::encode(i->second, bl, features);
582 ::encode(data_pools, bl);
583 ::encode(cas_pool, bl);
585 // kclient ignores everything from here
588 ::encode(compat, bl);
589 ::encode(metadata_pool, bl);
590 ::encode(created, bl);
591 ::encode(modified, bl);
592 ::encode(tableserver, bl);
596 ::encode(failed, bl);
597 ::encode(stopped, bl);
598 ::encode(last_failure_osd_epoch, bl);
602 ENCODE_START(5, 4, bl);
605 ::encode(last_failure, bl);
607 ::encode(session_timeout, bl);
608 ::encode(session_autoclose, bl);
609 ::encode(max_file_size, bl);
610 ::encode(max_mds, bl);
611 ::encode(mds_info, bl, features);
612 ::encode(data_pools, bl);
613 ::encode(cas_pool, bl);
615 // kclient ignores everything from here
618 ::encode(compat, bl);
619 ::encode(metadata_pool, bl);
620 ::encode(created, bl);
621 ::encode(modified, bl);
622 ::encode(tableserver, bl);
626 ::encode(failed, bl);
627 ::encode(stopped, bl);
628 ::encode(last_failure_osd_epoch, bl);
629 ::encode(ever_allowed_features, bl);
630 ::encode(explicitly_allowed_features, bl);
631 ::encode(inline_data_enabled, bl);
632 ::encode(enabled, bl);
633 ::encode(fs_name, bl);
634 ::encode(damaged, bl);
635 ::encode(balancer, bl);
636 ::encode(standby_count_wanted, bl);
640 void MDSMap::sanitize(std::function<bool(int64_t pool)> pool_exists)
642 /* Before we did stricter checking, it was possible to remove a data pool
643 * without also deleting it from the MDSMap. Check for that here after
644 * decoding the data pools.
647 for (auto it = data_pools.begin(); it != data_pools.end();) {
648 if (!pool_exists(*it)) {
649 dout(0) << "removed non-existant data pool " << *it << " from MDSMap" << dendl;
650 it = data_pools.erase(it);
657 void MDSMap::decode(bufferlist::iterator& p)
659 std::map<mds_rank_t,int32_t> inc; // Legacy field, parse and drop
661 cached_up_features = 0;
662 DECODE_START_LEGACY_COMPAT_LEN_16(5, 4, 4, p);
665 ::decode(last_failure, p);
667 ::decode(session_timeout, p);
668 ::decode(session_autoclose, p);
669 ::decode(max_file_size, p);
670 ::decode(max_mds, p);
671 ::decode(mds_info, p);
678 data_pools.push_back(m);
684 ::decode(data_pools, p);
685 ::decode(cas_pool, p);
688 // kclient ignores everything from here
695 compat = get_mdsmap_compat_set_base();
701 ::decode(metadata_pool, p);
703 ::decode(created, p);
704 ::decode(modified, p);
705 ::decode(tableserver, p);
710 ::decode(stopped, p);
712 ::decode(last_failure_osd_epoch, p);
715 // previously this was a bool about snaps, not a flag map
718 ever_allowed_features = flag ? CEPH_MDSMAP_ALLOW_SNAPS : 0;
719 ever_allowed_features |= CEPH_MDSMAP_ALLOW_MULTIMDS|CEPH_MDSMAP_ALLOW_DIRFRAGS;
721 explicitly_allowed_features = flag ? CEPH_MDSMAP_ALLOW_SNAPS : 0;
723 set_multimds_allowed();
726 ::decode(ever_allowed_features, p);
727 ::decode(explicitly_allowed_features, p);
730 ever_allowed_features = CEPH_MDSMAP_ALLOW_CLASSICS;
731 explicitly_allowed_features = 0;
733 set_multimds_allowed();
737 ::decode(inline_data_enabled, p);
740 assert(struct_v >= 5);
741 ::decode(enabled, p);
742 ::decode(fs_name, p);
745 // If an MDS has ever been started, epoch will be greater than 1,
746 // assume filesystem is enabled.
749 // Upgrading from a cluster that never used an MDS, switch off
750 // filesystem until it's explicitly enabled.
756 ::decode(damaged, p);
760 ::decode(balancer, p);
764 ::decode(standby_count_wanted, p);
770 MDSMap::availability_t MDSMap::is_cluster_available() const
773 // If I'm a client, this means I'm looking at an MDSMap instance
774 // that was never actually initialized from the mons. Client should
776 return TRANSIENT_UNAVAILABLE;
779 // If a rank is marked damage (unavailable until operator intervenes)
780 if (damaged.size()) {
781 return STUCK_UNAVAILABLE;
784 // If no ranks are created (filesystem not initialized)
786 return STUCK_UNAVAILABLE;
789 for (const auto rank : in) {
790 if (up.count(rank) && mds_info.at(up.at(rank)).laggy()) {
791 // This might only be transient, but because we can't see
792 // standbys, we have no way of knowing whether there is a
793 // standby available to replace the laggy guy.
794 return STUCK_UNAVAILABLE;
798 if (get_num_mds(CEPH_MDS_STATE_ACTIVE) > 0) {
799 // Nobody looks stuck, so indicate to client they should go ahead
800 // and try mounting if anybody is active. This may include e.g.
801 // one MDS failing over and another active: the client should
802 // proceed to start talking to the active one and let the
803 // transiently-unavailable guy catch up later.
806 // Nothing indicating we were stuck, but nobody active (yet)
807 //return TRANSIENT_UNAVAILABLE;
809 // Because we don't have standbys in the MDSMap any more, we can't
810 // reliably indicate transient vs. stuck, so always say stuck so
811 // that the client doesn't block.
812 return STUCK_UNAVAILABLE;
816 bool MDSMap::state_transition_valid(DaemonState prev, DaemonState next)
818 bool state_valid = true;
820 if (prev == MDSMap::STATE_REPLAY) {
821 if (next != MDSMap::STATE_RESOLVE && next != MDSMap::STATE_RECONNECT) {
824 } else if (prev == MDSMap::STATE_REJOIN) {
825 if (next != MDSMap::STATE_ACTIVE
826 && next != MDSMap::STATE_CLIENTREPLAY
827 && next != MDSMap::STATE_STOPPED) {
830 } else if (prev >= MDSMap::STATE_RECONNECT && prev < MDSMap::STATE_ACTIVE) {
831 // Once I have entered replay, the only allowable transitions are to
832 // the next next along in the sequence.
833 if (next != prev + 1) {
842 bool MDSMap::check_health(mds_rank_t standby_daemon_count)
844 std::set<mds_rank_t> standbys;
845 get_standby_replay_mds_set(standbys);
846 std::set<mds_rank_t> actives;
847 get_active_mds_set(actives);
848 mds_rank_t standbys_avail = (mds_rank_t)standbys.size()+standby_daemon_count;
850 /* If there are standby daemons available/replaying and
851 * standby_count_wanted is unset (default), then we set it to 1. This will
852 * happen during health checks by the mons. Also, during initial creation
853 * of the FS we will have no actives so we don't want to change the default
856 if (standby_count_wanted == -1 && actives.size() > 0 && standbys_avail > 0) {
857 set_standby_count_wanted(1);