MXS-1929: Make filters configurable at runtime

The filters can now be altered at runtime. Currently, the filter usage
uses a service level lock. The next is to allocate a per-service key to
the worker local data and use that to orchestrate the storage of the
filter lists.
This commit is contained in:
Markus Mäkelä 2018-08-02 21:21:45 +03:00
parent 1d92eabb91
commit 7d6338d65b
No known key found for this signature in database
GPG Key ID: 72D48FCE664F7B19
3 changed files with 92 additions and 43 deletions

View File

@ -58,8 +58,42 @@ public:
*/
bool update_basic_parameter(const std::string& name, const std::string& value);
std::vector<SFilterDef> filters; /**< Ordered list of filters */
/**
* Set the list of filters for this service
*
* @param filters Filters to set
*
* @return True if filters were all found and were valid
*/
bool set_filters(const std::string& filters);
/**
* Get the list of filters this service uses
*
* @note This locks the service
*
* @return A list of filters or an empty list of no filters are in use
*/
std::vector<SFilterDef> get_filters() const;
inline bool has_filters() const
{
/**
* Note: Temporarily used to check whether filters are available. This is
* not thread-safe but can be replaced with a check to worker local data to
* make it so.
*/
return !m_filters.empty();
}
// TODO: Make JSON output internal (could iterate over get_filters() but that takes the service lock)
json_t* json_relationships(const char* host) const;
// TODO: Make private
mutable std::mutex lock;
private:
std::vector<SFilterDef> m_filters; /**< Ordered list of filters */
};
/**

View File

@ -1048,20 +1048,11 @@ int service_enable_root(Service *svc, int action)
return 1;
}
/**
* Set the filters used by the service
*
* @param service The service itself
* @param filters The filters to use separated by the pipe character |
*
* @return True if loading and creating all filters was successful. False if a
* filter module was not found or the instance creation failed.
*/
bool service_set_filters(Service* service, const char* filters)
bool Service::set_filters(const std::string& filters)
{
bool rval = true;
std::vector<SFilterDef> flist;
uint64_t capabilities = 0;
uint64_t my_capabilities = 0;
for (auto& f : mxs::strtok(filters, "|"))
{
@ -1073,30 +1064,50 @@ bool service_set_filters(Service* service, const char* filters)
const MXS_MODULE* module = get_module(def->module.c_str(), MODULE_FILTER);
ss_dassert(module);
capabilities |= module->module_capabilities;
my_capabilities |= module->module_capabilities;
if (def->obj->getCapabilities)
{
capabilities |= def->obj->getCapabilities(def->filter);
my_capabilities |= def->obj->getCapabilities(def->filter);
}
}
else
{
MXS_ERROR("Unable to find filter '%s' for service '%s'", f.c_str(), service->name);
MXS_ERROR("Unable to find filter '%s' for service '%s'", f.c_str(), name);
rval = false;
}
}
if (rval)
{
Guard guard(service->lock);
service->filters = flist;
service->capabilities |= capabilities;
Guard guard(lock);
m_filters = flist;
capabilities |= my_capabilities;
}
return rval;
}
std::vector<SFilterDef> Service::get_filters() const
{
Guard guard(lock);
return m_filters;
}
/**
* Set the filters used by the service
*
* @param service The service itself
* @param filters The filters to use separated by the pipe character |
*
* @return True if loading and creating all filters was successful. False if a
* filter module was not found or the instance creation failed.
*/
bool service_set_filters(Service* service, const char* filters)
{
return service->set_filters(filters);
}
Service* service_internal_find(const char *name)
{
Guard guard(service_spin);
@ -1178,11 +1189,13 @@ void dprintService(DCB *dcb, SERVICE *svc)
asctime_r(localtime_r(&service->stats.started, &result), timebuf));
dcb_printf(dcb, "\tRoot user access: %s\n",
service->enable_root ? "Enabled" : "Disabled");
if (!service->filters.empty())
auto filters = service->get_filters();
if (!filters.empty())
{
dcb_printf(dcb, "\tFilter chain: ");
const char* sep = "";
for (const auto& f : service->filters)
for (const auto& f : filters)
{
dcb_printf(dcb, "%s %s ", f->name.c_str(), sep);
sep = "|";
@ -1692,12 +1705,12 @@ bool service_filter_in_use(const SFilterDef& filter)
for (Service* service : all_services)
{
Guard guard(service->lock);
if (std::find(service->filters.begin(),
service->filters.end(), filter) != service->filters.end())
for (const auto& f : service->get_filters())
{
return true;
if (filter == f)
{
return true;
}
}
}
@ -2055,18 +2068,16 @@ json_t* service_attributes(const SERVICE* service)
return attr;
}
json_t* service_relationships(const SERVICE* svc, const char* host)
json_t* Service::json_relationships(const char* host) const
{
const Service* service = static_cast<const Service*>(svc);
/** Store relationships to other objects */
json_t* rel = json_object();
if (!service->filters.empty())
if (!m_filters.empty())
{
json_t* filters = mxs_json_relationship(host, MXS_JSON_API_FILTERS);
for (const auto& f : service->filters)
for (const auto& f : m_filters)
{
mxs_json_add_relation(filters, f->name.c_str(), CN_FILTERS);
}
@ -2074,11 +2085,11 @@ json_t* service_relationships(const SERVICE* svc, const char* host)
json_object_set_new(rel, CN_FILTERS, filters);
}
if (have_active_servers(service))
if (have_active_servers(this))
{
json_t* servers = mxs_json_relationship(host, MXS_JSON_API_SERVERS);
for (SERVER_REF* ref = service->dbref; ref; ref = ref->next)
for (SERVER_REF* ref = dbref; ref; ref = ref->next)
{
if (SERVER_REF_IS_ACTIVE(ref))
{
@ -2101,7 +2112,7 @@ json_t* service_json_data(const SERVICE* svc, const char* host)
json_object_set_new(rval, CN_ID, json_string(service->name));
json_object_set_new(rval, CN_TYPE, json_string(CN_SERVICES));
json_object_set_new(rval, CN_ATTRIBUTES, service_attributes(service));
json_object_set_new(rval, CN_RELATIONSHIPS, service_relationships(service, host));
json_object_set_new(rval, CN_RELATIONSHIPS, service->json_relationships(host));
json_object_set_new(rval, CN_LINKS, mxs_json_self_link(host, CN_SERVICES, service->name));
return rval;
@ -2162,9 +2173,7 @@ json_t* service_relations_to_filter(const SFilterDef& filter, const char* host)
for (Service* service : all_services)
{
Guard guard(service->lock);
for (const auto& f : service->filters)
for (const auto& f : service->get_filters())
{
if (f == filter)
{
@ -2321,7 +2330,8 @@ bool Service::is_basic_parameter(const std::string& name)
CN_STRIP_DB_ESC,
CN_USER,
CN_VERSION_STRING,
CN_WEIGHTBY
CN_WEIGHTBY,
CN_FILTERS
};
return names.find(name) != names.end();
@ -2415,6 +2425,10 @@ bool Service::update_basic_parameter(const std::string& key, const std::string&
retry_start = config_truth_value(value.c_str());
valid = true;
}
else if (key == CN_FILTERS)
{
valid = set_filters(value);
}
return valid;
}

View File

@ -657,20 +657,21 @@ session_setup_filters(MXS_SESSION *session)
MXS_UPSTREAM *tail;
int i = 0;
if (service->filters.empty())
if (!service->has_filters())
{
return 1;
}
if ((session->filters = (SESSION_FILTER*)MXS_CALLOC(service->filters.size(),
sizeof(SESSION_FILTER))) == NULL)
auto filters = service->get_filters();
if ((session->filters = (SESSION_FILTER*)MXS_CALLOC(filters.size(), sizeof(SESSION_FILTER))) == NULL)
{
return 0;
}
session->n_filters = service->filters.size();
session->n_filters = filters.size();
for (auto r = service->filters.rbegin(); r != service->filters.rend(); r++)
for (auto r = filters.rbegin(); r != filters.rend(); r++)
{
if ((head = filter_apply(*r, session, &session->head)) == NULL)
{
@ -686,7 +687,7 @@ session_setup_filters(MXS_SESSION *session)
MXS_FREE(head);
}
for (auto r = service->filters.begin(); r != service->filters.end(); r++)
for (auto r = filters.begin(); r != filters.end(); r++)
{
if ((tail = filter_upstream(*r, session->filters[i].session, &session->tail)) == NULL)
{