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.
22 #include <boost/utility/string_view.hpp>
26 #include "include/types.h"
27 #include "common/Clock.h"
28 #include "msg/Message.h"
29 #include "mds/MDSMap.h"
31 #include "common/config.h"
33 #include "include/CompatSet.h"
34 #include "include/ceph_features.h"
35 #include "common/Formatter.h"
36 #include "mds/mdstypes.h"
39 class health_check_map_t
;
41 #define MDS_FS_NAME_DEFAULT "cephfs"
44 * The MDSMap and any additional fields describing a particular
45 * filesystem (a unique fs_cluster_id_t).
50 fs_cluster_id_t fscid
;
53 void encode(bufferlist
& bl
, uint64_t features
) const;
54 void decode(bufferlist::iterator
& p
);
58 fscid(FS_CLUSTER_ID_NONE
)
62 void dump(Formatter
*f
) const;
63 void print(std::ostream
& out
) const;
66 * Return true if a daemon is already assigned as
67 * STANDBY_REPLAY for the gid `who`
69 bool has_standby_replay(mds_gid_t who
) const
71 for (const auto &i
: mds_map
.mds_info
) {
72 const auto &info
= i
.second
;
73 if (info
.state
== MDSMap::STATE_STANDBY_REPLAY
74 && info
.rank
== mds_map
.mds_info
.at(who
).rank
) {
82 WRITE_CLASS_ENCODER_FEATURES(Filesystem
)
87 uint64_t next_filesystem_id
;
88 fs_cluster_id_t legacy_client_fscid
;
91 bool ever_enabled_multiple
; // < the cluster had multiple MDSes enabled once
93 std::map
<fs_cluster_id_t
, std::shared_ptr
<Filesystem
> > filesystems
;
95 // Remember which Filesystem an MDS daemon's info is stored in
96 // (or in standby_daemons for FS_CLUSTER_ID_NONE)
97 std::map
<mds_gid_t
, fs_cluster_id_t
> mds_roles
;
99 // For MDS daemons not yet assigned to a Filesystem
100 std::map
<mds_gid_t
, MDSMap::mds_info_t
> standby_daemons
;
101 std::map
<mds_gid_t
, epoch_t
> standby_epochs
;
105 friend class MDSMonitor
;
106 friend class PaxosFSMap
;
110 next_filesystem_id(FS_CLUSTER_ID_ANONYMOUS
+ 1),
111 legacy_client_fscid(FS_CLUSTER_ID_NONE
),
112 compat(get_mdsmap_compat_set_default()),
113 enable_multiple(false), ever_enabled_multiple(false)
116 FSMap(const FSMap
&rhs
)
119 next_filesystem_id(rhs
.next_filesystem_id
),
120 legacy_client_fscid(rhs
.legacy_client_fscid
),
122 enable_multiple(rhs
.enable_multiple
),
123 ever_enabled_multiple(rhs
.ever_enabled_multiple
),
124 mds_roles(rhs
.mds_roles
),
125 standby_daemons(rhs
.standby_daemons
),
126 standby_epochs(rhs
.standby_epochs
)
129 for (const auto &i
: rhs
.filesystems
) {
130 const auto &fs
= i
.second
;
131 filesystems
[fs
->fscid
] = std::make_shared
<Filesystem
>(*fs
);
135 FSMap
&operator=(const FSMap
&rhs
)
138 next_filesystem_id
= rhs
.next_filesystem_id
;
139 legacy_client_fscid
= rhs
.legacy_client_fscid
;
141 enable_multiple
= rhs
.enable_multiple
;
142 mds_roles
= rhs
.mds_roles
;
143 standby_daemons
= rhs
.standby_daemons
;
144 standby_epochs
= rhs
.standby_epochs
;
147 for (const auto &i
: rhs
.filesystems
) {
148 const auto &fs
= i
.second
;
149 filesystems
[fs
->fscid
] = std::make_shared
<Filesystem
>(*fs
);
155 const CompatSet
&get_compat() const {return compat
;}
157 void set_enable_multiple(const bool v
)
161 ever_enabled_multiple
= true;
165 bool get_enable_multiple() const
167 return enable_multiple
;
170 void set_legacy_client_fscid(fs_cluster_id_t fscid
)
172 assert(fscid
== FS_CLUSTER_ID_NONE
|| filesystems
.count(fscid
));
173 legacy_client_fscid
= fscid
;
176 fs_cluster_id_t
get_legacy_client_fscid() const
178 return legacy_client_fscid
;
182 * Get state of all daemons (for all filesystems, including all standbys)
184 std::map
<mds_gid_t
, MDSMap::mds_info_t
> get_mds_info() const
186 std::map
<mds_gid_t
, MDSMap::mds_info_t
> result
;
187 for (const auto &i
: standby_daemons
) {
188 result
[i
.first
] = i
.second
;
191 for (const auto &i
: filesystems
) {
192 const auto &fs_info
= i
.second
->mds_map
.get_mds_info();
193 for (const auto &j
: fs_info
) {
194 result
[j
.first
] = j
.second
;
202 * Resolve daemon name to GID
204 mds_gid_t
find_mds_gid_by_name(boost::string_view s
) const
206 const auto info
= get_mds_info();
207 for (const auto &p
: info
) {
208 if (p
.second
.name
== s
) {
216 * Resolve daemon name to status
218 const MDSMap::mds_info_t
* find_by_name(boost::string_view name
) const
220 std::map
<mds_gid_t
, MDSMap::mds_info_t
> result
;
221 for (const auto &i
: standby_daemons
) {
222 if (i
.second
.name
== name
) {
227 for (const auto &i
: filesystems
) {
228 const auto &fs_info
= i
.second
->mds_map
.get_mds_info();
229 for (const auto &j
: fs_info
) {
230 if (j
.second
.name
== name
) {
240 * Does a daemon exist with this GID?
242 bool gid_exists(mds_gid_t gid
) const
244 return mds_roles
.count(gid
) > 0;
248 * Does a daemon with this GID exist, *and* have an MDS rank assigned?
250 bool gid_has_rank(mds_gid_t gid
) const
252 return gid_exists(gid
) && mds_roles
.at(gid
) != FS_CLUSTER_ID_NONE
;
256 * Insert a new MDS daemon, as a standby
258 void insert(const MDSMap::mds_info_t
&new_info
);
261 * Assign an MDS cluster standby replay rank to a standby daemon
263 void assign_standby_replay(
264 const mds_gid_t standby_gid
,
265 const fs_cluster_id_t leader_ns
,
266 const mds_rank_t leader_rank
);
269 * Assign an MDS cluster rank to a standby daemon
272 mds_gid_t standby_gid
,
273 const std::shared_ptr
<Filesystem
> &filesystem
,
274 mds_rank_t assigned_rank
);
277 * A daemon reports that it is STATE_STOPPED: remove it,
278 * and the rank it held.
280 * @returns a list of any additional GIDs that were removed from the map
281 * as a side effect (like standby replays)
283 std::list
<mds_gid_t
> stop(mds_gid_t who
);
286 * The rank held by 'who', if any, is to be relinquished, and
287 * the state for the daemon GID is to be forgotten.
289 void erase(mds_gid_t who
, epoch_t blacklist_epoch
);
292 * Update to indicate that the rank held by 'who' is damaged
294 void damaged(mds_gid_t who
, epoch_t blacklist_epoch
);
297 * Update to indicate that the rank `rank` is to be removed
298 * from the damaged list of the filesystem `fscid`
300 bool undamaged(const fs_cluster_id_t fscid
, const mds_rank_t rank
);
303 * Initialize a Filesystem and assign a fscid. Update legacy_client_fscid
304 * to point to the new filesystem if it's the only one.
306 * Caller must already have validated all arguments vs. the existing
307 * FSMap and OSDMap contents.
309 void create_filesystem(boost::string_view name
,
310 int64_t metadata_pool
, int64_t data_pool
,
314 * Remove the filesystem (it must exist). Caller should already
315 * have failed out any MDSs that were assigned to the filesystem.
317 void erase_filesystem(fs_cluster_id_t fscid
)
319 filesystems
.erase(fscid
);
323 * Reset all the state information (not configuration information)
324 * in a particular filesystem. Caller must have verified that
325 * the filesystem already exists.
327 void reset_filesystem(fs_cluster_id_t fscid
);
330 * Mutator helper for Filesystem objects: expose a non-const
331 * Filesystem pointer to `fn` and update epochs appropriately.
333 void modify_filesystem(
334 const fs_cluster_id_t fscid
,
335 std::function
<void(std::shared_ptr
<Filesystem
> )> fn
)
337 auto fs
= filesystems
.at(fscid
);
339 fs
->mds_map
.epoch
= epoch
;
343 * Apply a mutation to the mds_info_t structure for a particular
344 * daemon (identified by GID), and make appropriate updates to epochs.
348 std::function
<void(MDSMap::mds_info_t
*info
)> fn
)
350 if (mds_roles
.at(who
) == FS_CLUSTER_ID_NONE
) {
351 auto &info
= standby_daemons
.at(who
);
353 assert(info
.state
== MDSMap::STATE_STANDBY
);
354 standby_epochs
[who
] = epoch
;
356 const auto &fs
= filesystems
[mds_roles
.at(who
)];
357 auto &info
= fs
->mds_map
.mds_info
.at(who
);
360 fs
->mds_map
.epoch
= epoch
;
365 * Given that gid exists in a filesystem or as a standby, return
366 * a reference to its info.
368 const MDSMap::mds_info_t
& get_info_gid(mds_gid_t gid
) const
370 auto fscid
= mds_roles
.at(gid
);
371 if (fscid
== FS_CLUSTER_ID_NONE
) {
372 return standby_daemons
.at(gid
);
374 return filesystems
.at(fscid
)->mds_map
.mds_info
.at(gid
);
379 * A daemon has told us it's compat, and it's too new
380 * for the one we had previously. Impose the new one
381 * on all filesystems.
383 void update_compat(const CompatSet
&c
)
385 // We could do something more complicated here to enable
386 // different filesystems to be served by different MDS versions,
387 // but this is a lot simpler because it doesn't require us to
388 // track the compat versions for standby daemons.
390 for (const auto &i
: filesystems
) {
391 MDSMap
&mds_map
= i
.second
->mds_map
;
393 mds_map
.epoch
= epoch
;
397 std::shared_ptr
<const Filesystem
> get_legacy_filesystem()
399 if (legacy_client_fscid
== FS_CLUSTER_ID_NONE
) {
402 return filesystems
.at(legacy_client_fscid
);
407 * A daemon has informed us of its offload targets
409 void update_export_targets(mds_gid_t who
, const std::set
<mds_rank_t
> targets
)
411 auto fscid
= mds_roles
.at(who
);
412 modify_filesystem(fscid
, [who
, &targets
](std::shared_ptr
<Filesystem
> fs
) {
413 fs
->mds_map
.mds_info
.at(who
).export_targets
= targets
;
417 epoch_t
get_epoch() const { return epoch
; }
418 void inc_epoch() { epoch
++; }
420 size_t filesystem_count() const {return filesystems
.size();}
421 bool filesystem_exists(fs_cluster_id_t fscid
) const {return filesystems
.count(fscid
) > 0;}
422 std::shared_ptr
<const Filesystem
> get_filesystem(fs_cluster_id_t fscid
) const {return std::const_pointer_cast
<const Filesystem
>(filesystems
.at(fscid
));}
423 std::shared_ptr
<const Filesystem
> get_filesystem(void) const {return std::const_pointer_cast
<const Filesystem
>(filesystems
.begin()->second
);}
424 std::shared_ptr
<const Filesystem
> get_filesystem(boost::string_view name
) const
426 for (const auto &i
: filesystems
) {
427 if (i
.second
->mds_map
.fs_name
== name
) {
428 return std::const_pointer_cast
<const Filesystem
>(i
.second
);
433 std::list
<std::shared_ptr
<const Filesystem
> > get_filesystems(void) const
435 std::list
<std::shared_ptr
<const Filesystem
> > ret
;
436 for (const auto &i
: filesystems
) {
437 ret
.push_back(std::const_pointer_cast
<const Filesystem
>(i
.second
));
442 int parse_filesystem(
443 boost::string_view ns_str
,
444 std::shared_ptr
<const Filesystem
> *result
448 boost::string_view role_str
,
450 std::ostream
&ss
) const;
453 * Return true if this pool is in use by any of the filesystems
455 bool pool_in_use(int64_t poolid
) const {
456 for (auto const &i
: filesystems
) {
457 if (i
.second
->mds_map
.is_data_pool(poolid
)
458 || i
.second
->mds_map
.metadata_pool
== poolid
) {
465 mds_gid_t
find_standby_for(mds_role_t mds
, boost::string_view name
) const;
467 mds_gid_t
find_unused_for(mds_role_t mds
, bool force_standby_active
) const;
469 mds_gid_t
find_replacement_for(mds_role_t mds
, boost::string_view name
,
470 bool force_standby_active
) const;
472 void get_health(list
<pair
<health_status_t
,std::string
> >& summary
,
473 list
<pair
<health_status_t
,std::string
> > *detail
) const;
475 void get_health_checks(health_check_map_t
*checks
) const;
477 bool check_health(void);
480 * Assert that the FSMap, Filesystem, MDSMap, mds_info_t relations are
481 * all self-consistent.
485 void encode(bufferlist
& bl
, uint64_t features
) const;
486 void decode(bufferlist::iterator
& p
);
487 void decode(bufferlist
& bl
) {
488 bufferlist::iterator p
= bl
.begin();
491 void sanitize(std::function
<bool(int64_t pool
)> pool_exists
);
493 void print(ostream
& out
) const;
494 void print_summary(Formatter
*f
, ostream
*out
) const;
496 void dump(Formatter
*f
) const;
497 static void generate_test_instances(list
<FSMap
*>& ls
);
499 WRITE_CLASS_ENCODER_FEATURES(FSMap
)
501 inline ostream
& operator<<(ostream
& out
, const FSMap
& m
) {
502 m
.print_summary(NULL
, &out
);