Cache: Now uses unordered_map instead of HASHTABLE

This commit is contained in:
Johan Wikman 2016-11-28 12:10:05 +02:00
parent 02265c5dc2
commit b4ddf23ba3
10 changed files with 147 additions and 156 deletions

View File

@ -99,5 +99,3 @@ bool Cache::should_use(const SESSION* pSession)
{
return cache_rules_should_use(m_pRules, pSession);
}

View File

@ -13,6 +13,7 @@
*/
#include <maxscale/cdefs.h>
#include <tr1/functional>
#include <string>
#include <maxscale/buffer.h>
#include <maxscale/session.h>

View File

@ -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;
}

View File

@ -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()); }\

View File

@ -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;
}
}

View File

@ -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&);

View File

@ -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);
}

View File

@ -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.
};

View File

@ -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;
}
}

View File

@ -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&);