MXS-2253 Make Cache use the new duration config type
Internally the Cache used seconds, so some changes were needed.
This commit is contained in:
@ -5,53 +5,7 @@ This filter was introduced in MariaDB MaxScale 2.1.
|
|||||||
Table of Contents
|
Table of Contents
|
||||||
=================
|
=================
|
||||||
|
|
||||||
* [Overview](#overview)
|
[TOC]
|
||||||
* [Limitations](#limitations)
|
|
||||||
* [Invalidation](#invalidation)
|
|
||||||
* [Prepared Statements](#prepared-statements)
|
|
||||||
* [Security](#security)
|
|
||||||
* [Configuration](#configuration)
|
|
||||||
* [Filter Parameters](#filter-parameters)
|
|
||||||
* [storage](#storage)
|
|
||||||
* [storage_options](#storage_options)
|
|
||||||
* [hard_ttl](#hard_ttl)
|
|
||||||
* [soft_ttl](#soft_ttl)
|
|
||||||
* [max_resultset_rows](#max_resultset_rows)
|
|
||||||
* [max_resultset_size](#max_resultset_size)
|
|
||||||
* [max_count](#max_count)
|
|
||||||
* [max_size](#max_size)
|
|
||||||
* [rules](#rules)
|
|
||||||
* [cached_data](#cached_data)
|
|
||||||
* [selects](#selects)
|
|
||||||
* [cache_inside_transactions](#cache_inside_transactions)
|
|
||||||
* [debug](#debug)
|
|
||||||
* [enabled](#enabled)
|
|
||||||
* [Runtime Configuration](#runtime-configuration)
|
|
||||||
* [@maxscale.cache.populate](#maxscalecachepopulate)
|
|
||||||
* [@maxscale.cache.use](#maxscalecacheuse)
|
|
||||||
* [@maxscale.cache.soft_ttl](#maxscalecachesoft_ttl)
|
|
||||||
* [@maxscale.cache.hard_ttl](#maxscalecachehard_ttl)
|
|
||||||
* [Client Driven Caching](#client-driven-caching)
|
|
||||||
* [Rules](#rules-1)
|
|
||||||
* [When to Store](#when-to-store)
|
|
||||||
* [Qualified Names](#qualified-names)
|
|
||||||
* [Implication of the <em>default</em> database](#implication-of-the-default-database)
|
|
||||||
* [Regexp Matching](#regexp-matching)
|
|
||||||
* [Examples](#examples)
|
|
||||||
* [When to Use](#when-to-use)
|
|
||||||
* [Examples](#examples-1)
|
|
||||||
* [Security](#security-1)
|
|
||||||
* [Storage](#storage-1)
|
|
||||||
* [storage_inmemory](#storage_inmemory)
|
|
||||||
* [storage_rocksdb](#storage_rocksdb)
|
|
||||||
* [Parameters](#parameters)
|
|
||||||
* [cache_directory](#cache_directory)
|
|
||||||
* [collect_statistics](#collect_statistics)
|
|
||||||
* [Example](#example)
|
|
||||||
* [Configuration](#configuration-1)
|
|
||||||
* [cache_rules.json](#cache_rulesjson)
|
|
||||||
* [Performance](#performance)
|
|
||||||
* [Summary](#summary)
|
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
@ -173,14 +127,19 @@ storage_options=storage_specific_option1=value1,storage_specific_option2=value2
|
|||||||
|
|
||||||
#### `hard_ttl`
|
#### `hard_ttl`
|
||||||
|
|
||||||
_Hard time to live_; the maximum amount of time - in seconds - the cached
|
_Hard time to live_; the maximum amount of time the cached
|
||||||
result is used before it is discarded and the result is fetched from the
|
result is used before it is discarded and the result is fetched from the
|
||||||
backend (and cached). See also `soft_ttl` below.
|
backend (and cached). See also `soft_ttl` below.
|
||||||
|
|
||||||
```
|
```
|
||||||
hard_ttl=60
|
hard_ttl=60s
|
||||||
```
|
```
|
||||||
The default value is `0`, which means no limit.
|
The default value is `0s`, which means no limit.
|
||||||
|
|
||||||
|
The duration can be specified as explained
|
||||||
|
[here](Getting-Started/Configuration-Guide.md#durations).
|
||||||
|
If no explicit unit has been specified, the value is interpreted as seconds
|
||||||
|
in MaxScale 2.4. In subsequent versions a value without a unit may be rejected.
|
||||||
|
|
||||||
#### `soft_ttl`
|
#### `soft_ttl`
|
||||||
|
|
||||||
@ -194,11 +153,16 @@ from the backend. That is, as long as `soft_ttl` but not `hard_ttl` has passed,
|
|||||||
even if several clients request the same value at the same time, there will be
|
even if several clients request the same value at the same time, there will be
|
||||||
just one request to the backend.
|
just one request to the backend.
|
||||||
```
|
```
|
||||||
soft_ttl=60
|
soft_ttl=60s
|
||||||
```
|
```
|
||||||
The default value is `0`, which means no limit. If the value of `soft_ttl` is
|
The default value is `0`, which means no limit. If the value of `soft_ttl` is
|
||||||
larger than `hard_ttl` it will be adjusted down to the same value.
|
larger than `hard_ttl` it will be adjusted down to the same value.
|
||||||
|
|
||||||
|
The duration can be specifed as explained
|
||||||
|
[here](Getting-Started/Configuration-Guide.md#durations).
|
||||||
|
If no explicit unit has been specified, the value is interpreted as seconds
|
||||||
|
in MaxScale 2.4. In subsequent versions a value without a unit may be rejected.
|
||||||
|
|
||||||
#### `max_resultset_rows`
|
#### `max_resultset_rows`
|
||||||
|
|
||||||
Specifies the maximum number of rows a resultset can have in order to be
|
Specifies the maximum number of rows a resultset can have in order to be
|
||||||
|
17
server/modules/filter/cache/cache.cc
vendored
17
server/modules/filter/cache/cache.cc
vendored
@ -209,3 +209,20 @@ json_t* Cache::do_get_info(uint32_t what) const
|
|||||||
|
|
||||||
return pInfo;
|
return pInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//static
|
||||||
|
uint64_t Cache::time_ms()
|
||||||
|
{
|
||||||
|
timespec t;
|
||||||
|
|
||||||
|
int rv = clock_gettime(CLOCK_MONOTONIC_COARSE, &t);
|
||||||
|
if (rv != 0)
|
||||||
|
{
|
||||||
|
mxb_assert(errno == EINVAL); // CLOCK_MONOTONIC_COARSE not supported.
|
||||||
|
rv = clock_gettime(CLOCK_MONOTONIC, &t);
|
||||||
|
mxb_assert(rv == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return t.tv_sec * 1000 + (t.tv_nsec / 1000000);
|
||||||
|
}
|
||||||
|
16
server/modules/filter/cache/cache.hh
vendored
16
server/modules/filter/cache/cache.hh
vendored
@ -56,10 +56,10 @@ typedef enum cache_selects
|
|||||||
#define CACHE_ZDEFAULT_MAX_RESULTSET_ROWS "0"
|
#define CACHE_ZDEFAULT_MAX_RESULTSET_ROWS "0"
|
||||||
// Bytes
|
// Bytes
|
||||||
#define CACHE_ZDEFAULT_MAX_RESULTSET_SIZE "0"
|
#define CACHE_ZDEFAULT_MAX_RESULTSET_SIZE "0"
|
||||||
// Seconds
|
// Duration
|
||||||
#define CACHE_ZDEFAULT_HARD_TTL "0"
|
#define CACHE_ZDEFAULT_HARD_TTL "0s"
|
||||||
// Seconds
|
// Duration
|
||||||
#define CACHE_ZDEFAULT_SOFT_TTL "0"
|
#define CACHE_ZDEFAULT_SOFT_TTL "0s"
|
||||||
// Integer value
|
// Integer value
|
||||||
#define CACHE_ZDEFAULT_DEBUG "0"
|
#define CACHE_ZDEFAULT_DEBUG "0"
|
||||||
// Positive integer
|
// Positive integer
|
||||||
@ -208,6 +208,14 @@ public:
|
|||||||
*/
|
*/
|
||||||
virtual cache_result_t del_value(const CACHE_KEY& key) = 0;
|
virtual cache_result_t del_value(const CACHE_KEY& key) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the monotonic time, expressed in milliseconds, since an
|
||||||
|
* unspecified starting point.
|
||||||
|
*
|
||||||
|
* @return The time.
|
||||||
|
*/
|
||||||
|
static uint64_t time_ms();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Cache(const std::string& name,
|
Cache(const std::string& name,
|
||||||
const CACHE_CONFIG* pConfig,
|
const CACHE_CONFIG* pConfig,
|
||||||
|
8
server/modules/filter/cache/cachefilter.cc
vendored
8
server/modules/filter/cache/cachefilter.cc
vendored
@ -191,12 +191,12 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"hard_ttl",
|
"hard_ttl",
|
||||||
MXS_MODULE_PARAM_COUNT,
|
MXS_MODULE_PARAM_DURATION,
|
||||||
CACHE_ZDEFAULT_HARD_TTL
|
CACHE_ZDEFAULT_HARD_TTL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"soft_ttl",
|
"soft_ttl",
|
||||||
MXS_MODULE_PARAM_COUNT,
|
MXS_MODULE_PARAM_DURATION,
|
||||||
CACHE_ZDEFAULT_SOFT_TTL
|
CACHE_ZDEFAULT_SOFT_TTL
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -346,8 +346,8 @@ bool CacheFilter::process_params(MXS_CONFIG_PARAMETER* ppParams, CACHE_CONFIG& c
|
|||||||
bool error = false;
|
bool error = false;
|
||||||
|
|
||||||
config.debug = ppParams->get_integer("debug");
|
config.debug = ppParams->get_integer("debug");
|
||||||
config.hard_ttl = ppParams->get_integer("hard_ttl");
|
config.hard_ttl = ppParams->get_duration("hard_ttl", mxs::config::INTERPRET_AS_SECONDS).count();
|
||||||
config.soft_ttl = ppParams->get_integer("soft_ttl");
|
config.soft_ttl = ppParams->get_duration("soft_ttl", mxs::config::INTERPRET_AS_SECONDS).count();
|
||||||
config.max_size = ppParams->get_size("max_size");
|
config.max_size = ppParams->get_size("max_size");
|
||||||
config.max_count = ppParams->get_integer("max_count");
|
config.max_count = ppParams->get_integer("max_count");
|
||||||
config.storage = ppParams->get_c_str_copy("storage");
|
config.storage = ppParams->get_c_str_copy("storage");
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <maxscale/alloc.h>
|
#include <maxscale/alloc.h>
|
||||||
#include <maxscale/modutil.hh>
|
#include <maxscale/modutil.hh>
|
||||||
#include <maxscale/query_classifier.hh>
|
#include <maxscale/query_classifier.hh>
|
||||||
|
#include "../../cache.hh"
|
||||||
#include "inmemorystoragest.hh"
|
#include "inmemorystoragest.hh"
|
||||||
#include "inmemorystoragemt.hh"
|
#include "inmemorystoragemt.hh"
|
||||||
|
|
||||||
@ -31,6 +32,7 @@ const size_t INMEMORY_KEY_LENGTH = 2 * SHA512_DIGEST_LENGTH;
|
|||||||
#if INMEMORY_KEY_LENGTH > CACHE_KEY_MAXLEN
|
#if INMEMORY_KEY_LENGTH > CACHE_KEY_MAXLEN
|
||||||
#error storage_inmemory key is too long.
|
#error storage_inmemory key is too long.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InMemoryStorage::InMemoryStorage(const string& name, const CACHE_STORAGE_CONFIG& config)
|
InMemoryStorage::InMemoryStorage(const string& name, const CACHE_STORAGE_CONFIG& config)
|
||||||
@ -162,7 +164,7 @@ cache_result_t InMemoryStorage::do_get_value(const CACHE_KEY& key,
|
|||||||
|
|
||||||
Entry& entry = i->second;
|
Entry& entry = i->second;
|
||||||
|
|
||||||
uint32_t now = time(NULL);
|
int64_t now = Cache::time_ms();
|
||||||
|
|
||||||
bool is_hard_stale = hard_ttl == 0 ? false : (now - entry.time > hard_ttl);
|
bool is_hard_stale = hard_ttl == 0 ? false : (now - entry.time > hard_ttl);
|
||||||
bool is_soft_stale = soft_ttl == 0 ? false : (now - entry.time > soft_ttl);
|
bool is_soft_stale = soft_ttl == 0 ? false : (now - entry.time > soft_ttl);
|
||||||
@ -251,7 +253,7 @@ cache_result_t InMemoryStorage::do_put_value(const CACHE_KEY& key, const GWBUF&
|
|||||||
const uint8_t* pData = GWBUF_DATA(&value);
|
const uint8_t* pData = GWBUF_DATA(&value);
|
||||||
|
|
||||||
copy(pData, pData + size, pEntry->value.begin());
|
copy(pData, pData + size, pEntry->value.begin());
|
||||||
pEntry->time = time(NULL);
|
pEntry->time = Cache::time_ms();
|
||||||
|
|
||||||
return CACHE_RESULT_OK;
|
return CACHE_RESULT_OK;
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ private:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t time;
|
int64_t time;
|
||||||
Value value;
|
Value value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,6 +18,24 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
unsigned int millisleep(unsigned int milliseconds)
|
||||||
|
{
|
||||||
|
unsigned int seconds = milliseconds / 1000;
|
||||||
|
milliseconds -= (seconds * 1000);
|
||||||
|
|
||||||
|
timespec req = { seconds, milliseconds * 1000000 };
|
||||||
|
timespec rem = { 0, 0 };
|
||||||
|
|
||||||
|
nanosleep(&req, &rem);
|
||||||
|
|
||||||
|
return rem.tv_sec * 1000 + rem.tv_nsec / 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// class TesterStorage::HitTask
|
// class TesterStorage::HitTask
|
||||||
//
|
//
|
||||||
@ -276,8 +294,8 @@ int TesterStorage::test_ttl(const CacheItems& cache_items)
|
|||||||
out() << "ST" << endl;
|
out() << "ST" << endl;
|
||||||
|
|
||||||
config.thread_model = CACHE_THREAD_MODEL_ST;
|
config.thread_model = CACHE_THREAD_MODEL_ST;
|
||||||
config.hard_ttl = 6;
|
config.hard_ttl = 6000;
|
||||||
config.soft_ttl = 3;
|
config.soft_ttl = 3000;
|
||||||
|
|
||||||
Storage* pStorage;
|
Storage* pStorage;
|
||||||
|
|
||||||
@ -293,8 +311,8 @@ int TesterStorage::test_ttl(const CacheItems& cache_items)
|
|||||||
out() << "MT" << endl;
|
out() << "MT" << endl;
|
||||||
|
|
||||||
config.thread_model = CACHE_THREAD_MODEL_MT;
|
config.thread_model = CACHE_THREAD_MODEL_MT;
|
||||||
config.hard_ttl = 6;
|
config.hard_ttl = 6000;
|
||||||
config.soft_ttl = 3;
|
config.soft_ttl = 3000;
|
||||||
|
|
||||||
int rv2 = EXIT_FAILURE;
|
int rv2 = EXIT_FAILURE;
|
||||||
pStorage = get_storage(config);
|
pStorage = get_storage(config);
|
||||||
@ -342,8 +360,8 @@ int TesterStorage::test_ttl(const CacheItems& cache_items, Storage& storage)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Let's stay just below the soft_ttl value.
|
// Let's stay just below the soft_ttl value.
|
||||||
sleep(soft_ttl - 1);
|
millisleep(soft_ttl - 1000);
|
||||||
slept += soft_ttl - 1;
|
slept += soft_ttl - 1000;
|
||||||
|
|
||||||
GWBUF* pValue;
|
GWBUF* pValue;
|
||||||
|
|
||||||
@ -359,8 +377,8 @@ int TesterStorage::test_ttl(const CacheItems& cache_items, Storage& storage)
|
|||||||
|
|
||||||
gwbuf_free(pValue);
|
gwbuf_free(pValue);
|
||||||
|
|
||||||
sleep(2); // Expected to get us passed the soft ttl.
|
millisleep(2000); // Expected to get us passed the soft ttl.
|
||||||
slept += 2;
|
slept += 2000;
|
||||||
|
|
||||||
pValue = NULL;
|
pValue = NULL;
|
||||||
result = storage.get_value(cache_item.first, 0, &pValue);
|
result = storage.get_value(cache_item.first, 0, &pValue);
|
||||||
@ -385,8 +403,8 @@ int TesterStorage::test_ttl(const CacheItems& cache_items, Storage& storage)
|
|||||||
|
|
||||||
gwbuf_free(pValue);
|
gwbuf_free(pValue);
|
||||||
|
|
||||||
sleep(hard_ttl - slept + 1); // Expected to get us passed the hard ttl.
|
millisleep(hard_ttl - slept + 1000); // Expected to get us passed the hard ttl.
|
||||||
slept += hard_ttl - slept + 1;
|
slept += hard_ttl - slept + 1000;
|
||||||
|
|
||||||
pValue = NULL;
|
pValue = NULL;
|
||||||
result = storage.get_value(cache_item.first, CACHE_FLAGS_INCLUDE_STALE, &pValue);
|
result = storage.get_value(cache_item.first, CACHE_FLAGS_INCLUDE_STALE, &pValue);
|
||||||
|
Reference in New Issue
Block a user