MXS-929: Add mapping function for module commands

The modulecmd_foreach function allows commands to be iterated without having
to manage the locking of the system. This allows the commands to be easily
iterated and gathered into filtered lists without having to build it into
the module command system itself.
This commit is contained in:
Markus Makela
2016-11-19 04:29:03 +02:00
parent 4a142b1ca9
commit d68172260d
3 changed files with 147 additions and 1 deletions

View File

@ -14,6 +14,7 @@
#include <maxscale/alloc.h>
#include <maxscale/config.h>
#include <maxscale/modulecmd.h>
#include <maxscale/pcre2.h>
#include <maxscale/platform.h>
#include <maxscale/spinlock.h>
@ -508,3 +509,58 @@ const char* modulecmd_get_error()
prepare_error();
return errbuf;
}
bool modulecmd_foreach(const char *domain_re, const char *ident_re,
bool(*fn)(const MODULECMD *cmd, void *data), void *data)
{
bool rval = true;
bool stop = false;
spinlock_acquire(&modulecmd_lock);
for (MODULECMD_DOMAIN *domain = modulecmd_domains; domain && rval && !stop; domain = domain->next)
{
int err;
mxs_pcre2_result_t d_res = domain_re ?
mxs_pcre2_simple_match(domain_re, domain->domain, 0, &err) :
MXS_PCRE2_MATCH;
if (d_res == MXS_PCRE2_MATCH)
{
for (MODULECMD *cmd = domain->commands; cmd && rval; cmd = cmd->next)
{
mxs_pcre2_result_t i_res = ident_re ?
mxs_pcre2_simple_match(ident_re, cmd->identifier, 0, &err) :
MXS_PCRE2_MATCH;
if (i_res == MXS_PCRE2_MATCH)
{
if (!fn(cmd, data))
{
stop = true;
break;
}
}
else if (i_res == MXS_PCRE2_ERROR)
{
PCRE2_UCHAR errbuf[MXS_STRERROR_BUFLEN];
pcre2_get_error_message(err, errbuf, sizeof(errbuf));
MXS_ERROR("Failed to match command identifier with '%s': %s", ident_re, errbuf);
modulecmd_set_error("Failed to match command identifier with '%s': %s", ident_re, errbuf);
rval = false;
}
}
}
else if (d_res == MXS_PCRE2_ERROR)
{
PCRE2_UCHAR errbuf[MXS_STRERROR_BUFLEN];
pcre2_get_error_message(err, errbuf, sizeof(errbuf));
MXS_ERROR("Failed to match command domain with '%s': %s", domain_re, errbuf);
modulecmd_set_error("Failed to match command domain with '%s': %s", domain_re, errbuf);
rval = false;
}
}
spinlock_release(&modulecmd_lock);
return rval;
}

View File

@ -236,6 +236,68 @@ int test_module_errors()
return 0;
}
bool test_fn_map(const MODULECMD_ARG *args)
{
return true;
}
const char *map_dom = "test_map";
bool mapfn(const MODULECMD *cmd, void *data)
{
int *i = (int*)data;
(*i)++;
return true;
}
int test_map()
{
for (int i = 0; i < 10; i++)
{
char id[200];
sprintf(id, "test_map%d", i + 1);
TEST(modulecmd_register_command(map_dom, id, test_fn_map, 0, NULL),
"Registering a command should succeed");
}
int n = 0;
TEST(modulecmd_foreach(NULL, NULL, mapfn, &n), "Mapping function should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
TEST(n == 10, "Every registered command should be called");
n = 0;
TEST(modulecmd_foreach("test_map", NULL, mapfn, &n), "Mapping function should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
TEST(n == 10, "Every registered command should be called");
n = 0;
TEST(modulecmd_foreach(NULL, "test_map", mapfn, &n), "Mapping function should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
TEST(n == 10, "Every registered command should be called");
n = 0;
TEST(modulecmd_foreach("test_map", "test_map", mapfn, &n), "Mapping function should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
TEST(n == 10, "Every registered command should be called");
n = 0;
TEST(modulecmd_foreach("wrong domain", "test_map", mapfn, &n), "Mapping function should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
TEST(n == 0, "No registered command should be called");
n = 0;
TEST(modulecmd_foreach("test_map", "test_map[2-4]", mapfn, &n), "Mapping function should succeed");
TEST(strlen(modulecmd_get_error()) == 0, "Error message should be empty");
TEST(n == 3, "Three registered commands should be called");
n = 0;
TEST(!modulecmd_foreach("(", NULL, mapfn, &n), "Mapping function should fail");
TEST(strlen(modulecmd_get_error()), "Error message should not be empty");
TEST(n == 0, "No registered command should be called");
return 0;
}
int main(int argc, char **argv)
{
int rc = 0;
@ -243,6 +305,7 @@ int main(int argc, char **argv)
rc += test_arguments();
rc += test_optional_arguments();
rc += test_module_errors();
rc += test_map();
return rc;
}