MXS-1929: Add worker local storage of data
Data can now be stored on thread-local storage of the worker. By acquiring a unique handle from the worker, a module can store a thread-local value. This functionality will be used to store configurations that are sometimes updated at runtime but are largely read-only. By avoiding shared data altogether, performance is not affected. The only synchronization that is done is on update. Also added a helper functions for broadcasting tasks on all routing workers. With the old mxs_rworker_broadcast_message function, if a function call was broadcasted it was always queued for execution. The mxs_rworker_broadcast will immediately execute the task on the local worker and queue it for execution of other routing workers.
This commit is contained in:
@ -13,8 +13,12 @@
|
||||
*/
|
||||
|
||||
#include <maxscale/cppdefs.hh>
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include <maxscale/routingworker.h>
|
||||
#include <maxscale/worker.hh>
|
||||
|
||||
#include "session.hh"
|
||||
|
||||
namespace maxscale
|
||||
@ -35,6 +39,9 @@ public:
|
||||
typedef Registry<MXS_SESSION> SessionsById;
|
||||
typedef std::vector<DCB*> Zombies;
|
||||
|
||||
typedef std::unordered_map<uint64_t, void*> LocalData;
|
||||
typedef std::unordered_map<uint64_t, void(*)(void*)> DataDeleters;
|
||||
|
||||
/**
|
||||
* Initialize the routing worker mechanism.
|
||||
*
|
||||
@ -278,6 +285,75 @@ public:
|
||||
*/
|
||||
static RoutingWorker* pick_worker();
|
||||
|
||||
/**
|
||||
* Worker local storage
|
||||
*/
|
||||
|
||||
/**
|
||||
* Initialize a globally unique data identifier
|
||||
*
|
||||
* @return The data identifier usable for worker local data storage
|
||||
*/
|
||||
static uint64_t create_key()
|
||||
{
|
||||
static uint64_t id_generator = 0;
|
||||
return atomic_add_uint64(&id_generator, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set local data
|
||||
*
|
||||
* @param key Key acquired with create_local_data
|
||||
* @param data Data to store
|
||||
*/
|
||||
void set_data(uint64_t key, void* data, void (*callback)(void*))
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
m_data_deleters[key] = callback;
|
||||
}
|
||||
|
||||
m_local_data[key] = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get local data
|
||||
*
|
||||
* @param key Key to use
|
||||
*
|
||||
* @return Data previously stored
|
||||
*/
|
||||
void* get_data(uint64_t key)
|
||||
{
|
||||
auto it = m_local_data.find(key);
|
||||
return it != m_local_data.end() ? it->second : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes local data
|
||||
*
|
||||
* If a callback was passed when the data was set, it will be called.
|
||||
*
|
||||
* @param key Key to remove
|
||||
*/
|
||||
void delete_data(uint64_t key)
|
||||
{
|
||||
auto data = m_local_data.find(key);
|
||||
|
||||
if (data != m_local_data.end())
|
||||
{
|
||||
auto deleter = m_data_deleters.find(key);
|
||||
|
||||
if (deleter != m_data_deleters.end())
|
||||
{
|
||||
deleter->second(data->second);
|
||||
m_data_deleters.erase(deleter);
|
||||
}
|
||||
|
||||
m_local_data.erase(data);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const int m_id; /*< The id of the worker. */
|
||||
SessionsById m_sessions; /*< A mapping of session_id->MXS_SESSION. The map
|
||||
@ -286,6 +362,8 @@ private:
|
||||
* it's up to the protocol to decide whether a new
|
||||
* session is added to the map. */
|
||||
Zombies m_zombies; /*< DCBs to be deleted. */
|
||||
LocalData m_local_data; /*< Data local to this worker */
|
||||
DataDeleters m_data_deleters; /*< Delete functions for the local data */
|
||||
|
||||
RoutingWorker();
|
||||
virtual ~RoutingWorker();
|
||||
|
Reference in New Issue
Block a user