在ceph中定时器是通过SafeTimer 类来实现的。
首先看看SafeTimer该如何使用,例子在src/mgr/mgrclient.cc 中
1:首先在其构造函数中构造SafeTimer的实例timer
MgrClient::MgrClient(CephContext *cct_, Messenger *msgr_)
: Dispatcher(cct_), cct(cct_), msgr(msgr_),
timer(cct_, lock)
{
assert(cct != nullptr);
}
2:然后在init函数中调用timer.init();
void MgrClient::init()
{
Mutex::Locker l(lock);
assert(msgr != nullptr);
timer.init();
}
3:通过timer.add_event_after增加要在stats_period时间执行的callback函数report_callback
void MgrClient::send_report()
{
if (stats_period != 0) {
report_callback = new FunctionContext([this](int r){send_report();});
timer.add_event_after(stats_period, report_callback);
}
}
4:如果不想这个timer执行callback可以通过下面的方法来取消这个callback的执行
if (connect_retry_callback) {
timer.cancel_event(connect_retry_callback);
connect_retry_callback = nullptr;
}
知道SafeTimer 如何使用后,具体来看看SafeTimer的源码,其路径在src/common/timer.cc 中
首先看构造函数
SafeTimer::SafeTimer(CephContext *cct_, Mutex &l, bool safe_callbacks)
: cct(cct_), lock(l),
safe_callbacks(safe_callbacks),
thread(NULL),
stopping(false)
{
}
主要是成员变量的初始化
其次在看init函数
void SafeTimer::init()
{
ldout(cct,10) << "init" << dendl;
thread = new SafeTimerThread(this);
thread->create("safe_timer");
}
这里就创建了一个SafeTimerThread,我们看看这个类的构造函数
class SafeTimerThread : public Thread {
SafeTimer *parent;
public:
explicit SafeTimerThread(SafeTimer *s) : parent(s) {}
void *entry() override {
parent->timer_thread();
return NULL;
}
};
由于是thread的子类,从entry的实现就知道这个thread的回调函数是timer_thread
void SafeTimer::timer_thread()
{
lock.Lock();
ldout(cct,10) << "timer_thread starting" << dendl;
while (!stopping) {
utime_t now = ceph_clock_now();
while (!schedule.empty()) {
scheduled_map_t::iterator p = schedule.begin();
// is the future now?
//如果没有到期则退出
if (p->first > now)
break;
//分别从schedule和event中删除这个callback
Context *callback = p->second;
events.erase(callback);
schedule.erase(p);
ldout(cct,10) << "timer_thread executing " << callback << dendl;
if (!safe_callbacks)
lock.Unlock();
执行callback
callback->complete(0);
if (!safe_callbacks)
lock.Lock();
}
// recheck stopping if we dropped the lock
if (!safe_callbacks && stopping)
break;
//如果schedule 中没有callback的话,则sleep,如果有的话,则通过cond.WaitUntil等待第一个到期执行的callback
ldout(cct,20) << "timer_thread going to sleep" << dendl;
if (schedule.empty())
cond.Wait(lock);
else
cond.WaitUntil(lock, schedule.begin()->first);
ldout(cct,20) << "timer_thread awake" << dendl;
}
ldout(cct,10) << "timer_thread exiting" << dendl;
lock.Unlock();
}
那现在看看如果将callback函数加到schedule 中
前面的例子中是调用add_event_after来添加到期执行的callback
bool SafeTimer::add_event_after(double seconds, Context *callback)
{
assert(lock.is_locked());
//收到通过ceph_clock_now()得到当前的时间,然后加上未来要执行callback的时间间隔,这里也可以看到timer是用的是相对时间
utime_t when = ceph_clock_now();
when += seconds;
return add_event_at(when, callback);
}
继续看add_event_at
bool SafeTimer::add_event_at(utime_t when, Context *callback)
{
assert(lock.is_locked());
ldout(cct,10) << __func__ << " " << when << " -> " << callback << dendl;
if (stopping) {
ldout(cct,5) << __func__ << " already shutdown, event not added" << dendl;
delete callback;
return false;
}
分别在scheduled和event中添加callback,这样就可以在timer_thread中从scheduled 拿到要执行的callback
scheduled_map_t::value_type s_val(when, callback);
scheduled_map_t::iterator i = schedule.insert(s_val);
event_lookup_map_t::value_type e_val(callback, i);
pair < event_lookup_map_t::iterator, bool > rval(events.insert(e_val));
/* If you hit this, you tried to insert the same Context* twice. */
assert(rval.second);
/* If the event we have just inserted comes before everything else, we need to
* adjust our timeout. */
if (i == schedule.begin())
cond.Signal();
return true;
}
取消callback执行的
bool SafeTimer::cancel_event(Context *callback)
{
assert(lock.is_locked());
//首先找到要取消的callback
auto p = events.find(callback);
if (p == events.end()) {
ldout(cct,10) << "cancel_event " << callback << " not found" << dendl;
return false;
}
ldout(cct,10) << "cancel_event " << p->second->first << " -> " << callback << dendl;
delete p->first;
//分别从schedule和events 中取消callback
schedule.erase(p->second);
events.erase(p);
return true;
}
ceph中的SafeTimer 用法和分析
最新推荐文章于 2023-01-03 12:28:39 发布