MXS-1461 Add template Module

This is the first in a series of commits that introduce components
that allow filters to be tested without MaxScale or backends.
Obviously the environment is not suited for all cases, but allow e.g.
the behaviour of the firewall filter to be tested in isolation.

The environment consists of helper classes loading and manipulating
modules and filters and mock-classes that provide the needed
scaffolding around a filter.

Currently all components exist under the test directory of the firewall
filter, but once proven they can be moved to a more general purpose
location.
This commit is contained in:
Johan Wikman
2017-11-14 13:20:41 +02:00
parent 8077d97e25
commit e434c7ec66
2 changed files with 249 additions and 0 deletions

View File

@ -0,0 +1,103 @@
#pragma once
/*
* 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: 2020-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/cppdefs.hh>
#include <memory>
namespace maxscale
{
/**
* The template Module is an abstraction for a MaxScale module, to
* be used as the base class of a concrete module.
*/
template<class T>
class Module;
/**
* The template specialization Module<void> provides functionality common
* to all modules.
*/
template <>
class Module<void>
{
public:
/**
* Load a module with a specific name, assumed to be of a specific type.
*
* @param zFile_name The name of the module.
* @param zType_name The expected type of the module.
*
* @return The module object, if the module could be loaded, otherwise NULL.
*/
static void* load(const char *zFile_name, const char *zType_name);
/**
* Perform process initialization of all modules. Should be called only
* when all modules intended to be loaded have been loaded.
*
* @return True, if the process initialization succeeded.
*/
static bool process_init();
/**
* Perform process finalization of all modules.
*/
static void process_finish();
/**
* Perform thread initialization of all modules. Should be called only
* when all modules intended to be loaded have been loaded.
*
* @return True, if the thread initialization could be performed.
*/
static bool thread_init();
/**
* Perform thread finalization of all modules.
*/
static void thread_finish();
};
/**
* The template Module is intended to be derived from using the derived
* class as template argument.
*
* class XyzModule : public Module<XyzModule> { ... }
*
* @param zFile_name The name of the module.
*
* @return A module instance if the module could be loaded and it was of
* the expected type.
*/
template<class T>
class Module
{
public:
static std::auto_ptr<T> load(const char* zFile_name)
{
std::auto_ptr<T> sT;
void* pApi = Module<void>::load(zFile_name, T::zName);
if (pApi)
{
sT.reset(new T(static_cast<typename T::type_t*>(pApi)));
}
return sT;
}
};
}

View File

@ -0,0 +1,146 @@
/*
* 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: 2020-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/module.hh"
#include "../../../../core/maxscale/modules.h"
namespace maxscale
{
//static
void* Module<void>::load(const char* zName, const char* zType)
{
return load_module(zName, zType);
}
//static
bool Module<void>::process_init()
{
bool initialized = false;
MXS_MODULE_ITERATOR i = mxs_module_iterator_get(NULL);
MXS_MODULE* module = NULL;
while ((module = mxs_module_iterator_get_next(&i)) != NULL)
{
if (module->process_init)
{
int rc = (module->process_init)();
if (rc != 0)
{
break;
}
}
}
if (module)
{
// If module is non-NULL it means that the initialization failed for
// that module. We now need to call finish on all modules that were
// successfully initialized.
MXS_MODULE* failed_module = module;
i = mxs_module_iterator_get(NULL);
while ((module = mxs_module_iterator_get_next(&i)) != failed_module)
{
if (module->process_finish)
{
(module->process_finish)();
}
}
}
else
{
initialized = true;
}
return initialized;
}
//static
void Module<void>::process_finish()
{
MXS_MODULE_ITERATOR i = mxs_module_iterator_get(NULL);
MXS_MODULE* module = NULL;
while ((module = mxs_module_iterator_get_next(&i)) != NULL)
{
if (module->process_finish)
{
(module->process_finish)();
}
}
}
//static
bool Module<void>::thread_init()
{
bool initialized = false;
MXS_MODULE_ITERATOR i = mxs_module_iterator_get(NULL);
MXS_MODULE* module = NULL;
while ((module = mxs_module_iterator_get_next(&i)) != NULL)
{
if (module->thread_init)
{
int rc = (module->thread_init)();
if (rc != 0)
{
break;
}
}
}
if (module)
{
// If module is non-NULL it means that the initialization failed for
// that module. We now need to call finish on all modules that were
// successfully initialized.
MXS_MODULE* failed_module = module;
i = mxs_module_iterator_get(NULL);
while ((module = mxs_module_iterator_get_next(&i)) != failed_module)
{
if (module->thread_finish)
{
(module->thread_finish)();
}
}
}
else
{
initialized = true;
}
return initialized;
}
//static
void Module<void>::thread_finish()
{
MXS_MODULE_ITERATOR i = mxs_module_iterator_get(NULL);
MXS_MODULE* module = NULL;
while ((module = mxs_module_iterator_get_next(&i)) != NULL)
{
if (module->thread_finish)
{
(module->thread_finish)();
}
}
}
}