]>
Commit | Line | Data |
---|---|---|
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 |