Cache: Take Cache class into use
Now the basic structure is in place: - cachefilter.cc is the MaxScale filter interface. - Cache is the actual cache class that will also handle LRU issues. - SessionCache (sessioncache.cc) is the session specific cache class that using Cache acts as the cache for a particular session. If an item is stale, then one SessionCache will update it. - StorageFactory is the component that is capable of loading a module providing storage facilities. - Storage is the actual key/value store.
This commit is contained in:
parent
719cffd596
commit
14c8a5bb5f
39
server/modules/filter/cache/cache.cc
vendored
39
server/modules/filter/cache/cache.cc
vendored
@ -23,6 +23,42 @@
|
||||
// are being fetches.
|
||||
#define CACHE_PENDING_ITEMS 50
|
||||
|
||||
static const CACHE_CONFIG DEFAULT_CONFIG =
|
||||
{
|
||||
CACHE_DEFAULT_MAX_RESULTSET_ROWS,
|
||||
CACHE_DEFAULT_MAX_RESULTSET_SIZE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
CACHE_DEFAULT_TTL,
|
||||
CACHE_DEFAULT_DEBUG
|
||||
};
|
||||
|
||||
/**
|
||||
* Hashes a cache key to an integer.
|
||||
*
|
||||
* @param key Pointer to cache key.
|
||||
*
|
||||
* @returns Corresponding integer hash.
|
||||
*/
|
||||
static int hash_of_key(const void* key)
|
||||
{
|
||||
int hash = 0;
|
||||
|
||||
const char* i = (const char*)key;
|
||||
const char* end = i + CACHE_KEY_MAXLEN;
|
||||
|
||||
while (i < end)
|
||||
{
|
||||
int c = *i;
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
++i;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int hashfn(const void* address)
|
||||
{
|
||||
@ -62,8 +98,7 @@ Cache* Cache::Create(const char* zName, char** pzOptions, FILTER_PARAMETER** ppP
|
||||
{
|
||||
Cache* pCache = NULL;
|
||||
|
||||
CACHE_CONFIG config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
CACHE_CONFIG config = DEFAULT_CONFIG;
|
||||
|
||||
if (process_params(pzOptions, ppParams, &config))
|
||||
{
|
||||
|
2
server/modules/filter/cache/cache.h
vendored
2
server/modules/filter/cache/cache.h
vendored
@ -65,6 +65,8 @@ public:
|
||||
*/
|
||||
void refreshed(const char* pKey, const SessionCache* pSessionCache);
|
||||
|
||||
const CACHE_CONFIG& config() const { return m_config; }
|
||||
|
||||
cache_result_t getKey(const char* zDefaultDb, const GWBUF* pQuery, char* pKey);
|
||||
|
||||
cache_result_t getValue(const char* pKey, uint32_t flags, GWBUF** ppValue);
|
||||
|
435
server/modules/filter/cache/cachefilter.cc
vendored
435
server/modules/filter/cache/cachefilter.cc
vendored
@ -12,27 +12,21 @@
|
||||
*/
|
||||
|
||||
#define MXS_MODULE_NAME "cache"
|
||||
#include "cachefilter.h"
|
||||
#include <maxscale/alloc.h>
|
||||
#include <maxscale/filter.h>
|
||||
#include <maxscale/gwdirs.h>
|
||||
#include <maxscale/log_manager.h>
|
||||
#include "rules.h"
|
||||
#include "cache.h"
|
||||
#include "sessioncache.h"
|
||||
#include "storage.h"
|
||||
#include "storagefactory.h"
|
||||
|
||||
static char VERSION_STRING[] = "V1.0.0";
|
||||
|
||||
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **);
|
||||
static void *newSession(FILTER *instance, SESSION *session);
|
||||
static void closeSession(FILTER *instance, void *sdata);
|
||||
static void freeSession(FILTER *instance, void *sdata);
|
||||
static void setDownstream(FILTER *instance, void *sdata, DOWNSTREAM *downstream);
|
||||
static void setUpstream(FILTER *instance, void *sdata, UPSTREAM *upstream);
|
||||
static int routeQuery(FILTER *instance, void *sdata, GWBUF *queue);
|
||||
static int clientReply(FILTER *instance, void *sdata, GWBUF *queue);
|
||||
static void diagnostics(FILTER *instance, void *sdata, DCB *dcb);
|
||||
static FILTER* createInstance(const char* zName, char** pzOptions, FILTER_PARAMETER** ppParams);
|
||||
static void* newSession(FILTER* pInstance, SESSION* pSession);
|
||||
static void closeSession(FILTER* pInstance, void* pSessionData);
|
||||
static void freeSession(FILTER* pInstance, void* pSessionData);
|
||||
static void setDownstream(FILTER* pInstance, void* pSessionData, DOWNSTREAM* pDownstream);
|
||||
static void setUpstream(FILTER* pInstance, void* pSessionData, UPSTREAM* pUpstream);
|
||||
static int routeQuery(FILTER* pInstance, void* pSessionData, GWBUF* pPacket);
|
||||
static int clientReply(FILTER* pInstance, void* pSessionData, GWBUF* pPacket);
|
||||
static void diagnostics(FILTER* pInstance, void* pSessionData, DCB* pDcb);
|
||||
static uint64_t getCapabilities(void);
|
||||
|
||||
//
|
||||
@ -86,168 +80,38 @@ extern "C" FILTER_OBJECT *GetModuleObject()
|
||||
};
|
||||
|
||||
//
|
||||
// Implementation
|
||||
//
|
||||
|
||||
static const CACHE_CONFIG DEFAULT_CONFIG =
|
||||
{
|
||||
CACHE_DEFAULT_MAX_RESULTSET_ROWS,
|
||||
CACHE_DEFAULT_MAX_RESULTSET_SIZE,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
CACHE_DEFAULT_TTL,
|
||||
CACHE_DEFAULT_DEBUG
|
||||
};
|
||||
|
||||
static bool process_params(char **options, FILTER_PARAMETER **params, CACHE_CONFIG* config);
|
||||
|
||||
/**
|
||||
* Hashes a cache key to an integer.
|
||||
*
|
||||
* @param key Pointer to cache key.
|
||||
*
|
||||
* @returns Corresponding integer hash.
|
||||
*/
|
||||
int hash_of_key(const void* key)
|
||||
{
|
||||
int hash = 0;
|
||||
|
||||
const char* i = (const char*)key;
|
||||
const char* end = i + CACHE_KEY_MAXLEN;
|
||||
|
||||
while (i < end)
|
||||
{
|
||||
int c = *i;
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
++i;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
static int hashfn(const void* address)
|
||||
{
|
||||
// TODO: Hash the address; pointers are not evenly distributed.
|
||||
return (long)address;
|
||||
}
|
||||
|
||||
static int hashcmp(const void* address1, const void* address2)
|
||||
{
|
||||
return (long)address2 - (long)address1;
|
||||
}
|
||||
|
||||
// Initial size of hashtable used for storing keys of queries that
|
||||
// are being fetches.
|
||||
#define CACHE_PENDING_ITEMS 50
|
||||
|
||||
//
|
||||
// API BEGIN
|
||||
// API Implementation
|
||||
//
|
||||
|
||||
/**
|
||||
* Create an instance of the cache filter for a particular service
|
||||
* within MaxScale.
|
||||
*
|
||||
* @param name The name of the instance (as defined in the config file).
|
||||
* @param options The options for this filter
|
||||
* @param params The array of name/value pair parameters for the filter
|
||||
* @param zName The name of the instance (as defined in the config file).
|
||||
* @param pzOptions The options for this filter
|
||||
* @param ppparams The array of name/value pair parameters for the filter
|
||||
*
|
||||
* @return The instance data for this new instance
|
||||
*/
|
||||
static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER **params)
|
||||
static FILTER *createInstance(const char* zName, char** pzOptions, FILTER_PARAMETER** ppParams)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = NULL;
|
||||
CACHE_CONFIG config = DEFAULT_CONFIG;
|
||||
Cache* pCache = Cache::Create(zName, pzOptions, ppParams);
|
||||
|
||||
if (process_params(options, params, &config))
|
||||
{
|
||||
CACHE_RULES *rules = NULL;
|
||||
|
||||
if (config.rules)
|
||||
{
|
||||
rules = cache_rules_load(config.rules, config.debug);
|
||||
}
|
||||
else
|
||||
{
|
||||
rules = cache_rules_create(config.debug);
|
||||
}
|
||||
|
||||
if (rules)
|
||||
{
|
||||
cinstance = (CACHE_INSTANCE*)MXS_CALLOC(1, sizeof(CACHE_INSTANCE));
|
||||
HASHTABLE* pending = hashtable_alloc(CACHE_PENDING_ITEMS, hashfn, hashcmp);
|
||||
|
||||
if (cinstance && pending)
|
||||
{
|
||||
StorageFactory *factory = StorageFactory::Open(config.storage);
|
||||
|
||||
if (factory)
|
||||
{
|
||||
uint32_t ttl = config.ttl;
|
||||
int argc = config.storage_argc;
|
||||
char** argv = config.storage_argv;
|
||||
|
||||
Storage *storage = factory->createStorage(name, ttl, argc, argv);
|
||||
|
||||
if (storage)
|
||||
{
|
||||
cinstance->name = name;
|
||||
cinstance->config = config;
|
||||
cinstance->rules = rules;
|
||||
cinstance->factory = factory;
|
||||
cinstance->storage = storage;
|
||||
cinstance->pending = pending;
|
||||
|
||||
MXS_NOTICE("Cache storage %s opened and initialized.", config.storage);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Could not create storage instance for '%s'.", name);
|
||||
cache_rules_free(rules);
|
||||
delete factory;
|
||||
MXS_FREE(cinstance);
|
||||
hashtable_free(pending);
|
||||
cinstance = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Could not load cache storage module '%s'.", name);
|
||||
cache_rules_free(rules);
|
||||
MXS_FREE(cinstance);
|
||||
cinstance = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(cinstance);
|
||||
if (pending)
|
||||
{
|
||||
hashtable_free(pending);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (FILTER*)cinstance;
|
||||
return reinterpret_cast<FILTER*>(pCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a new session with this instance of the filter.
|
||||
*
|
||||
* @param instance The cache instance data
|
||||
* @param session The session itself
|
||||
* @param pInstance The cache instance data
|
||||
* @param pSession The session itself
|
||||
*
|
||||
* @return Session specific data for this session
|
||||
*/
|
||||
static void *newSession(FILTER *instance, SESSION *session)
|
||||
static void *newSession(FILTER* pInstance, SESSION* pSession)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
|
||||
SessionCache *pSessionCache = SessionCache::Create(cinstance, session);
|
||||
Cache* pCache = reinterpret_cast<Cache*>(pInstance);
|
||||
SessionCache* pSessionCache = SessionCache::Create(pCache, pSession);
|
||||
|
||||
return pSessionCache;
|
||||
}
|
||||
@ -255,14 +119,12 @@ static void *newSession(FILTER *instance, SESSION *session)
|
||||
/**
|
||||
* A session has been closed.
|
||||
*
|
||||
* @param instance The cache instance data
|
||||
* @param sdata The session data of the session being closed
|
||||
* @param pInstance The cache instance data
|
||||
* @param pSessionData The session data of the session being closed
|
||||
*/
|
||||
static void closeSession(FILTER *instance, void *sdata)
|
||||
static void closeSession(FILTER* pInstance, void* pSessionData)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
pSessionCache->close();
|
||||
}
|
||||
@ -270,14 +132,12 @@ static void closeSession(FILTER *instance, void *sdata)
|
||||
/**
|
||||
* Free the session data.
|
||||
*
|
||||
* @param instance The cache instance data
|
||||
* @param sdata The session data of the session being closed
|
||||
* @param pInstance The cache instance data
|
||||
* @param pSessionData The session data of the session being closed
|
||||
*/
|
||||
static void freeSession(FILTER *instance, void *sdata)
|
||||
static void freeSession(FILTER* pInstance, void* pSessionData)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
delete pSessionCache;
|
||||
}
|
||||
@ -285,84 +145,74 @@ static void freeSession(FILTER *instance, void *sdata)
|
||||
/**
|
||||
* Set the downstream component for this filter.
|
||||
*
|
||||
* @param instance The cache instance data
|
||||
* @param sdata The session data of the session
|
||||
* @param down The downstream filter or router
|
||||
* @param pInstance The cache instance data
|
||||
* @param pSessionData The session data of the session
|
||||
* @param pDownstream The downstream filter or router
|
||||
*/
|
||||
static void setDownstream(FILTER *instance, void *sdata, DOWNSTREAM *down)
|
||||
static void setDownstream(FILTER* pInstance, void* pSessionData, DOWNSTREAM* pDownstream)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
|
||||
pSessionCache->setDownstream(down);
|
||||
pSessionCache->setDownstream(pDownstream);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the upstream component for this filter.
|
||||
*
|
||||
* @param instance The cache instance data
|
||||
* @param sdata The session data of the session
|
||||
* @param up The upstream filter or router
|
||||
* @param pInstance The cache instance data
|
||||
* @param pSessionData The session data of the session
|
||||
* @param pUpstream The upstream filter or router
|
||||
*/
|
||||
static void setUpstream(FILTER *instance, void *sdata, UPSTREAM *up)
|
||||
static void setUpstream(FILTER* pInstance, void* pSessionData, UPSTREAM* pUpstream)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
|
||||
pSessionCache->setUpstream(up);
|
||||
pSessionCache->setUpstream(pUpstream);
|
||||
}
|
||||
|
||||
/**
|
||||
* A request on its way to a backend is delivered to this function.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param sdata The filter session data
|
||||
* @param buffer Buffer containing an MySQL protocol packet.
|
||||
* @param pInstance The filter instance data
|
||||
* @param pSessionData The filter session data
|
||||
* @param pPacket Buffer containing an MySQL protocol packet.
|
||||
*/
|
||||
static int routeQuery(FILTER *instance, void *sdata, GWBUF *packet)
|
||||
static int routeQuery(FILTER* pInstance, void* pSessionData, GWBUF* pPacket)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
|
||||
return pSessionCache->routeQuery(packet);
|
||||
return pSessionCache->routeQuery(pPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* A response on its way to the client is delivered to this function.
|
||||
*
|
||||
* @param instance The filter instance data
|
||||
* @param sdata The filter session data
|
||||
* @param queue The query data
|
||||
* @param pInstance The filter instance data
|
||||
* @param pSessionData The filter session data
|
||||
* @param pPacket The response data
|
||||
*/
|
||||
static int clientReply(FILTER *instance, void *sdata, GWBUF *data)
|
||||
static int clientReply(FILTER* pInstance, void* pSessionData, GWBUF* pPacket)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
|
||||
return pSessionCache->clientReply(data);
|
||||
return pSessionCache->clientReply(pPacket);
|
||||
}
|
||||
|
||||
/**
|
||||
* Diagnostics routine
|
||||
*
|
||||
* If csdata is NULL then print diagnostics on the instance as a whole,
|
||||
* If cpSessionData is NULL then print diagnostics on the instance as a whole,
|
||||
* otherwise print diagnostics for the particular session.
|
||||
*
|
||||
* @param instance The filter instance
|
||||
* @param fsession Filter session, may be NULL
|
||||
* @param dcb The DCB for diagnostic output
|
||||
* @param pInstance The filter instance
|
||||
* @param pSessionData Filter session, may be NULL
|
||||
* @param pDcb The DCB for diagnostic output
|
||||
*/
|
||||
static void diagnostics(FILTER *instance, void *sdata, DCB *dcb)
|
||||
static void diagnostics(FILTER* pInstance, void* pSessionData, DCB* pDcb)
|
||||
{
|
||||
CACHE_INSTANCE *cinstance = (CACHE_INSTANCE*)instance;
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(pSessionData);
|
||||
|
||||
SessionCache* pSessionCache = static_cast<SessionCache*>(sdata);
|
||||
|
||||
pSessionCache->diagnostics(dcb);
|
||||
pSessionCache->diagnostics(pDcb);
|
||||
}
|
||||
|
||||
|
||||
@ -375,166 +225,3 @@ static uint64_t getCapabilities(void)
|
||||
{
|
||||
return RCAP_TYPE_TRANSACTION_TRACKING;
|
||||
}
|
||||
|
||||
//
|
||||
// API END
|
||||
//
|
||||
|
||||
/**
|
||||
* Processes the cache params
|
||||
*
|
||||
* @param options Options as passed to the filter.
|
||||
* @param params Parameters as passed to the filter.
|
||||
* @param config Pointer to config instance where params will be stored.
|
||||
*
|
||||
* @return True if all parameters could be processed, false otherwise.
|
||||
*/
|
||||
static bool process_params(char **options, FILTER_PARAMETER **params, CACHE_CONFIG* config)
|
||||
{
|
||||
bool error = false;
|
||||
|
||||
for (int i = 0; params[i]; ++i)
|
||||
{
|
||||
const FILTER_PARAMETER *param = params[i];
|
||||
|
||||
if (strcmp(param->name, "max_resultset_rows") == 0)
|
||||
{
|
||||
int v = atoi(param->value);
|
||||
|
||||
if (v > 0)
|
||||
{
|
||||
config->max_resultset_rows = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
config->max_resultset_rows = CACHE_DEFAULT_MAX_RESULTSET_ROWS;
|
||||
}
|
||||
}
|
||||
else if (strcmp(param->name, "max_resultset_size") == 0)
|
||||
{
|
||||
int v = atoi(param->value);
|
||||
|
||||
if (v > 0)
|
||||
{
|
||||
config->max_resultset_size = v * 1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("The value of the configuration entry '%s' must "
|
||||
"be an integer larger than 0.", param->name);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else if (strcmp(param->name, "rules") == 0)
|
||||
{
|
||||
if (*param->value == '/')
|
||||
{
|
||||
config->rules = MXS_STRDUP(param->value);
|
||||
}
|
||||
else
|
||||
{
|
||||
const char *datadir = get_datadir();
|
||||
size_t len = strlen(datadir) + 1 + strlen(param->value) + 1;
|
||||
|
||||
char *rules = (char*)MXS_MALLOC(len);
|
||||
|
||||
if (rules)
|
||||
{
|
||||
sprintf(rules, "%s/%s", datadir, param->value);
|
||||
config->rules = rules;
|
||||
}
|
||||
}
|
||||
|
||||
if (!config->rules)
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else if (strcmp(param->name, "storage_options") == 0)
|
||||
{
|
||||
config->storage_options = MXS_STRDUP(param->value);
|
||||
|
||||
if (config->storage_options)
|
||||
{
|
||||
int argc = 1;
|
||||
char *arg = config->storage_options;
|
||||
|
||||
while ((arg = strchr(config->storage_options, ',')))
|
||||
{
|
||||
++argc;
|
||||
}
|
||||
|
||||
config->storage_argv = (char**) MXS_MALLOC((argc + 1) * sizeof(char*));
|
||||
|
||||
if (config->storage_argv)
|
||||
{
|
||||
config->storage_argc = argc;
|
||||
|
||||
int i = 0;
|
||||
arg = config->storage_options;
|
||||
config->storage_argv[i++] = arg;
|
||||
|
||||
while ((arg = strchr(config->storage_options, ',')))
|
||||
{
|
||||
*arg = 0;
|
||||
++arg;
|
||||
config->storage_argv[i++] = arg;
|
||||
}
|
||||
|
||||
config->storage_argv[i] = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_FREE(config->storage_options);
|
||||
config->storage_options = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else if (strcmp(param->name, "storage") == 0)
|
||||
{
|
||||
config->storage = param->value;
|
||||
}
|
||||
else if (strcmp(param->name, "ttl") == 0)
|
||||
{
|
||||
int v = atoi(param->value);
|
||||
|
||||
if (v > 0)
|
||||
{
|
||||
config->ttl = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("The value of the configuration entry '%s' must "
|
||||
"be an integer larger than 0.", param->name);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else if (strcmp(param->name, "debug") == 0)
|
||||
{
|
||||
int v = atoi(param->value);
|
||||
|
||||
if ((v >= CACHE_DEBUG_MIN) && (v <= CACHE_DEBUG_MAX))
|
||||
{
|
||||
config->debug = v;
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("The value of the configuration entry '%s' must "
|
||||
"be between %d and %d, inclusive.",
|
||||
param->name, CACHE_DEBUG_MIN, CACHE_DEBUG_MAX);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
else if (!filter_standard_parameter(params[i]->name))
|
||||
{
|
||||
MXS_ERROR("Unknown configuration entry '%s'.", param->name);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !error;
|
||||
}
|
||||
|
13
server/modules/filter/cache/cachefilter.h
vendored
13
server/modules/filter/cache/cachefilter.h
vendored
@ -57,17 +57,4 @@ typedef struct cache_config
|
||||
uint32_t debug;
|
||||
} CACHE_CONFIG;
|
||||
|
||||
typedef struct cache_instance
|
||||
{
|
||||
const char *name; // The name of the instance; the section name in the config.
|
||||
CACHE_CONFIG config; // The configuration of the cache instance.
|
||||
CACHE_RULES *rules; // The rules of the cache instance.
|
||||
StorageFactory *factory; // The storage factory.
|
||||
Storage *storage; // The storage instance to use.
|
||||
HASHTABLE *pending; // Pending items; being fetched from the backend.
|
||||
SPINLOCK pending_lock; // Lock used for protecting 'pending'.
|
||||
} CACHE_INSTANCE;
|
||||
|
||||
int hash_of_key(const void* key);
|
||||
|
||||
#endif
|
||||
|
61
server/modules/filter/cache/sessioncache.cc
vendored
61
server/modules/filter/cache/sessioncache.cc
vendored
@ -11,6 +11,7 @@
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#define MXS_MODULE_NAME "cache"
|
||||
#include "sessioncache.h"
|
||||
#include <new>
|
||||
#include <maxscale/alloc.h>
|
||||
@ -18,13 +19,10 @@
|
||||
#include <maxscale/mysql_utils.h>
|
||||
#include "storage.h"
|
||||
|
||||
#define DUMMY_VALUE (void*)0xdeadbeef
|
||||
|
||||
SessionCache::SessionCache(CACHE_INSTANCE* pInstance, SESSION* pSession, char* zDefaultDb)
|
||||
SessionCache::SessionCache(Cache* pCache, SESSION* pSession, char* zDefaultDb)
|
||||
: m_state(CACHE_EXPECTING_NOTHING)
|
||||
, m_pInstance(pInstance)
|
||||
, m_pCache(pCache)
|
||||
, m_pSession(pSession)
|
||||
, m_pStorage(pInstance->storage)
|
||||
, m_zDefaultDb(zDefaultDb)
|
||||
, m_zUseDb(NULL)
|
||||
, m_refreshing(false)
|
||||
@ -43,7 +41,7 @@ SessionCache::~SessionCache()
|
||||
}
|
||||
|
||||
//static
|
||||
SessionCache* SessionCache::Create(CACHE_INSTANCE* pInstance, SESSION* pSession)
|
||||
SessionCache* SessionCache::Create(Cache* pCache, SESSION* pSession)
|
||||
{
|
||||
SessionCache* pSessionCache = NULL;
|
||||
|
||||
@ -60,7 +58,7 @@ SessionCache* SessionCache::Create(CACHE_INSTANCE* pInstance, SESSION* pSession)
|
||||
|
||||
if ((pMysqlSession->db[0] == 0) || zDefaultDb)
|
||||
{
|
||||
pSessionCache = new (std::nothrow) SessionCache(pInstance, pSession, zDefaultDb);
|
||||
pSessionCache = new (std::nothrow) SessionCache(pCache, pSession, zDefaultDb);
|
||||
|
||||
if (!pSessionCache)
|
||||
{
|
||||
@ -140,9 +138,9 @@ int SessionCache::routeQuery(GWBUF* pPacket)
|
||||
if ((session_is_autocommit(session) && !session_trx_is_active(session)) ||
|
||||
session_trx_is_read_only(session))
|
||||
{
|
||||
if (cache_rules_should_store(m_pInstance->rules, m_zDefaultDb, pPacket))
|
||||
if (m_pCache->shouldStore(m_zDefaultDb, pPacket))
|
||||
{
|
||||
if (cache_rules_should_use(m_pInstance->rules, m_pSession))
|
||||
if (m_pCache->shouldUse(m_pSession))
|
||||
{
|
||||
GWBUF* pResponse;
|
||||
cache_result_t result = get_cached_response(pPacket, &pResponse);
|
||||
@ -154,21 +152,7 @@ int SessionCache::routeQuery(GWBUF* pPacket)
|
||||
// The value was found, but it was stale. Now we need to
|
||||
// figure out whether somebody else is already fetching it.
|
||||
|
||||
long key = hash_of_key(m_key);
|
||||
|
||||
spinlock_acquire(&m_pInstance->pending_lock);
|
||||
// TODO: Remove the internal locking of hashtable. The internal
|
||||
// TODO: locking is no good if you need transactional behaviour.
|
||||
// TODO: Now we lock twice.
|
||||
void *value = hashtable_fetch(m_pInstance->pending, (void*)key);
|
||||
if (!value)
|
||||
{
|
||||
// It's not being fetched, so we make a note that we are.
|
||||
hashtable_add(m_pInstance->pending, (void*)key, DUMMY_VALUE);
|
||||
}
|
||||
spinlock_release(&m_pInstance->pending_lock);
|
||||
|
||||
if (!value)
|
||||
if (m_pCache->mustRefresh(m_key, this))
|
||||
{
|
||||
// We were the first ones who hit the stale item. It's
|
||||
// our responsibility now to fetch it.
|
||||
@ -229,7 +213,7 @@ int SessionCache::routeQuery(GWBUF* pPacket)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pInstance->config.debug & CACHE_DEBUG_DECISIONS)
|
||||
if (log_decisions())
|
||||
{
|
||||
MXS_NOTICE("autocommit = %s and transaction state %s => Not using or "
|
||||
"storing to cache.",
|
||||
@ -268,14 +252,14 @@ int SessionCache::clientReply(GWBUF* pData)
|
||||
|
||||
if (m_state != CACHE_IGNORING_RESPONSE)
|
||||
{
|
||||
if (gwbuf_length(m_res.pData) > m_pInstance->config.max_resultset_size)
|
||||
if (gwbuf_length(m_res.pData) > m_pCache->config().max_resultset_size)
|
||||
{
|
||||
if (m_pInstance->config.debug & CACHE_DEBUG_DECISIONS)
|
||||
if (log_decisions())
|
||||
{
|
||||
MXS_NOTICE("Current size %uB of resultset, at least as much "
|
||||
"as maximum allowed size %uKiB. Not caching.",
|
||||
gwbuf_length(m_res.pData),
|
||||
m_pInstance->config.max_resultset_size / 1024);
|
||||
m_pCache->config().max_resultset_size / 1024);
|
||||
}
|
||||
|
||||
m_state = CACHE_IGNORING_RESPONSE;
|
||||
@ -503,9 +487,9 @@ int SessionCache::handle_expecting_rows()
|
||||
m_res.offset += packetlen;
|
||||
++m_res.nRows;
|
||||
|
||||
if (m_res.nRows > m_pInstance->config.max_resultset_rows)
|
||||
if (m_res.nRows > m_pCache->config().max_resultset_rows)
|
||||
{
|
||||
if (m_pInstance->config.debug & CACHE_DEBUG_DECISIONS)
|
||||
if (log_decisions())
|
||||
{
|
||||
MXS_NOTICE("Max rows %lu reached, not caching result.", m_res.nRows);
|
||||
}
|
||||
@ -623,13 +607,13 @@ void SessionCache::reset_response_state()
|
||||
*/
|
||||
cache_result_t SessionCache::get_cached_response(const GWBUF *pQuery, GWBUF **ppResponse)
|
||||
{
|
||||
cache_result_t result = m_pStorage->getKey(m_zDefaultDb, pQuery, m_key);
|
||||
cache_result_t result = m_pCache->getKey(m_zDefaultDb, pQuery, m_key);
|
||||
|
||||
if (result == CACHE_RESULT_OK)
|
||||
{
|
||||
uint32_t flags = CACHE_FLAGS_INCLUDE_STALE;
|
||||
|
||||
result = m_pStorage->getValue(m_key, flags, ppResponse);
|
||||
result = m_pCache->getValue(m_key, flags, ppResponse);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -654,13 +638,13 @@ void SessionCache::store_result()
|
||||
{
|
||||
m_res.pData = pData;
|
||||
|
||||
cache_result_t result = m_pStorage->putValue(m_key, m_res.pData);
|
||||
cache_result_t result = m_pCache->putValue(m_key, m_res.pData);
|
||||
|
||||
if (result != CACHE_RESULT_OK)
|
||||
{
|
||||
MXS_ERROR("Could not store cache item, deleting it.");
|
||||
|
||||
result = m_pStorage->delValue(m_key);
|
||||
result = m_pCache->delValue(m_key);
|
||||
|
||||
if ((result != CACHE_RESULT_OK) || (result != CACHE_RESULT_NOT_FOUND))
|
||||
{
|
||||
@ -671,14 +655,7 @@ void SessionCache::store_result()
|
||||
|
||||
if (m_refreshing)
|
||||
{
|
||||
long key = hash_of_key(m_key);
|
||||
|
||||
spinlock_acquire(&m_pInstance->pending_lock);
|
||||
ss_dassert(hashtable_fetch(m_pInstance->pending, (void*)key) == DUMMY_VALUE);
|
||||
ss_debug(int n =) hashtable_delete(m_pInstance->pending, (void*)key);
|
||||
ss_dassert(n == 1);
|
||||
spinlock_release(&m_pInstance->pending_lock);
|
||||
|
||||
m_pCache->refreshed(m_key, this);
|
||||
m_refreshing = false;
|
||||
}
|
||||
}
|
||||
|
14
server/modules/filter/cache/sessioncache.h
vendored
14
server/modules/filter/cache/sessioncache.h
vendored
@ -15,9 +15,12 @@
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <maxscale/buffer.h>
|
||||
#include <maxscale/filter.h>
|
||||
#include "cache.h"
|
||||
#include "cachefilter.h"
|
||||
#include "cache_storage_api.h"
|
||||
|
||||
class Cache;
|
||||
|
||||
class SessionCache
|
||||
{
|
||||
public:
|
||||
@ -48,7 +51,7 @@ public:
|
||||
/**
|
||||
* Creates a SessionCache instance.
|
||||
*
|
||||
* @param pInstance Pointer to the cache instance to which this session cache
|
||||
* @param pCache Pointer to the cache instance to which this session cache
|
||||
* belongs. Must remain valid for the lifetime of the SessionCache
|
||||
* instance being created.
|
||||
* @param pSession Pointer to the session this session cache instance is
|
||||
@ -57,7 +60,7 @@ public:
|
||||
*
|
||||
* @return A new instance or NULL if memory allocation fails.
|
||||
*/
|
||||
static SessionCache* Create(CACHE_INSTANCE* pInstance, SESSION* pSession);
|
||||
static SessionCache* Create(Cache* pCache, SESSION* pSession);
|
||||
|
||||
/**
|
||||
* The session has been closed.
|
||||
@ -113,22 +116,21 @@ private:
|
||||
|
||||
bool log_decisions() const
|
||||
{
|
||||
return m_pInstance->config.debug & CACHE_DEBUG_DECISIONS ? true : false;
|
||||
return m_pCache->config().debug & CACHE_DEBUG_DECISIONS ? true : false;
|
||||
}
|
||||
|
||||
void store_result();
|
||||
|
||||
private:
|
||||
SessionCache(CACHE_INSTANCE* pInstance, SESSION* pSession, char* zDefaultDb);
|
||||
SessionCache(Cache* pCache, SESSION* pSession, char* zDefaultDb);
|
||||
|
||||
SessionCache(const SessionCache&);
|
||||
SessionCache& operator = (const SessionCache&);
|
||||
|
||||
private:
|
||||
cache_session_state_t m_state; /**< What state is the session in, what data is expected. */
|
||||
CACHE_INSTANCE* m_pInstance; /**< The cache instance the session is associated with. */
|
||||
Cache* m_pCache; /**< The cache instance the session is associated with. */
|
||||
SESSION* m_pSession; /**< The session this data is associated with. */
|
||||
Storage* m_pStorage; /**< The storage to be used with this session data. */
|
||||
DOWNSTREAM m_down; /**< The previous filter or equivalent. */
|
||||
UPSTREAM m_up; /**< The next filter or equivalent. */
|
||||
CACHE_RESPONSE_STATE m_res; /**< The response state. */
|
||||
|
Loading…
x
Reference in New Issue
Block a user