OPTION(osd_agent_max_ops, OPT_INT, 4)
OPTION(osd_agent_min_evict_effort, OPT_FLOAT, .1)
OPTION(osd_agent_quantize_effort, OPT_FLOAT, .1)
+OPTION(osd_agent_delay_time, OPT_FLOAT, 5.0)
// decay atime and hist histograms after how many objects go by
OPTION(osd_agent_hist_halflife, OPT_INT, 1000)
agent_active(true),
agent_thread(this),
agent_stop_flag(false),
+ agent_timer_lock("OSD::agent_timer_lock"),
+ agent_timer(osd->client_messenger->cct, agent_timer_lock),
objecter_lock("OSD::objecter_lock"),
objecter_timer(osd->client_messenger->cct, objecter_lock),
objecter(new Objecter(osd->client_messenger->cct, osd->objecter_messenger, osd->monc, &objecter_osdmap,
Mutex::Locker l(backfill_request_lock);
backfill_request_timer.shutdown();
}
+ {
+ Mutex::Locker l(agent_timer_lock);
+ agent_timer.shutdown();
+ }
osdmap = OSDMapRef();
next_osdmap = OSDMapRef();
}
objecter->init_locked();
}
watch_timer.init();
+ agent_timer.init();
agent_thread.create();
}
agent_lock.Unlock();
}
+class AgentTimeoutCB : public Context {
+ PGRef pg;
+public:
+ AgentTimeoutCB(PGRef _pg) : pg(_pg) {}
+ void finish(int) {
+ pg->agent_choose_mode_restart();
+ }
+};
+
void OSDService::agent_entry()
{
dout(10) << __func__ << " start" << dendl;
PGRef pg = *agent_queue_pos;
int max = g_conf->osd_agent_max_ops - agent_ops;
agent_lock.Unlock();
- pg->agent_work(max);
+ if (!pg->agent_work(max)) {
+ dout(10) << __func__ << " " << *pg
+ << " no agent_work, delay for " << g_conf->osd_agent_delay_time
+ << " seconds" << dendl;
+
+ osd->logger->inc(l_osd_tier_delay);
+ // Queue a timer to call agent_choose_mode for this pg in 5 seconds
+ agent_timer_lock.Lock();
+ Context *cb = new AgentTimeoutCB(pg);
+ agent_timer.add_event_after(g_conf->osd_agent_delay_time, cb);
+ agent_timer_lock.Unlock();
+ }
agent_lock.Lock();
}
agent_lock.Unlock();
osd_plb.add_u64_counter(l_osd_tier_whiteout, "tier_whiteout");
osd_plb.add_u64_counter(l_osd_tier_dirty, "tier_dirty");
osd_plb.add_u64_counter(l_osd_tier_clean, "tier_clean");
+ osd_plb.add_u64_counter(l_osd_tier_delay, "tier_delay");
osd_plb.add_u64_counter(l_osd_agent_wake, "agent_wake");
osd_plb.add_u64_counter(l_osd_agent_skip, "agent_skip");
l_osd_tier_whiteout,
l_osd_tier_dirty,
l_osd_tier_clean,
+ l_osd_tier_delay,
l_osd_agent_wake,
l_osd_agent_skip,
}
} agent_thread;
bool agent_stop_flag;
+ Mutex agent_timer_lock;
+ SafeTimer agent_timer;
void agent_entry();
void agent_stop();
virtual void check_blacklisted_watchers() = 0;
virtual void get_watchers(std::list<obj_watch_item_t>&) = 0;
- virtual void agent_work(int max) = 0;
+ virtual bool agent_work(int max) = 0;
virtual void agent_stop() = 0;
+ virtual void agent_delay() = 0;
virtual void agent_clear() = 0;
+ virtual void agent_choose_mode_restart() = 0;
};
ostream& operator<<(ostream& out, const PG& pg);
agent_state->position.hash = pool.info.get_random_pg_position(
info.pgid.pgid,
rand());
+ agent_state->start = agent_state->position;
dout(10) << __func__ << " allocated new state, position "
<< agent_state->position << dendl;
agent_state.reset(NULL);
}
-void ReplicatedPG::agent_work(int start_max)
+// Return false if no objects operated on since start of object hash space
+bool ReplicatedPG::agent_work(int start_max)
{
lock();
if (!agent_state) {
dout(10) << __func__ << " no agent state, stopping" << dendl;
unlock();
- return;
+ return true;
}
assert(!deleting);
if (agent_state->is_idle()) {
dout(10) << __func__ << " idle, stopping" << dendl;
unlock();
- return;
+ return true;
}
osd->logger->inc(l_osd_agent_wake);
agent_state->temp_hist.decay();
}
+ // Total objects operated on so far
+ int total_started = agent_state->started + started;
+ bool need_delay = false;
+
+ dout(20) << __func__ << " start pos " << agent_state->position
+ << " next start pos " << next
+ << " started " << total_started << dendl;
+
+ // See if we've made a full pass over the object hash space
+ // This might check at most ls_max objects a second time to notice that
+ // we've checked every objects at least once.
+ if (agent_state->position < agent_state->start && next >= agent_state->start) {
+ dout(20) << __func__ << " wrap around " << agent_state->start << dendl;
+ if (total_started == 0)
+ need_delay = true;
+ else
+ total_started = 0;
+ agent_state->start = next;
+ }
+ agent_state->started = total_started;
+
+ // See if we are starting from beginning
if (next.is_max())
agent_state->position = hobject_t();
else
agent_state->position = next;
- dout(20) << __func__ << " final position " << agent_state->position << dendl;
+
+ if (need_delay) {
+ assert(agent_state->delaying == false);
+ agent_delay();
+ unlock();
+ return false;
+ }
agent_choose_mode();
unlock();
+ return true;
}
void ReplicatedPG::agent_load_hit_sets()
}
}
-void ReplicatedPG::agent_choose_mode()
+void ReplicatedPG::agent_delay()
{
+ dout(20) << __func__ << dendl;
+ if (agent_state && !agent_state->is_idle()) {
+ assert(agent_state->delaying == false);
+ agent_state->delaying = true;
+ osd->agent_disable_pg(this, agent_state->evict_effort);
+ }
+}
+
+void ReplicatedPG::agent_choose_mode_restart()
+{
+ dout(20) << __func__ << dendl;
+ lock();
+ if (agent_state && agent_state->delaying) {
+ agent_state->delaying = false;
+ agent_choose_mode(true);
+ }
+ unlock();
+}
+
+void ReplicatedPG::agent_choose_mode(bool restart)
+{
+ // Let delay play out
+ if (agent_state->delaying) {
+ dout(20) << __func__ << this << " delaying, ignored" << dendl;
+ return;
+ }
+
uint64_t divisor = pool.info.get_pg_num_divisor(info.pgid.pgid);
uint64_t num_user_objects = info.stats.stats.sum.num_objects;
TierAgentState::flush_mode_t flush_mode = TierAgentState::FLUSH_MODE_IDLE;
uint64_t flush_target = pool.info.cache_target_dirty_ratio_micro;
uint64_t flush_slop = (float)flush_target * g_conf->osd_agent_slop;
- if (agent_state->flush_mode == TierAgentState::FLUSH_MODE_IDLE)
+ if (restart || agent_state->flush_mode == TierAgentState::FLUSH_MODE_IDLE)
flush_target += flush_slop;
else
flush_target -= MIN(flush_target, flush_slop);
unsigned evict_effort = 0;
uint64_t evict_target = pool.info.cache_target_full_ratio_micro;
uint64_t evict_slop = (float)evict_target * g_conf->osd_agent_slop;
- if (agent_state->evict_mode == TierAgentState::EVICT_MODE_IDLE)
+ if (restart || agent_state->evict_mode == TierAgentState::EVICT_MODE_IDLE)
evict_target += evict_slop;
else
evict_target -= MIN(evict_target, evict_slop);
// (including flush). This is probably fine (they should be
// correlated) but it is not precisely correct.
if (agent_state->is_idle()) {
- if (!old_idle) {
+ if (!restart && !old_idle) {
osd->agent_disable_pg(this, old_effort);
}
} else {
- if (old_idle) {
+ if (restart || old_idle) {
osd->agent_enable_pg(this, agent_state->evict_effort);
} else if (old_effort != agent_state->evict_effort) {
osd->agent_adjust_pg(this, old_effort, agent_state->evict_effort);
friend class C_HitSetFlushing;
void agent_setup(); ///< initialize agent state
- void agent_work(int max); ///< entry point to do some agent work
+ bool agent_work(int max); ///< entry point to do some agent work
bool agent_maybe_flush(ObjectContextRef& obc); ///< maybe flush
bool agent_maybe_evict(ObjectContextRef& obc); ///< maybe evict
/// stop the agent
void agent_stop();
+ void agent_delay();
/// clear agent state
void agent_clear();
- void agent_choose_mode(); ///< choose (new) agent mode(s)
+ void agent_choose_mode(bool restart = false); ///< choose (new) agent mode(s)
+ void agent_choose_mode_restart();
/// true if we can send an ondisk/commit for v
bool already_complete(eversion_t v) {
struct TierAgentState {
/// current position iterating across pool
hobject_t position;
+ /// Count of agent_work since "start" position of object hash space
+ int started;
+ hobject_t start;
+ bool delaying;
/// histogram of ages we've encountered
pow2_hist_t atime_hist;
unsigned evict_effort;
TierAgentState()
- : hist_age(0),
+ : started(0),
+ delaying(false),
+ hist_age(0),
flush_mode(FLUSH_MODE_IDLE),
evict_mode(EVICT_MODE_IDLE),
evict_effort(0)
/// false if we have any work to do
bool is_idle() const {
return
- flush_mode == FLUSH_MODE_IDLE &&
- evict_mode == EVICT_MODE_IDLE;
+ delaying ||
+ (flush_mode == FLUSH_MODE_IDLE &&
+ evict_mode == EVICT_MODE_IDLE);
}
/// add archived HitSet