Merge branch 'develop' into binlog_server_wait_data
This commit is contained in:
113
Documentation/Filters/Cache.md
Normal file
113
Documentation/Filters/Cache.md
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#Cache
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
The cache filter is capable of caching the result of SELECTs, so that subsequent identical
|
||||||
|
SELECTs are served directly by MaxScale, without being routed to any server.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The cache filter is straightforward to configure and simple to add to any
|
||||||
|
existing service.
|
||||||
|
|
||||||
|
```
|
||||||
|
[Cache]
|
||||||
|
type=filter
|
||||||
|
module=cache
|
||||||
|
ttl=5
|
||||||
|
storage=...
|
||||||
|
storage_args=...
|
||||||
|
|
||||||
|
[Cached Routing Service]
|
||||||
|
type=service
|
||||||
|
...
|
||||||
|
filters=Cache
|
||||||
|
```
|
||||||
|
|
||||||
|
Each configured cache filter uses a storage of its own. That is, if there
|
||||||
|
are two services, each configured with a specific cache filter, then,
|
||||||
|
even if queries target the very same servers the cached data will not
|
||||||
|
be shared.
|
||||||
|
|
||||||
|
Two services can use the same cache filter, but then either the services
|
||||||
|
should use the very same servers _or_ a completely different set of servers,
|
||||||
|
where the used table names are different. Otherwise there can be unintended
|
||||||
|
sharing.
|
||||||
|
|
||||||
|
|
||||||
|
### Filter Parameters
|
||||||
|
|
||||||
|
The cache filter has one mandatory parameter - `storage` - and a few
|
||||||
|
optional ones.
|
||||||
|
|
||||||
|
#### `storage`
|
||||||
|
|
||||||
|
The name of the module that provides the storage for the cache. That
|
||||||
|
module will be loaded and provided with the value of `storage_args` as
|
||||||
|
argument. For instance:
|
||||||
|
```
|
||||||
|
storage=storage_rocksdb
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `storage_args`
|
||||||
|
|
||||||
|
A comma separated list of arguments to be provided to the storage module,
|
||||||
|
specified in `storage`, when it is loaded. Note that the needed arguments
|
||||||
|
depend upon the specific module. For instance,
|
||||||
|
```
|
||||||
|
storage_args=path=/usr/maxscale/cache/rocksdb
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `allowed_references`
|
||||||
|
|
||||||
|
Specifies whether any or only fully qualified references are allowed in
|
||||||
|
queries stored to the cache.
|
||||||
|
```
|
||||||
|
allowed_references=[fully-qualified|any]
|
||||||
|
```
|
||||||
|
The default is `fully-qualified`, which means that only queries where
|
||||||
|
the database name is included in the table name are subject to caching.
|
||||||
|
```
|
||||||
|
select col from db.tbl;
|
||||||
|
```
|
||||||
|
If `any` is specified, then also queries where the table name is not
|
||||||
|
fully qualified are subject to caching.
|
||||||
|
```
|
||||||
|
select col from tbl;
|
||||||
|
```
|
||||||
|
Care should be excersized before this setting is changed, because, for
|
||||||
|
instance, the following is likely to produce unexpected results.
|
||||||
|
```
|
||||||
|
use db1;
|
||||||
|
select col from tbl;
|
||||||
|
...
|
||||||
|
use db2;
|
||||||
|
select col from tbl;
|
||||||
|
```
|
||||||
|
The setting can be changed to `any`, provided fully qualified names
|
||||||
|
are always used or if the names of tables in different databases are
|
||||||
|
different.
|
||||||
|
|
||||||
|
#### `maximum_resultset_size`
|
||||||
|
|
||||||
|
Specifies the maximum size a resultset can have, measured in kibibytes,
|
||||||
|
in order to be stored in the cache. A resultset larger than this, will
|
||||||
|
not be stored.
|
||||||
|
```
|
||||||
|
maximum_resultset_size=64
|
||||||
|
```
|
||||||
|
The default value is TBD.
|
||||||
|
|
||||||
|
#### `ttl`
|
||||||
|
|
||||||
|
_Time to live_; the amount of time - in seconds - the cached result is used
|
||||||
|
before it is refreshed from the server.
|
||||||
|
|
||||||
|
If nothing is specified, the default _ttl_ value is 10.
|
||||||
|
|
||||||
|
```
|
||||||
|
ttl=60
|
||||||
|
```
|
||||||
|
|
||||||
|
#Storage
|
||||||
|
|
||||||
|
## Storage RocksDB
|
||||||
@ -384,6 +384,13 @@ bool filter_load(FILTER_DEF* filter)
|
|||||||
{
|
{
|
||||||
bool rval = false;
|
bool rval = false;
|
||||||
if (filter)
|
if (filter)
|
||||||
|
{
|
||||||
|
if (filter->filter)
|
||||||
|
{
|
||||||
|
// Already loaded and created.
|
||||||
|
rval = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (filter->obj == NULL)
|
if (filter->obj == NULL)
|
||||||
{
|
{
|
||||||
@ -391,11 +398,15 @@ bool filter_load(FILTER_DEF* filter)
|
|||||||
if ((filter->obj = load_module(filter->module, MODULE_FILTER)) == NULL)
|
if ((filter->obj = load_module(filter->module, MODULE_FILTER)) == NULL)
|
||||||
{
|
{
|
||||||
MXS_ERROR("Failed to load filter module '%s'.", filter->module);
|
MXS_ERROR("Failed to load filter module '%s'.", filter->module);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((filter->filter = (filter->obj->createInstance)(filter->options,
|
if (filter->obj)
|
||||||
|
{
|
||||||
|
ss_dassert(!filter->filter);
|
||||||
|
|
||||||
|
if ((filter->filter = (filter->obj->createInstance)(filter->name,
|
||||||
|
filter->options,
|
||||||
filter->parameters)))
|
filter->parameters)))
|
||||||
{
|
{
|
||||||
rval = true;
|
rval = true;
|
||||||
@ -404,7 +415,8 @@ bool filter_load(FILTER_DEF* filter)
|
|||||||
{
|
{
|
||||||
MXS_ERROR("Failed to create filter '%s' instance.", filter->name);
|
MXS_ERROR("Failed to create filter '%s' instance.", filter->name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return rval;
|
return rval;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,7 +32,7 @@
|
|||||||
|
|
||||||
|
|
||||||
static int mysql_send_fieldcount(DCB *, int);
|
static int mysql_send_fieldcount(DCB *, int);
|
||||||
static int mysql_send_columndef(DCB *, char *, int, int, uint8_t);
|
static int mysql_send_columndef(DCB *, const char *, int, int, uint8_t);
|
||||||
static int mysql_send_eof(DCB *, int);
|
static int mysql_send_eof(DCB *, int);
|
||||||
static int mysql_send_row(DCB *, RESULT_ROW *, int);
|
static int mysql_send_row(DCB *, RESULT_ROW *, int);
|
||||||
|
|
||||||
@ -95,9 +95,9 @@ resultset_free(RESULTSET *resultset)
|
|||||||
* @return The numebr of columns added to the result set
|
* @return The numebr of columns added to the result set
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
resultset_add_column(RESULTSET *set, char *name, int len, RESULT_COL_TYPE type)
|
resultset_add_column(RESULTSET *set, const char *cname, int len, RESULT_COL_TYPE type)
|
||||||
{
|
{
|
||||||
name = MXS_STRDUP(name);
|
char *name = MXS_STRDUP(cname);
|
||||||
RESULT_COLUMN *newcol = (RESULT_COLUMN *)MXS_MALLOC(sizeof(RESULT_COLUMN));
|
RESULT_COLUMN *newcol = (RESULT_COLUMN *)MXS_MALLOC(sizeof(RESULT_COLUMN));
|
||||||
|
|
||||||
if (!name || !newcol)
|
if (!name || !newcol)
|
||||||
@ -207,7 +207,7 @@ resultset_free_row(RESULT_ROW *row)
|
|||||||
* @return The number of columns inserted
|
* @return The number of columns inserted
|
||||||
*/
|
*/
|
||||||
int
|
int
|
||||||
resultset_row_set(RESULT_ROW *row, int col, char *value)
|
resultset_row_set(RESULT_ROW *row, int col, const char *value)
|
||||||
{
|
{
|
||||||
if (col < 0 || col >= row->n_cols)
|
if (col < 0 || col >= row->n_cols)
|
||||||
{
|
{
|
||||||
@ -299,7 +299,7 @@ mysql_send_fieldcount(DCB *dcb, int count)
|
|||||||
* @return Non-zero on success
|
* @return Non-zero on success
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
mysql_send_columndef(DCB *dcb, char *name, int type, int len, uint8_t seqno)
|
mysql_send_columndef(DCB *dcb, const char *name, int type, int len, uint8_t seqno)
|
||||||
{
|
{
|
||||||
GWBUF *pkt;
|
GWBUF *pkt;
|
||||||
uint8_t *ptr;
|
uint8_t *ptr;
|
||||||
@ -443,7 +443,7 @@ mysql_send_row(DCB *dcb, RESULT_ROW *row, int seqno)
|
|||||||
* @return Non-zero if the string is made of of numeric values
|
* @return Non-zero if the string is made of of numeric values
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
value_is_numeric(char *value)
|
value_is_numeric(const char *value)
|
||||||
{
|
{
|
||||||
int rval = 0;
|
int rval = 0;
|
||||||
|
|
||||||
|
|||||||
@ -67,7 +67,9 @@ typedef struct
|
|||||||
*/
|
*/
|
||||||
typedef struct filter_object
|
typedef struct filter_object
|
||||||
{
|
{
|
||||||
FILTER *(*createInstance)(char **options, FILTER_PARAMETER **);
|
FILTER *(*createInstance)(const char *name,
|
||||||
|
char **options,
|
||||||
|
FILTER_PARAMETER **params);
|
||||||
void *(*newSession)(FILTER *instance, SESSION *session);
|
void *(*newSession)(FILTER *instance, SESSION *session);
|
||||||
void (*closeSession)(FILTER *instance, void *fsession);
|
void (*closeSession)(FILTER *instance, void *fsession);
|
||||||
void (*freeSession)(FILTER *instance, void *fsession);
|
void (*freeSession)(FILTER *instance, void *fsession);
|
||||||
@ -83,7 +85,7 @@ typedef struct filter_object
|
|||||||
* is changed these values must be updated in line with the rules in the
|
* is changed these values must be updated in line with the rules in the
|
||||||
* file modinfo.h.
|
* file modinfo.h.
|
||||||
*/
|
*/
|
||||||
#define FILTER_VERSION {1, 1, 0}
|
#define FILTER_VERSION {2, 1, 0}
|
||||||
/**
|
/**
|
||||||
* The definition of a filter from the configuration file.
|
* The definition of a filter from the configuration file.
|
||||||
* This is basically the link between a plugin to load and the
|
* This is basically the link between a plugin to load and the
|
||||||
|
|||||||
@ -77,11 +77,11 @@ typedef struct resultset
|
|||||||
|
|
||||||
extern RESULTSET *resultset_create(RESULT_ROW_CB, void *);
|
extern RESULTSET *resultset_create(RESULT_ROW_CB, void *);
|
||||||
extern void resultset_free(RESULTSET *);
|
extern void resultset_free(RESULTSET *);
|
||||||
extern int resultset_add_column(RESULTSET *, char *, int, RESULT_COL_TYPE);
|
extern int resultset_add_column(RESULTSET *, const char *, int, RESULT_COL_TYPE);
|
||||||
extern void resultset_column_free(RESULT_COLUMN *);
|
extern void resultset_column_free(RESULT_COLUMN *);
|
||||||
extern RESULT_ROW *resultset_make_row(RESULTSET *);
|
extern RESULT_ROW *resultset_make_row(RESULTSET *);
|
||||||
extern void resultset_free_row(RESULT_ROW *);
|
extern void resultset_free_row(RESULT_ROW *);
|
||||||
extern int resultset_row_set(RESULT_ROW *, int, char *);
|
extern int resultset_row_set(RESULT_ROW *, int, const char *);
|
||||||
extern void resultset_stream_mysql(RESULTSET *, DCB *);
|
extern void resultset_stream_mysql(RESULTSET *, DCB *);
|
||||||
extern void resultset_stream_json(RESULTSET *, DCB *);
|
extern void resultset_stream_json(RESULTSET *, DCB *);
|
||||||
|
|
||||||
|
|||||||
2
server/modules/filter/cache/CMakeLists.txt
vendored
2
server/modules/filter/cache/CMakeLists.txt
vendored
@ -1,4 +1,4 @@
|
|||||||
add_library(cache SHARED cache.c)
|
add_library(cache SHARED cache.c storage.c)
|
||||||
target_link_libraries(cache maxscale-common)
|
target_link_libraries(cache maxscale-common)
|
||||||
set_target_properties(cache PROPERTIES VERSION "1.0.0")
|
set_target_properties(cache PROPERTIES VERSION "1.0.0")
|
||||||
install_module(cache experimental)
|
install_module(cache experimental)
|
||||||
|
|||||||
285
server/modules/filter/cache/cache.c
vendored
285
server/modules/filter/cache/cache.c
vendored
@ -11,13 +11,20 @@
|
|||||||
* Public License.
|
* Public License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <filter.h>
|
#define MXS_MODULE_NAME "cache"
|
||||||
#include <modinfo.h>
|
|
||||||
#include <maxscale/alloc.h>
|
#include <maxscale/alloc.h>
|
||||||
|
#include <filter.h>
|
||||||
|
#include <log_manager.h>
|
||||||
|
#include <modinfo.h>
|
||||||
|
#include <modutil.h>
|
||||||
|
#include <query_classifier.h>
|
||||||
|
#include "storage.h"
|
||||||
|
|
||||||
static char VERSION_STRING[] = "V1.0.0";
|
static char VERSION_STRING[] = "V1.0.0";
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
|
static const int DEFAULT_TTL = 10;
|
||||||
|
|
||||||
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *sdata);
|
static void closeSession(FILTER *instance, void *sdata);
|
||||||
static void freeSession(FILTER *instance, void *sdata);
|
static void freeSession(FILTER *instance, void *sdata);
|
||||||
@ -27,6 +34,8 @@ static int routeQuery(FILTER *instance, void *sdata, GWBUF *queue);
|
|||||||
static int clientReply(FILTER *instance, void *sdata, GWBUF *queue);
|
static int clientReply(FILTER *instance, void *sdata, GWBUF *queue);
|
||||||
static void diagnostics(FILTER *instance, void *sdata, DCB *dcb);
|
static void diagnostics(FILTER *instance, void *sdata, DCB *dcb);
|
||||||
|
|
||||||
|
#define C_DEBUG(format, ...) MXS_LOG_MESSAGE(LOG_NOTICE, format, ##__VA_ARGS__)
|
||||||
|
|
||||||
//
|
//
|
||||||
// Global symbols of the Module
|
// Global symbols of the Module
|
||||||
//
|
//
|
||||||
@ -81,29 +90,129 @@ FILTER_OBJECT *GetModuleObject()
|
|||||||
|
|
||||||
typedef struct cache_instance
|
typedef struct cache_instance
|
||||||
{
|
{
|
||||||
|
const char *name;
|
||||||
|
const char *storage_name;
|
||||||
|
const char *storage_args;
|
||||||
|
uint32_t ttl; // Time to live in seconds.
|
||||||
|
CACHE_STORAGE_MODULE *module;
|
||||||
|
CACHE_STORAGE *storage;
|
||||||
} CACHE_INSTANCE;
|
} CACHE_INSTANCE;
|
||||||
|
|
||||||
typedef struct cache_session_data
|
typedef struct cache_session_data
|
||||||
{
|
{
|
||||||
DOWNSTREAM down;
|
CACHE_STORAGE_API *api; /**< The storage API to be used. */
|
||||||
UPSTREAM up;
|
CACHE_STORAGE *storage; /**< The storage to be used with this session data. */
|
||||||
|
DOWNSTREAM down; /**< The previous filter or equivalent. */
|
||||||
|
UPSTREAM up; /**< The next filter or equivalent. */
|
||||||
|
GWBUF *packets; /**< A possible incomplete packet. */
|
||||||
|
SESSION *session; /**< The session this data is associated with. */
|
||||||
|
char key[CACHE_KEY_MAXLEN]; /**< Key storage. */
|
||||||
|
char *used_key; /**< A key if one is ued. */
|
||||||
} CACHE_SESSION_DATA;
|
} CACHE_SESSION_DATA;
|
||||||
|
|
||||||
|
static bool route_using_cache(CACHE_INSTANCE *instance,
|
||||||
|
CACHE_SESSION_DATA *sdata,
|
||||||
|
const GWBUF *key,
|
||||||
|
GWBUF **value);
|
||||||
|
|
||||||
|
//
|
||||||
|
// API BEGIN
|
||||||
|
//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of the cache filter for a particular service
|
* Create an instance of the cache filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params)
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
CACHE_INSTANCE *cinstance;
|
const char *storage_name = NULL;
|
||||||
|
const char *storage_args = NULL;
|
||||||
|
uint32_t ttl = DEFAULT_TTL;
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
for (int i = 0; params[i]; ++i)
|
||||||
|
{
|
||||||
|
const FILTER_PARAMETER *param = params[i];
|
||||||
|
|
||||||
|
if (strcmp(param->name, "storage_name") == 0)
|
||||||
|
{
|
||||||
|
storage_name = param->value;
|
||||||
|
}
|
||||||
|
else if (strcmp(param->name, "storage_args") == 0)
|
||||||
|
{
|
||||||
|
storage_args = param->value;
|
||||||
|
}
|
||||||
|
else if (strcmp(param->name, "ttl") == 0)
|
||||||
|
{
|
||||||
|
int v = atoi(param->value);
|
||||||
|
|
||||||
|
if (v > 0)
|
||||||
|
{
|
||||||
|
ttl = v;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("The value of the configuration entry 'ttl' must "
|
||||||
|
"be an integer larger than 0.");
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!filter_standard_parameter(params[i]->name))
|
||||||
|
{
|
||||||
|
MXS_ERROR("Unknown configuration entry '%s'.", param->name);
|
||||||
|
error = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CACHE_INSTANCE *cinstance = NULL;
|
||||||
|
|
||||||
|
if (!error)
|
||||||
|
{
|
||||||
if ((cinstance = MXS_CALLOC(1, sizeof(CACHE_INSTANCE))) != NULL)
|
if ((cinstance = MXS_CALLOC(1, sizeof(CACHE_INSTANCE))) != NULL)
|
||||||
{
|
{
|
||||||
|
CACHE_STORAGE_MODULE *module = cache_storage_open(storage_name);
|
||||||
|
|
||||||
|
if (module)
|
||||||
|
{
|
||||||
|
CACHE_STORAGE *storage = module->api->createInstance(name, ttl, 0, NULL);
|
||||||
|
|
||||||
|
if (storage)
|
||||||
|
{
|
||||||
|
cinstance->name = name;
|
||||||
|
cinstance->storage_name = storage_name;
|
||||||
|
cinstance->storage_args = storage_args;
|
||||||
|
cinstance->ttl = ttl;
|
||||||
|
cinstance->module = module;
|
||||||
|
cinstance->storage = storage;
|
||||||
|
|
||||||
|
MXS_NOTICE("Cache storage %s opened and initialized.", storage_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Could not create storage instance for %s.", name);
|
||||||
|
cache_storage_close(module);
|
||||||
|
MXS_FREE(cinstance);
|
||||||
|
cinstance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Could not load cache storage module %s.", name);
|
||||||
|
MXS_FREE(cinstance);
|
||||||
|
cinstance = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cinstance = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (FILTER*)cinstance;
|
return (FILTER*)cinstance;
|
||||||
@ -124,6 +233,9 @@ static void *newSession(FILTER *instance, SESSION *session)
|
|||||||
|
|
||||||
if (csdata)
|
if (csdata)
|
||||||
{
|
{
|
||||||
|
csdata->api = cinstance->module->api;
|
||||||
|
csdata->storage = cinstance->storage;
|
||||||
|
csdata->session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
return csdata;
|
return csdata;
|
||||||
@ -190,14 +302,97 @@ static void setUpstream(FILTER *instance, void *sdata, UPSTREAM *up)
|
|||||||
*
|
*
|
||||||
* @param instance The filter instance data
|
* @param instance The filter instance data
|
||||||
* @param sdata The filter session data
|
* @param sdata The filter session data
|
||||||
* @param queue The query data
|
* @param packets The query data
|
||||||
*/
|
*/
|
||||||
static int routeQuery(FILTER *instance, void *sdata, GWBUF *queue)
|
static int routeQuery(FILTER *instance, void *sdata, GWBUF *packets)
|
||||||
{
|
{
|
||||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||||
CACHE_SESSION_DATA *csdata = (CACHE_SESSION_DATA*)sdata;
|
CACHE_SESSION_DATA *csdata = (CACHE_SESSION_DATA*)sdata;
|
||||||
|
|
||||||
return csdata->down.routeQuery(csdata->down.instance, csdata->down.session, queue);
|
if (csdata->packets)
|
||||||
|
{
|
||||||
|
C_DEBUG("Old packets exist.");
|
||||||
|
gwbuf_append(csdata->packets, packets);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
C_DEBUG("NO old packets exist.");
|
||||||
|
csdata->packets = packets;
|
||||||
|
}
|
||||||
|
|
||||||
|
packets = modutil_get_complete_packets(&csdata->packets);
|
||||||
|
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (packets)
|
||||||
|
{
|
||||||
|
C_DEBUG("At least one complete packet exist.");
|
||||||
|
GWBUF *packet;
|
||||||
|
|
||||||
|
// TODO: Is it really possible to get more that one packet
|
||||||
|
// TODO: is this loop? If so, can those packets be sent
|
||||||
|
// TODO: after one and other, or do we need to wait for
|
||||||
|
// TODO: a replies? If there are more complete packets
|
||||||
|
// TODO: than one, then either CACHE_SESSION_DATA::key
|
||||||
|
// TODO: needs to be a queue
|
||||||
|
|
||||||
|
// TODO: modutil_get_next_MySQL_packet *copies* the data.
|
||||||
|
while ((packet = modutil_get_next_MySQL_packet(&packets)))
|
||||||
|
{
|
||||||
|
C_DEBUG("Processing packet.");
|
||||||
|
bool use_default = true;
|
||||||
|
|
||||||
|
if (modutil_is_SQL(packet))
|
||||||
|
{
|
||||||
|
C_DEBUG("Is SQL.");
|
||||||
|
// We do not care whether the query was fully parsed or not.
|
||||||
|
// If a query cannot be fully parsed, the worst thing that can
|
||||||
|
// happen is that caching is not used, even though it would be
|
||||||
|
// possible.
|
||||||
|
|
||||||
|
if (qc_get_operation(packet) == QUERY_OP_SELECT)
|
||||||
|
{
|
||||||
|
C_DEBUG("Is a SELECT");
|
||||||
|
|
||||||
|
GWBUF *result;
|
||||||
|
use_default = !route_using_cache(cinstance, csdata, packet, &result);
|
||||||
|
|
||||||
|
if (!use_default)
|
||||||
|
{
|
||||||
|
C_DEBUG("Using data from cache.");
|
||||||
|
gwbuf_free(packet);
|
||||||
|
DCB *dcb = csdata->session->client_dcb;
|
||||||
|
|
||||||
|
// TODO: This is not ok. Any filters before this filter, will not
|
||||||
|
// TODO: see this data.
|
||||||
|
rv = dcb->func.write(dcb, result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
C_DEBUG("Is NOT a SELECT");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
C_DEBUG("Is NOT SQL.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (use_default)
|
||||||
|
{
|
||||||
|
C_DEBUG("Using default processing.");
|
||||||
|
rv = csdata->down.routeQuery(csdata->down.instance, csdata->down.session, packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
C_DEBUG("Not even one complete packet exist; more data needed.");
|
||||||
|
// Ok, we need more data before we can do something.
|
||||||
|
rv = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -212,6 +407,27 @@ static int clientReply(FILTER *instance, void *sdata, GWBUF *queue)
|
|||||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||||
CACHE_SESSION_DATA *csdata = (CACHE_SESSION_DATA*)sdata;
|
CACHE_SESSION_DATA *csdata = (CACHE_SESSION_DATA*)sdata;
|
||||||
|
|
||||||
|
// TODO: queue can be put to the cache only if it is a complete
|
||||||
|
// TODO: response. If it isn't, then we need to stash it and wait
|
||||||
|
// TODO: we get a complete response.
|
||||||
|
// TODO: Since we will know from the first queue how big the
|
||||||
|
// TODO: entire response will be, this is also where we can decide
|
||||||
|
// TODO: that something is too large to cache. If it is, an existing
|
||||||
|
// TODO: item must be deleted.
|
||||||
|
|
||||||
|
if (csdata->used_key)
|
||||||
|
{
|
||||||
|
C_DEBUG("Key available, storing result.");
|
||||||
|
|
||||||
|
cache_result_t result = csdata->api->putValue(csdata->storage, csdata->used_key, queue);
|
||||||
|
csdata->used_key = NULL;
|
||||||
|
|
||||||
|
if (result != CACHE_RESULT_OK)
|
||||||
|
{
|
||||||
|
MXS_ERROR("Could not store cache item.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return csdata->up.clientReply(csdata->up.instance, csdata->up.session, queue);
|
return csdata->up.clientReply(csdata->up.instance, csdata->up.session, queue);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,3 +448,52 @@ static void diagnostics(FILTER *instance, void *sdata, DCB *dcb)
|
|||||||
|
|
||||||
dcb_printf(dcb, "Hello World from Cache!\n");
|
dcb_printf(dcb, "Hello World from Cache!\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// API END
|
||||||
|
//
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Route a query via the cache.
|
||||||
|
*
|
||||||
|
* @param instance The filter instance.
|
||||||
|
* @param sdata Session data
|
||||||
|
* @param key A SELECT packet.
|
||||||
|
* @param value The result.
|
||||||
|
* @return True if the query was satisfied from the query.
|
||||||
|
*/
|
||||||
|
static bool route_using_cache(CACHE_INSTANCE *instance,
|
||||||
|
CACHE_SESSION_DATA *csdata,
|
||||||
|
const GWBUF *query,
|
||||||
|
GWBUF **value)
|
||||||
|
{
|
||||||
|
// TODO: This works *only* if only one request/response is handled at a time.
|
||||||
|
// TODO: Is that the case, or is it not?
|
||||||
|
|
||||||
|
cache_result_t result = csdata->api->getKey(csdata->storage, query, csdata->key);
|
||||||
|
|
||||||
|
if (result == CACHE_RESULT_OK)
|
||||||
|
{
|
||||||
|
result = csdata->api->getValue(csdata->storage, csdata->key, value);
|
||||||
|
|
||||||
|
switch (result)
|
||||||
|
{
|
||||||
|
case CACHE_RESULT_OK:
|
||||||
|
csdata->used_key = NULL;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
MXS_ERROR("Could not get value from cache storage.");
|
||||||
|
case CACHE_RESULT_NOT_FOUND:
|
||||||
|
csdata->used_key = csdata->key;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Could not create cache key.");
|
||||||
|
csdata->used_key = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result == CACHE_RESULT_OK;
|
||||||
|
}
|
||||||
|
|||||||
120
server/modules/filter/cache/cache_storage_api.h
vendored
Normal file
120
server/modules/filter/cache/cache_storage_api.h
vendored
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
#ifndef _MAXSCALE_FILTER_CACHE_CACHE_H
|
||||||
|
#define _MAXSCALE_FILTER_CACHE_CACHE_H
|
||||||
|
/*
|
||||||
|
* 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/bsl.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-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 <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <buffer.h>
|
||||||
|
#include <mysql_client_server_protocol.h>
|
||||||
|
#include <skygw_debug.h>
|
||||||
|
|
||||||
|
EXTERN_C_BLOCK_BEGIN
|
||||||
|
|
||||||
|
typedef enum cache_result
|
||||||
|
{
|
||||||
|
CACHE_RESULT_OK,
|
||||||
|
CACHE_RESULT_NOT_FOUND,
|
||||||
|
CACHE_RESULT_OUT_OF_RESOURCES,
|
||||||
|
CACHE_RESULT_ERROR
|
||||||
|
} cache_result_t;
|
||||||
|
|
||||||
|
typedef void* CACHE_STORAGE;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
CACHE_KEY_MAXLEN = 128
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct cache_storage_api
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Called immediately after the storage module has been loaded.
|
||||||
|
*
|
||||||
|
* @return True if the initialization succeeded, false otherwise.
|
||||||
|
*/
|
||||||
|
bool (*initialize)();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of cache storage. This function should, if necessary,
|
||||||
|
* create the actual storage, initialize it and prepare to put and get
|
||||||
|
* cache items.
|
||||||
|
*
|
||||||
|
* @param name The name of the cache instance.
|
||||||
|
* @param ttl Time to live; number of seconds the value is valid.
|
||||||
|
* @param argc The number of elements in the argv array.
|
||||||
|
* @param argv Array of arguments, as passed in the `storage_args` parameter
|
||||||
|
* in the cache section in the MaxScale configuration file.
|
||||||
|
* @return A new cache instance, or NULL if the instance could not be
|
||||||
|
* created.
|
||||||
|
*/
|
||||||
|
CACHE_STORAGE* (*createInstance)(const char *name,
|
||||||
|
uint32_t ttl,
|
||||||
|
int argc, char* argv[]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees an CACHE_STORAGE instance earlier created with createInstance.
|
||||||
|
*
|
||||||
|
* @param instance The CACHE_STORAGE instance to be freed.
|
||||||
|
*/
|
||||||
|
void (*freeInstance)(CACHE_STORAGE* instance);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a key for a GWBUF.
|
||||||
|
*
|
||||||
|
* @param storage Pointer to a CACHE_STORAGE.
|
||||||
|
* @param query An SQL query. Must be one contiguous buffer.
|
||||||
|
* @param key Pointer to array of CACHE_KEY_MAXLEN size where
|
||||||
|
* the key will be written.
|
||||||
|
* @return CACHE_RESULT_OK if a key was created, otherwise some error code.
|
||||||
|
*/
|
||||||
|
cache_result_t (*getKey)(CACHE_STORAGE* storage,
|
||||||
|
const GWBUF* query,
|
||||||
|
char* key);
|
||||||
|
/**
|
||||||
|
* Get a value from the cache.
|
||||||
|
*
|
||||||
|
* @param storage Pointer to a CACHE_STORAGE.
|
||||||
|
* @param key A key generated with getKey.
|
||||||
|
* @param result Pointer to variable that after a successful return will
|
||||||
|
* point to a GWBUF.
|
||||||
|
* @return CACHE_RESULT_OK if item was found,
|
||||||
|
* CACHE_RESULT_NOT_FOUND if item was not found (which may be because
|
||||||
|
* the ttl was reached), or some other error code.
|
||||||
|
*/
|
||||||
|
cache_result_t (*getValue)(CACHE_STORAGE* storage,
|
||||||
|
const char* key,
|
||||||
|
GWBUF** result);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Put a value to the cache.
|
||||||
|
*
|
||||||
|
* @param storage Pointer to a CACHE_STORAGE.
|
||||||
|
* @param key A key generated with getKey.
|
||||||
|
* @param value Pointer to GWBUF containing the value to be stored.
|
||||||
|
* Must be one contiguous buffer.
|
||||||
|
* @return CACHE_RESULT_OK if item was successfully put,
|
||||||
|
* CACHE_RESULT_OUT_OF_RESOURCES if item could not be put, due to
|
||||||
|
* some resource having become exhausted, or some other error code.
|
||||||
|
*/
|
||||||
|
cache_result_t (*putValue)(CACHE_STORAGE* storage,
|
||||||
|
const char* key,
|
||||||
|
const GWBUF* value);
|
||||||
|
} CACHE_STORAGE_API;
|
||||||
|
|
||||||
|
#define CACHE_STORAGE_ENTRY_POINT "CacheGetStorageAPI"
|
||||||
|
typedef CACHE_STORAGE_API* (*CacheGetStorageAPIFN)();
|
||||||
|
|
||||||
|
EXTERN_C_BLOCK_END
|
||||||
|
|
||||||
|
#endif
|
||||||
96
server/modules/filter/cache/storage.c
vendored
Normal file
96
server/modules/filter/cache/storage.c
vendored
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
/*
|
||||||
|
* 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/bsl.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-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 "storage.h"
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <sys/param.h>
|
||||||
|
#include <maxscale/alloc.h>
|
||||||
|
#include <gwdirs.h>
|
||||||
|
#include <log_manager.h>
|
||||||
|
|
||||||
|
CACHE_STORAGE_MODULE* cache_storage_open(const char *name)
|
||||||
|
{
|
||||||
|
CACHE_STORAGE_MODULE* module = (CACHE_STORAGE_MODULE*)MXS_CALLOC(1, sizeof(CACHE_STORAGE_MODULE));
|
||||||
|
|
||||||
|
if (module)
|
||||||
|
{
|
||||||
|
char path[MAXPATHLEN + 1];
|
||||||
|
sprintf(path, "%s/lib%s.so", get_libdir(), name);
|
||||||
|
|
||||||
|
void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL);
|
||||||
|
|
||||||
|
if (handle)
|
||||||
|
{
|
||||||
|
module->handle = handle;
|
||||||
|
|
||||||
|
void *f = dlsym(module->handle, CACHE_STORAGE_ENTRY_POINT);
|
||||||
|
|
||||||
|
if (f)
|
||||||
|
{
|
||||||
|
module->api = ((CacheGetStorageAPIFN)f)();
|
||||||
|
|
||||||
|
if (module->api)
|
||||||
|
{
|
||||||
|
if (!(module->api->initialize)())
|
||||||
|
{
|
||||||
|
MXS_ERROR("Initialization of %s failed.", path);
|
||||||
|
|
||||||
|
(void)dlclose(module->handle);
|
||||||
|
MXS_FREE(module);
|
||||||
|
module = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MXS_ERROR("Could not obtain API object from %s.", name);
|
||||||
|
|
||||||
|
(void)dlclose(module->handle);
|
||||||
|
MXS_FREE(module);
|
||||||
|
module = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char* s = dlerror();
|
||||||
|
MXS_ERROR("Could not look up symbol %s from %s: %s",
|
||||||
|
name, CACHE_STORAGE_ENTRY_POINT, s ? s : "");
|
||||||
|
MXS_FREE(module);
|
||||||
|
module = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const char* s = dlerror();
|
||||||
|
MXS_ERROR("Could not load %s: %s", name, s ? s : "");
|
||||||
|
MXS_FREE(module);
|
||||||
|
module = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void cache_storage_close(CACHE_STORAGE_MODULE *module)
|
||||||
|
{
|
||||||
|
if (module)
|
||||||
|
{
|
||||||
|
if (dlclose(module->handle) != 0)
|
||||||
|
{
|
||||||
|
const char *s = dlerror();
|
||||||
|
MXS_ERROR("Could not close module %s: ", s ? s : "");
|
||||||
|
}
|
||||||
|
|
||||||
|
MXS_FREE(module);
|
||||||
|
}
|
||||||
|
}
|
||||||
27
server/modules/filter/cache/storage.h
vendored
Normal file
27
server/modules/filter/cache/storage.h
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef _MAXSCALE_FILTER_CACHE_STORAGE_H
|
||||||
|
#define _MAXSCALE_FILTER_CACHE_STORAGE_H
|
||||||
|
/*
|
||||||
|
* 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/bsl.
|
||||||
|
*
|
||||||
|
* Change Date: 2019-07-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 "cache_storage_api.h"
|
||||||
|
|
||||||
|
typedef struct cache_storage_module_t
|
||||||
|
{
|
||||||
|
void* handle;
|
||||||
|
CACHE_STORAGE_API* api;
|
||||||
|
} CACHE_STORAGE_MODULE;
|
||||||
|
|
||||||
|
CACHE_STORAGE_MODULE* cache_storage_open(const char *name);
|
||||||
|
void cache_storage_close(CACHE_STORAGE_MODULE *module);
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -57,7 +57,7 @@ MODULE_INFO info =
|
|||||||
|
|
||||||
static char *version_str = "V1.1.0";
|
static char *version_str = "V1.1.0";
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -156,13 +156,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
CCR_INSTANCE *my_instance;
|
CCR_INSTANCE *my_instance;
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
@ -99,7 +99,7 @@ static char *version_str = "V1.2.0";
|
|||||||
/*
|
/*
|
||||||
* The filter entry points
|
* The filter entry points
|
||||||
*/
|
*/
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -1357,12 +1357,14 @@ static bool process_rule_file(const char* filename, FW_INSTANCE* instance)
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
FW_INSTANCE *my_instance;
|
FW_INSTANCE *my_instance;
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
@ -82,7 +82,7 @@ static const char* datafile_name = "gatekeeper.data";
|
|||||||
* return a non-NULL value when a hash hit is made */
|
* return a non-NULL value when a hash hit is made */
|
||||||
static bool trueval = true;
|
static bool trueval = true;
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -140,12 +140,13 @@ FILTER_OBJECT* GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER* createInstance(char **options, FILTER_PARAMETER **params)
|
static FILTER* createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
GK_INSTANCE *inst = MXS_CALLOC(1, sizeof(GK_INSTANCE));
|
GK_INSTANCE *inst = MXS_CALLOC(1, sizeof(GK_INSTANCE));
|
||||||
|
|
||||||
|
|||||||
@ -33,7 +33,7 @@ MODULE_INFO info =
|
|||||||
|
|
||||||
static char *version_str = "V1.0.0";
|
static char *version_str = "V1.0.0";
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
static FILTER *createInstance(const char* name, char **options, FILTER_PARAMETER **params);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -97,12 +97,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
HINT_INSTANCE *my_instance;
|
HINT_INSTANCE *my_instance;
|
||||||
|
|
||||||
|
|||||||
@ -92,7 +92,7 @@ static int hktask_id = 0;
|
|||||||
/*
|
/*
|
||||||
* The filter entry points
|
* The filter entry points
|
||||||
*/
|
*/
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -497,12 +497,14 @@ char** parse_optstr(char* str, char* tok, int* szstore)
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
MQ_INSTANCE *my_instance;
|
MQ_INSTANCE *my_instance;
|
||||||
int paramcount = 0, parammax = 64, i = 0, x = 0, arrsize = 0;
|
int paramcount = 0, parammax = 64, i = 0, x = 0, arrsize = 0;
|
||||||
|
|||||||
@ -51,7 +51,7 @@ MODULE_INFO info =
|
|||||||
|
|
||||||
static char *version_str = "V1.1.0";
|
static char *version_str = "V1.1.0";
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -137,13 +137,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param params The array of name/value pair parameters for the filter
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
REGEXHINT_INSTANCE *my_instance = (REGEXHINT_INSTANCE*)MXS_MALLOC(sizeof(REGEXHINT_INSTANCE));
|
REGEXHINT_INSTANCE *my_instance = (REGEXHINT_INSTANCE*)MXS_MALLOC(sizeof(REGEXHINT_INSTANCE));
|
||||||
|
|
||||||
|
|||||||
@ -65,7 +65,7 @@ static char *version_str = "V1.1.1";
|
|||||||
/*
|
/*
|
||||||
* The filter entry points
|
* The filter entry points
|
||||||
*/
|
*/
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -166,13 +166,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
QLA_INSTANCE *my_instance = (QLA_INSTANCE*) MXS_MALLOC(sizeof(QLA_INSTANCE));
|
QLA_INSTANCE *my_instance = (QLA_INSTANCE*) MXS_MALLOC(sizeof(QLA_INSTANCE));
|
||||||
|
|
||||||
|
|||||||
@ -51,7 +51,7 @@ MODULE_INFO info =
|
|||||||
|
|
||||||
static char *version_str = "V1.1.0";
|
static char *version_str = "V1.1.0";
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -172,13 +172,14 @@ void free_instance(REGEX_INSTANCE *instance)
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
REGEX_INSTANCE *my_instance;
|
REGEX_INSTANCE *my_instance;
|
||||||
int i, errnumber, cflags = PCRE2_CASELESS;
|
int i, errnumber, cflags = PCRE2_CASELESS;
|
||||||
|
|||||||
@ -108,7 +108,7 @@ static char *version_str = "V1.0.0";
|
|||||||
/*
|
/*
|
||||||
* The filter entry points
|
* The filter entry points
|
||||||
*/
|
*/
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
|
static FILTER *createInstance(const char* name, char **options, FILTER_PARAMETER **);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -351,13 +351,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
TEE_INSTANCE *my_instance;
|
TEE_INSTANCE *my_instance;
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
@ -39,7 +39,7 @@ MODULE_INFO info =
|
|||||||
|
|
||||||
static char *version_str = "V1.0.0";
|
static char *version_str = "V1.0.0";
|
||||||
|
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **params);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -119,13 +119,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
TEST_INSTANCE *my_instance;
|
TEST_INSTANCE *my_instance;
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ static char *version_str = "V1.0.1";
|
|||||||
/*
|
/*
|
||||||
* The filter entry points
|
* The filter entry points
|
||||||
*/
|
*/
|
||||||
static FILTER *createInstance(char **options, FILTER_PARAMETER **);
|
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
|
||||||
static void *newSession(FILTER *instance, SESSION *session);
|
static void *newSession(FILTER *instance, SESSION *session);
|
||||||
static void closeSession(FILTER *instance, void *session);
|
static void closeSession(FILTER *instance, void *session);
|
||||||
static void freeSession(FILTER *instance, void *session);
|
static void freeSession(FILTER *instance, void *session);
|
||||||
@ -179,13 +179,14 @@ GetModuleObject()
|
|||||||
* Create an instance of the filter for a particular service
|
* Create an instance of the filter for a particular service
|
||||||
* within MaxScale.
|
* within MaxScale.
|
||||||
*
|
*
|
||||||
|
* @param name The name of the instance (as defined in the config file).
|
||||||
* @param options The options for this filter
|
* @param options The options for this filter
|
||||||
* @param params The array of name/value pair parameters for the filter
|
* @param params The array of name/value pair parameters for the filter
|
||||||
*
|
*
|
||||||
* @return The instance data for this new instance
|
* @return The instance data for this new instance
|
||||||
*/
|
*/
|
||||||
static FILTER *
|
static FILTER *
|
||||||
createInstance(char **options, FILTER_PARAMETER **params)
|
createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||||
{
|
{
|
||||||
TOPN_INSTANCE *my_instance = (TOPN_INSTANCE*)MXS_MALLOC(sizeof(TOPN_INSTANCE));
|
TOPN_INSTANCE *my_instance = (TOPN_INSTANCE*)MXS_MALLOC(sizeof(TOPN_INSTANCE));
|
||||||
|
|
||||||
|
|||||||
@ -63,7 +63,7 @@
|
|||||||
#include <housekeeper.h>
|
#include <housekeeper.h>
|
||||||
#include <mysql.h>
|
#include <mysql.h>
|
||||||
|
|
||||||
#define GW_MYSQL_VERSION "5.5.5-10.0.0 "MAXSCALE_VERSION"-maxscale"
|
#define GW_MYSQL_VERSION "5.5.5-10.0.0 " MAXSCALE_VERSION "-maxscale"
|
||||||
#define GW_MYSQL_LOOP_TIMEOUT 300000000
|
#define GW_MYSQL_LOOP_TIMEOUT 300000000
|
||||||
#define GW_MYSQL_READ 0
|
#define GW_MYSQL_READ 0
|
||||||
#define GW_MYSQL_WRITE 1
|
#define GW_MYSQL_WRITE 1
|
||||||
|
|||||||
Reference in New Issue
Block a user