Cache: Now uses unordered_map instead of HASHTABLE
This commit is contained in:
parent
02265c5dc2
commit
b4ddf23ba3
2
server/modules/filter/cache/cache.cc
vendored
2
server/modules/filter/cache/cache.cc
vendored
@ -99,5 +99,3 @@ bool Cache::should_use(const SESSION* pSession)
|
||||
{
|
||||
return cache_rules_should_use(m_pRules, pSession);
|
||||
}
|
||||
|
||||
|
||||
|
1
server/modules/filter/cache/cache.h
vendored
1
server/modules/filter/cache/cache.h
vendored
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <tr1/functional>
|
||||
#include <string>
|
||||
#include <maxscale/buffer.h>
|
||||
#include <maxscale/session.h>
|
||||
|
58
server/modules/filter/cache/cachefilter.cc
vendored
58
server/modules/filter/cache/cachefilter.cc
vendored
@ -22,6 +22,8 @@
|
||||
#include "cachept.h"
|
||||
#include "sessioncache.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
static char VERSION_STRING[] = "V1.0.0";
|
||||
|
||||
static const CACHE_CONFIG DEFAULT_CONFIG =
|
||||
@ -544,3 +546,59 @@ void cache_config_reset(CACHE_CONFIG& config)
|
||||
{
|
||||
memset(&config, 0, sizeof(config));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a CACHE_KEY to size_t.
|
||||
*
|
||||
* @param key The key to be hashed.
|
||||
*
|
||||
* @return The corresponding hash.
|
||||
*/
|
||||
size_t cache_key_hash(const CACHE_KEY& key)
|
||||
{
|
||||
size_t 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are two CACHE_KEYs equal.
|
||||
*
|
||||
* @param lhs One cache key.
|
||||
* @param rhs Another cache key.
|
||||
*
|
||||
* @return True, if the keys are equal.
|
||||
*/
|
||||
bool cache_key_equal_to(const CACHE_KEY& lhs, const CACHE_KEY& rhs)
|
||||
{
|
||||
return memcmp(lhs.data, rhs.data, CACHE_KEY_MAXLEN) == 0;
|
||||
}
|
||||
|
||||
std::string cache_key_to_string(const CACHE_KEY& key)
|
||||
{
|
||||
string s;
|
||||
|
||||
for (int i = 0; i < CACHE_KEY_MAXLEN; ++i)
|
||||
{
|
||||
char c = key.data[i];
|
||||
|
||||
if (!isprint(c))
|
||||
{
|
||||
c = '.';
|
||||
}
|
||||
|
||||
s += c;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
34
server/modules/filter/cache/cachefilter.h
vendored
34
server/modules/filter/cache/cachefilter.h
vendored
@ -17,6 +17,7 @@
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <limits.h>
|
||||
#include <exception>
|
||||
#include <tr1/functional>
|
||||
#include <maxscale/hashtable.h>
|
||||
#include <maxscale/spinlock.h>
|
||||
#include "rules.h"
|
||||
@ -66,6 +67,39 @@ void cache_config_finish(CACHE_CONFIG& config);
|
||||
void cache_config_free(CACHE_CONFIG* pConfig);
|
||||
void cache_config_reset(CACHE_CONFIG& config);
|
||||
|
||||
size_t cache_key_hash(const CACHE_KEY& key);
|
||||
bool cache_key_equal_to(const CACHE_KEY& lhs, const CACHE_KEY& rhs);
|
||||
|
||||
std::string cache_key_to_string(const CACHE_KEY& key);
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
struct equal_to<CACHE_KEY>
|
||||
{
|
||||
bool operator()(const CACHE_KEY& lhs, const CACHE_KEY& rhs) const
|
||||
{
|
||||
return cache_key_equal_to(lhs, rhs);
|
||||
}
|
||||
};
|
||||
|
||||
namespace tr1
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<CACHE_KEY>
|
||||
{
|
||||
size_t operator()(const CACHE_KEY& key) const
|
||||
{
|
||||
return cache_key_hash(key);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define CPP_GUARD(statement)\
|
||||
do { try { statement; } \
|
||||
catch (const std::exception& x) { MXS_ERROR("Caught standard exception: %s", x.what()); }\
|
||||
|
26
server/modules/filter/cache/cachemt.cc
vendored
26
server/modules/filter/cache/cachemt.cc
vendored
@ -19,9 +19,8 @@ CacheMT::CacheMT(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending,
|
||||
Storage* pStorage)
|
||||
: CacheSimple(name, pConfig, pRules, pFactory, pPending, pStorage)
|
||||
: CacheSimple(name, pConfig, pRules, pFactory, pStorage)
|
||||
{
|
||||
spinlock_init(&m_lockPending);
|
||||
}
|
||||
@ -37,12 +36,11 @@ CacheMT* CacheMT::Create(const std::string& name, const CACHE_CONFIG* pConfig)
|
||||
CacheMT* pCache = NULL;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
|
||||
if (CacheSimple::Create(*pConfig, &pRules, &pPending, &pFactory))
|
||||
if (CacheSimple::Create(*pConfig, &pRules, &pFactory))
|
||||
{
|
||||
pCache = Create(name, pConfig, pRules, pFactory, pPending);
|
||||
pCache = Create(name, pConfig, pRules, pFactory);
|
||||
}
|
||||
|
||||
return pCache;
|
||||
@ -57,11 +55,10 @@ CacheMT* CacheMT::Create(const std::string& name, StorageFactory* pFactory, cons
|
||||
CacheMT* pCache = NULL;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
|
||||
if (CacheSimple::Create(*pConfig, &pRules, &pPending))
|
||||
if (CacheSimple::Create(*pConfig, &pRules))
|
||||
{
|
||||
pCache = Create(name, pConfig, pRules, pFactory, pPending);
|
||||
pCache = Create(name, pConfig, pRules, pFactory);
|
||||
}
|
||||
|
||||
return pCache;
|
||||
@ -69,10 +66,8 @@ CacheMT* CacheMT::Create(const std::string& name, StorageFactory* pFactory, cons
|
||||
|
||||
bool CacheMT::must_refresh(const CACHE_KEY& key, const SessionCache* pSessionCache)
|
||||
{
|
||||
long k = hash_of_key(key);
|
||||
|
||||
spinlock_acquire(&m_lockPending);
|
||||
bool rv = CacheSimple::must_refresh(k, pSessionCache);
|
||||
bool rv = CacheSimple::do_must_refresh(key, pSessionCache);
|
||||
spinlock_release(&m_lockPending);
|
||||
|
||||
return rv;
|
||||
@ -80,10 +75,8 @@ bool CacheMT::must_refresh(const CACHE_KEY& key, const SessionCache* pSessionCac
|
||||
|
||||
void CacheMT::refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache)
|
||||
{
|
||||
long k = hash_of_key(key);
|
||||
|
||||
spinlock_acquire(&m_lockPending);
|
||||
CacheSimple::refreshed(k, pSessionCache);
|
||||
CacheSimple::do_refreshed(key, pSessionCache);
|
||||
spinlock_release(&m_lockPending);
|
||||
}
|
||||
|
||||
@ -91,8 +84,7 @@ void CacheMT::refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache
|
||||
CacheMT* CacheMT::Create(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending)
|
||||
StorageFactory* pFactory)
|
||||
{
|
||||
CacheMT* pCache = NULL;
|
||||
|
||||
@ -108,14 +100,12 @@ CacheMT* CacheMT::Create(const std::string& name,
|
||||
pConfig,
|
||||
pRules,
|
||||
pFactory,
|
||||
pPending,
|
||||
pStorage));
|
||||
|
||||
if (!pCache)
|
||||
{
|
||||
delete pStorage;
|
||||
cache_rules_free(pRules);
|
||||
hashtable_free(pPending);
|
||||
delete pFactory;
|
||||
}
|
||||
}
|
||||
|
4
server/modules/filter/cache/cachemt.h
vendored
4
server/modules/filter/cache/cachemt.h
vendored
@ -33,14 +33,12 @@ private:
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending,
|
||||
Storage* pStorage);
|
||||
|
||||
static CacheMT* Create(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending);
|
||||
StorageFactory* pFactory);
|
||||
|
||||
private:
|
||||
CacheMT(const CacheMT&);
|
||||
|
128
server/modules/filter/cache/cachesimple.cc
vendored
128
server/modules/filter/cache/cachesimple.cc
vendored
@ -15,59 +15,12 @@
|
||||
#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 std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending,
|
||||
Storage* pStorage)
|
||||
: Cache(name, pConfig, pRules, pFactory)
|
||||
, m_pPending(pPending)
|
||||
, m_pStorage(pStorage)
|
||||
{
|
||||
}
|
||||
@ -75,58 +28,42 @@ CacheSimple::CacheSimple(const std::string& name,
|
||||
CacheSimple::~CacheSimple()
|
||||
{
|
||||
delete m_pStorage;
|
||||
hashtable_free(m_pPending);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool CacheSimple::Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
HASHTABLE** ppPending)
|
||||
CACHE_RULES** ppRules)
|
||||
{
|
||||
int rv = false;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
|
||||
if (Cache::Create(config, &pRules) && Create(&pPending))
|
||||
if (Cache::Create(config, &pRules))
|
||||
{
|
||||
*ppRules = pRules;
|
||||
*ppPending = pPending;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_rules_free(pRules);
|
||||
}
|
||||
|
||||
return pPending != NULL;;
|
||||
return pRules != NULL;;
|
||||
}
|
||||
|
||||
// static
|
||||
bool CacheSimple::Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
HASHTABLE** ppPending,
|
||||
StorageFactory** ppFactory)
|
||||
{
|
||||
int rv = false;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
|
||||
if (Cache::Create(config, &pRules, &pFactory) && Create(&pPending))
|
||||
if (Cache::Create(config, &pRules, &pFactory))
|
||||
{
|
||||
*ppRules = pRules;
|
||||
*ppPending = pPending;
|
||||
*ppFactory = pFactory;
|
||||
}
|
||||
else
|
||||
{
|
||||
cache_rules_free(pRules);
|
||||
delete pFactory;
|
||||
}
|
||||
|
||||
return pPending != NULL;
|
||||
return pRules != NULL;
|
||||
}
|
||||
|
||||
cache_result_t CacheSimple::get_key(const char* zDefaultDb,
|
||||
@ -155,41 +92,32 @@ cache_result_t CacheSimple::del_value(const CACHE_KEY& key)
|
||||
}
|
||||
|
||||
// protected
|
||||
long CacheSimple::hash_of_key(const CACHE_KEY& key)
|
||||
bool CacheSimple::do_must_refresh(const CACHE_KEY& key, const SessionCache* pSessionCache)
|
||||
{
|
||||
return ::hash_of_key(key);
|
||||
bool rv = false;
|
||||
Pending::iterator i = m_pending.find(key);
|
||||
|
||||
if (i == m_pending.end())
|
||||
{
|
||||
try
|
||||
{
|
||||
m_pending.insert(std::make_pair(key, pSessionCache));
|
||||
rv = true;
|
||||
}
|
||||
catch (const std::exception& x)
|
||||
{
|
||||
rv = false;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
// protected
|
||||
bool CacheSimple::must_refresh(long key, const SessionCache* pSessionCache)
|
||||
void CacheSimple::do_refreshed(const CACHE_KEY& 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);
|
||||
}
|
||||
|
||||
// static
|
||||
bool CacheSimple::Create(HASHTABLE** ppPending)
|
||||
{
|
||||
HASHTABLE* pPending = hashtable_alloc(CACHE_PENDING_ITEMS, hashfn, hashcmp);
|
||||
|
||||
if (pPending)
|
||||
{
|
||||
*ppPending = pPending;
|
||||
}
|
||||
|
||||
return pPending != NULL;
|
||||
Pending::iterator i = m_pending.find(key);
|
||||
ss_dassert(i != m_pending.end());
|
||||
ss_dassert(i->second == pSessionCache);
|
||||
m_pending.erase(i);
|
||||
}
|
||||
|
20
server/modules/filter/cache/cachesimple.h
vendored
20
server/modules/filter/cache/cachesimple.h
vendored
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include <maxscale/cdefs.h>
|
||||
#include <tr1/unordered_map>
|
||||
#include <maxscale/hashtable.h>
|
||||
#include "cache.h"
|
||||
|
||||
@ -36,32 +37,27 @@ protected:
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending,
|
||||
Storage* pStorage);
|
||||
|
||||
static bool Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
HASHTABLE** ppPending);
|
||||
CACHE_RULES** ppRules);
|
||||
|
||||
static bool Create(const CACHE_CONFIG& config,
|
||||
CACHE_RULES** ppRules,
|
||||
HASHTABLE** ppPending,
|
||||
StorageFactory** ppFactory);
|
||||
|
||||
|
||||
long hash_of_key(const CACHE_KEY& key);
|
||||
bool do_must_refresh(const CACHE_KEY& key, const SessionCache* pSessionCache);
|
||||
|
||||
bool must_refresh(long key, const SessionCache* pSessionCache);
|
||||
|
||||
void refreshed(long key, const SessionCache* pSessionCache);
|
||||
void do_refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache);
|
||||
|
||||
private:
|
||||
CacheSimple(const Cache&);
|
||||
CacheSimple& operator = (const CacheSimple&);
|
||||
|
||||
static bool Create(HASHTABLE** ppPending);
|
||||
|
||||
protected:
|
||||
HASHTABLE* m_pPending; // Pending items; being fetched from the backend.
|
||||
Storage* m_pStorage; // The storage instance to use.
|
||||
typedef std::tr1::unordered_map<CACHE_KEY, const SessionCache*> Pending;
|
||||
|
||||
Pending m_pending; // Pending items; being fetched from the backend.
|
||||
Storage* m_pStorage; // The storage instance to use.
|
||||
};
|
||||
|
26
server/modules/filter/cache/cachest.cc
vendored
26
server/modules/filter/cache/cachest.cc
vendored
@ -19,9 +19,8 @@ CacheST::CacheST(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending,
|
||||
Storage* pStorage)
|
||||
: CacheSimple(name, pConfig, pRules, pFactory, pPending, pStorage)
|
||||
: CacheSimple(name, pConfig, pRules, pFactory, pStorage)
|
||||
{
|
||||
}
|
||||
|
||||
@ -36,12 +35,11 @@ CacheST* CacheST::Create(const std::string& name, const CACHE_CONFIG* pConfig)
|
||||
CacheST* pCache = NULL;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
StorageFactory* pFactory = NULL;
|
||||
|
||||
if (CacheSimple::Create(*pConfig, &pRules, &pPending, &pFactory))
|
||||
if (CacheSimple::Create(*pConfig, &pRules, &pFactory))
|
||||
{
|
||||
pCache = Create(name, pConfig, pRules, pFactory, pPending);
|
||||
pCache = Create(name, pConfig, pRules, pFactory);
|
||||
}
|
||||
|
||||
return pCache;
|
||||
@ -56,11 +54,10 @@ CacheST* CacheST::Create(const std::string& name, StorageFactory* pFactory, cons
|
||||
CacheST* pCache = NULL;
|
||||
|
||||
CACHE_RULES* pRules = NULL;
|
||||
HASHTABLE* pPending = NULL;
|
||||
|
||||
if (CacheSimple::Create(*pConfig, &pRules, &pPending))
|
||||
if (CacheSimple::Create(*pConfig, &pRules))
|
||||
{
|
||||
pCache = Create(name, pConfig, pRules, pFactory, pPending);
|
||||
pCache = Create(name, pConfig, pRules, pFactory);
|
||||
}
|
||||
|
||||
return pCache;
|
||||
@ -68,24 +65,19 @@ CacheST* CacheST::Create(const std::string& name, StorageFactory* pFactory, cons
|
||||
|
||||
bool CacheST::must_refresh(const CACHE_KEY& key, const SessionCache* pSessionCache)
|
||||
{
|
||||
long k = hash_of_key(key);
|
||||
|
||||
return CacheSimple::must_refresh(k, pSessionCache);
|
||||
return CacheSimple::do_must_refresh(key, pSessionCache);
|
||||
}
|
||||
|
||||
void CacheST::refreshed(const CACHE_KEY& key, const SessionCache* pSessionCache)
|
||||
{
|
||||
long k = hash_of_key(key);
|
||||
|
||||
CacheSimple::refreshed(k, pSessionCache);
|
||||
CacheSimple::do_refreshed(key, pSessionCache);
|
||||
}
|
||||
|
||||
// static
|
||||
CacheST* CacheST::Create(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending)
|
||||
StorageFactory* pFactory)
|
||||
{
|
||||
CacheST* pCache = NULL;
|
||||
|
||||
@ -101,14 +93,12 @@ CacheST* CacheST::Create(const std::string& name,
|
||||
pConfig,
|
||||
pRules,
|
||||
pFactory,
|
||||
pPending,
|
||||
pStorage));
|
||||
|
||||
if (!pCache)
|
||||
{
|
||||
delete pStorage;
|
||||
cache_rules_free(pRules);
|
||||
hashtable_free(pPending);
|
||||
delete pFactory;
|
||||
}
|
||||
}
|
||||
|
4
server/modules/filter/cache/cachest.h
vendored
4
server/modules/filter/cache/cachest.h
vendored
@ -32,14 +32,12 @@ private:
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending,
|
||||
Storage* pStorage);
|
||||
|
||||
static CacheST* Create(const std::string& name,
|
||||
const CACHE_CONFIG* pConfig,
|
||||
CACHE_RULES* pRules,
|
||||
StorageFactory* pFactory,
|
||||
HASHTABLE* pPending);
|
||||
StorageFactory* pFactory);
|
||||
private:
|
||||
CacheST(const CacheST&);
|
||||
CacheST& operator = (const CacheST&);
|
||||
|
Loading…
x
Reference in New Issue
Block a user