]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/FSMap.h
import 15.2.0 Octopus source
[ceph.git] / ceph / src / mds / FSMap.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_FSMAP_H
17 #define CEPH_FSMAP_H
18
19 #include <map>
20 #include <memory>
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 "mds/MDSMap.h"
30
31 #include "include/CompatSet.h"
32 #include "include/ceph_features.h"
33 #include "include/common_fwd.h"
34 #include "common/Formatter.h"
35 #include "mds/mdstypes.h"
36
37 class health_check_map_t;
38
39 /**
40 * The MDSMap and any additional fields describing a particular
41 * filesystem (a unique fs_cluster_id_t).
42 */
43 class Filesystem
44 {
45 public:
46 using ref = std::shared_ptr<Filesystem>;
47 using const_ref = std::shared_ptr<Filesystem const>;
48
49 template<typename... Args>
50 static ref create(Args&&... args)
51 {
52 return std::make_shared<Filesystem>(std::forward<Args>(args)...);
53 }
54
55 void encode(bufferlist& bl, uint64_t features) const;
56 void decode(bufferlist::const_iterator& p);
57
58 void dump(Formatter *f) const;
59 void print(std::ostream& out) const;
60
61 /**
62 * Return true if a daemon is already assigned as
63 * STANDBY_REPLAY for the gid `who`
64 */
65 bool has_standby_replay(mds_gid_t who) const
66 {
67 return get_standby_replay(who) != MDS_GID_NONE;
68 }
69 mds_gid_t get_standby_replay(mds_gid_t who) const;
70 bool is_standby_replay(mds_gid_t who) const
71 {
72 auto p = mds_map.mds_info.find(who);
73 if (p != mds_map.mds_info.end() &&
74 p->second.state == MDSMap::STATE_STANDBY_REPLAY) {
75 return true;
76 }
77 return false;
78 }
79
80 fs_cluster_id_t fscid = FS_CLUSTER_ID_NONE;
81 MDSMap mds_map;
82 };
83 WRITE_CLASS_ENCODER_FEATURES(Filesystem)
84
85 class FSMap {
86 public:
87 friend class MDSMonitor;
88 friend class PaxosFSMap;
89 using mds_info_t = MDSMap::mds_info_t;
90
91 FSMap() : compat(MDSMap::get_compat_set_default()) {}
92
93 FSMap(const FSMap &rhs)
94 :
95 epoch(rhs.epoch),
96 next_filesystem_id(rhs.next_filesystem_id),
97 legacy_client_fscid(rhs.legacy_client_fscid),
98 compat(rhs.compat),
99 enable_multiple(rhs.enable_multiple),
100 ever_enabled_multiple(rhs.ever_enabled_multiple),
101 mds_roles(rhs.mds_roles),
102 standby_daemons(rhs.standby_daemons),
103 standby_epochs(rhs.standby_epochs)
104 {
105 filesystems.clear();
106 for (const auto &i : rhs.filesystems) {
107 const auto &fs = i.second;
108 filesystems[fs->fscid] = std::make_shared<Filesystem>(*fs);
109 }
110 }
111
112 FSMap &operator=(const FSMap &rhs);
113
114 const CompatSet &get_compat() const {return compat;}
115
116 void set_enable_multiple(const bool v)
117 {
118 enable_multiple = v;
119 if (true == v) {
120 ever_enabled_multiple = true;
121 }
122 }
123
124 bool get_enable_multiple() const
125 {
126 return enable_multiple;
127 }
128
129 void set_legacy_client_fscid(fs_cluster_id_t fscid)
130 {
131 ceph_assert(fscid == FS_CLUSTER_ID_NONE || filesystems.count(fscid));
132 legacy_client_fscid = fscid;
133 }
134
135 fs_cluster_id_t get_legacy_client_fscid() const
136 {
137 return legacy_client_fscid;
138 }
139
140 size_t get_num_standby() const {
141 return standby_daemons.size();
142 }
143
144 bool is_any_degraded() const;
145
146 /**
147 * Get state of all daemons (for all filesystems, including all standbys)
148 */
149 std::map<mds_gid_t, mds_info_t> get_mds_info() const;
150
151 const mds_info_t* get_available_standby(fs_cluster_id_t fscid) const;
152
153 /**
154 * Resolve daemon name to GID
155 */
156 mds_gid_t find_mds_gid_by_name(std::string_view s) const;
157
158 /**
159 * Resolve daemon name to status
160 */
161 const mds_info_t* find_by_name(std::string_view name) const;
162
163 /**
164 * Does a daemon exist with this GID?
165 */
166 bool gid_exists(mds_gid_t gid) const
167 {
168 return mds_roles.count(gid) > 0;
169 }
170
171 /**
172 * Does a daemon with this GID exist, *and* have an MDS rank assigned?
173 */
174 bool gid_has_rank(mds_gid_t gid) const
175 {
176 return gid_exists(gid) && mds_roles.at(gid) != FS_CLUSTER_ID_NONE;
177 }
178
179 fs_cluster_id_t gid_fscid(mds_gid_t gid) const
180 {
181 return mds_roles.at(gid);
182 }
183
184 /**
185 * Insert a new MDS daemon, as a standby
186 */
187 void insert(const mds_info_t& new_info);
188
189 /**
190 * Assign an MDS cluster standby replay rank to a standby daemon
191 */
192 void assign_standby_replay(
193 const mds_gid_t standby_gid,
194 const fs_cluster_id_t leader_ns,
195 const mds_rank_t leader_rank);
196
197 /**
198 * Assign an MDS cluster rank to a standby daemon
199 */
200 void promote(
201 mds_gid_t standby_gid,
202 Filesystem& filesystem,
203 mds_rank_t assigned_rank);
204
205 /**
206 * A daemon reports that it is STATE_STOPPED: remove it,
207 * and the rank it held.
208 *
209 * @returns a list of any additional GIDs that were removed from the map
210 * as a side effect (like standby replays)
211 */
212 std::vector<mds_gid_t> stop(mds_gid_t who);
213
214 /**
215 * The rank held by 'who', if any, is to be relinquished, and
216 * the state for the daemon GID is to be forgotten.
217 */
218 void erase(mds_gid_t who, epoch_t blacklist_epoch);
219
220 /**
221 * Update to indicate that the rank held by 'who' is damaged
222 */
223 void damaged(mds_gid_t who, epoch_t blacklist_epoch);
224
225 /**
226 * Update to indicate that the rank `rank` is to be removed
227 * from the damaged list of the filesystem `fscid`
228 */
229 bool undamaged(const fs_cluster_id_t fscid, const mds_rank_t rank);
230
231 /**
232 * Initialize a Filesystem and assign a fscid. Update legacy_client_fscid
233 * to point to the new filesystem if it's the only one.
234 *
235 * Caller must already have validated all arguments vs. the existing
236 * FSMap and OSDMap contents.
237 */
238 Filesystem::ref create_filesystem(
239 std::string_view name, int64_t metadata_pool,
240 int64_t data_pool, uint64_t features);
241
242 /**
243 * Remove the filesystem (it must exist). Caller should already
244 * have failed out any MDSs that were assigned to the filesystem.
245 */
246 void erase_filesystem(fs_cluster_id_t fscid);
247
248 /**
249 * Reset all the state information (not configuration information)
250 * in a particular filesystem. Caller must have verified that
251 * the filesystem already exists.
252 */
253 void reset_filesystem(fs_cluster_id_t fscid);
254
255 /**
256 * Mutator helper for Filesystem objects: expose a non-const
257 * Filesystem pointer to `fn` and update epochs appropriately.
258 */
259 template<typename T>
260 void modify_filesystem(fs_cluster_id_t fscid, T&& fn)
261 {
262 auto& fs = filesystems.at(fscid);
263 fn(fs);
264 fs->mds_map.epoch = epoch;
265 }
266
267 /**
268 * Apply a mutation to the mds_info_t structure for a particular
269 * daemon (identified by GID), and make appropriate updates to epochs.
270 */
271 template<typename T>
272 void modify_daemon(mds_gid_t who, T&& fn)
273 {
274 const auto& fscid = mds_roles.at(who);
275 if (fscid == FS_CLUSTER_ID_NONE) {
276 auto& info = standby_daemons.at(who);
277 fn(info);
278 ceph_assert(info.state == MDSMap::STATE_STANDBY);
279 standby_epochs[who] = epoch;
280 } else {
281 auto& fs = filesystems.at(fscid);
282 auto& info = fs->mds_map.mds_info.at(who);
283 fn(info);
284 fs->mds_map.epoch = epoch;
285 }
286 }
287
288 /**
289 * Given that gid exists in a filesystem or as a standby, return
290 * a reference to its info.
291 */
292 const mds_info_t& get_info_gid(mds_gid_t gid) const
293 {
294 auto fscid = mds_roles.at(gid);
295 if (fscid == FS_CLUSTER_ID_NONE) {
296 return standby_daemons.at(gid);
297 } else {
298 return filesystems.at(fscid)->mds_map.mds_info.at(gid);
299 }
300 }
301
302 bool is_standby_replay(mds_gid_t who) const
303 {
304 return filesystems.at(mds_roles.at(who))->is_standby_replay(who);
305 }
306
307 mds_gid_t get_standby_replay(mds_gid_t who) const
308 {
309 return filesystems.at(mds_roles.at(who))->get_standby_replay(who);
310 }
311
312 /**
313 * A daemon has told us it's compat, and it's too new
314 * for the one we had previously. Impose the new one
315 * on all filesystems.
316 */
317 void update_compat(const CompatSet &c);
318
319 Filesystem::const_ref get_legacy_filesystem()
320 {
321 if (legacy_client_fscid == FS_CLUSTER_ID_NONE) {
322 return nullptr;
323 } else {
324 return filesystems.at(legacy_client_fscid);
325 }
326 }
327
328 /**
329 * A daemon has informed us of its offload targets
330 */
331 void update_export_targets(mds_gid_t who, const std::set<mds_rank_t> &targets)
332 {
333 auto fscid = mds_roles.at(who);
334 modify_filesystem(fscid, [who, &targets](auto&& fs) {
335 fs->mds_map.mds_info.at(who).export_targets = targets;
336 });
337 }
338
339 epoch_t get_epoch() const { return epoch; }
340 void inc_epoch() { epoch++; }
341
342 size_t filesystem_count() const {return filesystems.size();}
343 bool filesystem_exists(fs_cluster_id_t fscid) const {return filesystems.count(fscid) > 0;}
344 Filesystem::const_ref get_filesystem(fs_cluster_id_t fscid) const {return std::const_pointer_cast<const Filesystem>(filesystems.at(fscid));}
345 Filesystem::ref get_filesystem(fs_cluster_id_t fscid) {return filesystems.at(fscid);}
346 Filesystem::const_ref get_filesystem(void) const {return std::const_pointer_cast<const Filesystem>(filesystems.begin()->second);}
347 Filesystem::const_ref get_filesystem(std::string_view name) const;
348
349 std::vector<Filesystem::const_ref> get_filesystems(void) const;
350
351 int parse_filesystem(
352 std::string_view ns_str,
353 Filesystem::const_ref *result
354 ) const;
355
356 int parse_role(
357 std::string_view role_str,
358 mds_role_t *role,
359 std::ostream &ss) const;
360
361 /**
362 * Return true if this pool is in use by any of the filesystems
363 */
364 bool pool_in_use(int64_t poolid) const;
365
366 const mds_info_t* find_replacement_for(mds_role_t role) const;
367
368 void get_health(list<pair<health_status_t,std::string> >& summary,
369 list<pair<health_status_t,std::string> > *detail) const;
370
371 void get_health_checks(health_check_map_t *checks) const;
372
373 bool check_health(void);
374
375 /**
376 * Assert that the FSMap, Filesystem, MDSMap, mds_info_t relations are
377 * all self-consistent.
378 */
379 void sanity() const;
380
381 void encode(bufferlist& bl, uint64_t features) const;
382 void decode(bufferlist::const_iterator& p);
383 void decode(bufferlist& bl) {
384 auto p = bl.cbegin();
385 decode(p);
386 }
387 void sanitize(const std::function<bool(int64_t pool)>& pool_exists);
388
389 void print(ostream& out) const;
390 void print_summary(Formatter *f, ostream *out) const;
391
392 void dump(Formatter *f) const;
393 static void generate_test_instances(std::list<FSMap*>& ls);
394
395 protected:
396 epoch_t epoch = 0;
397 uint64_t next_filesystem_id = FS_CLUSTER_ID_ANONYMOUS + 1;
398 fs_cluster_id_t legacy_client_fscid = FS_CLUSTER_ID_NONE;
399 CompatSet compat;
400 bool enable_multiple = false;
401 bool ever_enabled_multiple = false; // < the cluster had multiple MDSes enabled once
402
403 std::map<fs_cluster_id_t, Filesystem::ref> filesystems;
404
405 // Remember which Filesystem an MDS daemon's info is stored in
406 // (or in standby_daemons for FS_CLUSTER_ID_NONE)
407 std::map<mds_gid_t, fs_cluster_id_t> mds_roles;
408
409 // For MDS daemons not yet assigned to a Filesystem
410 std::map<mds_gid_t, mds_info_t> standby_daemons;
411 std::map<mds_gid_t, epoch_t> standby_epochs;
412 };
413 WRITE_CLASS_ENCODER_FEATURES(FSMap)
414
415 inline ostream& operator<<(ostream& out, const FSMap& m) {
416 m.print_summary(NULL, &out);
417 return out;
418 }
419
420 #endif