]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/FSMap.h
update sources to v12.2.3
[ceph.git] / ceph / src / mds / FSMap.h
CommitLineData
7c673cae
FG
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 <errno.h>
20
21#include "include/types.h"
22#include "common/Clock.h"
23#include "msg/Message.h"
24#include "mds/MDSMap.h"
25
26#include <set>
27#include <map>
28#include <string>
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
37class CephContext;
224ce89b 38class health_check_map_t;
7c673cae 39
7c673cae
FG
40#define MDS_FS_NAME_DEFAULT "cephfs"
41
42/**
43 * The MDSMap and any additional fields describing a particular
44 * filesystem (a unique fs_cluster_id_t).
45 */
46class Filesystem
47{
48 public:
49 fs_cluster_id_t fscid;
50 MDSMap mds_map;
51
52 void encode(bufferlist& bl, uint64_t features) const;
53 void decode(bufferlist::iterator& p);
54
55 Filesystem()
56 :
57 fscid(FS_CLUSTER_ID_NONE)
58 {
59 }
60
61 void dump(Formatter *f) const;
62 void print(std::ostream& out) const;
63
64 /**
65 * Return true if a daemon is already assigned as
66 * STANDBY_REPLAY for the gid `who`
67 */
68 bool has_standby_replay(mds_gid_t who) const
69 {
70 for (const auto &i : mds_map.mds_info) {
71 const auto &info = i.second;
72 if (info.state == MDSMap::STATE_STANDBY_REPLAY
73 && info.rank == mds_map.mds_info.at(who).rank) {
74 return true;
75 }
76 }
77
78 return false;
79 }
80};
81WRITE_CLASS_ENCODER_FEATURES(Filesystem)
82
83class FSMap {
84protected:
85 epoch_t epoch;
86 uint64_t next_filesystem_id;
87 fs_cluster_id_t legacy_client_fscid;
88 CompatSet compat;
89 bool enable_multiple;
90 bool ever_enabled_multiple; // < the cluster had multiple MDSes enabled once
91
92 std::map<fs_cluster_id_t, std::shared_ptr<Filesystem> > filesystems;
93
94 // Remember which Filesystem an MDS daemon's info is stored in
95 // (or in standby_daemons for FS_CLUSTER_ID_NONE)
96 std::map<mds_gid_t, fs_cluster_id_t> mds_roles;
97
98 // For MDS daemons not yet assigned to a Filesystem
99 std::map<mds_gid_t, MDSMap::mds_info_t> standby_daemons;
100 std::map<mds_gid_t, epoch_t> standby_epochs;
101
102public:
103
104 friend class MDSMonitor;
105
106 FSMap()
107 : epoch(0),
108 next_filesystem_id(FS_CLUSTER_ID_ANONYMOUS + 1),
109 legacy_client_fscid(FS_CLUSTER_ID_NONE),
110 compat(get_mdsmap_compat_set_default()),
111 enable_multiple(false), ever_enabled_multiple(false)
112 { }
113
114 FSMap(const FSMap &rhs)
115 :
116 epoch(rhs.epoch),
117 next_filesystem_id(rhs.next_filesystem_id),
118 legacy_client_fscid(rhs.legacy_client_fscid),
119 compat(rhs.compat),
120 enable_multiple(rhs.enable_multiple),
121 ever_enabled_multiple(rhs.ever_enabled_multiple),
122 mds_roles(rhs.mds_roles),
123 standby_daemons(rhs.standby_daemons),
124 standby_epochs(rhs.standby_epochs)
125 {
b32b8144 126 filesystems.clear();
7c673cae
FG
127 for (const auto &i : rhs.filesystems) {
128 const auto &fs = i.second;
129 filesystems[fs->fscid] = std::make_shared<Filesystem>(*fs);
130 }
131 }
132
133 FSMap &operator=(const FSMap &rhs)
134 {
135 epoch = rhs.epoch;
136 next_filesystem_id = rhs.next_filesystem_id;
137 legacy_client_fscid = rhs.legacy_client_fscid;
138 compat = rhs.compat;
139 enable_multiple = rhs.enable_multiple;
140 mds_roles = rhs.mds_roles;
141 standby_daemons = rhs.standby_daemons;
142 standby_epochs = rhs.standby_epochs;
143
b32b8144 144 filesystems.clear();
7c673cae
FG
145 for (const auto &i : rhs.filesystems) {
146 const auto &fs = i.second;
147 filesystems[fs->fscid] = std::make_shared<Filesystem>(*fs);
148 }
149
150 return *this;
151 }
152
153 const CompatSet &get_compat() const {return compat;}
154
155 void set_enable_multiple(const bool v)
156 {
157 enable_multiple = v;
158 if (true == v) {
159 ever_enabled_multiple = true;
160 }
161 }
162
163 bool get_enable_multiple() const
164 {
165 return enable_multiple;
166 }
167
168 void set_legacy_client_fscid(fs_cluster_id_t fscid)
169 {
170 assert(fscid == FS_CLUSTER_ID_NONE || filesystems.count(fscid));
171 legacy_client_fscid = fscid;
172 }
173
174 fs_cluster_id_t get_legacy_client_fscid() const
175 {
176 return legacy_client_fscid;
177 }
178
179 /**
180 * Get state of all daemons (for all filesystems, including all standbys)
181 */
182 std::map<mds_gid_t, MDSMap::mds_info_t> get_mds_info() const
183 {
184 std::map<mds_gid_t, MDSMap::mds_info_t> result;
185 for (const auto &i : standby_daemons) {
186 result[i.first] = i.second;
187 }
188
189 for (const auto &i : filesystems) {
190 const auto &fs_info = i.second->mds_map.get_mds_info();
191 for (const auto &j : fs_info) {
192 result[j.first] = j.second;
193 }
194 }
195
196 return result;
197 }
198
199 /**
200 * Resolve daemon name to GID
201 */
202 mds_gid_t find_mds_gid_by_name(const std::string& s) const
203 {
204 const auto info = get_mds_info();
205 for (const auto &p : info) {
206 if (p.second.name == s) {
207 return p.first;
208 }
209 }
210 return MDS_GID_NONE;
211 }
212
213 /**
214 * Resolve daemon name to status
215 */
216 const MDSMap::mds_info_t* find_by_name(const std::string& name) const
217 {
218 std::map<mds_gid_t, MDSMap::mds_info_t> result;
219 for (const auto &i : standby_daemons) {
220 if (i.second.name == name) {
221 return &(i.second);
222 }
223 }
224
225 for (const auto &i : filesystems) {
226 const auto &fs_info = i.second->mds_map.get_mds_info();
227 for (const auto &j : fs_info) {
228 if (j.second.name == name) {
229 return &(j.second);
230 }
231 }
232 }
233
234 return nullptr;
235 }
236
237 /**
238 * Does a daemon exist with this GID?
239 */
240 bool gid_exists(mds_gid_t gid) const
241 {
242 return mds_roles.count(gid) > 0;
243 }
244
245 /**
246 * Does a daemon with this GID exist, *and* have an MDS rank assigned?
247 */
248 bool gid_has_rank(mds_gid_t gid) const
249 {
250 return gid_exists(gid) && mds_roles.at(gid) != FS_CLUSTER_ID_NONE;
251 }
252
253 /**
254 * Insert a new MDS daemon, as a standby
255 */
256 void insert(const MDSMap::mds_info_t &new_info);
257
258 /**
259 * Assign an MDS cluster standby replay rank to a standby daemon
260 */
261 void assign_standby_replay(
262 const mds_gid_t standby_gid,
263 const fs_cluster_id_t leader_ns,
264 const mds_rank_t leader_rank);
265
266 /**
267 * Assign an MDS cluster rank to a standby daemon
268 */
269 void promote(
270 mds_gid_t standby_gid,
271 const std::shared_ptr<Filesystem> &filesystem,
272 mds_rank_t assigned_rank);
273
274 /**
275 * A daemon reports that it is STATE_STOPPED: remove it,
276 * and the rank it held.
277 *
278 * @returns a list of any additional GIDs that were removed from the map
279 * as a side effect (like standby replays)
280 */
281 std::list<mds_gid_t> stop(mds_gid_t who);
282
283 /**
284 * The rank held by 'who', if any, is to be relinquished, and
285 * the state for the daemon GID is to be forgotten.
286 */
287 void erase(mds_gid_t who, epoch_t blacklist_epoch);
288
289 /**
290 * Update to indicate that the rank held by 'who' is damaged
291 */
292 void damaged(mds_gid_t who, epoch_t blacklist_epoch);
293
294 /**
295 * Update to indicate that the rank `rank` is to be removed
296 * from the damaged list of the filesystem `fscid`
297 */
298 bool undamaged(const fs_cluster_id_t fscid, const mds_rank_t rank);
299
300 /**
301 * Initialize a Filesystem and assign a fscid. Update legacy_client_fscid
302 * to point to the new filesystem if it's the only one.
303 *
304 * Caller must already have validated all arguments vs. the existing
305 * FSMap and OSDMap contents.
306 */
307 void create_filesystem(const std::string &name,
308 int64_t metadata_pool, int64_t data_pool,
309 uint64_t features);
310
311 /**
312 * Remove the filesystem (it must exist). Caller should already
313 * have failed out any MDSs that were assigned to the filesystem.
314 */
315 void erase_filesystem(fs_cluster_id_t fscid)
316 {
317 filesystems.erase(fscid);
318 }
319
320 /**
321 * Reset all the state information (not configuration information)
322 * in a particular filesystem. Caller must have verified that
323 * the filesystem already exists.
324 */
325 void reset_filesystem(fs_cluster_id_t fscid);
326
327 /**
328 * Mutator helper for Filesystem objects: expose a non-const
329 * Filesystem pointer to `fn` and update epochs appropriately.
330 */
331 void modify_filesystem(
332 const fs_cluster_id_t fscid,
333 std::function<void(std::shared_ptr<Filesystem> )> fn)
334 {
335 auto fs = filesystems.at(fscid);
336 fn(fs);
337 fs->mds_map.epoch = epoch;
338 }
339
340 /**
341 * Apply a mutation to the mds_info_t structure for a particular
342 * daemon (identified by GID), and make appropriate updates to epochs.
343 */
344 void modify_daemon(
345 mds_gid_t who,
346 std::function<void(MDSMap::mds_info_t *info)> fn)
347 {
348 if (mds_roles.at(who) == FS_CLUSTER_ID_NONE) {
349 auto &info = standby_daemons.at(who);
350 fn(&info);
351 assert(info.state == MDSMap::STATE_STANDBY);
352 standby_epochs[who] = epoch;
353 } else {
354 const auto &fs = filesystems[mds_roles.at(who)];
355 auto &info = fs->mds_map.mds_info.at(who);
356 fn(&info);
357
358 fs->mds_map.epoch = epoch;
359 }
360 }
361
362 /**
363 * Given that gid exists in a filesystem or as a standby, return
364 * a reference to its info.
365 */
366 const MDSMap::mds_info_t& get_info_gid(mds_gid_t gid) const
367 {
368 auto fscid = mds_roles.at(gid);
369 if (fscid == FS_CLUSTER_ID_NONE) {
370 return standby_daemons.at(gid);
371 } else {
372 return filesystems.at(fscid)->mds_map.mds_info.at(gid);
373 }
374 }
375
376 /**
377 * A daemon has told us it's compat, and it's too new
378 * for the one we had previously. Impose the new one
379 * on all filesystems.
380 */
381 void update_compat(const CompatSet &c)
382 {
383 // We could do something more complicated here to enable
384 // different filesystems to be served by different MDS versions,
385 // but this is a lot simpler because it doesn't require us to
386 // track the compat versions for standby daemons.
387 compat = c;
388 for (const auto &i : filesystems) {
389 MDSMap &mds_map = i.second->mds_map;
390 mds_map.compat = c;
391 mds_map.epoch = epoch;
392 }
393 }
394
395 std::shared_ptr<const Filesystem> get_legacy_filesystem()
396 {
397 if (legacy_client_fscid == FS_CLUSTER_ID_NONE) {
398 return nullptr;
399 } else {
400 return filesystems.at(legacy_client_fscid);
401 }
402 }
403
404 /**
405 * A daemon has informed us of its offload targets
406 */
407 void update_export_targets(mds_gid_t who, const std::set<mds_rank_t> targets)
408 {
409 auto fscid = mds_roles.at(who);
410 modify_filesystem(fscid, [who, &targets](std::shared_ptr<Filesystem> fs) {
411 fs->mds_map.mds_info.at(who).export_targets = targets;
412 });
413 }
414
415 epoch_t get_epoch() const { return epoch; }
416 void inc_epoch() { epoch++; }
417
418 size_t filesystem_count() const {return filesystems.size();}
419 bool filesystem_exists(fs_cluster_id_t fscid) const {return filesystems.count(fscid) > 0;}
420 std::shared_ptr<const Filesystem> get_filesystem(fs_cluster_id_t fscid) const {return std::const_pointer_cast<const Filesystem>(filesystems.at(fscid));}
421 std::shared_ptr<const Filesystem> get_filesystem(void) const {return std::const_pointer_cast<const Filesystem>(filesystems.begin()->second);}
422 std::shared_ptr<const Filesystem> get_filesystem(const std::string &name) const
423 {
424 for (const auto &i : filesystems) {
425 if (i.second->mds_map.fs_name == name) {
426 return std::const_pointer_cast<const Filesystem>(i.second);
427 }
428 }
429 return nullptr;
430 }
431 std::list<std::shared_ptr<const Filesystem> > get_filesystems(void) const
432 {
433 std::list<std::shared_ptr<const Filesystem> > ret;
434 for (const auto &i : filesystems) {
435 ret.push_back(std::const_pointer_cast<const Filesystem>(i.second));
436 }
437 return ret;
438 }
439
440 int parse_filesystem(
441 std::string const &ns_str,
442 std::shared_ptr<const Filesystem> *result
443 ) const;
444
445 int parse_role(
446 const std::string &role_str,
447 mds_role_t *role,
448 std::ostream &ss) const;
449
450 /**
451 * Return true if this pool is in use by any of the filesystems
452 */
453 bool pool_in_use(int64_t poolid) const {
454 for (auto const &i : filesystems) {
455 if (i.second->mds_map.is_data_pool(poolid)
456 || i.second->mds_map.metadata_pool == poolid) {
457 return true;
458 }
459 }
460 return false;
461 }
462
463 mds_gid_t find_standby_for(mds_role_t mds, const std::string& name) const;
464
31f18b77 465 mds_gid_t find_unused_for(mds_role_t mds, bool force_standby_active) const;
7c673cae
FG
466
467 mds_gid_t find_replacement_for(mds_role_t mds, const std::string& name,
468 bool force_standby_active) const;
469
470 void get_health(list<pair<health_status_t,std::string> >& summary,
471 list<pair<health_status_t,std::string> > *detail) const;
472
224ce89b
WB
473 void get_health_checks(health_check_map_t *checks) const;
474
7c673cae
FG
475 bool check_health(void);
476
477 /**
478 * Assert that the FSMap, Filesystem, MDSMap, mds_info_t relations are
479 * all self-consistent.
480 */
481 void sanity() const;
482
483 void encode(bufferlist& bl, uint64_t features) const;
484 void decode(bufferlist::iterator& p);
485 void decode(bufferlist& bl) {
486 bufferlist::iterator p = bl.begin();
487 decode(p);
488 }
3efd9988 489 void sanitize(std::function<bool(int64_t pool)> pool_exists);
7c673cae
FG
490
491 void print(ostream& out) const;
492 void print_summary(Formatter *f, ostream *out) const;
493
494 void dump(Formatter *f) const;
495 static void generate_test_instances(list<FSMap*>& ls);
496};
497WRITE_CLASS_ENCODER_FEATURES(FSMap)
498
499inline ostream& operator<<(ostream& out, const FSMap& m) {
500 m.print_summary(NULL, &out);
501 return out;
502}
503
504#endif