// Detect MDS_HEALTH_SLOW_REQUEST condition
{
int slow = mds->get_mds_slow_req_count();
- dout(20) << slow << " slow request found" << dendl;
if (slow) {
+ dout(20) << slow << " slow request found" << dendl;
std::ostringstream oss;
- oss << slow << " slow requests are blocked > " << g_conf->mds_op_complaint_time << " sec";
+ oss << slow << " slow requests are blocked > " << g_conf->mds_op_complaint_time << " secs";
MDSHealthMetric m(MDS_HEALTH_SLOW_REQUEST, HEALTH_WARN, oss.str());
health.metrics.push_back(m);
}
}
+ {
+ auto complaint_time = g_conf->osd_op_complaint_time;
+ auto now = ceph::coarse_mono_clock::now();
+ auto cutoff = now - ceph::make_timespan(complaint_time);
+
+ std::string count;
+ ceph::coarse_mono_time oldest;
+ if (MDSIOContextBase::check_ios_in_flight(cutoff, count, oldest)) {
+ dout(20) << count << " slow metadata IOs found" << dendl;
+
+ auto oldest_secs = std::chrono::duration<double>(now - oldest).count();
+ std::ostringstream oss;
+ oss << count << " slow metadata IOs are blocked > " << complaint_time
+ << " secs, oldest blocked for " << (int64_t)oldest_secs << " secs";
+
+ MDSHealthMetric m(MDS_HEALTH_SLOW_METADATA_IO, HEALTH_WARN, oss.str());
+ health.metrics.push_back(m);
+ }
+ }
+
// Report a health warning if we are readonly
if (mds->mdcache->is_readonly()) {
MDSHealthMetric m(MDS_HEALTH_READ_ONLY, HEALTH_WARN,
fin->complete(r);
}
}
+ void print(ostream& out) const override {
+ out << "dirfrag_fetch_more(" << dir->dirfrag() << ")";
+ }
};
class C_IO_Dir_OMAP_Fetched : public CDirIOContext {
fin->complete(r);
}
}
+ void print(ostream& out) const override {
+ out << "dirfrag_fetch(" << dir->dirfrag() << ")";
+ }
};
void CDir::_omap_fetch(MDSInternalContextBase *c, const std::set<dentry_key_t>& keys)
void finish(int r) override {
dir->_committed(r, version);
}
+ void print(ostream& out) const override {
+ out << "dirfrag_commit(" << dir->dirfrag() << ")";
+ }
};
/**
void finish(int r) override {
in->_stored(r, version, fin);
}
+ void print(ostream& out) const override {
+ out << "inode_store(" << in->ino() << ")";
+ }
};
object_t InodeStoreBase::get_object_name(inodeno_t ino, frag_t fg, const char *suffix)
// Ignore 'r', because we fetch from two places, so r is usually ENOENT
in->_fetched(bl, bl2, fin);
}
+ void print(ostream& out) const override {
+ out << "inode_fetch(" << in->ino() << ")";
+ }
};
void CInode::fetch(MDSInternalContextBase *fin)
void finish(int r) override {
in->_stored_backtrace(r, version, fin);
}
+ void print(ostream& out) const override {
+ out << "backtrace_store(" << in->ino() << ")";
+ }
};
void CInode::store_backtrace(MDSInternalContextBase *fin, int op_prio)
return mdcache->mds;
}
public:
- explicit MDCacheIOContext(MDCache *mdc_) : mdcache(mdc_) {}
+ explicit MDCacheIOContext(MDCache *mdc_, bool track=true) :
+ MDSIOContextBase(track), mdcache(mdc_) {}
};
class MDCacheLogContext : public virtual MDSLogContextBase {
CInode *in;
LogSegment *ls;
C_IO_MDC_TruncateFinish(MDCache *c, CInode *i, LogSegment *l) :
- MDCacheIOContext(c), in(i), ls(l) {}
+ MDCacheIOContext(c, false), in(i), ls(l) {
+ }
void finish(int r) override {
assert(r == 0 || r == -ENOENT);
mdcache->truncate_inode_finish(in, ls);
}
+ void print(ostream& out) const override {
+ out << "file_truncate(" << in->ino() << ")";
+ }
};
void MDCache::_truncate_inode(CInode *in, LogSegment *ls)
void finish(int r) override {
mdcache->_open_ino_backtrace_fetched(ino, bl, r);
}
+ void print(ostream& out) const override {
+ out << "openino_backtrace_fetch" << ino << ")";
+ }
};
struct C_MDC_OpenInoTraverseDir : public MDCacheContext {
assert(r == 0 || r == -ENOENT);
mdcache->_fragment_finish(basedirfrag, resultfrags);
}
+ void print(ostream& out) const override {
+ out << "dirfrags_commit(" << basedirfrag << ")";
+ }
};
void MDCache::fragment_frozen(MDRequestRef& mdr, int r)
}
public:
- explicit C_MDL_WriteError(MDLog *m) : mdlog(m) {}
+ explicit C_MDL_WriteError(MDLog *m) :
+ MDSIOContextBase(false), mdlog(m) {}
+ void print(ostream& out) const override {
+ out << "mdlog_write_error";
+ }
};
fin->complete(r);
}
+elist<MDSIOContextBase*> MDSIOContextBase::ctx_list(member_offset(MDSIOContextBase, list_item));
+ceph::spinlock MDSIOContextBase::ctx_list_lock;
+
+MDSIOContextBase::MDSIOContextBase(bool track)
+{
+ created_at = ceph::coarse_mono_clock::now();
+ if (track) {
+ ctx_list_lock.lock();
+ ctx_list.push_back(&list_item);
+ ctx_list_lock.unlock();
+ }
+}
+
+MDSIOContextBase::~MDSIOContextBase()
+{
+ ctx_list_lock.lock();
+ list_item.remove_myself();
+ ctx_list_lock.unlock();
+}
+
+bool MDSIOContextBase::check_ios_in_flight(ceph::coarse_mono_time cutoff,
+ std::string& slow_count,
+ ceph::coarse_mono_time& oldest)
+{
+ static const unsigned MAX_COUNT = 100;
+ unsigned slow = 0;
+
+ ctx_list_lock.lock();
+ for (elist<MDSIOContextBase*>::iterator p = ctx_list.begin(); !p.end(); ++p) {
+ MDSIOContextBase *c = *p;
+ if (c->created_at >= cutoff)
+ break;
+ ++slow;
+ if (slow > MAX_COUNT)
+ break;
+ if (slow == 1)
+ oldest = c->created_at;
+ }
+ ctx_list_lock.unlock();
+
+ if (slow > 0) {
+ if (slow > MAX_COUNT)
+ slow_count = std::to_string(MAX_COUNT) + "+";
+ else
+ slow_count = std::to_string(slow);
+ return true;
+ } else {
+ return false;
+ }
+}
+
void MDSIOContextBase::complete(int r) {
MDSRank *mds = get_mds();
dout(10) << "MDSIOContextBase::complete: " << typeid(*this).name() << dendl;
assert(mds != NULL);
Mutex::Locker l(mds->mds_lock);
+
if (mds->is_daemon_stopping()) {
dout(4) << "MDSIOContextBase::complete: dropping for stopping "
<< typeid(*this).name() << dendl;
#define MDS_CONTEXT_H
#include "include/Context.h"
+#include "include/elist.h"
+#include "common/ceph_time.h"
class MDSRank;
MDSRank *mds;
Context *fin;
MDSRank *get_mds() override;
+ void finish(int r) override;
public:
MDSInternalContextWrapper(MDSRank *m, Context *c) : mds(m), fin(c) {}
- void finish(int r) override;
};
class MDSIOContextBase : public MDSContext
{
public:
+ MDSIOContextBase(bool track=true);
+ virtual ~MDSIOContextBase();
+ MDSIOContextBase(const MDSIOContextBase&) = delete;
+ MDSIOContextBase& operator=(const MDSIOContextBase&) = delete;
+
void complete(int r) override;
+
+ virtual void print(ostream& out) const = 0;
+
+ static bool check_ios_in_flight(ceph::coarse_mono_time cutoff,
+ std::string& slow_count,
+ ceph::coarse_mono_time& oldest);
+private:
+ ceph::coarse_mono_time created_at;
+ elist<MDSIOContextBase*>::item list_item;
+
+ static elist<MDSIOContextBase*> ctx_list;
+ static ceph::spinlock ctx_list_lock;
};
/**
void complete(int r) final;
void set_write_pos(uint64_t wp) { write_pos = wp; }
virtual void pre_finish(int r) {}
+ void print(ostream& out) const override {
+ out << "log_event(" << write_pos << ")";
+ }
};
/**
public:
MDSIOContextWrapper(MDSRank *m, Context *c) : mds(m), fin(c) {}
void finish(int r) override;
+ void print(ostream& out) const override {
+ out << "io_context_wrapper(" << fin << ")";
+ }
};
/**
}
}
void complete(int r) final;
+ void print(ostream& out) const override {
+ out << "io_wrapper(" << wrapped << ")";
+ }
};
void finish(int r) override {
mds->_standby_replay_restart_finish(r, old_read_pos);
}
+ void print(ostream& out) const override {
+ out << "standby_replay_restart";
+ }
};
void MDSRank::_standby_replay_restart_finish(int r, uint64_t old_read_pos)
void finish(int r) override {
ida->save_2(r, version);
}
+ void print(ostream& out) const override {
+ out << "table_save(" << ida->table_name << ")";
+ }
};
void MDSTable::save(MDSInternalContextBase *onfinish, version_t v)
void finish(int r) override {
ida->load_2(r, bl, onfinish);
}
+ void print(ostream& out) const override {
+ out << "table_load(" << ida->table_name << ")";
+ }
};
object_t MDSTable::get_object_name() const
virtual void reset_state() = 0;
virtual void decode_state(bufferlist::iterator& p) = 0;
virtual void encode_state(bufferlist& bl) const = 0;
+
+ friend class C_IO_MT_Load;
+ friend class C_IO_MT_Save;
};
#endif
void finish(int r) {
oft->_commit_finish(r, log_seq, fin);
}
+ void print(ostream& out) const override {
+ out << "openfiles_save";
+ }
};
void OpenFileTable::_commit_finish(int r, uint64_t log_seq, MDSInternalContextBase *fin)
void finish(int r) {
oft->_journal_finish(r, log_seq, fin, ops_map);
}
+ void print(ostream& out) const override {
+ out << "openfiles_journal";
+ }
};
void OpenFileTable::_journal_finish(int r, uint64_t log_seq, MDSInternalContextBase *c,
C_IO_OFT_Load(OpenFileTable *t, unsigned i, bool f) :
oft(t), index(i), first(f) {}
- void finish(int r) {
+ void finish(int r) override {
oft->_load_finish(r, header_r, values_r, index, first, more, header_bl, values);
}
+ void print(ostream& out) const override {
+ out << "openfiles_load";
+ }
};
class C_IO_OFT_Recover : public MDSIOContextBase {
MDSRank *get_mds() override { return oft->mds; }
public:
C_IO_OFT_Recover(OpenFileTable *t) : oft(t) {}
- void finish(int r) {
+ void finish(int r) override {
oft->_recover_finish(r);
}
+ void print(ostream& out) const override {
+ out << "openfiles_recover";
+ }
};
void OpenFileTable::_recover_finish(int r)
uint64_t size;
utime_t mtime;
- C_MDC_Recover(RecoveryQueue *rq_, CInode *i) : rq(rq_), in(i), size(0) {
+ C_MDC_Recover(RecoveryQueue *rq_, CInode *i) :
+ MDSIOContextBase(false), rq(rq_), in(i), size(0) {
assert(rq != NULL);
}
+ void print(ostream& out) const override {
+ out << "file_recover(" << in->ino() << ")";
+ }
};
sessionmap->_load_finish(r, header_r, values_r, first, header_bl, session_vals,
more_session_vals);
}
+ void print(ostream& out) const override {
+ out << "session_load";
+ }
};
}
void finish(int r) override {
sessionmap->_load_legacy_finish(r, bl);
}
+ void print(ostream& out) const override {
+ out << "session_load_legacy";
+ }
};
}
sessionmap->_save_finish(version);
}
}
+ void print(ostream& out) const override {
+ out << "session_save";
+ }
};
}
on_safe->complete(r);
}
}
+ void print(ostream& out) const override {
+ out << "session_save_one";
+ }
};
}
object_locator_t oloc(mds->mdsmap->get_metadata_pool());
MDSInternalContextBase *on_safe = gather_bld->new_sub();
mds->objecter->mutate(oid, oloc, op, snapc,
- ceph::real_clock::now(),
- 0, new C_OnFinisher(
+ ceph::real_clock::now(), 0,
+ new C_OnFinisher(
new C_IO_SM_Save_One(this, on_safe),
mds->finisher));
}
assert(r == 0 || r == -ENOENT);
sm->_purge_stray_purged(dn, only_head);
}
+ void print(ostream& out) const override {
+ CInode *in = dn->get_projected_linkage()->get_inode();
+ out << "purge_stray(" << in->ino() << ")";
+ }
};
MDS_HEALTH_DAMAGE,
MDS_HEALTH_READ_ONLY,
MDS_HEALTH_SLOW_REQUEST,
- MDS_HEALTH_CACHE_OVERSIZED
+ MDS_HEALTH_CACHE_OVERSIZED,
+ MDS_HEALTH_SLOW_METADATA_IO,
};
inline const char *mds_metric_name(mds_metric_t m)
case MDS_HEALTH_READ_ONLY: return "MDS_READ_ONLY";
case MDS_HEALTH_SLOW_REQUEST: return "MDS_SLOW_REQUEST";
case MDS_HEALTH_CACHE_OVERSIZED: return "MDS_CACHE_OVERSIZED";
+ case MDS_HEALTH_SLOW_METADATA_IO: return "MDS_SLOW_METADATA_IO";
default:
return "???";
}
return "%num% MDSs report slow requests";
case MDS_HEALTH_CACHE_OVERSIZED:
return "%num% MDSs report oversized cache";
+ case MDS_HEALTH_SLOW_METADATA_IO:
+ return "%num% MDSs report slow metadata IOs";
default:
return "???";
}