ceph中的SafeTimer 用法和分析

在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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值