diff --git a/server/modules/filter/cache/CMakeLists.txt b/server/modules/filter/cache/CMakeLists.txt index 2c785973a..72201e31d 100644 --- a/server/modules/filter/cache/CMakeLists.txt +++ b/server/modules/filter/cache/CMakeLists.txt @@ -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) diff --git a/server/modules/filter/cache/cache.cc b/server/modules/filter/cache/cache.cc index 8aaabd339..1d506c616 100644 --- a/server/modules/filter/cache/cache.cc +++ b/server/modules/filter/cache/cache.cc @@ -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); -} - diff --git a/server/modules/filter/cache/cache.h b/server/modules/filter/cache/cache.h index 702742e8c..b2f3da803 100644 --- a/server/modules/filter/cache/cache.h +++ b/server/modules/filter/cache/cache.h @@ -14,7 +14,6 @@ #include #include -#include #include #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. }; diff --git a/server/modules/filter/cache/cachemt.cc b/server/modules/filter/cache/cachemt.cc index 7dec54e5d..95e5ef454 100644 --- a/server/modules/filter/cache/cachemt.cc +++ b/server/modules/filter/cache/cachemt.cc @@ -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); } diff --git a/server/modules/filter/cache/cachemt.h b/server/modules/filter/cache/cachemt.h index 9ad7455a5..7ce1d8ba4 100644 --- a/server/modules/filter/cache/cachemt.h +++ b/server/modules/filter/cache/cachemt.h @@ -14,9 +14,9 @@ #include #include -#include "cache.h" +#include "cachesimple.h" -class CacheMT : public Cache +class CacheMT : public CacheSimple { public: ~CacheMT(); diff --git a/server/modules/filter/cache/cachesimple.cc b/server/modules/filter/cache/cachesimple.cc new file mode 100644 index 000000000..7dd66b086 --- /dev/null +++ b/server/modules/filter/cache/cachesimple.cc @@ -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); +} diff --git a/server/modules/filter/cache/cachesimple.h b/server/modules/filter/cache/cachesimple.h new file mode 100644 index 000000000..d7cac8812 --- /dev/null +++ b/server/modules/filter/cache/cachesimple.h @@ -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 +#include +#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. +}; diff --git a/server/modules/filter/cache/cachest.cc b/server/modules/filter/cache/cachest.cc index b2fcdbc34..e2f428d4f 100644 --- a/server/modules/filter/cache/cachest.cc +++ b/server/modules/filter/cache/cachest.cc @@ -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); } diff --git a/server/modules/filter/cache/cachest.h b/server/modules/filter/cache/cachest.h index 67a1f9e39..73323c846 100644 --- a/server/modules/filter/cache/cachest.h +++ b/server/modules/filter/cache/cachest.h @@ -13,9 +13,9 @@ */ #include -#include "cache.h" +#include "cachesimple.h" -class CacheST : public Cache +class CacheST : public CacheSimple { public: ~CacheST();