Add global to ccrfilter

The `global` parameter causes the time window defined by the `time`
parameter to be applied at the instance level instead of the session
level. This means that a write from one connection will cause all other
connections to use the master for a certain period of time.

Using a configurable time window for consistency is not good as it is not
absolute and cannot adjust to how servers behave.

One example that demonstrates this is when a slave is normally lagging
behind by less than a second but some event causes the lag to spike up to
several seconds. In this case the configured time window would no longer
guarantee consistency.

Another reason to avoid a "static" time window is the fact taht it
prevents load balancing in the cases where slaves catch up to the master
within time window. This happens when time is configured to a higher value
to avoid inconsistencies at all costs.

Added a test case that verified the feature works.
This commit is contained in:
Markus Mäkelä
2019-10-29 16:35:51 +02:00
parent dcd3e60630
commit a1e8287265
5 changed files with 115 additions and 3 deletions

View File

@ -32,6 +32,8 @@ namespace
const char PARAM_MATCH[] = "match";
const char PARAM_IGNORE[] = "ignore";
const char PARAM_GLOBAL[] = "global";
const MXS_ENUM_VALUE option_values[] =
{
{"ignorecase", PCRE2_CASELESS},
@ -85,6 +87,12 @@ public:
static CCRFilter* create(const char* name, MXS_CONFIG_PARAMETER* params)
{
if (params->get_integer("count") && params->get_bool(PARAM_GLOBAL))
{
MXS_ERROR("'count' and 'global' cannot be used at the same time.");
return nullptr;
}
CCRFilter* new_instance = new(std::nothrow) CCRFilter;
if (new_instance)
{
@ -92,6 +100,7 @@ public:
new_instance->m_time = params->get_duration<std::chrono::seconds>("time").count();
new_instance->m_match = params->get_string(PARAM_MATCH);
new_instance->m_nomatch = params->get_string(PARAM_IGNORE);
new_instance->m_global = params->get_bool(PARAM_GLOBAL);
int cflags = params->get_enum("options", option_values);
bool compile_error = false;
@ -181,6 +190,9 @@ private:
* a data modification operation is done. */
int m_count = 0; /* Number of hints to add after each operation that modifies data. */
bool m_global;
std::atomic<time_t> m_last_modification {0}; /* Time of the last data modifying operation */
LagStats m_stats;
pcre2_code* re = nullptr; /* Compiled regex text of match */
pcre2_code* nore = nullptr; /* Compiled regex text of ignore */
@ -251,6 +263,11 @@ int CCRSession::routeQuery(GWBUF* queue)
m_last_modification = now;
MXS_INFO("Write operation detected, queries routed to master for %d seconds",
filter->m_time);
if (filter->m_global)
{
filter->m_last_modification.store(now, std::memory_order_relaxed);
}
}
filter->m_stats.n_modified++;
@ -266,7 +283,8 @@ int CCRSession::routeQuery(GWBUF* queue)
}
else if (filter->m_time)
{
double dt = difftime(now, m_last_modification);
double dt = std::min(difftime(now, m_last_modification),
difftime(now, filter->m_last_modification.load(std::memory_order_relaxed)));
if (dt < filter->m_time)
{
@ -347,8 +365,9 @@ extern "C" MXS_MODULE* MXS_CREATE_MODULE()
NULL,
NULL,
{
{"count", MXS_MODULE_PARAM_COUNT, "0" },
{"time", MXS_MODULE_PARAM_DURATION, "60s"},
{"count", MXS_MODULE_PARAM_COUNT, "0" },
{"time", MXS_MODULE_PARAM_DURATION, "60s" },
{PARAM_GLOBAL, MXS_MODULE_PARAM_BOOL, "false"},
{PARAM_MATCH, MXS_MODULE_PARAM_REGEX},
{PARAM_IGNORE, MXS_MODULE_PARAM_REGEX},
{