.set_default(20)
.set_description(""),
+ Option("osd_heartbeat_stale", Option::TYPE_INT, Option::LEVEL_ADVANCED)
+ .set_default(600)
+ .set_description("Interval (in seconds) we mark an unresponsive heartbeat peer as stale.")
+ .set_long_description("Automatically mark unresponsive heartbeat sessions as stale and tear them down. "
+ "The primary benefit is that OSD doesn't need to keep a flood of "
+ "blocked heartbeat messages around in memory."),
+
Option("osd_heartbeat_min_peers", Option::TYPE_INT, Option::LEVEL_ADVANCED)
.set_default(10)
.set_description(""),
osd_lock.Lock();
boot_finisher.stop();
- reset_heartbeat_peers();
+ reset_heartbeat_peers(true);
tick_timer.shutdown();
dout(10) << "maybe_update_heartbeat_peers forcing update after " << dur << " seconds" << dendl;
heartbeat_set_peers_need_update();
last_heartbeat_resample = now;
- if (is_waiting_for_healthy()) {
- reset_heartbeat_peers(); // we want *new* peers!
- }
+ // automatically clean up any stale heartbeat peers
+ // if we are unhealthy, then clean all
+ reset_heartbeat_peers(is_waiting_for_healthy());
}
}
}
dout(10) << "maybe_update_heartbeat_peers " << heartbeat_peers.size() << " peers, extras " << extras << dendl;
}
-void OSD::reset_heartbeat_peers()
+void OSD::reset_heartbeat_peers(bool all)
{
ceph_assert(osd_lock.is_locked());
dout(10) << "reset_heartbeat_peers" << dendl;
+ utime_t stale = ceph_clock_now();
+ stale -= cct->_conf.get_val<int64_t>("osd_heartbeat_stale");
std::lock_guard l(heartbeat_lock);
- while (!heartbeat_peers.empty()) {
- HeartbeatInfo& hi = heartbeat_peers.begin()->second;
- hi.con_back->mark_down();
- if (hi.con_front) {
- hi.con_front->mark_down();
+ for (auto it = heartbeat_peers.begin(); it != heartbeat_peers.end();) {
+ HeartbeatInfo& hi = it->second;
+ if (all || hi.is_stale(stale)) {
+ hi.con_back->mark_down();
+ if (hi.con_front) {
+ hi.con_front->mark_down();
+ }
+ // stop sending failure_report to mon too
+ failure_queue.erase(it->first);
+ heartbeat_peers.erase(it++);
+ } else {
+ it++;
}
- heartbeat_peers.erase(heartbeat_peers.begin());
}
- failure_queue.clear();
}
void OSD::handle_osd_ping(MOSDPing *m)
hb_front_client_messenger->mark_down_all();
hb_back_client_messenger->mark_down_all();
- reset_heartbeat_peers();
+ reset_heartbeat_peers(true);
}
}
}
/// send time -> deadline -> remaining replies
map<utime_t, pair<utime_t, int>> ping_history;
+ bool is_stale(utime_t stale) {
+ if (ping_history.empty()) {
+ return false;
+ }
+ utime_t oldest_deadline = ping_history.begin()->second.first;
+ return oldest_deadline <= stale;
+ }
+
bool is_unhealthy(utime_t now) {
if (ping_history.empty()) {
/// we haven't sent a ping yet or we have got all replies,
void _remove_heartbeat_peer(int p);
bool heartbeat_reset(Connection *con);
void maybe_update_heartbeat_peers();
- void reset_heartbeat_peers();
+ void reset_heartbeat_peers(bool all);
bool heartbeat_peers_need_update() {
return heartbeat_need_update.load();
}