From b4ddf23ba3165dcbeaeaf6c428c843423a4aef60 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Mon, 28 Nov 2016 12:10:05 +0200 Subject: [PATCH] Cache: Now uses unordered_map instead of HASHTABLE --- server/modules/filter/cache/cache.cc | 2 - server/modules/filter/cache/cache.h | 1 + server/modules/filter/cache/cachefilter.cc | 58 ++++++++++ server/modules/filter/cache/cachefilter.h | 34 ++++++ server/modules/filter/cache/cachemt.cc | 26 ++--- server/modules/filter/cache/cachemt.h | 4 +- server/modules/filter/cache/cachesimple.cc | 128 +++++---------------- server/modules/filter/cache/cachesimple.h | 20 ++-- server/modules/filter/cache/cachest.cc | 26 ++--- server/modules/filter/cache/cachest.h | 4 +- 10 files changed, 147 insertions(+), 156 deletions(-) diff --git a/server/modules/filter/cache/cache.cc b/server/modules/filter/cache/cache.cc index c241efd93..3ea4e4fd7 100644 --- a/server/modules/filter/cache/cache.cc +++ b/server/modules/filter/cache/cache.cc @@ -99,5 +99,3 @@ bool Cache::should_use(const SESSION* pSession) { return cache_rules_should_use(m_pRules, pSession); } - - diff --git a/server/modules/filter/cache/cache.h b/server/modules/filter/cache/cache.h index 2a9f40f41..d8e857b27 100644 --- a/server/modules/filter/cache/cache.h +++ b/server/modules/filter/cache/cache.h @@ -13,6 +13,7 @@ */ #include +#include #include #include #include diff --git a/server/modules/filter/cache/cachefilter.cc b/server/modules/filter/cache/cachefilter.cc index 9094259c4..69335ebb1 100644 --- a/server/modules/filter/cache/cachefilter.cc +++ b/server/modules/filter/cache/cachefilter.cc @@ -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; +} diff --git a/server/modules/filter/cache/cachefilter.h b/server/modules/filter/cache/cachefilter.h index 6427161bc..92c99bbf8 100644 --- a/server/modules/filter/cache/cachefilter.h +++ b/server/modules/filter/cache/cachefilter.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #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 +{ + bool operator()(const CACHE_KEY& lhs, const CACHE_KEY& rhs) const + { + return cache_key_equal_to(lhs, rhs); + } +}; + +namespace tr1 +{ + +template<> +struct hash +{ + 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()); }\ diff --git a/server/modules/filter/cache/cachemt.cc b/server/modules/filter/cache/cachemt.cc index 427f98c6e..6694032fe 100644 --- a/server/modules/filter/cache/cachemt.cc +++ b/server/modules/filter/cache/cachemt.cc @@ -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; } } diff --git a/server/modules/filter/cache/cachemt.h b/server/modules/filter/cache/cachemt.h index 237794d96..edf01d254 100644 --- a/server/modules/filter/cache/cachemt.h +++ b/server/modules/filter/cache/cachemt.h @@ -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&); diff --git a/server/modules/filter/cache/cachesimple.cc b/server/modules/filter/cache/cachesimple.cc index fb70acdad..052821e80 100644 --- a/server/modules/filter/cache/cachesimple.cc +++ b/server/modules/filter/cache/cachesimple.cc @@ -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); } diff --git a/server/modules/filter/cache/cachesimple.h b/server/modules/filter/cache/cachesimple.h index 3a2c017a3..67ee58765 100644 --- a/server/modules/filter/cache/cachesimple.h +++ b/server/modules/filter/cache/cachesimple.h @@ -13,6 +13,7 @@ */ #include +#include #include #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 Pending; + + Pending m_pending; // Pending items; being fetched from the backend. + Storage* m_pStorage; // The storage instance to use. }; diff --git a/server/modules/filter/cache/cachest.cc b/server/modules/filter/cache/cachest.cc index 45c02faec..65e2db078 100644 --- a/server/modules/filter/cache/cachest.cc +++ b/server/modules/filter/cache/cachest.cc @@ -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; } } diff --git a/server/modules/filter/cache/cachest.h b/server/modules/filter/cache/cachest.h index 7f4bcfb30..62903d85f 100644 --- a/server/modules/filter/cache/cachest.h +++ b/server/modules/filter/cache/cachest.h @@ -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&);