Merge branch '2.1' into develop

This commit is contained in:
Markus Mäkelä
2017-03-22 15:20:21 +02:00
107 changed files with 3365 additions and 3638 deletions

View File

@ -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);

View File

@ -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

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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.
*

View File

@ -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;
}
};

View File

@ -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)
{

View File

@ -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;

View File

@ -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";
}

View File

@ -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

View File

@ -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);

View File

@ -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
{

View File

@ -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);

View File

@ -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);
}

View File

@ -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

View File

@ -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.
*

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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)
{

View File

@ -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));

View File

@ -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
{

View File

@ -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
{

View File

@ -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
{

View File

@ -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)
{

View File

@ -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;
};
/**

View File

@ -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()