Remove housekeeper.cc
It is no longer used.
This commit is contained in:
		@ -1,336 +0,0 @@
 | 
				
			|||||||
/*
 | 
					 | 
				
			||||||
 * Copyright (c) 2016 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/ccdefs.hh>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <cstdlib>
 | 
					 | 
				
			||||||
#include <list>
 | 
					 | 
				
			||||||
#include <string.h>
 | 
					 | 
				
			||||||
#include <string>
 | 
					 | 
				
			||||||
#include <thread>
 | 
					 | 
				
			||||||
#include <mutex>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <maxbase/semaphore.h>
 | 
					 | 
				
			||||||
#include <maxscale/alloc.h>
 | 
					 | 
				
			||||||
#include <maxbase/atomic.hh>
 | 
					 | 
				
			||||||
#include <maxscale/clock.h>
 | 
					 | 
				
			||||||
#include <maxscale/config.hh>
 | 
					 | 
				
			||||||
#include <maxscale/housekeeper.h>
 | 
					 | 
				
			||||||
#include <maxscale/json_api.hh>
 | 
					 | 
				
			||||||
#include <maxscale/query_classifier.hh>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * @file housekeeper.cc  Provide a mechanism to run periodic tasks
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The housekeeper provides a mechanism to allow for tasks, function
 | 
					 | 
				
			||||||
 * calls basically, to be run on a time basis. A task may be run
 | 
					 | 
				
			||||||
 * repeatedly, with a given frequency (in seconds), or may be a one
 | 
					 | 
				
			||||||
 * shot task that will only be run once after a specified number of
 | 
					 | 
				
			||||||
 * seconds.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * The housekeeper also maintains a global variable that
 | 
					 | 
				
			||||||
 * is incremented every 100ms and can be read with the mxs_clock() function.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// Helper struct used when starting the housekeeper
 | 
					 | 
				
			||||||
struct hkstart_result
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    sem_t sem;
 | 
					 | 
				
			||||||
    bool  ok;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void hkthread(hkstart_result*);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// TODO: Move these into a separate file
 | 
					 | 
				
			||||||
static int64_t mxs_clock_ticks = 0;     /*< One clock tick is 100 milliseconds */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int64_t mxs_clock()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return mxb::atomic::load(&mxs_clock_ticks, mxb::atomic::RELAXED);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// A task to perform
 | 
					 | 
				
			||||||
