MXS-1475 Introduce @maxscale.cache.[soft_ttl|hard_ttl]
Now it is possible to control the soft and hard ttl of the cache on a session basis. That is, it is possible to use different TTLs for different SELECTs.
This commit is contained in:
parent
2c49f90bc4
commit
51251fd9f3
@ -378,6 +378,61 @@ SELECT @maxscale.cache.use;
|
||||
```
|
||||
but only after it has explicitly been set once.
|
||||
|
||||
### `@maxscale.cache.soft_ttl`
|
||||
Using the variable `@maxscale.cache.soft_ttl` it is possible to specify
|
||||
at runtime what _soft ttl_ should be applied. Its initial value is the
|
||||
value of the configuration parameter `soft_ttl`. That is, by default the
|
||||
value is 0.
|
||||
|
||||
The purpose of this variable is make it possible for an application to decide
|
||||
statement by statement what _soft ttl_ should be applied.
|
||||
```
|
||||
set @maxscale.cache.soft_ttl=600;
|
||||
SELECT a, b FROM unimportant;
|
||||
set @maxscale.cache.soft_ttl=60;
|
||||
SELECT c, d FROM important;
|
||||
```
|
||||
When data is `SELECT`ed from the unimportant table `unimportant`, the data
|
||||
will be returned from the cache provided it is no older than 10 minutes,
|
||||
but when data is `SELECT`ed from the important table `important`, the
|
||||
data will be returned from the cache provided it is no older than 1 minute.
|
||||
|
||||
Note that `@maxscale.cache.hard_ttl` overrules `@maxscale.cache.soft_ttl`
|
||||
in the sense that if the former is less that the latter, then _soft ttl_
|
||||
will, when used, be adjusted down to the value of _hard ttl_.
|
||||
|
||||
The value of `@maxscale.cache.soft_ttl` can be queried
|
||||
```
|
||||
SELECT @maxscale.cache.soft_ttl;
|
||||
```
|
||||
but only after it has explicitly been set once.
|
||||
|
||||
### `@maxscale.cache.hard_ttl`
|
||||
Using the variable `@maxscale.cache.hard_ttl` it is possible to specify
|
||||
at runtime what _hard ttl_ should be applied. Its initial value is the
|
||||
value of the configuration parameter `hard_ttl`. That is, by default the
|
||||
value is 0.
|
||||
|
||||
The purpose of this variable is make it possible for an application to decide
|
||||
statement by statement what _hard ttl_ should be applied.
|
||||
|
||||
Note that as `@maxscale.cache.hard_ttl` overrules `@maxscale.cache.soft_ttl`,
|
||||
is is important to ensure that the former is at least as large as the latter
|
||||
and for best overall performance that it is larger.
|
||||
|
||||
```
|
||||
set @maxscale.cache.soft_ttl=600, @maxscale.cache.hard_ttl=610;
|
||||
SELECT a, b FROM unimportant;
|
||||
set @maxscale.cache.soft_ttl=60, @maxscale.cache.hard_ttl=65;
|
||||
SELECT c, d FROM important;
|
||||
```
|
||||
|
||||
The value of `@maxscale.cache.hard_ttl` can be queried
|
||||
```
|
||||
SELECT @maxscale.cache.hard_ttl;
|
||||
```
|
||||
but only after it has explicitly been set once.
|
||||
|
||||
### Client Driven Caching
|
||||
With `@maxscale.cache.populate` and `@maxscale.cache.use` is it possible
|
||||
to make the caching completely client driven.
|
||||
|
226
server/modules/filter/cache/cachefiltersession.cc
vendored
226
server/modules/filter/cache/cachefiltersession.cc
vendored
@ -39,7 +39,9 @@ namespace
|
||||
{
|
||||
|
||||
const char SV_MAXSCALE_CACHE_POPULATE[] = "@maxscale.cache.populate";
|
||||
const char SV_MAXSCALE_CACHE_USE[] = "@maxscale.cache.use";
|
||||
const char SV_MAXSCALE_CACHE_USE[] = "@maxscale.cache.use";
|
||||
const char SV_MAXSCALE_CACHE_SOFT_TTL[] = "@maxscale.cache.soft_ttl";
|
||||
const char SV_MAXSCALE_CACHE_HARD_TTL[] = "@maxscale.cache.hard_ttl";
|
||||
|
||||
const char* NON_CACHEABLE_FUNCTIONS[] =
|
||||
{
|
||||
@ -198,20 +200,40 @@ CacheFilterSession::CacheFilterSession(MXS_SESSION* pSession, Cache* pCache, cha
|
||||
reset_response_state();
|
||||
|
||||
if (!session_add_variable(pSession, SV_MAXSCALE_CACHE_POPULATE,
|
||||
&CacheFilterSession::session_variable_handler, this))
|
||||
&CacheFilterSession::set_cache_populate, this))
|
||||
{
|
||||
ss_dassert(!true);
|
||||
MXS_ERROR("Could not add MaxScale user variable '%s', dynamically "
|
||||
"enabling/disabling the populating of the cache is not possible.",
|
||||
SV_MAXSCALE_CACHE_POPULATE);
|
||||
}
|
||||
|
||||
if (!session_add_variable(pSession, SV_MAXSCALE_CACHE_USE,
|
||||
&CacheFilterSession::session_variable_handler, this))
|
||||
&CacheFilterSession::set_cache_use, this))
|
||||
{
|
||||
ss_dassert(!true);
|
||||
MXS_ERROR("Could not add MaxScale user variable '%s', dynamically "
|
||||
"enabling/disabling the using of the cache not possible.",
|
||||
SV_MAXSCALE_CACHE_USE);
|
||||
}
|
||||
|
||||
if (!session_add_variable(pSession, SV_MAXSCALE_CACHE_SOFT_TTL,
|
||||
&CacheFilterSession::set_cache_soft_ttl, this))
|
||||
{
|
||||
ss_dassert(!true);
|
||||
MXS_ERROR("Could not add MaxScale user variable '%s', dynamically "
|
||||
"setting the soft TTL not possible.",
|
||||
SV_MAXSCALE_CACHE_SOFT_TTL);
|
||||
}
|
||||
|
||||
if (!session_add_variable(pSession, SV_MAXSCALE_CACHE_HARD_TTL,
|
||||
&CacheFilterSession::set_cache_hard_ttl, this))
|
||||
{
|
||||
ss_dassert(!true);
|
||||
MXS_ERROR("Could not add MaxScale user variable '%s', dynamically "
|
||||
"setting the hard TTL not possible.",
|
||||
SV_MAXSCALE_CACHE_HARD_TTL);
|
||||
}
|
||||
}
|
||||
|
||||
CacheFilterSession::~CacheFilterSession()
|
||||
@ -1172,54 +1194,200 @@ bool get_truth_value(const char* begin, const char* end, bool* pValue)
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool get_uint32_value(const char* begin, const char* end, uint32_t* pValue)
|
||||
{
|
||||
bool rv = false;
|
||||
|
||||
size_t len = end - begin;
|
||||
char copy[len + 1];
|
||||
|
||||
memcpy(copy, begin, len);
|
||||
copy[len] = 0;
|
||||
|
||||
errno = 0;
|
||||
char* p;
|
||||
long int l = strtol(copy, &p, 10);
|
||||
|
||||
if ((errno == 0) && (*p == 0))
|
||||
{
|
||||
if (l >= 0)
|
||||
{
|
||||
*pValue = l;
|
||||
rv = true;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
char* CacheFilterSession::handle_session_variable(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
char* create_bool_error_message(const char* zName, const char* pValue_begin, const char* pValue_end)
|
||||
{
|
||||
static const char FORMAT[] = "The variable %s can only have the values true/false/1/0";
|
||||
int n = snprintf(NULL, 0, FORMAT, zName) + 1;
|
||||
|
||||
char* zMessage = static_cast<char*>(MXS_MALLOC(n));
|
||||
|
||||
if (zMessage)
|
||||
{
|
||||
sprintf(zMessage, FORMAT, zName);
|
||||
}
|
||||
|
||||
int len = pValue_end - pValue_begin;
|
||||
MXS_WARNING("Attempt to set the variable %s to the invalid value \"%.*s\".",
|
||||
zName, len, pValue_begin);
|
||||
|
||||
return zMessage;
|
||||
}
|
||||
|
||||
char* create_uint32_error_message(const char* zName, const char* pValue_begin, const char* pValue_end)
|
||||
{
|
||||
static const char FORMAT[] = "The variable %s can have as value 0 or a positive integer.";
|
||||
int n = snprintf(NULL, 0, FORMAT, zName) + 1;
|
||||
|
||||
char* zMessage = static_cast<char*>(MXS_MALLOC(n));
|
||||
|
||||
if (zMessage)
|
||||
{
|
||||
sprintf(zMessage, FORMAT, zName);
|
||||
}
|
||||
|
||||
int len = pValue_end - pValue_begin;
|
||||
MXS_WARNING("Attempt to set the variable %s to the invalid value \"%.*s\".",
|
||||
zName, len, pValue_begin);
|
||||
|
||||
return zMessage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
char* CacheFilterSession::set_cache_populate(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
ss_dassert(strcmp(SV_MAXSCALE_CACHE_POPULATE, zName) == 0);
|
||||
|
||||
char* zMessage = NULL;
|
||||
|
||||
bool enabled;
|
||||
|
||||
if (get_truth_value(pValue_begin, pValue_end, &enabled))
|
||||
{
|
||||
if (strcmp(zName, SV_MAXSCALE_CACHE_POPULATE) == 0)
|
||||
{
|
||||
m_populate = enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss_dassert(strcmp(zName, SV_MAXSCALE_CACHE_USE) == 0);
|
||||
m_use = enabled;
|
||||
}
|
||||
m_populate = enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
static const char FORMAT[] = "The variable %s can only have the values true/false/1/0";
|
||||
int n = snprintf(NULL, 0, FORMAT, zName) + 1;
|
||||
zMessage = create_bool_error_message(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
zMessage = static_cast<char*>(MXS_MALLOC(n));
|
||||
return zMessage;
|
||||
}
|
||||
|
||||
if (zMessage)
|
||||
{
|
||||
sprintf(zMessage, FORMAT, zName);
|
||||
}
|
||||
char* CacheFilterSession::set_cache_use(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
ss_dassert(strcmp(SV_MAXSCALE_CACHE_USE, zName) == 0);
|
||||
|
||||
MXS_WARNING("Attempt to set the variable %s to the invalid value \"%.*s\".",
|
||||
zName, n, pValue_begin);
|
||||
char* zMessage = NULL;
|
||||
|
||||
bool enabled;
|
||||
|
||||
if (get_truth_value(pValue_begin, pValue_end, &enabled))
|
||||
{
|
||||
m_use = enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
zMessage = create_bool_error_message(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
return zMessage;
|
||||
}
|
||||
|
||||
char* CacheFilterSession::set_cache_soft_ttl(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
ss_dassert(strcmp(SV_MAXSCALE_CACHE_SOFT_TTL, zName) == 0);
|
||||
|
||||
char* zMessage = NULL;
|
||||
|
||||
uint32_t value;
|
||||
|
||||
if (get_uint32_value(pValue_begin, pValue_end, &value))
|
||||
{
|
||||
m_soft_ttl = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
zMessage = create_uint32_error_message(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
return zMessage;
|
||||
}
|
||||
|
||||
char* CacheFilterSession::set_cache_hard_ttl(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
ss_dassert(strcmp(SV_MAXSCALE_CACHE_HARD_TTL, zName) == 0);
|
||||
|
||||
char* zMessage = NULL;
|
||||
|
||||
uint32_t value;
|
||||
|
||||
if (get_uint32_value(pValue_begin, pValue_end, &value))
|
||||
{
|
||||
m_hard_ttl = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
zMessage = create_uint32_error_message(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
return zMessage;
|
||||
}
|
||||
|
||||
//static
|
||||
char* CacheFilterSession::session_variable_handler(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
char* CacheFilterSession::set_cache_populate(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
CacheFilterSession* pThis = static_cast<CacheFilterSession*>(pContext);
|
||||
|
||||
return pThis->handle_session_variable(zName, pValue_begin, pValue_end);
|
||||
return pThis->set_cache_populate(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
//static
|
||||
char* CacheFilterSession::set_cache_use(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
CacheFilterSession* pThis = static_cast<CacheFilterSession*>(pContext);
|
||||
|
||||
return pThis->set_cache_use(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
//static
|
||||
char* CacheFilterSession::set_cache_soft_ttl(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
CacheFilterSession* pThis = static_cast<CacheFilterSession*>(pContext);
|
||||
|
||||
return pThis->set_cache_soft_ttl(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
||||
//static
|
||||
char* CacheFilterSession::set_cache_hard_ttl(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end)
|
||||
{
|
||||
CacheFilterSession* pThis = static_cast<CacheFilterSession*>(pContext);
|
||||
|
||||
return pThis->set_cache_hard_ttl(zName, pValue_begin, pValue_end);
|
||||
}
|
||||
|
@ -141,14 +141,35 @@ private:
|
||||
routing_action_t route_COM_QUERY(GWBUF* pPacket);
|
||||
routing_action_t route_SELECT(cache_action_t action, GWBUF* pPacket);
|
||||
|
||||
char* handle_session_variable(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
char* set_cache_populate(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
char* set_cache_use(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
char* set_cache_soft_ttl(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
char* set_cache_hard_ttl(const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
|
||||
static char* session_variable_handler(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
static char* set_cache_populate(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
static char* set_cache_use(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
static char* set_cache_soft_ttl(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
static char* set_cache_hard_ttl(void* pContext,
|
||||
const char* zName,
|
||||
const char* pValue_begin,
|
||||
const char* pValue_end);
|
||||
|
||||
private:
|
||||
CacheFilterSession(MXS_SESSION* pSession, Cache* pCache, char* zDefaultDb);
|
||||
|
Loading…
x
Reference in New Issue
Block a user