Merge branch '2.1' into develop
This commit is contained in:
48
server/modules/filter/cache/cache.cc
vendored
48
server/modules/filter/cache/cache.cc
vendored
@ -14,11 +14,19 @@
|
||||
#define MXS_MODULE_NAME "cache"
|
||||
#include "cache.hh"
|
||||
#include <new>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <zlib.h>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/buffer.h>
|
||||
#include <maxscale/modutil.h>
|
||||
#include <maxscale/query_classifier.h>
|
||||
#include <maxscale/paths.h>
|
||||
#include "storagefactory.hh"
|
||||
#include "storage.hh"
|
||||
|
||||
using namespace std;
|
||||
|
||||
Cache::Cache(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
SCacheRules sRules,
|
||||
@ -102,6 +110,46 @@ void Cache::show(DCB* pDcb) const
|
||||
}
|
||||
}
|
||||
|
||||
cache_result_t Cache::get_key(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const
|
||||
{
|
||||
// TODO: Take config into account.
|
||||
return get_default_key(zDefault_db, pQuery, pKey);
|
||||
}
|
||||
|
||||
//static
|
||||
cache_result_t Cache::get_default_key(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey)
|
||||
{
|
||||
ss_dassert(GWBUF_IS_CONTIGUOUS(pQuery));
|
||||
|
||||
char *pSql;
|
||||
int length;
|
||||
|
||||
modutil_extract_SQL(const_cast<GWBUF*>(pQuery), &pSql, &length);
|
||||
|
||||
uint64_t crc1 = crc32(0, Z_NULL, 0);
|
||||
|
||||
const Bytef* pData;
|
||||
|
||||
if (zDefault_db)
|
||||
{
|
||||
pData = reinterpret_cast<const Bytef*>(zDefault_db);
|
||||
crc1 = crc32(crc1, pData, strlen(zDefault_db));
|
||||
}
|
||||
|
||||
pData = reinterpret_cast<const Bytef*>(pSql);
|
||||
|
||||
crc1 = crc32(crc1, pData, length);
|
||||
uint64_t crc2 = crc32(crc1, pData, length);
|
||||
|
||||
pKey->data = (crc1 << 32 | crc2);
|
||||
|
||||
return CACHE_RESULT_OK;
|
||||
}
|
||||
|
||||
bool Cache::should_store(const char* zDefaultDb, const GWBUF* pQuery)
|
||||
{
|
||||
return m_sRules->should_store(zDefaultDb, pQuery);
|
||||
|
||||
28
server/modules/filter/cache/cache.hh
vendored
28
server/modules/filter/cache/cache.hh
vendored
@ -87,11 +87,31 @@ public:
|
||||
virtual void refreshed(const CACHE_KEY& key, const CacheFilterSession* pSession) = 0;
|
||||
|
||||
/**
|
||||
* See @Storage::get_key
|
||||
* Returns a key for the statement. Takes the current config into account.
|
||||
*
|
||||
* @param zDefault_db The default database, can be NULL.
|
||||
* @param pQuery A statement.
|
||||
* @param pKey On output a key.
|
||||
*
|
||||
* @return CACHE_RESULT_OK if a key could be created.
|
||||
*/
|
||||
virtual cache_result_t get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const = 0;
|
||||
cache_result_t get_key(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const;
|
||||
|
||||
/**
|
||||
* Returns a key for the statement. Does not take the current config
|
||||
* into account.
|
||||
*
|
||||
* @param zDefault_db The default database, can be NULL.
|
||||
* @param pQuery A statement.
|
||||
* @param pKey On output a key.
|
||||
*
|
||||
* @return CACHE_RESULT_OK if a key could be created.
|
||||
*/
|
||||
static cache_result_t get_default_key(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey);
|
||||
|
||||
/**
|
||||
* See @Storage::get_value
|
||||
|
||||
17
server/modules/filter/cache/cache_storage_api.c
vendored
17
server/modules/filter/cache/cache_storage_api.c
vendored
@ -17,20 +17,9 @@
|
||||
size_t cache_key_hash(const CACHE_KEY* key)
|
||||
{
|
||||
ss_dassert(key);
|
||||
ss_dassert(sizeof(key->data) == sizeof(size_t));
|
||||
|
||||
size_t hash = 0;
|
||||
|
||||
const char* i = key->data;
|
||||
const char* end = i + CACHE_KEY_MAXLEN;
|
||||
|
||||
while (i < end)
|
||||
{
|
||||
int c = *i;
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
++i;
|
||||
}
|
||||
|
||||
return hash;
|
||||
return key->data;
|
||||
}
|
||||
|
||||
bool cache_key_equal_to(const CACHE_KEY* lhs, const CACHE_KEY* rhs)
|
||||
@ -38,7 +27,7 @@ bool cache_key_equal_to(const CACHE_KEY* lhs, const CACHE_KEY* rhs)
|
||||
ss_dassert(lhs);
|
||||
ss_dassert(rhs);
|
||||
|
||||
return memcmp(lhs->data, rhs->data, CACHE_KEY_MAXLEN) == 0;
|
||||
return lhs->data == rhs->data;
|
||||
}
|
||||
|
||||
|
||||
|
||||
19
server/modules/filter/cache/cache_storage_api.cc
vendored
19
server/modules/filter/cache/cache_storage_api.cc
vendored
@ -14,24 +14,15 @@
|
||||
#define MXS_MODULE_NAME "cache"
|
||||
#include "cache_storage_api.hh"
|
||||
#include <ctype.h>
|
||||
#include <sstream>
|
||||
|
||||
using std::string;
|
||||
using std::stringstream;
|
||||
|
||||
std::string cache_key_to_string(const CACHE_KEY& key)
|
||||
{
|
||||
string s;
|
||||
stringstream ss;
|
||||
ss << key.data;
|
||||
|
||||
for (int i = 0; i < CACHE_KEY_MAXLEN; ++i)
|
||||
{
|
||||
char c = key.data[i];
|
||||
|
||||
if (!isprint(c))
|
||||
{
|
||||
c = '.';
|
||||
}
|
||||
|
||||
s += c;
|
||||
}
|
||||
|
||||
return s;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
19
server/modules/filter/cache/cache_storage_api.h
vendored
19
server/modules/filter/cache/cache_storage_api.h
vendored
@ -60,14 +60,9 @@ typedef enum cache_thread_model
|
||||
|
||||
typedef void* CACHE_STORAGE;
|
||||
|
||||
enum
|
||||
{
|
||||
CACHE_KEY_MAXLEN = 128
|
||||
};
|
||||
|
||||
typedef struct cache_key
|
||||
{
|
||||
char data[CACHE_KEY_MAXLEN];
|
||||
uint64_t data;
|
||||
} CACHE_KEY;
|
||||
|
||||
/**
|
||||
@ -176,18 +171,6 @@ typedef struct cache_storage_api
|
||||
const CACHE_STORAGE_CONFIG* config,
|
||||
int argc, char* argv[]);
|
||||
|
||||
/**
|
||||
* Create a key for a GWBUF.
|
||||
*
|
||||
* @param query An SQL query. Must be one contiguous buffer.
|
||||
* @param key Pointer to key.
|
||||
*
|
||||
* @return CACHE_RESULT_OK if a key was created, otherwise some error code.
|
||||
*/
|
||||
cache_result_t (*getKey)(const char* default_db,
|
||||
const GWBUF* query,
|
||||
CACHE_KEY* key);
|
||||
|
||||
/**
|
||||
* Frees an CACHE_STORAGE instance earlier created with createInstance.
|
||||
*
|
||||
|
||||
@ -51,7 +51,7 @@ std::string cache_key_to_string(const CACHE_KEY& key);
|
||||
|
||||
inline bool operator == (const CACHE_KEY& lhs, const CACHE_KEY& rhs)
|
||||
{
|
||||
return memcmp(lhs.data, rhs.data, sizeof(lhs.data)) == 0;
|
||||
return lhs.data == rhs.data;
|
||||
}
|
||||
|
||||
inline bool operator != (const CACHE_KEY& lhs, const CACHE_KEY& rhs)
|
||||
@ -64,7 +64,7 @@ class CacheKey : public CACHE_KEY
|
||||
public:
|
||||
CacheKey()
|
||||
{
|
||||
memset(data, 0, sizeof(data));
|
||||
data = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
45
server/modules/filter/cache/cachefilter.cc
vendored
45
server/modules/filter/cache/cachefilter.cc
vendored
@ -49,6 +49,8 @@ void cache_config_finish(CACHE_CONFIG& config)
|
||||
config.hard_ttl = 0;
|
||||
config.soft_ttl = 0;
|
||||
config.debug = 0;
|
||||
config.thread_model = CACHE_THREAD_MODEL_MT;
|
||||
config.selects = CACHE_SELECTS_VERIFY_CACHEABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -100,6 +102,20 @@ bool cache_command_show(const MODULECMD_ARG* pArgs)
|
||||
return true;
|
||||
}
|
||||
|
||||
int cache_process_init()
|
||||
{
|
||||
uint32_t jit_available;
|
||||
pcre2_config(PCRE2_CONFIG_JIT, &jit_available);
|
||||
|
||||
if (!jit_available)
|
||||
{
|
||||
MXS_WARNING("pcre2 JIT is not available; regex matching will not be "
|
||||
"as efficient as it could be.");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
@ -107,13 +123,21 @@ bool cache_command_show(const MODULECMD_ARG* pArgs)
|
||||
//
|
||||
|
||||
// Enumeration values for `cached_data`
|
||||
static const MXS_ENUM_VALUE cached_data_values[] =
|
||||
static const MXS_ENUM_VALUE parameter_cached_data_values[] =
|
||||
{
|
||||
{"shared", CACHE_THREAD_MODEL_MT},
|
||||
{"thread_specific", CACHE_THREAD_MODEL_ST},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
// Enumeration values for `selects`
|
||||
static const MXS_ENUM_VALUE parameter_selects_values[] =
|
||||
{
|
||||
{"assume_cacheable", CACHE_SELECTS_ASSUME_CACHEABLE},
|
||||
{"verify_cacheable", CACHE_SELECTS_VERIFY_CACHEABLE},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||
{
|
||||
static modulecmd_arg_type_t show_argv[] =
|
||||
@ -136,7 +160,7 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||
VERSION_STRING,
|
||||
RCAP_TYPE_TRANSACTION_TRACKING,
|
||||
&CacheFilter::s_object,
|
||||
NULL, /* Process init. */
|
||||
cache_process_init, /* Process init. */
|
||||
NULL, /* Process finish. */
|
||||
NULL, /* Thread init. */
|
||||
NULL, /* Thread finish. */
|
||||
@ -144,8 +168,7 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||
{
|
||||
"storage",
|
||||
MXS_MODULE_PARAM_STRING,
|
||||
NULL,
|
||||
MXS_MODULE_OPT_REQUIRED
|
||||
CACHE_DEFAULT_STORAGE
|
||||
},
|
||||
{
|
||||
"storage_options",
|
||||
@ -195,7 +218,14 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||
MXS_MODULE_PARAM_ENUM,
|
||||
CACHE_DEFAULT_THREAD_MODEL,
|
||||
MXS_MODULE_OPT_NONE,
|
||||
cached_data_values
|
||||
parameter_cached_data_values
|
||||
},
|
||||
{
|
||||
"selects",
|
||||
MXS_MODULE_PARAM_ENUM,
|
||||
CACHE_DEFAULT_SELECTS,
|
||||
MXS_MODULE_OPT_NONE,
|
||||
parameter_selects_values
|
||||
},
|
||||
{MXS_END_MODULE_PARAMS}
|
||||
}
|
||||
@ -292,7 +322,10 @@ bool CacheFilter::process_params(char **pzOptions, MXS_CONFIG_PARAMETER *ppParam
|
||||
config.max_resultset_size = config_get_size(ppParams, "max_resultset_size");
|
||||
config.thread_model = static_cast<cache_thread_model_t>(config_get_enum(ppParams,
|
||||
"cached_data",
|
||||
cached_data_values));
|
||||
parameter_cached_data_values));
|
||||
config.selects = static_cast<cache_selects_t>(config_get_enum(ppParams,
|
||||
"selects",
|
||||
parameter_selects_values));
|
||||
|
||||
if (!config.storage)
|
||||
{
|
||||
|
||||
11
server/modules/filter/cache/cachefilter.h
vendored
11
server/modules/filter/cache/cachefilter.h
vendored
@ -54,6 +54,16 @@
|
||||
#define CACHE_DEFAULT_MAX_SIZE "0"
|
||||
// Thread model
|
||||
#define CACHE_DEFAULT_THREAD_MODEL "shared"
|
||||
// Cacheable selects
|
||||
#define CACHE_DEFAULT_SELECTS "verify_cacheable"
|
||||
// Storage
|
||||
#define CACHE_DEFAULT_STORAGE "storage_inmemory"
|
||||
|
||||
typedef enum cache_selects
|
||||
{
|
||||
CACHE_SELECTS_ASSUME_CACHEABLE,
|
||||
CACHE_SELECTS_VERIFY_CACHEABLE,
|
||||
} cache_selects_t;
|
||||
|
||||
typedef struct cache_config
|
||||
{
|
||||
@ -70,4 +80,5 @@ typedef struct cache_config
|
||||
uint64_t max_size; /**< Maximum size of the cache.*/
|
||||
uint32_t debug; /**< Debug settings. */
|
||||
cache_thread_model_t thread_model; /**< Thread model. */
|
||||
cache_selects_t selects; /**< Assume/verify that selects are cacheable. */
|
||||
} CACHE_CONFIG;
|
||||
|
||||
100
server/modules/filter/cache/cachefiltersession.cc
vendored
100
server/modules/filter/cache/cachefiltersession.cc
vendored
@ -136,6 +136,46 @@ bool uses_non_cacheable_variable(GWBUF* pPacket)
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool is_select_statement(GWBUF* pStmt)
|
||||
{
|
||||
bool is_select = false;
|
||||
|
||||
char* pSql;
|
||||
int len;
|
||||
|
||||
ss_debug(int rc =) modutil_extract_SQL(pStmt, &pSql, &len);
|
||||
ss_dassert(rc == 1);
|
||||
|
||||
char* pSql_end = pSql + len;
|
||||
|
||||
pSql = modutil_MySQL_bypass_whitespace(pSql, len);
|
||||
|
||||
const char SELECT[] = "SELECT";
|
||||
|
||||
const char* pSelect = SELECT;
|
||||
const char* pSelect_end = pSelect + sizeof(SELECT) - 1;
|
||||
|
||||
while ((pSql < pSql_end) && (pSelect < pSelect_end) && (toupper(*pSql) == *pSelect))
|
||||
{
|
||||
++pSql;
|
||||
++pSelect;
|
||||
}
|
||||
|
||||
if (pSelect == pSelect_end)
|
||||
{
|
||||
if ((pSql == pSql_end) || !isalpha(*pSql))
|
||||
{
|
||||
is_select = true;
|
||||
}
|
||||
}
|
||||
|
||||
return is_select;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CacheFilterSession::CacheFilterSession(MXS_SESSION* pSession, Cache* pCache, char* zDefaultDb)
|
||||
: maxscale::FilterSession(pSession)
|
||||
@ -146,7 +186,7 @@ CacheFilterSession::CacheFilterSession(MXS_SESSION* pSession, Cache* pCache, cha
|
||||
, m_refreshing(false)
|
||||
, m_is_read_only(true)
|
||||
{
|
||||
memset(m_key.data, 0, CACHE_KEY_MAXLEN);
|
||||
m_key.data = 0;
|
||||
|
||||
reset_response_state();
|
||||
}
|
||||
@ -772,7 +812,7 @@ bool CacheFilterSession::should_consult_cache(GWBUF* pPacket)
|
||||
{
|
||||
bool consult_cache = false;
|
||||
|
||||
uint32_t type_mask = qc_get_type_mask(pPacket);
|
||||
uint32_t type_mask = qc_get_trx_type_mask(pPacket); // Note, only trx-related type mask
|
||||
|
||||
const char* zReason = NULL;
|
||||
|
||||
@ -781,13 +821,6 @@ bool CacheFilterSession::should_consult_cache(GWBUF* pPacket)
|
||||
// When a transaction is started, we initially assume it is read-only.
|
||||
m_is_read_only = true;
|
||||
}
|
||||
else if (!qc_query_is_type(type_mask, QUERY_TYPE_READ))
|
||||
{
|
||||
// Thereafter, if there's any non-read statement we mark it as non-readonly.
|
||||
// Note that the state of m_is_read_only is not consulted if there is no
|
||||
// on-going transaction of if there is an explicitly read-only transaction.
|
||||
m_is_read_only = false;
|
||||
}
|
||||
|
||||
if (!session_trx_is_active(m_pSession))
|
||||
{
|
||||
@ -823,31 +856,42 @@ bool CacheFilterSession::should_consult_cache(GWBUF* pPacket)
|
||||
|
||||
if (consult_cache)
|
||||
{
|
||||
if (qc_get_operation(pPacket) == QUERY_OP_SELECT)
|
||||
if (is_select_statement(pPacket))
|
||||
{
|
||||
if (qc_query_is_type(type_mask, QUERY_TYPE_USERVAR_READ))
|
||||
if (m_pCache->config().selects == CACHE_SELECTS_VERIFY_CACHEABLE)
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "user variables are read";
|
||||
}
|
||||
else if (qc_query_is_type(type_mask, QUERY_TYPE_SYSVAR_READ))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "system variables are read";
|
||||
}
|
||||
else if (uses_non_cacheable_function(pPacket))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "uses non-cacheable function";
|
||||
}
|
||||
else if (uses_non_cacheable_variable(pPacket))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "uses non-cacheable variable";
|
||||
// Note that the type mask must be obtained a new. A few lines
|
||||
// above we only got the transaction state related type mask.
|
||||
type_mask = qc_get_type_mask(pPacket);
|
||||
|
||||
if (qc_query_is_type(type_mask, QUERY_TYPE_USERVAR_READ))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "user variables are read";
|
||||
}
|
||||
else if (qc_query_is_type(type_mask, QUERY_TYPE_SYSVAR_READ))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "system variables are read";
|
||||
}
|
||||
else if (uses_non_cacheable_function(pPacket))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "uses non-cacheable function";
|
||||
}
|
||||
else if (uses_non_cacheable_variable(pPacket))
|
||||
{
|
||||
consult_cache = false;
|
||||
zReason = "uses non-cacheable variable";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// A bit broad, as e.g. SHOW will cause the read only state to be turned
|
||||
// off. However, during normal use this will always be an UPDATE, INSERT
|
||||
// or DELETE.
|
||||
m_is_read_only = false;
|
||||
consult_cache = false;
|
||||
zReason = "statement is not SELECT";
|
||||
}
|
||||
|
||||
7
server/modules/filter/cache/cachesimple.cc
vendored
7
server/modules/filter/cache/cachesimple.cc
vendored
@ -50,13 +50,6 @@ bool CacheSimple::Create(const CACHE_CONFIG& config,
|
||||
return pRules != NULL;
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const
|
||||
{
|
||||
return m_pStorage->get_key(zDefaultDb, pQuery, pKey);
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::get_value(const CACHE_KEY& key,
|
||||
uint32_t flags,
|
||||
GWBUF** ppValue) const
|
||||
|
||||
2
server/modules/filter/cache/cachesimple.hh
vendored
2
server/modules/filter/cache/cachesimple.hh
vendored
@ -25,8 +25,6 @@ class CacheSimple : public Cache
|
||||
public:
|
||||
~CacheSimple();
|
||||
|
||||
cache_result_t get_key(const char* zDefaultDb, const GWBUF* pQuery, CACHE_KEY* pKey) const;
|
||||
|
||||
cache_result_t get_value(const CACHE_KEY& key, uint32_t flags, GWBUF** ppValue) const;
|
||||
|
||||
cache_result_t put_value(const CACHE_KEY& key, const GWBUF* pValue);
|
||||
|
||||
7
server/modules/filter/cache/lrustorage.cc
vendored
7
server/modules/filter/cache/lrustorage.cc
vendored
@ -41,13 +41,6 @@ void LRUStorage::get_config(CACHE_STORAGE_CONFIG* pConfig)
|
||||
*pConfig = m_config;
|
||||
}
|
||||
|
||||
cache_result_t LRUStorage::get_key(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const
|
||||
{
|
||||
return m_pStorage->get_key(zDefault_db, pQuery, pKey);
|
||||
}
|
||||
|
||||
cache_result_t LRUStorage::do_get_info(uint32_t what,
|
||||
json_t** ppInfo) const
|
||||
{
|
||||
|
||||
7
server/modules/filter/cache/lrustorage.hh
vendored
7
server/modules/filter/cache/lrustorage.hh
vendored
@ -28,13 +28,6 @@ public:
|
||||
*/
|
||||
void get_config(CACHE_STORAGE_CONFIG* pConfig);
|
||||
|
||||
/**
|
||||
* @see Storage::get_key
|
||||
*/
|
||||
cache_result_t get_key(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const;
|
||||
|
||||
protected:
|
||||
LRUStorage(const CACHE_STORAGE_CONFIG& config, Storage* pStorage);
|
||||
|
||||
|
||||
218
server/modules/filter/cache/rules.cc
vendored
218
server/modules/filter/cache/rules.cc
vendored
@ -19,11 +19,25 @@
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/modutil.h>
|
||||
#include <maxscale/mysql_utils.h>
|
||||
#include <maxscale/platform.h>
|
||||
#include <maxscale/protocol/mysql.h>
|
||||
#include <maxscale/query_classifier.h>
|
||||
#include <maxscale/session.h>
|
||||
#include "cachefilter.h"
|
||||
|
||||
static int next_thread_id = 0;
|
||||
static thread_local int current_thread_id = -1;
|
||||
|
||||
inline int get_current_thread_id()
|
||||
{
|
||||
if (current_thread_id == -1)
|
||||
{
|
||||
current_thread_id = atomic_add(&next_thread_id, 1);
|
||||
}
|
||||
|
||||
return current_thread_id;
|
||||
}
|
||||
|
||||
static const char KEY_ATTRIBUTE[] = "attribute";
|
||||
static const char KEY_OP[] = "op";
|
||||
static const char KEY_STORE[] = "store";
|
||||
@ -68,8 +82,8 @@ static bool cache_rule_attribute_get(struct cache_attribute_mapping *mapping,
|
||||
|
||||
static bool cache_rule_op_get(const char *s, cache_rule_op_t *op);
|
||||
|
||||
static bool cache_rule_compare(CACHE_RULE *rule, const char *value);
|
||||
static bool cache_rule_compare_n(CACHE_RULE *rule, const char *value, size_t length);
|
||||
static bool cache_rule_compare(CACHE_RULE *rule, int thread_id, const char *value);
|
||||
static bool cache_rule_compare_n(CACHE_RULE *rule, int thread_id, const char *value, size_t length);
|
||||
static CACHE_RULE *cache_rule_create_regexp(cache_rule_attribute_t attribute,
|
||||
cache_rule_op_t op,
|
||||
const char *value,
|
||||
@ -95,36 +109,42 @@ static CACHE_RULE *cache_rule_create(cache_rule_attribute_t attribute,
|
||||
const char *value,
|
||||
uint32_t debug);
|
||||
static bool cache_rule_matches_column_regexp(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_column_simple(CACHE_RULE *rule,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_column(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_database(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_query(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_table(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_table_regexp(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_table_simple(CACHE_RULE *rule,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
static bool cache_rule_matches_user(CACHE_RULE *rule, const char *user);
|
||||
static bool cache_rule_matches_user(CACHE_RULE *rule, int thread_id, const char *user);
|
||||
static bool cache_rule_matches(CACHE_RULE *rule,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query);
|
||||
|
||||
static void cache_rule_free(CACHE_RULE *rule);
|
||||
static bool cache_rule_matches(CACHE_RULE *rule, const char *default_db, const GWBUF *query);
|
||||
|
||||
static void cache_rules_add_store_rule(CACHE_RULES* self, CACHE_RULE* rule);
|
||||
static void cache_rules_add_use_rule(CACHE_RULES* self, CACHE_RULE* rule);
|
||||
@ -138,6 +158,9 @@ static bool cache_rules_parse_array(CACHE_RULES *self, json_t *store, const char
|
||||
static bool cache_rules_parse_store_element(CACHE_RULES *self, json_t *object, size_t index);
|
||||
static bool cache_rules_parse_use_element(CACHE_RULES *self, json_t *object, size_t index);
|
||||
|
||||
static pcre2_match_data** alloc_match_datas(int count, pcre2_code* code);
|
||||
static void free_match_datas(int count, pcre2_match_data** datas);
|
||||
|
||||
/*
|
||||
* API begin
|
||||
*/
|
||||
@ -297,7 +320,7 @@ void cache_rules_print(const CACHE_RULES *self, DCB *dcb, size_t indent)
|
||||
}
|
||||
}
|
||||
|
||||
bool cache_rules_should_store(CACHE_RULES *self, const char *default_db, const GWBUF* query)
|
||||
bool cache_rules_should_store(CACHE_RULES *self, int thread_id, const char *default_db, const GWBUF* query)
|
||||
{
|
||||
bool should_store = false;
|
||||
|
||||
@ -307,7 +330,7 @@ bool cache_rules_should_store(CACHE_RULES *self, const char *default_db, const G
|
||||
{
|
||||
while (rule && !should_store)
|
||||
{
|
||||
should_store = cache_rule_matches(rule, default_db, query);
|
||||
should_store = cache_rule_matches(rule, thread_id, default_db, query);
|
||||
rule = rule->next;
|
||||
}
|
||||
}
|
||||
@ -319,7 +342,7 @@ bool cache_rules_should_store(CACHE_RULES *self, const char *default_db, const G
|
||||
return should_store;
|
||||
}
|
||||
|
||||
bool cache_rules_should_use(CACHE_RULES *self, const MXS_SESSION *session)
|
||||
bool cache_rules_should_use(CACHE_RULES *self, int thread_id, const MXS_SESSION *session)
|
||||
{
|
||||
bool should_use = false;
|
||||
|
||||
@ -344,7 +367,7 @@ bool cache_rules_should_use(CACHE_RULES *self, const MXS_SESSION *session)
|
||||
|
||||
while (rule && !should_use)
|
||||
{
|
||||
should_use = cache_rule_matches_user(rule, account);
|
||||
should_use = cache_rule_matches_user(rule, thread_id, account);
|
||||
rule = rule->next;
|
||||
}
|
||||
}
|
||||
@ -404,12 +427,12 @@ const json_t* CacheRules::json() const
|
||||
|
||||
bool CacheRules::should_store(const char* zDefault_db, const GWBUF* pQuery) const
|
||||
{
|
||||
return cache_rules_should_store(m_pRules, zDefault_db, pQuery);
|
||||
return cache_rules_should_store(m_pRules, get_current_thread_id(), zDefault_db, pQuery);
|
||||
}
|
||||
|
||||
bool CacheRules::should_use(const MXS_SESSION* pSession) const
|
||||
{
|
||||
return cache_rules_should_use(m_pRules, pSession);
|
||||
return cache_rules_should_use(m_pRules, get_current_thread_id(), pSession);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -507,9 +530,15 @@ static CACHE_RULE *cache_rule_create_regexp(cache_rule_attribute_t attribute,
|
||||
|
||||
if (code)
|
||||
{
|
||||
pcre2_match_data *data = pcre2_match_data_create_from_pattern(code, NULL);
|
||||
// We do not care about the result. If JIT is not present, we have
|
||||
// complained about it already.
|
||||
pcre2_jit_compile(code, PCRE2_JIT_COMPLETE);
|
||||
|
||||
if (data)
|
||||
int n_threads = config_threadcount();
|
||||
|
||||
pcre2_match_data **datas = alloc_match_datas(n_threads, code);
|
||||
|
||||
if (datas)
|
||||
{
|
||||
rule = (CACHE_RULE*)MXS_CALLOC(1, sizeof(CACHE_RULE));
|
||||
char* value = MXS_STRDUP(cvalue);
|
||||
@ -520,14 +549,14 @@ static CACHE_RULE *cache_rule_create_regexp(cache_rule_attribute_t attribute,
|
||||
rule->op = op;
|
||||
rule->value = value;
|
||||
rule->regexp.code = code;
|
||||
rule->regexp.data = data;
|
||||
rule->regexp.datas = datas;
|
||||
rule->debug = debug;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(value);
|
||||
MXS_FREE(rule);
|
||||
pcre2_match_data_free(data);
|
||||
free_match_datas(n_threads, datas);
|
||||
pcre2_code_free(code);
|
||||
}
|
||||
}
|
||||
@ -967,7 +996,7 @@ static void cache_rule_free(CACHE_RULE* rule)
|
||||
}
|
||||
else if ((rule->op == CACHE_OP_LIKE) || (rule->op == CACHE_OP_UNLIKE))
|
||||
{
|
||||
pcre2_match_data_free(rule->regexp.data);
|
||||
free_match_datas(config_threadcount(), rule->regexp.datas);
|
||||
pcre2_code_free(rule->regexp.code);
|
||||
}
|
||||
|
||||
@ -978,18 +1007,19 @@ static void cache_rule_free(CACHE_RULE* rule)
|
||||
/**
|
||||
* Check whether a value matches a rule.
|
||||
*
|
||||
* @param self The rule object.
|
||||
* @param value The value to check.
|
||||
* @param self The rule object.
|
||||
* @param thread_id The thread id of the calling thread.
|
||||
* @param value The value to check.
|
||||
*
|
||||
* @return True if the value matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_compare(CACHE_RULE *self, const char *value)
|
||||
static bool cache_rule_compare(CACHE_RULE *self, int thread_id, const char *value)
|
||||
{
|
||||
bool rv;
|
||||
|
||||
if (value)
|
||||
{
|
||||
rv = cache_rule_compare_n(self, value, strlen(value));
|
||||
rv = cache_rule_compare_n(self, thread_id, value, strlen(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1009,13 +1039,14 @@ static bool cache_rule_compare(CACHE_RULE *self, const char *value)
|
||||
/**
|
||||
* Check whether a value matches a rule.
|
||||
*
|
||||
* @param self The rule object.
|
||||
* @param value The value to check.
|
||||
* @param len The length of value.
|
||||
* @param self The rule object.
|
||||
* @param thread_id The thread id of the calling thread.
|
||||
* @param value The value to check.
|
||||
* @param len The length of value.
|
||||
*
|
||||
* @return True if the value matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_compare_n(CACHE_RULE *self, const char *value, size_t length)
|
||||
static bool cache_rule_compare_n(CACHE_RULE *self, int thread_id, const char *value, size_t length)
|
||||
{
|
||||
bool compares = false;
|
||||
|
||||
@ -1028,9 +1059,10 @@ static bool cache_rule_compare_n(CACHE_RULE *self, const char *value, size_t len
|
||||
|
||||
case CACHE_OP_LIKE:
|
||||
case CACHE_OP_UNLIKE:
|
||||
ss_dassert((thread_id >= 0) && (thread_id < config_threadcount()));
|
||||
compares = (pcre2_match(self->regexp.code,
|
||||
(PCRE2_SPTR)value, length,
|
||||
0, 0, self->regexp.data, NULL) >= 0);
|
||||
0, 0, self->regexp.datas[thread_id], NULL) >= 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1049,12 +1081,16 @@ static bool cache_rule_compare_n(CACHE_RULE *self, const char *value, size_t len
|
||||
* Returns boolean indicating whether the column rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_column_regexp(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches_column_regexp(CACHE_RULE *self,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_COLUMN);
|
||||
ss_dassert((self->op == CACHE_OP_LIKE) || (self->op == CACHE_OP_UNLIKE));
|
||||
@ -1154,7 +1190,7 @@ static bool cache_rule_matches_column_regexp(CACHE_RULE *self, const char *defau
|
||||
|
||||
strcat(buffer, info->column);
|
||||
|
||||
matches = cache_rule_compare(self, buffer);
|
||||
matches = cache_rule_compare(self, thread_id, buffer);
|
||||
}
|
||||
|
||||
++i;
|
||||
@ -1346,12 +1382,16 @@ static bool cache_rule_matches_column_simple(CACHE_RULE *self, const char *defau
|
||||
* Returns boolean indicating whether the column rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_column(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches_column(CACHE_RULE *self,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_COLUMN);
|
||||
|
||||
@ -1366,7 +1406,7 @@ static bool cache_rule_matches_column(CACHE_RULE *self, const char *default_db,
|
||||
|
||||
case CACHE_OP_LIKE:
|
||||
case CACHE_OP_UNLIKE:
|
||||
matches = cache_rule_matches_column_regexp(self, default_db, query);
|
||||
matches = cache_rule_matches_column_regexp(self, thread_id, default_db, query);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1380,12 +1420,16 @@ static bool cache_rule_matches_column(CACHE_RULE *self, const char *default_db,
|
||||
* Returns boolean indicating whether the database rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_database(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches_database(CACHE_RULE *self,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_DATABASE);
|
||||
|
||||
@ -1415,7 +1459,7 @@ static bool cache_rule_matches_database(CACHE_RULE *self, const char *default_db
|
||||
database = default_db;
|
||||
}
|
||||
|
||||
matches = cache_rule_compare(self, database);
|
||||
matches = cache_rule_compare(self, thread_id, database);
|
||||
|
||||
MXS_FREE(name);
|
||||
++i;
|
||||
@ -1435,13 +1479,17 @@ static bool cache_rule_matches_database(CACHE_RULE *self, const char *default_db
|
||||
/**
|
||||
* Returns boolean indicating whether the query rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of the calling thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_query(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches_query(CACHE_RULE *self,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_QUERY);
|
||||
|
||||
@ -1451,19 +1499,23 @@ static bool cache_rule_matches_query(CACHE_RULE *self, const char *default_db, c
|
||||
// Will succeed, query contains a contiguous COM_QUERY.
|
||||
modutil_extract_SQL((GWBUF*)query, &sql, &len);
|
||||
|
||||
return cache_rule_compare_n(self, sql, len);
|
||||
return cache_rule_compare_n(self, thread_id, sql, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns boolean indicating whether the table regexp rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_table_regexp(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches_table_regexp(CACHE_RULE *self,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_TABLE);
|
||||
ss_dassert((self->op == CACHE_OP_LIKE) || (self->op == CACHE_OP_UNLIKE));
|
||||
@ -1499,11 +1551,11 @@ static bool cache_rule_matches_table_regexp(CACHE_RULE *self, const char *defaul
|
||||
strcpy(name + default_db_len, ".");
|
||||
strcpy(name + default_db_len + 1, name);
|
||||
|
||||
matches = cache_rule_compare(self, name);
|
||||
matches = cache_rule_compare(self, thread_id, name);
|
||||
}
|
||||
else
|
||||
{
|
||||
matches = cache_rule_compare(self, name);
|
||||
matches = cache_rule_compare(self, thread_id, name);
|
||||
}
|
||||
|
||||
MXS_FREE(names[i]);
|
||||
@ -1511,7 +1563,7 @@ static bool cache_rule_matches_table_regexp(CACHE_RULE *self, const char *defaul
|
||||
else
|
||||
{
|
||||
// A qualified name "db.tbl".
|
||||
matches = cache_rule_compare(self, name);
|
||||
matches = cache_rule_compare(self, thread_id, name);
|
||||
}
|
||||
|
||||
++i;
|
||||
@ -1626,12 +1678,16 @@ static bool cache_rule_matches_table_simple(CACHE_RULE *self, const char *defaul
|
||||
* Returns boolean indicating whether the table rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_table(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches_table(CACHE_RULE *self,
|
||||
int thread_id,
|
||||
const char *default_db,
|
||||
const GWBUF *query)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_TABLE);
|
||||
|
||||
@ -1646,7 +1702,7 @@ static bool cache_rule_matches_table(CACHE_RULE *self, const char *default_db, c
|
||||
|
||||
case CACHE_OP_LIKE:
|
||||
case CACHE_OP_UNLIKE:
|
||||
matches = cache_rule_matches_table_regexp(self, default_db, query);
|
||||
matches = cache_rule_matches_table_regexp(self, thread_id, default_db, query);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -1659,16 +1715,17 @@ static bool cache_rule_matches_table(CACHE_RULE *self, const char *default_db, c
|
||||
/**
|
||||
* Returns boolean indicating whether the user rule matches the account or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param account The account.
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param account The account.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches_user(CACHE_RULE *self, const char *account)
|
||||
static bool cache_rule_matches_user(CACHE_RULE *self, int thread_id, const char *account)
|
||||
{
|
||||
ss_dassert(self->attribute == CACHE_ATTRIBUTE_USER);
|
||||
|
||||
bool matches = cache_rule_compare(self, account);
|
||||
bool matches = cache_rule_compare(self, thread_id, account);
|
||||
|
||||
if ((matches && (self->debug & CACHE_DEBUG_MATCHING)) ||
|
||||
(!matches && (self->debug & CACHE_DEBUG_NON_MATCHING)))
|
||||
@ -1698,31 +1755,32 @@ static bool cache_rule_matches_user(CACHE_RULE *self, const char *account)
|
||||
* Returns boolean indicating whether the rule matches the query or not.
|
||||
*
|
||||
* @param self The CACHE_RULE object.
|
||||
* @param thread_id The thread id of the calling thread.
|
||||
* @param default_db The current default db.
|
||||
* @param query The query.
|
||||
*
|
||||
* @return True, if the rule matches, false otherwise.
|
||||
*/
|
||||
static bool cache_rule_matches(CACHE_RULE *self, const char *default_db, const GWBUF *query)
|
||||
static bool cache_rule_matches(CACHE_RULE *self, int thread_id, const char *default_db, const GWBUF *query)
|
||||
{
|
||||
bool matches = false;
|
||||
|
||||
switch (self->attribute)
|
||||
{
|
||||
case CACHE_ATTRIBUTE_COLUMN:
|
||||
matches = cache_rule_matches_column(self, default_db, query);
|
||||
matches = cache_rule_matches_column(self, thread_id, default_db, query);
|
||||
break;
|
||||
|
||||
case CACHE_ATTRIBUTE_DATABASE:
|
||||
matches = cache_rule_matches_database(self, default_db, query);
|
||||
matches = cache_rule_matches_database(self, thread_id, default_db, query);
|
||||
break;
|
||||
|
||||
case CACHE_ATTRIBUTE_TABLE:
|
||||
matches = cache_rule_matches_table(self, default_db, query);
|
||||
matches = cache_rule_matches_table(self, thread_id, default_db, query);
|
||||
break;
|
||||
|
||||
case CACHE_ATTRIBUTE_QUERY:
|
||||
matches = cache_rule_matches_query(self, default_db, query);
|
||||
matches = cache_rule_matches_query(self, thread_id, default_db, query);
|
||||
break;
|
||||
|
||||
case CACHE_ATTRIBUTE_USER:
|
||||
@ -1884,6 +1942,10 @@ static bool cache_rules_parse_json(CACHE_RULES *self, json_t *root)
|
||||
MXS_ERROR("The cache rules object contains a `%s` key, but it is not an array.", KEY_USE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return parsed;
|
||||
@ -2029,3 +2091,59 @@ static bool cache_rules_parse_use_element(CACHE_RULES *self, json_t *object, siz
|
||||
|
||||
return rule != NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocates array of pcre2 match datas
|
||||
*
|
||||
* @param count How many match datas should be allocated.
|
||||
* @param code The pattern to be used.
|
||||
*
|
||||
* @return Array of specified length, or NULL.
|
||||
*/
|
||||
static pcre2_match_data** alloc_match_datas(int count, pcre2_code* code)
|
||||
{
|
||||
pcre2_match_data** datas = (pcre2_match_data**)MXS_CALLOC(count, sizeof(pcre2_match_data*));
|
||||
|
||||
if (datas)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < count; ++i)
|
||||
{
|
||||
datas[i] = pcre2_match_data_create_from_pattern(code, NULL);
|
||||
|
||||
if (!datas[i])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i != count)
|
||||
{
|
||||
for (; i >= 0; --i)
|
||||
{
|
||||
pcre2_match_data_free(datas[i]);
|
||||
}
|
||||
|
||||
MXS_FREE(datas);
|
||||
datas = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return datas;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees array of pcre2 match datas
|
||||
*
|
||||
* @param count The length of the array.
|
||||
* @param datas The array of pcre2 match datas.
|
||||
*/
|
||||
static void free_match_datas(int count, pcre2_match_data** datas)
|
||||
{
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
pcre2_match_data_free(datas[i]);
|
||||
}
|
||||
|
||||
MXS_FREE(datas);
|
||||
}
|
||||
|
||||
14
server/modules/filter/cache/rules.h
vendored
14
server/modules/filter/cache/rules.h
vendored
@ -54,8 +54,8 @@ typedef struct cache_rule
|
||||
} simple; // Details, only for CACHE_OP_[EQ|NEQ]
|
||||
struct
|
||||
{
|
||||
pcre2_code *code;
|
||||
pcre2_match_data *data;
|
||||
pcre2_code *code;
|
||||
pcre2_match_data **datas;
|
||||
} regexp; // Regexp data, only for CACHE_OP_[LIKE|UNLIKE].
|
||||
uint32_t debug; // The debug level.
|
||||
struct cache_rule *next;
|
||||
@ -137,22 +137,24 @@ void cache_rules_print(const CACHE_RULES *rules, DCB* dcb, size_t indent);
|
||||
* Returns boolean indicating whether the result of the query should be stored.
|
||||
*
|
||||
* @param rules The CACHE_RULES object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param default_db The current default database, NULL if there is none.
|
||||
* @param query The query, expected to contain a COM_QUERY.
|
||||
*
|
||||
* @return True, if the results should be stored.
|
||||
*/
|
||||
bool cache_rules_should_store(CACHE_RULES *rules, const char *default_db, const GWBUF* query);
|
||||
bool cache_rules_should_store(CACHE_RULES *rules, int thread_id, const char *default_db, const GWBUF* query);
|
||||
|
||||
/**
|
||||
* Returns boolean indicating whether the cache should be used, that is consulted.
|
||||
*
|
||||
* @param rules The CACHE_RULES object.
|
||||
* @param session The current session.
|
||||
* @param rules The CACHE_RULES object.
|
||||
* @param thread_id The thread id of current thread.
|
||||
* @param session The current session.
|
||||
*
|
||||
* @return True, if the cache should be used.
|
||||
*/
|
||||
bool cache_rules_should_use(CACHE_RULES *rules, const MXS_SESSION *session);
|
||||
bool cache_rules_should_use(CACHE_RULES *rules, int thread_id, const MXS_SESSION *session);
|
||||
|
||||
MXS_END_DECLS
|
||||
|
||||
|
||||
13
server/modules/filter/cache/storage.hh
vendored
13
server/modules/filter/cache/storage.hh
vendored
@ -44,19 +44,6 @@ public:
|
||||
*/
|
||||
virtual cache_result_t get_info(uint32_t what, json_t** ppInfo) const = 0;
|
||||
|
||||
/**
|
||||
* Create a key for a GWBUF.
|
||||
*
|
||||
* @param zDefaultDb The default DB or NULL.
|
||||
* @param query An SQL query. Must be one contiguous buffer.
|
||||
* @param pKey Pointer to object where key will be stored.
|
||||
*
|
||||
* @return CACHE_RESULT_OK if a key was created, otherwise some error code.
|
||||
*/
|
||||
virtual cache_result_t get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const = 0;
|
||||
|
||||
/**
|
||||
* Get a value from the cache.
|
||||
*
|
||||
|
||||
@ -13,10 +13,6 @@
|
||||
|
||||
#define MXS_MODULE_NAME "storage_inmemory"
|
||||
#include "inmemorystorage.hh"
|
||||
#include <openssl/sha.h>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/modutil.h>
|
||||
#include <maxscale/query_classifier.h>
|
||||
@ -24,7 +20,6 @@
|
||||
#include "inmemorystoragemt.hh"
|
||||
|
||||
using std::auto_ptr;
|
||||
using std::set;
|
||||
using std::string;
|
||||
|
||||
|
||||
@ -96,67 +91,6 @@ InMemoryStorage* InMemoryStorage::Create_instance(const char* zName,
|
||||
return sStorage.release();
|
||||
}
|
||||
|
||||
cache_result_t InMemoryStorage::Get_key(const char* zDefault_db, const GWBUF& query, CACHE_KEY* pKey)
|
||||
{
|
||||
ss_dassert(GWBUF_IS_CONTIGUOUS(&query));
|
||||
|
||||
int n;
|
||||
bool fullnames = true;
|
||||
char** pzTables = qc_get_table_names(const_cast<GWBUF*>(&query), &n, fullnames);
|
||||
|
||||
set<string> dbs; // Elements in set are sorted.
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
char *zTable = pzTables[i];
|
||||
char *zDot = strchr(zTable, '.');
|
||||
|
||||
if (zDot)
|
||||
{
|
||||
*zDot = 0;
|
||||
dbs.insert(zTable);
|
||||
}
|
||||
else if (zDefault_db)
|
||||
{
|
||||
// If zdefault_db is NULL, then there will be a table for which we
|
||||
// do not know the database. However, that will fail in the server,
|
||||
// so nothing will be stored.
|
||||
dbs.insert(zDefault_db);
|
||||
}
|
||||
MXS_FREE(zTable);
|
||||
}
|
||||
MXS_FREE(pzTables);
|
||||
|
||||
// dbs now contain each accessed database in sorted order. Now copy them to a single string.
|
||||
string tag;
|
||||
for (set<string>::const_iterator i = dbs.begin(); i != dbs.end(); ++i)
|
||||
{
|
||||
tag.append(*i);
|
||||
}
|
||||
|
||||
memset(pKey->data, 0, CACHE_KEY_MAXLEN);
|
||||
|
||||
const unsigned char* pData;
|
||||
|
||||
// We store the databases in the first half of the key. That will ensure that
|
||||
// identical queries targeting different default databases will not clash.
|
||||
// This will also mean that entries related to the same databases will
|
||||
// be placed near each other.
|
||||
pData = reinterpret_cast<const unsigned char*>(tag.data());
|
||||
SHA512(pData, tag.length(), reinterpret_cast<unsigned char*>(pKey->data));
|
||||
|
||||
char *pSql;
|
||||
int length;
|
||||
|
||||
modutil_extract_SQL(const_cast<GWBUF*>(&query), &pSql, &length);
|
||||
|
||||
// Then we store the query itself in the second half of the key.
|
||||
pData = reinterpret_cast<const unsigned char*>(pSql);
|
||||
SHA512(pData, length, reinterpret_cast<unsigned char*>(pKey->data) + SHA512_DIGEST_LENGTH);
|
||||
|
||||
return CACHE_RESULT_OK;
|
||||
}
|
||||
|
||||
void InMemoryStorage::get_config(CACHE_STORAGE_CONFIG* pConfig)
|
||||
{
|
||||
*pConfig = m_config;
|
||||
|
||||
@ -30,8 +30,6 @@ public:
|
||||
const CACHE_STORAGE_CONFIG& config,
|
||||
int argc, char* argv[]);
|
||||
|
||||
static cache_result_t Get_key(const char* zDefault_db, const GWBUF& query, CACHE_KEY* pKey);
|
||||
|
||||
void get_config(CACHE_STORAGE_CONFIG* pConfig);
|
||||
virtual cache_result_t get_info(uint32_t what, json_t** ppInfo) const = 0;
|
||||
virtual cache_result_t get_value(const CACHE_KEY& key, uint32_t flags, GWBUF** ppResult) = 0;
|
||||
|
||||
@ -13,12 +13,10 @@
|
||||
|
||||
#define MXS_MODULE_NAME "storage_rocksdb"
|
||||
#include "rocksdbstorage.hh"
|
||||
#include <openssl/sha.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fts.h>
|
||||
#include <algorithm>
|
||||
#include <set>
|
||||
#include <rocksdb/env.h>
|
||||
#include <rocksdb/statistics.h>
|
||||
#include <maxscale/alloc.h>
|
||||
@ -28,7 +26,6 @@
|
||||
#include "rocksdbinternals.hh"
|
||||
|
||||
using std::for_each;
|
||||
using std::set;
|
||||
using std::string;
|
||||
using std::unique_ptr;
|
||||
|
||||
@ -36,12 +33,6 @@ using std::unique_ptr;
|
||||
namespace
|
||||
{
|
||||
|
||||
const size_t ROCKSDB_KEY_LENGTH = 2 * SHA512_DIGEST_LENGTH;
|
||||
|
||||
#if ROCKSDB_KEY_LENGTH > CACHE_KEY_MAXLEN
|
||||
#error storage_rocksdb key is too long.
|
||||
#endif
|
||||
|
||||
// See https://github.com/facebook/rocksdb/wiki/Basic-Operations#thread-pools
|
||||
// These figures should perhaps depend upon the number of cache instances.
|
||||
const size_t ROCKSDB_N_LOW_THREADS = 2;
|
||||
@ -314,67 +305,6 @@ RocksDBStorage* RocksDBStorage::Create(const char* zName,
|
||||
return sStorage.release();
|
||||
}
|
||||
|
||||
cache_result_t RocksDBStorage::Get_key(const char* zDefault_db, const GWBUF& query, CACHE_KEY* pKey)
|
||||
{
|
||||
ss_dassert(GWBUF_IS_CONTIGUOUS(&query));
|
||||
|
||||
int n;
|
||||
bool fullnames = true;
|
||||
char** pzTables = qc_get_table_names(const_cast<GWBUF*>(&query), &n, fullnames);
|
||||
|
||||
set<string> dbs; // Elements in set are sorted.
|
||||
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
char *zTable = pzTables[i];
|
||||
char *zDot = strchr(zTable, '.');
|
||||
|
||||
if (zDot)
|
||||
{
|
||||
*zDot = 0;
|
||||
dbs.insert(zTable);
|
||||
}
|
||||
else if (zDefault_db)
|
||||
{
|
||||
// If zDefaultDB is NULL, then there will be a table for which we
|
||||
// do not know the database. However, that will fail in the server,
|
||||
// so nothing will be stored.
|
||||
dbs.insert(zDefault_db);
|
||||
}
|
||||
MXS_FREE(zTable);
|
||||
}
|
||||
MXS_FREE(pzTables);
|
||||
|
||||
// dbs now contain each accessed database in sorted order. Now copy them to a single string.
|
||||
string tag;
|
||||
for_each(dbs.begin(), dbs.end(), [&tag](const string & db)
|
||||
{
|
||||
tag.append(db);
|
||||
});
|
||||
|
||||
memset(pKey->data, 0, CACHE_KEY_MAXLEN);
|
||||
|
||||
const unsigned char* pData;
|
||||
|
||||
// We store the databases in the first half of the key. That will ensure that
|
||||
// identical queries targeting different default databases will not clash.
|
||||
// This will also mean that entries related to the same databases will
|
||||
// be placed near each other.
|
||||
pData = reinterpret_cast<const unsigned char*>(tag.data());
|
||||
SHA512(pData, tag.length(), reinterpret_cast<unsigned char*>(pKey->data));
|
||||
|
||||
char *pSql;
|
||||
int length;
|
||||
|
||||
modutil_extract_SQL(const_cast<GWBUF*>(&query), &pSql, &length);
|
||||
|
||||
// Then we store the query itself in the second half of the key.
|
||||
pData = reinterpret_cast<const unsigned char*>(pSql);
|
||||
SHA512(pData, length, reinterpret_cast<unsigned char*>(pKey->data) + SHA512_DIGEST_LENGTH);
|
||||
|
||||
return CACHE_RESULT_OK;
|
||||
}
|
||||
|
||||
void RocksDBStorage::get_config(CACHE_STORAGE_CONFIG* pConfig)
|
||||
{
|
||||
*pConfig = m_config;
|
||||
@ -410,7 +340,7 @@ cache_result_t RocksDBStorage::get_value(const CACHE_KEY& key, uint32_t flags, G
|
||||
{
|
||||
// Use the root DB so that we get the value *with* the timestamp at the end.
|
||||
rocksdb::DB* pDb = m_sDb->GetRootDB();
|
||||
rocksdb::Slice rocksdb_key(key.data, ROCKSDB_KEY_LENGTH);
|
||||
rocksdb::Slice rocksdb_key(reinterpret_cast<const char*>(&key.data), sizeof(key.data));
|
||||
string value;
|
||||
|
||||
rocksdb::Status status = pDb->Get(rocksdb::ReadOptions(), rocksdb_key, &value);
|
||||
@ -497,7 +427,7 @@ cache_result_t RocksDBStorage::put_value(const CACHE_KEY& key, const GWBUF& valu
|
||||
{
|
||||
ss_dassert(GWBUF_IS_CONTIGUOUS(&value));
|
||||
|
||||
rocksdb::Slice rocksdb_key(key.data, ROCKSDB_KEY_LENGTH);
|
||||
rocksdb::Slice rocksdb_key(reinterpret_cast<const char*>(&key.data), sizeof(key.data));
|
||||
rocksdb::Slice rocksdb_value((char*)GWBUF_DATA(&value), GWBUF_LENGTH(&value));
|
||||
|
||||
rocksdb::Status status = m_sDb->Put(Write_options(), rocksdb_key, rocksdb_value);
|
||||
@ -507,7 +437,7 @@ cache_result_t RocksDBStorage::put_value(const CACHE_KEY& key, const GWBUF& valu
|
||||
|
||||
cache_result_t RocksDBStorage::del_value(const CACHE_KEY& key)
|
||||
{
|
||||
rocksdb::Slice rocksdb_key(key.data, ROCKSDB_KEY_LENGTH);
|
||||
rocksdb::Slice rocksdb_key(reinterpret_cast<const char*>(&key.data), sizeof(key.data));
|
||||
|
||||
rocksdb::Status status = m_sDb->Delete(Write_options(), rocksdb_key);
|
||||
|
||||
|
||||
@ -30,8 +30,6 @@ public:
|
||||
int argc, char* argv[]);
|
||||
~RocksDBStorage();
|
||||
|
||||
static cache_result_t Get_key(const char* zDefault_db, const GWBUF& query, CACHE_KEY* pKey);
|
||||
|
||||
void get_config(CACHE_STORAGE_CONFIG* pConfig);
|
||||
cache_result_t get_info(uint32_t flags, json_t** ppInfo) const;
|
||||
cache_result_t get_value(const CACHE_KEY& key, uint32_t flags, GWBUF** ppResult);
|
||||
|
||||
@ -37,21 +37,6 @@ public:
|
||||
return reinterpret_cast<CACHE_STORAGE*>(pStorage);
|
||||
}
|
||||
|
||||
static cache_result_t getKey(const char* zDefault_db,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey)
|
||||
{
|
||||
// zdefault_db may be NULL.
|
||||
ss_dassert(pQuery);
|
||||
ss_dassert(pKey);
|
||||
|
||||
cache_result_t result = CACHE_RESULT_ERROR;
|
||||
|
||||
MXS_EXCEPTION_GUARD(result = StorageType::Get_key(zDefault_db, *pQuery, pKey));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void freeInstance(CACHE_STORAGE* pInstance)
|
||||
{
|
||||
MXS_EXCEPTION_GUARD(delete reinterpret_cast<StorageType*>(pInstance));
|
||||
@ -196,7 +181,6 @@ CACHE_STORAGE_API StorageModule<StorageType>::s_api =
|
||||
{
|
||||
&StorageModule<StorageType>::initialize,
|
||||
&StorageModule<StorageType>::createInstance,
|
||||
&StorageModule<StorageType>::getKey,
|
||||
&StorageModule<StorageType>::freeInstance,
|
||||
&StorageModule<StorageType>::getConfig,
|
||||
&StorageModule<StorageType>::getInfo,
|
||||
|
||||
@ -223,11 +223,3 @@ Storage* StorageFactory::createRawStorage(const char* zName,
|
||||
|
||||
return pStorage;
|
||||
}
|
||||
|
||||
cache_result_t StorageFactory::get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const
|
||||
{
|
||||
return m_pApi->getKey(zDefaultDb, pQuery, pKey);
|
||||
}
|
||||
|
||||
|
||||
13
server/modules/filter/cache/storagefactory.hh
vendored
13
server/modules/filter/cache/storagefactory.hh
vendored
@ -85,19 +85,6 @@ public:
|
||||
const CACHE_STORAGE_CONFIG& config,
|
||||
int argc = 0, char* argv[] = NULL);
|
||||
|
||||
/**
|
||||
* Create a key for a GWBUF.
|
||||
*
|
||||
* @param zDefaultDb The default DB or NULL.
|
||||
* @param query An SQL query. Must be one contiguous buffer.
|
||||
* @param pKey Pointer to object where key will be stored.
|
||||
*
|
||||
* @return CACHE_RESULT_OK if a key was created, otherwise some error code.
|
||||
*/
|
||||
cache_result_t get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const;
|
||||
|
||||
private:
|
||||
StorageFactory(void* handle, CACHE_STORAGE_API* pApi, uint32_t capabilities);
|
||||
|
||||
|
||||
7
server/modules/filter/cache/storagereal.cc
vendored
7
server/modules/filter/cache/storagereal.cc
vendored
@ -38,13 +38,6 @@ cache_result_t StorageReal::get_info(uint32_t flags, json_t** ppInfo) const
|
||||
return m_pApi->getInfo(m_pStorage, flags, ppInfo);
|
||||
}
|
||||
|
||||
cache_result_t StorageReal::get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const
|
||||
{
|
||||
return m_pApi->getKey(zDefaultDb, pQuery, pKey);
|
||||
}
|
||||
|
||||
cache_result_t StorageReal::get_value(const CACHE_KEY& key,
|
||||
uint32_t flags,
|
||||
GWBUF** ppValue) const
|
||||
|
||||
4
server/modules/filter/cache/storagereal.hh
vendored
4
server/modules/filter/cache/storagereal.hh
vendored
@ -25,10 +25,6 @@ public:
|
||||
cache_result_t get_info(uint32_t flags,
|
||||
json_t** ppInfo) const;
|
||||
|
||||
cache_result_t get_key(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey) const;
|
||||
|
||||
cache_result_t get_value(const CACHE_KEY& key,
|
||||
uint32_t flags,
|
||||
GWBUF** ppValue) const;
|
||||
|
||||
3
server/modules/filter/cache/test/tester.cc
vendored
3
server/modules/filter/cache/test/tester.cc
vendored
@ -15,6 +15,7 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
#include "cache.hh"
|
||||
#include "storagefactory.hh"
|
||||
// TODO: Move this to a common place.
|
||||
#include "../../../../../query_classifier/test/testreader.hh"
|
||||
@ -245,7 +246,7 @@ bool Tester::get_cache_items(const Statements& statements,
|
||||
if (pQuery)
|
||||
{
|
||||
CACHE_KEY key;
|
||||
cache_result_t result = factory.get_key(NULL, pQuery, &key);
|
||||
cache_result_t result = Cache::get_default_key(NULL, pQuery, &key);
|
||||
|
||||
if (result == CACHE_RESULT_OK)
|
||||
{
|
||||
|
||||
@ -178,7 +178,7 @@ int TesterStorage::run(size_t n_threads,
|
||||
|
||||
CacheKey key;
|
||||
|
||||
sprintf(key.data, "%lu", i);
|
||||
key.data = i;
|
||||
|
||||
vector<uint8_t> value(size, static_cast<uint8_t>(i));
|
||||
|
||||
|
||||
@ -18,6 +18,7 @@
|
||||
#include <maxscale/query_classifier.h>
|
||||
#include <maxscale/log_manager.h>
|
||||
#include "storagefactory.hh"
|
||||
#include "cache.hh"
|
||||
#include "cache_storage_api.hh"
|
||||
#include "tester.hh"
|
||||
|
||||
@ -60,7 +61,7 @@ int test(StorageFactory& factory, istream& in)
|
||||
if (pQuery)
|
||||
{
|
||||
CACHE_KEY key;
|
||||
cache_result_t result = factory.get_key(NULL, pQuery, &key);
|
||||
cache_result_t result = Cache::get_default_key(NULL, pQuery, &key);
|
||||
|
||||
if (result == CACHE_RESULT_OK)
|
||||
{
|
||||
@ -127,7 +128,7 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||
{
|
||||
if (qc_setup(NULL, NULL) && qc_process_init())
|
||||
if (qc_setup(NULL, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||
{
|
||||
const char* zModule = argv[1];
|
||||
|
||||
@ -158,7 +159,7 @@ int main(int argc, char* argv[])
|
||||
cerr << "error: Could not initialize factory." << endl;
|
||||
}
|
||||
|
||||
qc_process_end();
|
||||
qc_process_end(QC_INIT_BOTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -195,7 +195,7 @@ int test_store()
|
||||
|
||||
GWBUF *packet = create_gwbuf(test_case->query);
|
||||
|
||||
bool matches = cache_rules_should_store(rules, test_case->default_db, packet);
|
||||
bool matches = cache_rules_should_store(rules, 0, test_case->default_db, packet);
|
||||
|
||||
if (matches != test_case->matches)
|
||||
{
|
||||
@ -237,12 +237,12 @@ int main()
|
||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||
{
|
||||
set_libdir(MXS_STRDUP_A("../../../../../query_classifier/qc_sqlite/"));
|
||||
if (qc_setup("qc_sqlite", "") && qc_process_init())
|
||||
if (qc_setup("qc_sqlite", "") && qc_process_init(QC_INIT_BOTH))
|
||||
{
|
||||
set_libdir(MXS_STRDUP_A("../"));
|
||||
rc = test();
|
||||
|
||||
qc_process_end();
|
||||
qc_process_end(QC_INIT_BOTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -50,7 +50,7 @@ int TestStorage::run(int argc, char** argv)
|
||||
{
|
||||
if (mxs_log_init(NULL, ".", MXS_LOG_TARGET_DEFAULT))
|
||||
{
|
||||
if (qc_setup(NULL, NULL) && qc_process_init())
|
||||
if (qc_setup(NULL, NULL) && qc_process_init(QC_INIT_BOTH))
|
||||
{
|
||||
const char* zModule = NULL;
|
||||
size_t threads = m_threads;
|
||||
@ -113,6 +113,8 @@ int TestStorage::run(int argc, char** argv)
|
||||
{
|
||||
cerr << "error: Could not initialize factory " << zModule << "." << endl;
|
||||
}
|
||||
|
||||
qc_process_end(QC_INIT_BOTH);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -2006,7 +2006,7 @@ bool rule_matches(FW_INSTANCE* my_instance,
|
||||
|
||||
if (is_sql)
|
||||
{
|
||||
qc_parse_result_t parse_result = qc_parse(queue);
|
||||
qc_parse_result_t parse_result = qc_parse(queue, QC_COLLECT_ALL);
|
||||
|
||||
if (parse_result == QC_QUERY_INVALID)
|
||||
{
|
||||
|
||||
@ -109,7 +109,6 @@ class AccountRegexp : public MaskingRules::Rule::Account
|
||||
public:
|
||||
~AccountRegexp()
|
||||
{
|
||||
pcre2_match_data_free(m_pData);
|
||||
pcre2_code_free(m_pCode);
|
||||
}
|
||||
|
||||
@ -126,24 +125,10 @@ public:
|
||||
{
|
||||
Closer<pcre2_code*> code(pCode);
|
||||
|
||||
pcre2_match_data* pData = pcre2_match_data_create_from_pattern(pCode, NULL);
|
||||
sAccount = shared_ptr<AccountRegexp>(new AccountRegexp(user, host, pCode));
|
||||
|
||||
if (pData)
|
||||
{
|
||||
Closer<pcre2_match_data*> data(pData);
|
||||
|
||||
sAccount = shared_ptr<AccountRegexp>(new AccountRegexp(user, host, pCode, pData));
|
||||
|
||||
// Ownership of pCode and pData has been moved to the
|
||||
// AccountRegexp instance.
|
||||
data.release();
|
||||
code.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("PCRE2 match data creation failed. Most likely due to a "
|
||||
"lack of available memory.");
|
||||
}
|
||||
// Ownership of pCode has been moved to the AccountRegexp object.
|
||||
code.release();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -171,20 +156,31 @@ public:
|
||||
ss_dassert(zUser);
|
||||
ss_dassert(zHost);
|
||||
|
||||
return
|
||||
(m_user.empty() || (m_user == zUser)) &&
|
||||
pcre2_match(m_pCode, (PCRE2_SPTR)zHost, 0, 0, 0, m_pData, NULL) >= 0;
|
||||
bool rv = (m_user.empty() || (m_user == zUser));
|
||||
|
||||
if (rv)
|
||||
{
|
||||
ss_dassert(m_pCode);
|
||||
pcre2_match_data* pData = pcre2_match_data_create_from_pattern(m_pCode, NULL);
|
||||
|
||||
if (pData)
|
||||
{
|
||||
Closer<pcre2_match_data*> data(pData);
|
||||
|
||||
rv = (pcre2_match(m_pCode, (PCRE2_SPTR)zHost, 0, 0, 0, pData, NULL) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
private:
|
||||
AccountRegexp(const string& user,
|
||||
const string& host,
|
||||
pcre2_code* pCode,
|
||||
pcre2_match_data* pData)
|
||||
pcre2_code* pCode)
|
||||
: m_user(user)
|
||||
, m_host(host)
|
||||
, m_pCode(pCode)
|
||||
, m_pData(pData)
|
||||
{
|
||||
}
|
||||
|
||||
@ -192,10 +188,9 @@ private:
|
||||
AccountRegexp& operator = (const AccountRegexp&);
|
||||
|
||||
private:
|
||||
string m_user;
|
||||
string m_host;
|
||||
pcre2_code* m_pCode;
|
||||
pcre2_match_data* m_pData;
|
||||
string m_user;
|
||||
string m_host;
|
||||
pcre2_code* m_pCode;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -25,8 +25,12 @@ namespace
|
||||
|
||||
const char CAPABILITIES_PARAM[] = "capabilities";
|
||||
|
||||
MXS_ENUM_VALUE capability_values[] =
|
||||
const char* DEFAULT_RCAP_TYPE_NAME = "RCAP_TYPE_NONE";
|
||||
const uint64_t DEFAULT_RCAP_TYPE_VALUE = 0;
|
||||
|
||||
const MXS_ENUM_VALUE capability_values[] =
|
||||
{
|
||||
{ DEFAULT_RCAP_TYPE_NAME, DEFAULT_RCAP_TYPE_VALUE },
|
||||
{ "RCAP_TYPE_STMT_INPUT", RCAP_TYPE_STMT_INPUT },
|
||||
{ "RCAP_TYPE_CONTIGUOUS_INPUT", RCAP_TYPE_CONTIGUOUS_INPUT },
|
||||
{ "RCAP_TYPE_TRANSACTION_TRACKING", RCAP_TYPE_TRANSACTION_TRACKING },
|
||||
@ -36,6 +40,9 @@ MXS_ENUM_VALUE capability_values[] =
|
||||
{ NULL, 0 }
|
||||
};
|
||||
|
||||
size_t RCAP_TYPE_NAME_MAXLEN = 30; // strlen(RCAP_TYPE_TRANSACTION_TRACKING)
|
||||
size_t RCAP_TYPE_COUNT = sizeof(capability_values)/sizeof(capability_values[0]);
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
@ -60,7 +67,13 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||
NULL, /* Thread init. */
|
||||
NULL, /* Thread finish. */
|
||||
{
|
||||
{ CAPABILITIES_PARAM, MXS_MODULE_PARAM_ENUM, NULL, MXS_MODULE_OPT_REQUIRED, capability_values },
|
||||
{
|
||||
CAPABILITIES_PARAM,
|
||||
MXS_MODULE_PARAM_ENUM,
|
||||
DEFAULT_RCAP_TYPE_NAME,
|
||||
MXS_MODULE_OPT_NONE,
|
||||
capability_values
|
||||
},
|
||||
{ MXS_END_MODULE_PARAMS }
|
||||
}
|
||||
};
|
||||
@ -75,7 +88,37 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
||||
NullFilter::NullFilter(const char* zName, uint64_t capabilities)
|
||||
: m_capabilities(capabilities)
|
||||
{
|
||||
MXS_NOTICE("Null filter [%s] created.", zName);
|
||||
const char format[] = "Null filter [%s] created, capabilities: ";
|
||||
|
||||
char message[sizeof(format) + strlen(zName) + (RCAP_TYPE_NAME_MAXLEN + 1) * RCAP_TYPE_COUNT + 1];
|
||||
|
||||
sprintf(message, format, zName);
|
||||
|
||||
if (m_capabilities)
|
||||
{
|
||||
const MXS_ENUM_VALUE* i = capability_values;
|
||||
const MXS_ENUM_VALUE* end = i + RCAP_TYPE_COUNT;
|
||||
|
||||
while (i != end)
|
||||
{
|
||||
if (i->enum_value != 0)
|
||||
{
|
||||
if ((m_capabilities & i->enum_value) == i->enum_value)
|
||||
{
|
||||
strcat(message, " ");
|
||||
strcat(message, i->name);
|
||||
}
|
||||
}
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
strcat(message, " (none)");
|
||||
}
|
||||
|
||||
MXS_NOTICE("%s", message);
|
||||
}
|
||||
|
||||
NullFilter::~NullFilter()
|
||||
|
||||
Reference in New Issue
Block a user