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"
19 #include "DamageTable.h"
21 #define dout_context g_ceph_context
22 #define dout_subsys ceph_subsys_mds
24 #define dout_prefix *_dout << "mds." << rank << ".damage " << __func__ << " "
28 * Record damage to a particular dirfrag, implicitly affecting
29 * any dentries within it.
31 class DirFragDamage
: public DamageEntry
37 DirFragDamage(inodeno_t ino_
, frag_t frag_
)
38 : ino(ino_
), frag(frag_
)
41 damage_entry_type_t
get_type() const override
43 return DAMAGE_ENTRY_DIRFRAG
;
46 void dump(Formatter
*f
) const override
48 f
->open_object_section("dir_frag_damage");
49 f
->dump_string("damage_type", "dir_frag");
50 f
->dump_int("id", id
);
51 f
->dump_int("ino", ino
);
52 f
->dump_stream("frag") << frag
;
53 f
->dump_string("path", path
);
60 * Record damage to a particular dname within a particular dirfrag
62 class DentryDamage
: public DamageEntry
73 std::string_view dname_
,
75 : ino(ino_
), frag(frag_
), dname(dname_
), snap_id(snap_id_
)
78 damage_entry_type_t
get_type() const override
80 return DAMAGE_ENTRY_DENTRY
;
83 void dump(Formatter
*f
) const override
85 f
->open_object_section("dentry_damage");
86 f
->dump_string("damage_type", "dentry");
87 f
->dump_int("id", id
);
88 f
->dump_int("ino", ino
);
89 f
->dump_stream("frag") << frag
;
90 f
->dump_string("dname", dname
);
91 f
->dump_stream("snap_id") << snap_id
;
92 f
->dump_string("path", path
);
99 * Record damage to our ability to look up an ino by number
101 class BacktraceDamage
: public DamageEntry
106 BacktraceDamage(inodeno_t ino_
)
110 damage_entry_type_t
get_type() const override
112 return DAMAGE_ENTRY_BACKTRACE
;
115 void dump(Formatter
*f
) const override
117 f
->open_object_section("backtrace_damage");
118 f
->dump_string("damage_type", "backtrace");
119 f
->dump_int("id", id
);
120 f
->dump_int("ino", ino
);
121 f
->dump_string("path", path
);
127 DamageEntry::~DamageEntry()
130 bool DamageTable::notify_dentry(
131 inodeno_t ino
, frag_t frag
,
132 snapid_t snap_id
, std::string_view dname
, std::string_view path
)
138 // Special cases: damage to these dirfrags is considered fatal to
139 // the MDS rank that owns them.
141 (MDS_INO_IS_MDSDIR(ino
) && MDS_INO_MDSDIR_OWNER(ino
) == rank
)
143 (MDS_INO_IS_STRAY(ino
) && MDS_INO_STRAY_OWNER(ino
) == rank
)
145 derr
<< "Damage to dentries in fragment " << frag
<< " of ino " << ino
146 << "is fatal because it is a system directory for this rank" << dendl
;
150 auto key
= DirFragIdent(ino
, frag
);
151 if (dentries
.count(key
) == 0) {
152 DamageEntryRef entry
= std::make_shared
<DentryDamage
>(
153 ino
, frag
, dname
, snap_id
);
155 dentries
[key
][DentryIdent(dname
, snap_id
)] = entry
;
156 by_id
[entry
->id
] = std::move(entry
);
162 bool DamageTable::notify_dirfrag(inodeno_t ino
, frag_t frag
,
163 std::string_view path
)
165 // Special cases: damage to these dirfrags is considered fatal to
166 // the MDS rank that owns them.
168 (MDS_INO_IS_STRAY(ino
) && MDS_INO_STRAY_OWNER(ino
) == rank
)
170 (ino
== MDS_INO_ROOT
)
172 derr
<< "Damage to fragment " << frag
<< " of ino " << ino
173 << " is fatal because it is a system directory for this rank" << dendl
;
181 auto key
= DirFragIdent(ino
, frag
);
182 if (dirfrags
.count(key
) == 0) {
183 DamageEntryRef entry
= std::make_shared
<DirFragDamage
>(ino
, frag
);
185 dirfrags
[key
] = entry
;
186 by_id
[entry
->id
] = std::move(entry
);
192 bool DamageTable::notify_remote_damaged(inodeno_t ino
, std::string_view path
)
198 if (remotes
.count(ino
) == 0) {
199 auto entry
= std::make_shared
<BacktraceDamage
>(ino
);
201 remotes
[ino
] = entry
;
202 by_id
[entry
->id
] = std::move(entry
);
208 bool DamageTable::oversized() const
210 return by_id
.size() > (size_t)(g_conf()->mds_damage_table_max_entries
);
213 bool DamageTable::is_dentry_damaged(
214 const CDir
*dir_frag
,
215 std::string_view dname
,
216 const snapid_t snap_id
) const
219 DirFragIdent(dir_frag
->inode
->ino(), dir_frag
->frag
)
224 const std::map
<DentryIdent
, DamageEntryRef
> &frag_dentries
=
225 dentries
.at(DirFragIdent(dir_frag
->inode
->ino(), dir_frag
->frag
));
227 return frag_dentries
.count(DentryIdent(dname
, snap_id
)) > 0;
230 bool DamageTable::is_dirfrag_damaged(
231 const CDir
*dir_frag
) const
233 return dirfrags
.count(
234 DirFragIdent(dir_frag
->inode
->ino(), dir_frag
->frag
)) > 0;
237 bool DamageTable::is_remote_damaged(
238 const inodeno_t ino
) const
240 return remotes
.count(ino
) > 0;
243 void DamageTable::dump(Formatter
*f
) const
245 f
->open_array_section("damage_table");
246 for (const auto &i
: by_id
)
253 void DamageTable::erase(damage_entry_id_t damage_id
)
255 auto by_id_entry
= by_id
.find(damage_id
);
256 if (by_id_entry
== by_id
.end()) {
260 DamageEntryRef entry
= by_id_entry
->second
;
261 ceph_assert(entry
->id
== damage_id
); // Sanity
263 const auto type
= entry
->get_type();
264 if (type
== DAMAGE_ENTRY_DIRFRAG
) {
265 auto dirfrag_entry
= std::static_pointer_cast
<DirFragDamage
>(entry
);
266 dirfrags
.erase(DirFragIdent(dirfrag_entry
->ino
, dirfrag_entry
->frag
));
267 } else if (type
== DAMAGE_ENTRY_DENTRY
) {
268 auto dentry_entry
= std::static_pointer_cast
<DentryDamage
>(entry
);
269 dentries
.erase(DirFragIdent(dentry_entry
->ino
, dentry_entry
->frag
));
270 } else if (type
== DAMAGE_ENTRY_BACKTRACE
) {
271 auto backtrace_entry
= std::static_pointer_cast
<BacktraceDamage
>(entry
);
272 remotes
.erase(backtrace_entry
->ino
);
274 derr
<< "Invalid type " << type
<< dendl
;
278 by_id
.erase(by_id_entry
);