to not attempt recalling too many caps at once, leading to instability.
MDS with a large cache (64GB+) should be more stable.
+* MDS now provides a config option "mds_max_caps_per_client" (default: 1M) to
+ limit the number of caps a client session may hold. Long running client
+ sessions with a large number of caps have been a source of instability in the
+ MDS when all of these caps need to be processed during certain session
+ events. It is recommended to not unnecessarily increase this value.
+
* The `cache drop` admin socket command has been removed. The `ceph tell mds.X
cache drop` remains.
.set_default(100)
.set_description("minimum number of capabilities a client may hold"),
+ Option("mds_max_caps_per_client", Option::TYPE_UINT, Option::LEVEL_ADVANCED)
+ .set_default(1_M)
+ .set_description("maximum number of capabilities a client may hold"),
+
Option("mds_hack_allow_loading_invalid_metadata", Option::TYPE_BOOL, Option::LEVEL_ADVANCED)
.set_default(0)
.set_description("INTENTIONALLY CAUSE DATA LOSS by bypasing checks for invalid metadata on disk. Allows testing repair tools."),
sessionmap.update_average_session_age();
if (is_active() || is_stopping()) {
+ server->recall_client_state(nullptr, Server::RecallFlags::ENFORCE_MAX);
mdcache->trim();
mdcache->trim_client_leases();
mdcache->check_memory_usage();
{
const auto now = clock::now();
const bool steady = flags&RecallFlags::STEADY;
+ const bool enforce_max = flags&RecallFlags::ENFORCE_MAX;
+ const auto max_caps_per_client = g_conf->get_val<uint64_t>("mds_max_caps_per_client");
const auto min_caps_per_client = g_conf->get_val<uint64_t>("mds_min_caps_per_client");
const auto recall_global_max_decay_threshold = g_conf->get_val<Option::size_t>("mds_recall_global_max_decay_threshold");
const auto recall_max_caps = g_conf->get_val<Option::size_t>("mds_recall_max_caps");
const auto recall_max_decay_threshold = g_conf->get_val<Option::size_t>("mds_recall_max_decay_threshold");
- dout(10) << __func__ << ": caps per client " << min_caps_per_client << "/" << Capability::count() << dendl;
+ dout(10) << __func__ << ":"
+ << " min=" << min_caps_per_client
+ << " max=" << max_caps_per_client
+ << " total=" << Capability::count()
+ << " flags=0x" << std::hex << flags
+ << dendl;
/* trim caps of sessions with the most caps first */
std::multimap<uint64_t, Session*> caps_session;
- auto f = [&caps_session](auto& s) {
- caps_session.emplace(std::piecewise_construct, std::forward_as_tuple(s->caps.size()), std::forward_as_tuple(s));
+ auto f = [&caps_session, enforce_max, max_caps_per_client](auto& s) {
+ auto num_caps = s->caps.size();
+ if (!enforce_max || num_caps > max_caps_per_client) {
+ caps_session.emplace(std::piecewise_construct, std::forward_as_tuple(num_caps), std::forward_as_tuple(s));
+ }
};
mds->sessionmap.get_client_sessions(std::move(f));