Cache: Add simple cache
A simple cache is one that does not transparently use multiple storages in the background. That will be the case when a separate cache per thread is used. Both CacheST and CacheMT are now derived from CacheSimple. A fair amount of what used to be in Cache has now been moved to CacheSimple. What remains is what surely is common for all cache types.
This commit is contained in:
2
server/modules/filter/cache/CMakeLists.txt
vendored
2
server/modules/filter/cache/CMakeLists.txt
vendored
@ -1,5 +1,5 @@
|
||||
if (JANSSON_FOUND)
|
||||
add_library(cache SHARED cache.cc cachefilter.cc cachemt.cc cachest.cc rules.cc sessioncache.cc storage.cc storagefactory.cc)
|
||||
add_library(cache SHARED cache.cc cachefilter.cc cachemt.cc cachesimple.cc cachest.cc rules.cc sessioncache.cc storage.cc storagefactory.cc)
|
||||
target_link_libraries(cache maxscale-common jansson)
|
||||
set_target_properties(cache PROPERTIES VERSION "1.0.0")
|
||||
set_target_properties(cache PROPERTIES LINK_FLAGS -Wl,-z,defs)
|
||||
|
||||
121
server/modules/filter/cache/cache.cc
vendored
121
server/modules/filter/cache/cache.cc
vendored
@ -19,76 +19,30 @@
|
||||
#include "storagefactory.h"
|
||||
#include "storage.h"
|
||||
|
||||
// Initial size of hashtable used for storing keys of queries that
|
||||
// are being fetches.
|
||||
#define CACHE_PENDING_ITEMS 50
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
Cache::Cache(const char* zName,
|
||||
CACHE_CONFIG& config,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
Storage* pStorage,
|
||||
HASHTABLE* pPending)
|
||||
StorageFactory* pFactory)
|
||||
: m_zName(zName)
|
||||
, m_config(config)
|
||||
, m_pRules(pRules)
|
||||
, m_pFactory(pFactory)
|
||||
, m_pStorage(pStorage)
|
||||
, m_pPending(pPending)
|
||||
{
|
||||
cache_config_reset(config);
|
||||
}
|
||||
|
||||
Cache::~Cache()
|
||||
{
|
||||
// TODO: Free everything.
|
||||
ss_dassert(false);
|
||||
cache_rules_free(m_pRules);
|
||||
delete m_pFactory;
|
||||
}
|
||||
|
||||
//static
|
||||
bool Cache::Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
StorageFactory** ppFactory,
|
||||
HASHTABLE** ppPending)
|
||||
StorageFactory** ppFactory)
|
||||
{
|
||||
CACHE_RULES* pRules = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
|
||||
if (config.rules)
|
||||
@ -102,31 +56,24 @@ bool Cache::Create(const CACHE_CONFIG& config,
|
||||
|
||||
if (pRules)
|
||||
{
|
||||
pPending = hashtable_alloc(CACHE_PENDING_ITEMS, hashfn, hashcmp);
|
||||
pFactory = StorageFactory::Open(config.storage);
|
||||
|
||||
if (pPending)
|
||||
if (!pFactory)
|
||||
{
|
||||
pFactory = StorageFactory::Open(config.storage);
|
||||
|
||||
if (!pFactory)
|
||||
{
|
||||
MXS_ERROR("Could not open storage factory '%s'.", config.storage);
|
||||
}
|
||||
MXS_ERROR("Could not open storage factory '%s'.", config.storage);
|
||||
}
|
||||
}
|
||||
|
||||
bool rv = (pRules && pPending && pFactory);
|
||||
bool rv = (pRules && pFactory);
|
||||
|
||||
if (rv)
|
||||
{
|
||||
*ppRules = pRules;
|
||||
*ppPending = pPending;
|
||||
*ppFactory = pFactory;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_rules_free(pRules);
|
||||
hashtable_free(pPending);
|
||||
delete pFactory;
|
||||
}
|
||||
|
||||
@ -143,56 +90,4 @@ bool Cache::shouldUse(const SESSION* pSession)
|
||||
return cache_rules_should_use(m_pRules, pSession);
|
||||
}
|
||||
|
||||
cache_result_t Cache::getKey(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey)
|
||||
{
|
||||
return m_pStorage->getKey(zDefaultDb, pQuery, pKey);
|
||||
}
|
||||
|
||||
cache_result_t Cache::getValue(const CACHE_KEY& key,
|
||||
uint32_t flags,
|
||||
GWBUF** ppValue)
|
||||
{
|
||||
return m_pStorage->getValue(key, flags, ppValue);
|
||||
}
|
||||
|
||||
cache_result_t Cache::putValue(const CACHE_KEY& key,
|
||||
const GWBUF* pValue)
|
||||
{
|
||||
return m_pStorage->putValue(key, pValue);
|
||||
}
|
||||
|
||||
cache_result_t Cache::delValue(const CACHE_KEY& key)
|
||||
{
|
||||
return m_pStorage->delValue(key);
|
||||
}
|
||||
|
||||
// protected
|
||||
long Cache::hashOfKey(const CACHE_KEY& key)
|
||||
{
|
||||
return hash_of_key(key.data);
|
||||
}
|
||||
|
||||
// protected
|
||||
bool Cache::mustRefresh(long key, const SessionCache* pSessionCache)
|
||||
{
|
||||
void *pValue = hashtable_fetch(m_pPending, (void*)key);
|
||||
if (!pValue)
|
||||
{
|
||||
// It's not being fetched, so we make a note that we are.
|
||||
hashtable_add(m_pPending, (void*)key, (void*)pSessionCache);
|
||||
}
|
||||
|
||||
return !pValue;
|
||||
}
|
||||
|
||||
// protected
|
||||
void Cache::refreshed(long key, const SessionCache* pSessionCache)
|
||||
{
|
||||
ss_dassert(hashtable_fetch(m_pPending, (void*)key) == pSessionCache);
|
||||
ss_debug(int n =) hashtable_delete(m_pPending, (void*)key);
|
||||
ss_dassert(n == 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
38
server/modules/filter/cache/cache.h
vendored
38
server/modules/filter/cache/cache.h
vendored
@ -14,7 +14,6 @@
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <maxscale/buffer.h>
|
||||
#include <maxscale/filter.h>
|
||||
#include <maxscale/session.h>
|
||||
#include "cachefilter.h"
|
||||
#include "cache_storage_api.h"
|
||||
@ -24,7 +23,9 @@ class SessionCache;
|
||||
class Cache
|
||||
{
|
||||
public:
|
||||
~Cache();
|
||||
virtual ~Cache();
|
||||
|
||||
const CACHE_CONFIG& config() const { return m_config; }
|
||||
|
||||
/**
|
||||
* Returns whether the results of a particular query should be stored.
|
||||
@ -63,44 +64,31 @@ public:
|
||||
*/
|
||||
virtual void refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache) = 0;
|
||||
|
||||
const CACHE_CONFIG& config() const { return m_config; }
|
||||
virtual cache_result_t getKey(const char* zDefaultDb, const GWBUF* pQuery, CACHE_KEY* pKey) = 0;
|
||||
|
||||
cache_result_t getKey(const char* zDefaultDb, const GWBUF* pQuery, CACHE_KEY* pKey);
|
||||
virtual cache_result_t getValue(const CACHE_KEY& key, uint32_t flags, GWBUF** ppValue) = 0;
|
||||
|
||||
cache_result_t getValue(const CACHE_KEY& key, uint32_t flags, GWBUF** ppValue);
|
||||
virtual cache_result_t putValue(const CACHE_KEY& key, const GWBUF* pValue) = 0;
|
||||
|
||||
cache_result_t putValue(const CACHE_KEY& key, const GWBUF* pValue);
|
||||
|
||||
cache_result_t delValue(const CACHE_KEY& key);
|
||||
virtual cache_result_t delValue(const CACHE_KEY& key) = 0;
|
||||
|
||||
protected:
|
||||
Cache(const char* zName,
|
||||
CACHE_CONFIG& config,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
Storage* pStorage,
|
||||
HASHTABLE* pPending);
|
||||
StorageFactory* pFactory);
|
||||
|
||||
static bool Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
StorageFactory** ppFactory,
|
||||
HASHTABLE** ppPending);
|
||||
|
||||
long hashOfKey(const CACHE_KEY& key);
|
||||
|
||||
bool mustRefresh(long key, const SessionCache* pSessionCache);
|
||||
|
||||
void refreshed(long key, const SessionCache* pSessionCache);
|
||||
StorageFactory** ppFactory);
|
||||
|
||||
private:
|
||||
Cache(const Cache&);
|
||||
Cache& operator = (const Cache&);
|
||||
|
||||
protected:
|
||||
const char* m_zName; // The name of the instance; the section name in the config.
|
||||
CACHE_CONFIG m_config; // The configuration of the cache instance.
|
||||
CACHE_RULES* m_pRules; // The rules of the cache instance.
|
||||
StorageFactory* m_pFactory; // The storage factory.
|
||||
Storage* m_pStorage; // The storage instance to use.
|
||||
HASHTABLE* m_pPending; // Pending items; being fetched from the backend.
|
||||
const char* m_zName; // The name of the instance; the section name in the config.
|
||||
CACHE_CONFIG m_config; // The configuration of the cache instance.
|
||||
CACHE_RULES* m_pRules; // The rules of the cache instance.
|
||||
StorageFactory* m_pFactory; // The storage factory.
|
||||
};
|
||||
|
||||
8
server/modules/filter/cache/cachemt.cc
vendored
8
server/modules/filter/cache/cachemt.cc
vendored
@ -21,7 +21,7 @@ CacheMT::CacheMT(const char* zName,
|
||||
StorageFactory* pFactory,
|
||||
Storage* pStorage,
|
||||
HASHTABLE* pPending)
|
||||
: Cache(zName, config, pRules, pFactory, pStorage, pPending)
|
||||
: CacheSimple(zName, config, pRules, pFactory, pStorage, pPending)
|
||||
{
|
||||
spinlock_init(&m_lockPending);
|
||||
}
|
||||
@ -38,7 +38,7 @@ CacheMT* CacheMT::Create(const char* zName, CACHE_CONFIG& config)
|
||||
HASHTABLE* pPending = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
|
||||
if (Cache::Create(config, &pRules, &pFactory, &pPending))
|
||||
if (CacheSimple::Create(config, &pRules, &pFactory, &pPending))
|
||||
{
|
||||
uint32_t ttl = config.ttl;
|
||||
int argc = config.storage_argc;
|
||||
@ -73,7 +73,7 @@ bool CacheMT::mustRefresh(const CACHE_KEY& key, const SessionCache* pSessionCach
|
||||
long k = hashOfKey(key);
|
||||
|
||||
spinlock_acquire(&m_lockPending);
|
||||
bool rv = Cache::mustRefresh(k, pSessionCache);
|
||||
bool rv = CacheSimple::mustRefresh(k, pSessionCache);
|
||||
spinlock_release(&m_lockPending);
|
||||
|
||||
return rv;
|
||||
@ -84,6 +84,6 @@ void CacheMT::refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache
|
||||
long k = hashOfKey(key);
|
||||
|
||||
spinlock_acquire(&m_lockPending);
|
||||
Cache::refreshed(k, pSessionCache);
|
||||
CacheSimple::refreshed(k, pSessionCache);
|
||||
spinlock_release(&m_lockPending);
|
||||
}
|
||||
|
||||
4
server/modules/filter/cache/cachemt.h
vendored
4
server/modules/filter/cache/cachemt.h
vendored
@ -14,9 +14,9 @@
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <maxscale/spinlock.h>
|
||||
#include "cache.h"
|
||||
#include "cachesimple.h"
|
||||
|
||||
class CacheMT : public Cache
|
||||
class CacheMT : public CacheSimple
|
||||
{
|
||||
public:
|
||||
~CacheMT();
|
||||
|
||||
164
server/modules/filter/cache/cachesimple.cc
vendored
Normal file
164
server/modules/filter/cache/cachesimple.cc
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include "cachesimple.h"
|
||||
#include "storage.h"
|
||||
#include "storagefactory.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// Initial size of hashtable used for storing keys of queries that
|
||||
// are being fetches.
|
||||
const size_t CACHE_PENDING_ITEMS = 50;
|
||||
|
||||
/**
|
||||
* Hashes a cache key to an integer.
|
||||
*
|
||||
* @param key Pointer to cache key.
|
||||
*
|
||||
* @returns Corresponding integer hash.
|
||||
*/
|
||||
int hash_of_key(const CACHE_KEY& key)
|
||||
{
|
||||
int 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;
|
||||
}
|
||||
|
||||
int hashfn(const void* address)
|
||||
{
|
||||
// TODO: Hash the address; pointers are not evenly distributed.
|
||||
return (long)address;
|
||||
}
|
||||
|
||||
int hashcmp(const void* address1, const void* address2)
|
||||
{
|
||||
return (long)address2 - (long)address1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
CacheSimple::CacheSimple(const char* zName,
|
||||
CACHE_CONFIG& config,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
Storage* pStorage,
|
||||
HASHTABLE* pPending)
|
||||
: Cache(zName, config, pRules, pFactory)
|
||||
, m_pStorage(pStorage)
|
||||
, m_pPending(pPending)
|
||||
{
|
||||
}
|
||||
|
||||
CacheSimple::~CacheSimple()
|
||||
{
|
||||
delete m_pStorage;
|
||||
hashtable_free(m_pPending);
|
||||
}
|
||||
|
||||
|
||||
// static protected
|
||||
bool CacheSimple::Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
StorageFactory** ppFactory,
|
||||
HASHTABLE** ppPending)
|
||||
{
|
||||
int rv = false;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
|
||||
if (Cache::Create(config, &pRules, &pFactory))
|
||||
{
|
||||
pPending = hashtable_alloc(CACHE_PENDING_ITEMS, hashfn, hashcmp);
|
||||
|
||||
if (pPending)
|
||||
{
|
||||
*ppRules = pRules;
|
||||
*ppPending = pPending;
|
||||
*ppFactory = pFactory;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_rules_free(pRules);
|
||||
delete pFactory;
|
||||
}
|
||||
}
|
||||
|
||||
return pPending != NULL;
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::getKey(const char* zDefaultDb,
|
||||
const GWBUF* pQuery,
|
||||
CACHE_KEY* pKey)
|
||||
{
|
||||
return m_pStorage->getKey(zDefaultDb, pQuery, pKey);
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::getValue(const CACHE_KEY& key,
|
||||
uint32_t flags,
|
||||
GWBUF** ppValue)
|
||||
{
|
||||
return m_pStorage->getValue(key, flags, ppValue);
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::putValue(const CACHE_KEY& key,
|
||||
const GWBUF* pValue)
|
||||
{
|
||||
return m_pStorage->putValue(key, pValue);
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::delValue(const CACHE_KEY& key)
|
||||
{
|
||||
return m_pStorage->delValue(key);
|
||||
}
|
||||
|
||||
// protected
|
||||
long CacheSimple::hashOfKey(const CACHE_KEY& key)
|
||||
{
|
||||
return hash_of_key(key);
|
||||
}
|
||||
|
||||
// protected
|
||||
bool CacheSimple::mustRefresh(long key, const SessionCache* pSessionCache)
|
||||
{
|
||||
void *pValue = hashtable_fetch(m_pPending, (void*)key);
|
||||
if (!pValue)
|
||||
{
|
||||
// It's not being fetched, so we make a note that we are.
|
||||
hashtable_add(m_pPending, (void*)key, (void*)pSessionCache);
|
||||
}
|
||||
|
||||
return !pValue;
|
||||
}
|
||||
|
||||
// protected
|
||||
void CacheSimple::refreshed(long key, const SessionCache* pSessionCache)
|
||||
{
|
||||
ss_dassert(hashtable_fetch(m_pPending, (void*)key) == pSessionCache);
|
||||
ss_debug(int n =) hashtable_delete(m_pPending, (void*)key);
|
||||
ss_dassert(n == 1);
|
||||
}
|
||||
60
server/modules/filter/cache/cachesimple.h
vendored
Normal file
60
server/modules/filter/cache/cachesimple.h
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
/*
|
||||
* Copyright (c) 2016 MariaDB Corporation Ab
|
||||
*
|
||||
* Use of this software is governed by the Business Source License included
|
||||
* in the LICENSE.TXT file and at www.mariadb.com/bsl.
|
||||
*
|
||||
* Change Date: 2019-07-01
|
||||
*
|
||||
* On the date above, in accordance with the Business Source License, use
|
||||
* of this software will be governed by version 2 or later of the General
|
||||
* Public License.
|
||||
*/
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <maxscale/hashtable.h>
|
||||
#include "cache.h"
|
||||
|
||||
class Storage;
|
||||
|
||||
class CacheSimple : public Cache
|
||||
{
|
||||
public:
|
||||
~CacheSimple();
|
||||
|
||||
protected:
|
||||
CacheSimple(const char* zName,
|
||||
CACHE_CONFIG& config,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
Storage* pStorage,
|
||||
HASHTABLE* pPending);
|
||||
|
||||
static bool Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
StorageFactory** ppFactory,
|
||||
HASHTABLE** ppPending);
|
||||
|
||||
cache_result_t getKey(const char* zDefaultDb, const GWBUF* pQuery, CACHE_KEY* pKey);
|
||||
|
||||
cache_result_t getValue(const CACHE_KEY& key, uint32_t flags, GWBUF** ppValue);
|
||||
|
||||
cache_result_t putValue(const CACHE_KEY& key, const GWBUF* pValue);
|
||||
|
||||
cache_result_t delValue(const CACHE_KEY& key);
|
||||
|
||||
long hashOfKey(const CACHE_KEY& key);
|
||||
|
||||
bool mustRefresh(long key, const SessionCache* pSessionCache);
|
||||
|
||||
void refreshed(long key, const SessionCache* pSessionCache);
|
||||
|
||||
private:
|
||||
CacheSimple(const Cache&);
|
||||
CacheSimple& operator = (const CacheSimple&);
|
||||
|
||||
protected:
|
||||
Storage* m_pStorage; // The storage instance to use.
|
||||
HASHTABLE* m_pPending; // Pending items; being fetched from the backend.
|
||||
};
|
||||
8
server/modules/filter/cache/cachest.cc
vendored
8
server/modules/filter/cache/cachest.cc
vendored
@ -21,7 +21,7 @@ CacheST::CacheST(const char* zName,
|
||||
StorageFactory* pFactory,
|
||||
Storage* pStorage,
|
||||
HASHTABLE* pPending)
|
||||
: Cache(zName, config, pRules, pFactory, pStorage, pPending)
|
||||
: CacheSimple(zName, config, pRules, pFactory, pStorage, pPending)
|
||||
{
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ CacheST* CacheST::Create(const char* zName, CACHE_CONFIG& config)
|
||||
HASHTABLE* pPending = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
|
||||
if (Cache::Create(config, &pRules, &pFactory, &pPending))
|
||||
if (CacheSimple::Create(config, &pRules, &pFactory, &pPending))
|
||||
{
|
||||
uint32_t ttl = config.ttl;
|
||||
int argc = config.storage_argc;
|
||||
@ -71,12 +71,12 @@ bool CacheST::mustRefresh(const CACHE_KEY& key, const SessionCache* pSessionCach
|
||||
{
|
||||
long k = hashOfKey(key);
|
||||
|
||||
return Cache::mustRefresh(k, pSessionCache);
|
||||
return CacheSimple::mustRefresh(k, pSessionCache);
|
||||
}
|
||||
|
||||
void CacheST::refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache)
|
||||
{
|
||||
long k = hashOfKey(key);
|
||||
|
||||
Cache::refreshed(k, pSessionCache);
|
||||
CacheSimple::refreshed(k, pSessionCache);
|
||||
}
|
||||
|
||||
4
server/modules/filter/cache/cachest.h
vendored
4
server/modules/filter/cache/cachest.h
vendored
@ -13,9 +13,9 @@
|
||||
*/
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include "cache.h"
|
||||
#include "cachesimple.h"
|
||||
|
||||
class CacheST : public Cache
|
||||
class CacheST : public CacheSimple
|
||||
{
|
||||
public:
|
||||
~CacheST();
|
||||
|
||||
Reference in New Issue
Block a user