MaxScale/server/core/mainworker.cc
Markus Mäkelä 6b8ca35408
Format core source files
Formatted core .cc files according to current uncrustify configuration.
2019-05-06 16:05:50 +03:00

243 lines
6.1 KiB
C++

/*
* Copyright (c) 2018 MariaDB Corporation Ab
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file and at www.mariadb.com/bsl11.
*
* Change Date: 2022-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2 or later of the General
* Public License.
*/
#include <maxscale/mainworker.hh>
#include <signal.h>
#include <maxscale/config.hh>
namespace
{
static struct ThisUnit
{
maxscale::MainWorker* pCurrent_main;
int64_t clock_ticks;
} this_unit;
}
namespace maxscale
{
MainWorker::MainWorker()
{
mxb_assert(!this_unit.pCurrent_main);
this_unit.pCurrent_main = this;
delayed_call(100, &MainWorker::inc_ticks);
}
MainWorker::~MainWorker()
{
mxb_assert(this_unit.pCurrent_main);
this_unit.pCurrent_main = nullptr;
}
// static
bool MainWorker::created()
{
return this_unit.pCurrent_main ? true : false;
}
// static
MainWorker& MainWorker::get()
{
mxb_assert(this_unit.pCurrent_main);
return *this_unit.pCurrent_main;
}
void MainWorker::add_task(const std::string& name, TASKFN func, void* pData, int frequency)
{
execute([=]() {
mxb_assert_message(m_tasks_by_name.find(name) == m_tasks_by_name.end(), name.c_str());
Task task(name.c_str(), func, pData, frequency);
auto p = m_tasks_by_name.insert(std::make_pair(name, task));
Task& inserted_task = (*p.first).second;
inserted_task.id = delayed_call(frequency * 1000,
&MainWorker::call_task,
this,
&inserted_task);
},
EXECUTE_AUTO);
}
void MainWorker::remove_task(const std::string& name)
{
call([this, name]() {
auto it = m_tasks_by_name.find(name);
mxb_assert(it != m_tasks_by_name.end());
if (it != m_tasks_by_name.end())
{
MXB_AT_DEBUG(bool cancelled = ) cancel_delayed_call(it->second.id);
mxb_assert(cancelled);
m_tasks_by_name.erase(it);
}
},
EXECUTE_AUTO);
}
void MainWorker::show_tasks(DCB* pDcb) const
{
// TODO: Make call() const.
MainWorker* pThis = const_cast<MainWorker*>(this);
pThis->call([this, pDcb]() {
dcb_printf(pDcb, "%-25s | Frequency | Next Due\n", "Name");
dcb_printf(pDcb, "--------------------------+-----------+-------------------------\n");
for (auto it = m_tasks_by_name.begin(); it != m_tasks_by_name.end(); ++it)
{
const Task& task = it->second;
struct tm tm;
char buf[40];
localtime_r(&task.nextdue, &tm);
asctime_r(&tm, buf);
dcb_printf(pDcb, "%-25s | %-9d | %s", task.name.c_str(), task.frequency, buf);
}
},
EXECUTE_AUTO);
}
json_t* MainWorker::tasks_to_json(const char* zHost) const
{
json_t* pResult = json_array();
// TODO: Make call() const.
MainWorker* pThis = const_cast<MainWorker*>(this);
pThis->call([this, zHost, pResult]() {
for (auto it = m_tasks_by_name.begin(); it != m_tasks_by_name.end(); ++it)
{
const Task& task = it->second;
struct tm tm;
char buf[40];
localtime_r(&task.nextdue, &tm);
asctime_r(&tm, buf);
char* nl = strchr(buf, '\n');
mxb_assert(nl);
*nl = '\0';
json_t* pObject = json_object();
json_object_set_new(pObject, CN_ID, json_string(task.name.c_str()));
json_object_set_new(pObject, CN_TYPE, json_string("tasks"));
json_t* pAttrs = json_object();
json_object_set_new(pAttrs, "frequency", json_integer(task.frequency));
json_object_set_new(pAttrs, "next_execution", json_string(buf));
json_object_set_new(pObject, CN_ATTRIBUTES, pAttrs);
json_array_append_new(pResult, pObject);
}
},
EXECUTE_AUTO);
return pResult;
}
// static
int64_t MainWorker::ticks()
{
return mxb::atomic::load(&this_unit.clock_ticks, mxb::atomic::RELAXED);
}
bool MainWorker::pre_run()
{
return true;
}
void MainWorker::post_run()
{
}
void MainWorker::epoll_tick()
{
}
bool MainWorker::call_task(Worker::Call::action_t action, MainWorker::Task* pTask)
{
bool call_again = false;
if (action == Worker::Call::EXECUTE)
{
mxb_assert(m_tasks_by_name.find(pTask->name) != m_tasks_by_name.end());
call_again = pTask->func(pTask->pData);
if (call_again)
{
pTask->nextdue = time(0) + pTask->frequency;
}
else
{
auto it = m_tasks_by_name.find(pTask->name);
if (it != m_tasks_by_name.end()) // Not found, if task function removes task.
{
m_tasks_by_name.erase(it);
}
}
}
return call_again;
}
// static
bool MainWorker::inc_ticks(Worker::Call::action_t action)
{
if (action == Worker::Call::EXECUTE)
{
mxb::atomic::add(&this_unit.clock_ticks, 1, mxb::atomic::RELAXED);
}
return true;
}
}
extern "C"
{
void hktask_add(const char* zName, TASKFN func, void* pData, int frequency)
{
mxs::MainWorker::get().add_task(zName, func, pData, frequency);
}
void hktask_remove(const char* zName)
{
mxs::MainWorker::get().remove_task(zName);
}
void hkshow_tasks(DCB* pDcb)
{
mxs::MainWorker::get().show_tasks(pDcb);
}
json_t* hk_tasks_json(const char* zHost)
{
return mxs::MainWorker::get().tasks_to_json(zHost);
}
int64_t mxs_clock()
{
return mxs::MainWorker::ticks();
}
}