struct Task
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    Task(std::string name, TASKFN func, void* data, int frequency)
 | 
					 | 
				
			||||||
        : name(name)
 | 
					 | 
				
			||||||
        , func(func)
 | 
					 | 
				
			||||||
        , data(data)
 | 
					 | 
				
			||||||
        , frequency(frequency)
 | 
					 | 
				
			||||||
        , nextdue(time(0) + frequency)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct NameMatch
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        NameMatch(std::string name)
 | 
					 | 
				
			||||||
            : m_name(name)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        bool operator()(const Task& task)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            return task.name == m_name;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::string m_name;
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::string name;       /*< Task name */
 | 
					 | 
				
			||||||
    TASKFN      func;       /*< The function to call */
 | 
					 | 
				
			||||||
    void*       data;       /*< Data to pass to the function */
 | 
					 | 
				
			||||||
    int         frequency;  /*< How often to call the tasks, in seconds */
 | 
					 | 
				
			||||||
    time_t      nextdue;    /*< When the task should be next run */
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class Housekeeper
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
public:
 | 
					 | 
				
			||||||
    Housekeeper();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    static bool init();
 | 
					 | 
				
			||||||
    static bool start();
 | 
					 | 
				
			||||||
    void        stop();
 | 
					 | 
				
			||||||
    void        run();
 | 
					 | 
				
			||||||
    void        add(const Task& task);
 | 
					 | 
				
			||||||
    void        remove(std::string name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    void    print_tasks(DCB* pDcb);
 | 
					 | 
				
			||||||
    json_t* tasks_json(const char* host);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private:
 | 
					 | 
				
			||||||
    std::thread     m_thread;
 | 
					 | 
				
			||||||
    uint32_t        m_running;
 | 
					 | 
				
			||||||
    std::list<Task> m_tasks;
 | 
					 | 
				
			||||||
    std::mutex      m_lock;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool is_running() const
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        return mxb::atomic::load(&m_running);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// The Housekeeper instance
 | 
					 | 
				
			||||||
static Housekeeper* hk = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Housekeeper::Housekeeper()
 | 
					 | 
				
			||||||
    : m_running(1)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Housekeeper::init()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    hk = new(std::nothrow) Housekeeper;
 | 
					 | 
				
			||||||
    return hk != nullptr;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Housekeeper::start()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mxb_assert(hk);                                         // init() has been called.
 | 
					 | 
				
			||||||
    mxb_assert(hk->m_thread.get_id() == std::thread::id()); // start has not been called.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    struct hkstart_result res;
 | 
					 | 
				
			||||||
    sem_init(&res.sem, 0, 0);
 | 
					 | 
				
			||||||
    res.ok = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    try
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        hk->m_thread = std::thread(hkthread, &res);
 | 
					 | 
				
			||||||
        sem_wait(&res.sem);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    catch (const std::exception& x)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        MXS_ERROR("Could not start housekeeping thread: %s", x.what());
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    sem_destroy(&res.sem);
 | 
					 | 
				
			||||||
    return res.ok;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Housekeeper::run()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    while (is_running())
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        for (int i = 0; i < 10; i++)
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
 | 
					 | 
				
			||||||
            mxb::atomic::add(&mxs_clock_ticks, 1, mxb::atomic::RELAXED);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        std::lock_guard<std::mutex> guard(m_lock);
 | 
					 | 
				
			||||||
        time_t now = time(0);
 | 
					 | 
				
			||||||
        auto it = m_tasks.begin();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        while (it != m_tasks.end() && is_running())
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            if (it->nextdue <= now)
 | 
					 | 
				
			||||||
            {
 | 
					 | 
				
			||||||
                it->nextdue = now + it->frequency;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                if (!it->func(it->data))
 | 
					 | 
				
			||||||
                {
 | 
					 | 
				
			||||||
                    it = m_tasks.erase(it);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            it++;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Housekeeper::stop()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mxb_assert(hk);                                         // init() has been called.
 | 
					 | 
				
			||||||
    mxb_assert(hk->m_thread.get_id() != std::thread::id()); // start has been called.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    mxb::atomic::store(&m_running, 0);
 | 
					 | 
				
			||||||
    m_thread.join();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Housekeeper::add(const Task& task)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    std::lock_guard<std::mutex> guard(m_lock);
 | 
					 | 
				
			||||||
    m_tasks.push_back(task);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Housekeeper::remove(std::string name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    std::lock_guard<std::mutex> guard(m_lock);
 | 
					 | 
				
			||||||
    m_tasks.remove_if(Task::NameMatch(name));
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Housekeeper::print_tasks(DCB* pDcb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    std::lock_guard<std::mutex> guard(m_lock);
 | 
					 | 
				
			||||||
    dcb_printf(pDcb, "%-25s | Type     | Frequency | Next Due\n", "Name");
 | 
					 | 
				
			||||||
    dcb_printf(pDcb, "--------------------------+----------+-----------+-------------------------\n");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (auto ptr = m_tasks.begin(); ptr != m_tasks.end(); ptr++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        struct tm tm;
 | 
					 | 
				
			||||||
        char buf[40];
 | 
					 | 
				
			||||||
        localtime_r(&ptr->nextdue, &tm);
 | 
					 | 
				
			||||||
        asctime_r(&tm, buf);
 | 
					 | 
				
			||||||
        dcb_printf(pDcb, "%-25s | %-9d | %s", ptr->name.c_str(), ptr->frequency, buf);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
json_t* Housekeeper::tasks_json(const char* host)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    json_t* arr = json_array();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    std::lock_guard<std::mutex> guard(m_lock);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for (auto ptr = m_tasks.begin(); ptr != m_tasks.end(); ptr++)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        struct tm tm;
 | 
					 | 
				
			||||||
        char buf[40];
 | 
					 | 
				
			||||||
        localtime_r(&ptr->nextdue, &tm);
 | 
					 | 
				
			||||||
        asctime_r(&tm, buf);
 | 
					 | 
				
			||||||
        char* nl = strchr(buf, '\n');
 | 
					 | 
				
			||||||
        mxb_assert(nl);
 | 
					 | 
				
			||||||
        *nl = '\0';
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        json_t* obj = json_object();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        json_object_set_new(obj, CN_ID, json_string(ptr->name.c_str()));
 | 
					 | 
				
			||||||
        json_object_set_new(obj, CN_TYPE, json_string("tasks"));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        json_t* attr = json_object();
 | 
					 | 
				
			||||||
        json_object_set_new(attr, "frequency", json_integer(ptr->frequency));
 | 
					 | 
				
			||||||
        json_object_set_new(attr, "next_execution", json_string(buf));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        json_object_set_new(obj, CN_ATTRIBUTES, attr);
 | 
					 | 
				
			||||||
        json_array_append_new(arr, obj);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return mxs_json_resource(host, MXS_JSON_API_TASKS, arr);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void hktask_add(const char* name, TASKFN func, void* data, int frequency)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mxb_assert(hk);
 | 
					 | 
				
			||||||
    Task task(name, func, data, frequency);
 | 
					 | 
				
			||||||
    hk->add(task);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void hktask_remove(const char* name)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mxb_assert(hk);
 | 
					 | 
				
			||||||
    hk->remove(name);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void hkthread(hkstart_result* res)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    // res is on the stack in Housekeeper::start() and remains valid only
 | 
					 | 
				
			||||||
    // until sem_post() is called.
 | 
					 | 
				
			||||||
    res->ok = qc_thread_init(QC_INIT_BOTH);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!res->ok)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        MXS_ERROR("Could not initialize query classifier in housekeeper thread.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    bool ok = res->ok;
 | 
					 | 
				
			||||||
    sem_post(&res->sem);
 | 
					 | 
				
			||||||
    // NOTE: res is no longer valid here.
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (ok)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        MXS_NOTICE("Housekeeper thread started.");
 | 
					 | 
				
			||||||
        hk->run();
 | 
					 | 
				
			||||||
        qc_thread_end(QC_INIT_BOTH);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    MXS_NOTICE("Housekeeper shutting down.");
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool hkinit()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return Housekeeper::init();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool hkstart()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    return Housekeeper::start();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void hkfinish()
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (hk)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        MXS_NOTICE("Waiting for housekeeper to shut down.");
 | 
					 | 
				
			||||||
        hk->stop();
 | 
					 | 
				
			||||||
        delete hk;
 | 
					 | 
				
			||||||
        hk = NULL;
 | 
					 | 
				
			||||||
        MXS_NOTICE("Housekeeper has shut down.");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void hkshow_tasks(DCB* pDcb)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mxb_assert(hk);
 | 
					 | 
				
			||||||
    hk->print_tasks(pDcb);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
json_t* hk_tasks_json(const char* host)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    mxb_assert(hk);
 | 
					 | 
				
			||||||
    return hk->tasks_json(host);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Reference in New Issue
	
	Block a user