polardbxengine/extra/IS/consensus/service/thread_timer.cc

273 lines
6.7 KiB
C++

/************************************************************************
*
* Copyright (c) 2016 Alibaba.com, Inc. All Rights Reserved
* $Id: thread_timer.cc,v 1.0 11/22/2016 03:08:37 PM yingqiang.zyq(yingqiang.zyq@alibaba-inc.com) $
*
************************************************************************/
/**
* @file thread_timer.cc
* @author yingqiang.zyq(yingqiang.zyq@alibaba-inc.com)
* @date 11/22/2016 03:08:37 PM
* @version 1.0
* @brief
*
**/
#include "thread_timer.h"
#include "paxos.h"
namespace alisql {
ThreadTimerService::ThreadTimerService()
//isTimerInited_(0)
//,isStoped_(1)
:loop_(NULL)
{
ld_= new LoopData();
loop_= ev_loop_new(0);
ld_->lock.lock();
ev_async_start(loop_, &ld_->asyncWatcher);
ev_set_userdata(loop_, ld_);
/* ev_set_invoke_pending_cb */
ev_set_loop_release_cb(loop_, ThreadTimerService::loopRelease, ThreadTimerService::loopAcquire);
ld_->lock.unlock();
thread_= new std::thread(ThreadTimerService::mainService, loop_);
}
/* TODO shutdown */
ThreadTimerService::~ThreadTimerService()
{
ld_->lock.lock();
ld_->shutdown= true;
wakeup();
ld_->lock.unlock();
thread_->join();
delete thread_;
ld_->lock.lock();
ev_loop_destroy(loop_);
ld_->lock.unlock();
loop_= NULL;
thread_= NULL;
delete ld_;
ld_= NULL;
}
/*
void ThreadTimerService::startService()
{
;
}
void ThreadTimerService::stopService()
{
;
}
*/
void ThreadTimerService::mainService(EV_P)
{
LoopData *ld= (LoopData *) ev_userdata (EV_A);
ld->lock.lock();
ev_run (EV_A, 0);
ld->lock.unlock();
}
void ThreadTimerService::loopRelease(EV_P)
{
LoopData *ld= (LoopData *) ev_userdata(EV_A);
ld->lock.unlock();
}
void ThreadTimerService::loopAcquire(EV_P)
{
LoopData *ld= (LoopData *) ev_userdata(EV_A);
ld->lock.lock();
}
void ThreadTimerService::loopAsync(EV_P, ev_async *w, int revents)
{
LoopData *ld= (LoopData *) ev_userdata(EV_A);
if (ld->shutdown)
ev_break(EV_A, EVBREAK_ALL);
}
ThreadTimer::~ThreadTimer()
{
stop();
}
void ThreadTimer::start()
{
if (type_ == Stage)
setStageExtraTime(time_);
service_->ldlock();
ev_now_update(service_->getEvLoop());
ev_timer_start(service_->getEvLoop(), &timer_);
service_->wakeup();
service_->ldunlock();
auto loop= service_->getEvLoop();
auto w= &timer_;
// easy_info_log("ThreadTimer::start ev_now:%lf mn_now:%lf at:%lf, repeat:%lf\n", ev_now(loop), ev_mn_now(loop), w->at, w->repeat);
}
void ThreadTimer::restart(double t)
{
assert(type_ == Repeatable || type_ == Stage);
auto loop= service_->getEvLoop();
auto w= &timer_;
// easy_info_log("ThreadTimer::restarts ev_now:%lf mn_now:%lf at:%lf, repeat:%lf\n", ev_now(loop), ev_mn_now(loop), w->at, w->repeat);
if (t != 0.0)
time_= t;
if (type_ == Stage)
setStageExtraTime(time_);
if (t == 0.0)
{
service_->ldlock();
/* We should update the mn_now&ev_rt_now because the loop may suspend a long time. */
ev_now_update(service_->getEvLoop());
if (type_ == Stage)
ev_timer_set(&timer_, time_, time_);
ev_timer_again(service_->getEvLoop(), &timer_);
service_->wakeup();
service_->ldunlock();
}
else
{
service_->ldlock();
/* We should update the mn_now&ev_rt_now because the loop may suspend a long time. */
ev_now_update(service_->getEvLoop());
ev_timer_set(&timer_, t, t);
ev_timer_again(service_->getEvLoop(), &timer_);
service_->wakeup();
service_->ldunlock();
}
// easy_info_log("ThreadTimer::restarte ev_now:%lf mn_now:%lf at:%lf, repeat:%lf\n", ev_now(loop), ev_mn_now(loop), w->at, w->repeat);
}
void ThreadTimer::restart()
{
restart(0.0);
}
void ThreadTimer::restart(uint64_t t, bool needRandom)
{
double f= (double)t;
f /= 1000;
restart(f);
}
void ThreadTimer::stop()
{
if (ev_is_active(&timer_))
{
service_->ldlock();
ev_timer_stop(service_->getEvLoop(), &timer_);
service_->wakeup();
service_->ldunlock();
auto loop= service_->getEvLoop();
auto w= &timer_;
easy_info_log("ThreadTimer::stop ev_now:%lf mn_now:%lf at:%lf, repeat:%lf\n", ev_now(loop), ev_mn_now(loop), w->at, w->repeat);
}
}
void ThreadTimer::setStageExtraTime(double baseTime)
{
assert(type_ == Stage);
uint64_t base= 10000, randn= rand() % base;
if (randWeight_ != 0)
{
/* if weigth == 9 we use lest time here. */
randn= randn/10 + 1000 * (9 - randWeight_);
}
double tmp= baseTime * randn / base;
stageExtraTime_ = (tmp < 0.001 ? 0.001 : tmp);
currentStage_.store(0);
}
uint64_t ThreadTimer::getAndSetStage()
{
if (currentStage_.load() == 0)
{
currentStage_.store(1);
return 0;
}
else
{
currentStage_.store(0);
return 1;
}
}
void ThreadTimer::callbackRunWeak(CallbackWeakType callBackPtr)
{
//if (callBackPtr != nullptr)
// callBackPtr->run();
if (auto spt = callBackPtr.lock())
spt->run();
else
easy_error_log("ThreadTimer::callbackRun : the callBackPtr already be deteled, stop this async call.");
}
void ThreadTimer::callbackRun(CallbackType callBackPtr)
{
if (callBackPtr != nullptr)
callBackPtr->run();
}
void ThreadTimer::timerCallbackInternal(struct ev_loop *loop, ev_timer *w, int revents)
{
// easy_info_log("timerCallbackInternal ev_now:%lf mn_now:%lf at:%lf, repeat:%lf\n", ev_now(loop), ev_mn_now(loop), w->at, w->repeat);
ThreadTimer *tt= (ThreadTimer *)(w->data);
if (tt->getType() == ThreadTimer::Stage)
{
double t;
if (tt->getAndSetStage() == 0)
{
t= tt->getStageExtraTime();
easy_warn_log("ThreadTimer change stage from 0 to 1, extraTime:%lf", t);
}
else
{
t= tt->getTime();
if (tt->getService() != nullptr)
{
assert(tt->callBackPtr != nullptr);
//tt->getService()->sendAsyncEvent(ThreadTimer::callbackRun, tt->callBackPtr);
tt->getService()->sendAsyncEvent(ThreadTimer::callbackRunWeak, std::move(CallbackWeakType(tt->callBackPtr)));
}
else
tt->callBackPtr->run();
}
ev_timer_set(w, t, t);
ev_timer_again(loop, w);
// easy_info_log("timerCallbackInternal Stage ev_now:%lf mn_now:%lf at:%lf, repeat:%lf\n", ev_now(loop), ev_mn_now(loop), w->at, w->repeat);
}
else
{
if (tt->getService() != nullptr) //&& tt->getType() != ThreadTimer::Oneshot)
{
/* Oneshot should also use asyc call.
otherwise deadlock will happened between LoopData::lock and Paxos::lock. */
//assert(tt->callBackPtr != nullptr);
if (tt->getType() != ThreadTimer::Oneshot)
tt->getService()->sendAsyncEvent(ThreadTimer::callbackRunWeak, std::move(CallbackWeakType(tt->callBackPtr)));
else
tt->getService()->sendAsyncEvent(ThreadTimer::callbackRun, tt->callBackPtr);
}
else
tt->callBackPtr->run();
if (tt->getType() == ThreadTimer::Oneshot)
delete tt;
}
}
};/* end of namespace alisql */