From a3a8b5523e71f2b6a6ee7678383a868b4572a8f0 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Tue, 24 Apr 2018 18:23:49 +0300 Subject: [PATCH] MXS-1401 Support multiple cache rules The possibility to have multiple cache rules in a cache configuration file is now handled throughout the cache filter. The major difference is that while you earlier directly queried the Cache whether data should be stored to the cache and whether data in the cache should be used, you now query the Cache whether data should be stored to the cache and, if so, get a CacheRules object from which you subsequently query whether data from the cache should be used. --- Documentation/Filters/Cache.md | 20 +++++- server/modules/filter/cache/cache.cc | 71 +++++++++++++------ server/modules/filter/cache/cache.hh | 35 ++++----- .../filter/cache/cachefiltersession.cc | 10 ++- .../filter/cache/cachefiltersession.hh | 2 +- server/modules/filter/cache/cachemt.cc | 29 ++++---- server/modules/filter/cache/cachemt.hh | 18 ++--- server/modules/filter/cache/cachept.cc | 31 ++++---- server/modules/filter/cache/cachept.hh | 18 ++--- server/modules/filter/cache/cachesimple.cc | 28 ++++---- server/modules/filter/cache/cachesimple.hh | 16 ++--- server/modules/filter/cache/cachest.cc | 40 +++++------ server/modules/filter/cache/cachest.hh | 20 +++--- server/modules/filter/cache/rules.cc | 55 +++++++++++--- server/modules/filter/cache/rules.h | 22 ++++-- 15 files changed, 249 insertions(+), 166 deletions(-) diff --git a/Documentation/Filters/Cache.md b/Documentation/Filters/Cache.md index 2e78676ca..1e6936678 100644 --- a/Documentation/Filters/Cache.md +++ b/Documentation/Filters/Cache.md @@ -481,13 +481,14 @@ SET @maxscale.cache.populate=false; # Rules -The caching rules are expressed as a JSON object. +The caching rules are expressed as a JSON object or as an array +of JSON objects. There are two decisions to be made regarding the caching; in what circumstances should data be stored to the cache and in what circumstances should the data in the cache be used. -In the JSON object this is visible as follows: +Expressed in JSON this looks as follows ``` { @@ -495,12 +496,27 @@ In the JSON object this is visible as follows: use: [ ... ] } ``` +or, in case an array is used, as +``` +[ + { + store: [ ... ], + use: [ ... ] + }, + { ... } +] +``` The `store` field specifies in what circumstances data should be stored to the cache and the `use` field specifies in what circumstances the data in the cache should be used. In both cases, the value is a JSON array containg objects. +If an array of rule objects is specified, then, when looking for a rule that +matches, the `store` field of each object are evaluated in sequential order +until a match is found. Then, the `use` field of that object is used when +deciding whether data in the cache should be used. + ## When to Store By default, if no rules file have been provided or if the `store` field is diff --git a/server/modules/filter/cache/cache.cc b/server/modules/filter/cache/cache.cc index 1542e03f5..457047aac 100644 --- a/server/modules/filter/cache/cache.cc +++ b/server/modules/filter/cache/cache.cc @@ -27,13 +27,13 @@ using namespace std; -Cache::Cache(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory) +Cache::Cache(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory) : m_name(name) , m_config(*pConfig) - , m_sRules(sRules) + , m_rules(rules) , m_sFactory(sFactory) { } @@ -43,35 +43,42 @@ Cache::~Cache() } //static -bool Cache::Create(const CACHE_CONFIG& config, - CacheRules** ppRules, - StorageFactory** ppFactory) +bool Cache::Create(const CACHE_CONFIG& config, + std::vector* pRules, + StorageFactory** ppFactory) { - CacheRules* pRules = NULL; + std::vector rules; StorageFactory* pFactory = NULL; + bool rv = false; + if (config.rules) { - pRules = CacheRules::load(config.rules, config.debug); + rv = CacheRules::load(config.rules, config.debug, &rules); } else { - pRules = CacheRules::create(config.debug); + auto_ptr sRules(CacheRules::create(config.debug)); + + if (sRules.get()) + { + rules.push_back(SCacheRules(sRules.release())); + rv = true; + } } - if (pRules) + if (rv) { pFactory = StorageFactory::Open(config.storage); if (pFactory) { *ppFactory = pFactory; - *ppRules = pRules; + pRules->swap(rules); } else { MXS_ERROR("Could not open storage factory '%s'.", config.storage); - delete pRules; } } else @@ -155,14 +162,25 @@ cache_result_t Cache::get_default_key(const char* zDefault_db, return CACHE_RESULT_OK; } -bool Cache::should_store(const char* zDefaultDb, const GWBUF* pQuery) +const CacheRules* Cache::should_store(const char* zDefaultDb, const GWBUF* pQuery) { - return m_sRules->should_store(zDefaultDb, pQuery); -} + CacheRules* pRules = NULL; -bool Cache::should_use(const MXS_SESSION* pSession) -{ - return m_sRules->should_use(pSession); + auto i = m_rules.begin(); + + while (!pRules && (i != m_rules.end())) + { + if ((*i)->should_store(zDefaultDb, pQuery)) + { + pRules = (*i).get(); + } + else + { + ++i; + } + } + + return pRules; } json_t* Cache::do_get_info(uint32_t what) const @@ -173,9 +191,18 @@ json_t* Cache::do_get_info(uint32_t what) const { if (what & INFO_RULES) { - json_t* pRules = const_cast(m_sRules->json()); + json_t* pArray = json_array(); - json_object_set(pInfo, "rules", pRules); // Increases ref-count of pRules, we ignore failure. + if (pArray) + { + for (auto i = m_rules.begin(); i < m_rules.end(); ++i) + { + json_t* pRules = const_cast((*i)->json()); + json_array_append(pArray, pRules); // Increases ref-count of pRules, we ignore failure. + } + + json_object_set(pInfo, "rules", pArray); + } } } diff --git a/server/modules/filter/cache/cache.hh b/server/modules/filter/cache/cache.hh index 097fb4d05..af6506694 100644 --- a/server/modules/filter/cache/cache.hh +++ b/server/modules/filter/cache/cache.hh @@ -56,18 +56,9 @@ public: * @param zDefaultDb The current default database. * @param pQuery Buffer containing a SELECT. * - * @return True of the result should be cached. + * @return A rules object, if the query should be stored, NULL otherwise. */ - bool should_store(const char* zDefaultDb, const GWBUF* pQuery); - - /** - * Returns whether cached results should be used. - * - * @param pSession The session in question. - * - * @return True of cached results should be used. - */ - bool should_use(const MXS_SESSION* pSession); + const CacheRules* should_store(const char* zDefaultDb, const GWBUF* pQuery); /** * Specifies whether a particular SessioCache should refresh the data. @@ -134,14 +125,14 @@ public: virtual cache_result_t del_value(const CACHE_KEY& key) = 0; protected: - Cache(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory); + Cache(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory); - static bool Create(const CACHE_CONFIG& config, - CacheRules** ppRules, - StorageFactory** ppFactory); + static bool Create(const CACHE_CONFIG& config, + std::vector* pRules, + StorageFactory** ppFactory); json_t* do_get_info(uint32_t what) const; @@ -150,8 +141,8 @@ private: Cache& operator = (const Cache&); protected: - const std::string m_name; // The name of the instance; the section name in the config. - const CACHE_CONFIG& m_config; // The configuration of the cache instance. - SCacheRules m_sRules; // The rules of the cache instance. - SStorageFactory m_sFactory; // The storage factory. + const std::string m_name; // The name of the instance; the section name in the config. + const CACHE_CONFIG& m_config; // The configuration of the cache instance. + std::vector m_rules; // The rules of the cache instance. + SStorageFactory m_sFactory; // The storage factory. }; diff --git a/server/modules/filter/cache/cachefiltersession.cc b/server/modules/filter/cache/cachefiltersession.cc index 5f1f01988..306dfd083 100644 --- a/server/modules/filter/cache/cachefiltersession.cc +++ b/server/modules/filter/cache/cachefiltersession.cc @@ -1005,13 +1005,15 @@ CacheFilterSession::routing_action_t CacheFilterSession::route_COM_QUERY(GWBUF* if (cache_action != CACHE_IGNORE) { - if (m_pCache->should_store(m_zDefaultDb, pPacket)) + const CacheRules* pRules = m_pCache->should_store(m_zDefaultDb, pPacket); + + if (pRules) { cache_result_t result = m_pCache->get_key(m_zDefaultDb, pPacket, &m_key); if (CACHE_RESULT_IS_OK(result)) { - routing_action = route_SELECT(cache_action, pPacket); + routing_action = route_SELECT(cache_action, *pRules, pPacket); } else { @@ -1033,6 +1035,7 @@ CacheFilterSession::routing_action_t CacheFilterSession::route_COM_QUERY(GWBUF* * Routes a SELECT packet. * * @param cache_action The desired action. + * @param rules The current rules. * @param pPacket A contiguous COM_QUERY packet containing a SELECT. * * @return ROUTING_ABORT if the processing of the packet should be aborted @@ -1040,11 +1043,12 @@ CacheFilterSession::routing_action_t CacheFilterSession::route_COM_QUERY(GWBUF* * ROUTING_CONTINUE if the normal processing should continue. */ CacheFilterSession::routing_action_t CacheFilterSession::route_SELECT(cache_action_t cache_action, + const CacheRules& rules, GWBUF* pPacket) { routing_action_t routing_action = ROUTING_CONTINUE; - if (should_use(cache_action) && m_pCache->should_use(m_pSession)) + if (should_use(cache_action) && rules.should_use(m_pSession)) { uint32_t flags = CACHE_FLAGS_INCLUDE_STALE; GWBUF* pResponse; diff --git a/server/modules/filter/cache/cachefiltersession.hh b/server/modules/filter/cache/cachefiltersession.hh index 7bef6a010..dca3b00a4 100644 --- a/server/modules/filter/cache/cachefiltersession.hh +++ b/server/modules/filter/cache/cachefiltersession.hh @@ -139,7 +139,7 @@ private: }; routing_action_t route_COM_QUERY(GWBUF* pPacket); - routing_action_t route_SELECT(cache_action_t action, GWBUF* pPacket); + routing_action_t route_SELECT(cache_action_t action, const CacheRules& rules, GWBUF* pPacket); char* set_cache_populate(const char* zName, const char* pValue_begin, diff --git a/server/modules/filter/cache/cachemt.cc b/server/modules/filter/cache/cachemt.cc index 274ced1af..1d0580657 100644 --- a/server/modules/filter/cache/cachemt.cc +++ b/server/modules/filter/cache/cachemt.cc @@ -19,12 +19,12 @@ using maxscale::SpinLockGuard; using std::tr1::shared_ptr; -CacheMT::CacheMT(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - Storage* pStorage) - : CacheSimple(name, pConfig, sRules, sFactory, pStorage) +CacheMT::CacheMT(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + Storage* pStorage) + : CacheSimple(name, pConfig, rules, sFactory, pStorage) { spinlock_init(&m_lock_pending); @@ -41,15 +41,14 @@ CacheMT* CacheMT::Create(const std::string& name, const CACHE_CONFIG* pConfig) CacheMT* pCache = NULL; - CacheRules* pRules = NULL; + std::vector rules; StorageFactory* pFactory = NULL; - if (CacheSimple::Create(*pConfig, &pRules, &pFactory)) + if (CacheSimple::Create(*pConfig, &rules, &pFactory)) { - shared_ptr sRules(pRules); shared_ptr sFactory(pFactory); - pCache = Create(name, pConfig, sRules, sFactory); + pCache = Create(name, pConfig, rules, sFactory); } return pCache; @@ -77,10 +76,10 @@ void CacheMT::refreshed(const CACHE_KEY& key, const CacheFilterSession* pSessio } // static -CacheMT* CacheMT::Create(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory) +CacheMT* CacheMT::Create(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory) { CacheMT* pCache = NULL; @@ -99,7 +98,7 @@ CacheMT* CacheMT::Create(const std::string& name, { MXS_EXCEPTION_GUARD(pCache = new CacheMT(name, pConfig, - sRules, + rules, sFactory, pStorage)); diff --git a/server/modules/filter/cache/cachemt.hh b/server/modules/filter/cache/cachemt.hh index 0965ed628..fb9a25e64 100644 --- a/server/modules/filter/cache/cachemt.hh +++ b/server/modules/filter/cache/cachemt.hh @@ -30,16 +30,16 @@ public: void refreshed(const CACHE_KEY& key, const CacheFilterSession* pSession); private: - CacheMT(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - Storage* pStorage); + CacheMT(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + Storage* pStorage); - static CacheMT* Create(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory); + static CacheMT* Create(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory); private: CacheMT(const CacheMT&); diff --git a/server/modules/filter/cache/cachept.cc b/server/modules/filter/cache/cachept.cc index 4dbbc70ed..69d05d60f 100644 --- a/server/modules/filter/cache/cachept.cc +++ b/server/modules/filter/cache/cachept.cc @@ -48,12 +48,12 @@ inline int thread_index() } -CachePT::CachePT(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - const Caches& caches) - : Cache(name, pConfig, sRules, sFactory) +CachePT::CachePT(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + const Caches& caches) + : Cache(name, pConfig, rules, sFactory) , m_caches(caches) { MXS_NOTICE("Created cache per thread."); @@ -70,15 +70,14 @@ CachePT* CachePT::Create(const std::string& name, const CACHE_CONFIG* pConfig) CachePT* pCache = NULL; - CacheRules* pRules = NULL; + std::vector rules; StorageFactory* pFactory = NULL; - if (Cache::Create(*pConfig, &pRules, &pFactory)) + if (Cache::Create(*pConfig, &rules, &pFactory)) { - shared_ptr sRules(pRules); shared_ptr sFactory(pFactory); - pCache = Create(name, pConfig, sRules, sFactory); + pCache = Create(name, pConfig, rules, sFactory); } return pCache; @@ -148,10 +147,10 @@ cache_result_t CachePT::del_value(const CACHE_KEY& key) } // static -CachePT* CachePT::Create(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory) +CachePT* CachePT::Create(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory) { CachePT* pCache = NULL; @@ -173,7 +172,7 @@ CachePT* CachePT::Create(const std::string& name, CacheST* pCacheST = 0; - MXS_EXCEPTION_GUARD(pCacheST = CacheST::Create(namest, sRules, sFactory, pConfig)); + MXS_EXCEPTION_GUARD(pCacheST = CacheST::Create(namest, rules, sFactory, pConfig)); if (pCacheST) { @@ -191,7 +190,7 @@ CachePT* CachePT::Create(const std::string& name, if (!error) { - pCache = new CachePT(name, pConfig, sRules, sFactory, caches); + pCache = new CachePT(name, pConfig, rules, sFactory, caches); } } catch (const std::exception&) diff --git a/server/modules/filter/cache/cachept.hh b/server/modules/filter/cache/cachept.hh index df2a09e2e..c5579b00f 100644 --- a/server/modules/filter/cache/cachept.hh +++ b/server/modules/filter/cache/cachept.hh @@ -44,16 +44,16 @@ private: typedef std::tr1::shared_ptr SCache; typedef std::vector Caches; - CachePT(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - const Caches& caches); + CachePT(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + const Caches& caches); - static CachePT* Create(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory); + static CachePT* Create(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory); Cache& thread_cache(); diff --git a/server/modules/filter/cache/cachesimple.cc b/server/modules/filter/cache/cachesimple.cc index 031a94adf..e49a9e573 100644 --- a/server/modules/filter/cache/cachesimple.cc +++ b/server/modules/filter/cache/cachesimple.cc @@ -16,12 +16,12 @@ #include "storage.hh" #include "storagefactory.hh" -CacheSimple::CacheSimple(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - Storage* pStorage) - : Cache(name, pConfig, sRules, sFactory) +CacheSimple::CacheSimple(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + Storage* pStorage) + : Cache(name, pConfig, rules, sFactory) , m_pStorage(pStorage) { } @@ -32,22 +32,24 @@ CacheSimple::~CacheSimple() } // static -bool CacheSimple::Create(const CACHE_CONFIG& config, - CacheRules** ppRules, - StorageFactory** ppFactory) +bool CacheSimple::Create(const CACHE_CONFIG& config, + std::vector* pRules, + StorageFactory** ppFactory) { int rv = false; - CacheRules* pRules = NULL; + std::vector rules; StorageFactory* pFactory = NULL; - if (Cache::Create(config, &pRules, &pFactory)) + rv = Cache::Create(config, &rules, &pFactory); + + if (rv) { - *ppRules = pRules; + pRules->swap(rules); *ppFactory = pFactory; } - return pRules != NULL; + return rv; } cache_result_t CacheSimple::get_value(const CACHE_KEY& key, diff --git a/server/modules/filter/cache/cachesimple.hh b/server/modules/filter/cache/cachesimple.hh index cee6ceb3c..e0d58206c 100644 --- a/server/modules/filter/cache/cachesimple.hh +++ b/server/modules/filter/cache/cachesimple.hh @@ -34,15 +34,15 @@ public: cache_result_t del_value(const CACHE_KEY& key); protected: - CacheSimple(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - Storage* pStorage); + CacheSimple(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& Rules, + SStorageFactory sFactory, + Storage* pStorage); - static bool Create(const CACHE_CONFIG& config, - CacheRules** ppRules, - StorageFactory** ppFactory); + static bool Create(const CACHE_CONFIG& config, + std::vector* pRules, + StorageFactory** ppFactory); json_t* do_get_info(uint32_t what) const; diff --git a/server/modules/filter/cache/cachest.cc b/server/modules/filter/cache/cachest.cc index c622cfa92..df47b4c6d 100644 --- a/server/modules/filter/cache/cachest.cc +++ b/server/modules/filter/cache/cachest.cc @@ -18,12 +18,12 @@ using std::tr1::shared_ptr; -CacheST::CacheST(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - Storage* pStorage) - : CacheSimple(name, pConfig, sRules, sFactory, pStorage) +CacheST::CacheST(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + Storage* pStorage) + : CacheSimple(name, pConfig, rules, sFactory, pStorage) { MXS_NOTICE("Created single threaded cache."); } @@ -38,31 +38,29 @@ CacheST* CacheST::Create(const std::string& name, const CACHE_CONFIG* pConfig) CacheST* pCache = NULL; - CacheRules* pRules = NULL; + std::vector rules; StorageFactory* pFactory = NULL; - if (CacheSimple::Create(*pConfig, &pRules, &pFactory)) + if (CacheSimple::Create(*pConfig, &rules, &pFactory)) { - shared_ptr sRules(pRules); shared_ptr sFactory(pFactory); - pCache = Create(name, pConfig, sRules, sFactory); + pCache = Create(name, pConfig, rules, sFactory); } return pCache; } // static -CacheST* CacheST::Create(const std::string& name, - SCacheRules sRules, - SStorageFactory sFactory, - const CACHE_CONFIG* pConfig) +CacheST* CacheST::Create(const std::string& name, + const std::vector& rules, + SStorageFactory sFactory, + const CACHE_CONFIG* pConfig) { - ss_dassert(sRules.get()); ss_dassert(sFactory.get()); ss_dassert(pConfig); - return Create(name, pConfig, sRules, sFactory); + return Create(name, pConfig, rules, sFactory); } json_t* CacheST::get_info(uint32_t flags) const @@ -81,10 +79,10 @@ void CacheST::refreshed(const CACHE_KEY& key, const CacheFilterSession* pSessio } // static -CacheST* CacheST::Create(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory) +CacheST* CacheST::Create(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory) { CacheST* pCache = NULL; @@ -103,7 +101,7 @@ CacheST* CacheST::Create(const std::string& name, { MXS_EXCEPTION_GUARD(pCache = new CacheST(name, pConfig, - sRules, + rules, sFactory, pStorage)); diff --git a/server/modules/filter/cache/cachest.hh b/server/modules/filter/cache/cachest.hh index f7ee25fdc..8d148b705 100644 --- a/server/modules/filter/cache/cachest.hh +++ b/server/modules/filter/cache/cachest.hh @@ -22,7 +22,7 @@ public: static CacheST* Create(const std::string& name, const CACHE_CONFIG* pConfig); static CacheST* Create(const std::string& name, - SCacheRules sRules, + const std::vector& rules, SStorageFactory sFactory, const CACHE_CONFIG* pConfig); @@ -33,16 +33,16 @@ public: void refreshed(const CACHE_KEY& key, const CacheFilterSession* pSession); private: - CacheST(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory, - Storage* pStorage); + CacheST(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory, + Storage* pStorage); - static CacheST* Create(const std::string& name, - const CACHE_CONFIG* pConfig, - SCacheRules sRules, - SStorageFactory sFactory); + static CacheST* Create(const std::string& name, + const CACHE_CONFIG* pConfig, + const std::vector& rules, + SStorageFactory sFactory); private: CacheST(const CacheST&); CacheST& operator = (const CacheST&); diff --git a/server/modules/filter/cache/rules.cc b/server/modules/filter/cache/rules.cc index a25b9f483..27f67e604 100644 --- a/server/modules/filter/cache/rules.cc +++ b/server/modules/filter/cache/rules.cc @@ -315,6 +315,16 @@ void cache_rules_free(CACHE_RULES *rules) } } +void cache_rules_free_array(CACHE_RULES** ppRules, int32_t nRules) +{ + for (auto i = 0; i < nRules; ++i) + { + cache_rules_free(ppRules[i]); + } + + MXS_FREE(ppRules); +} + void cache_rules_print(const CACHE_RULES *self, DCB *dcb, size_t indent) { if (self->root) @@ -405,39 +415,64 @@ CacheRules::~CacheRules() } // static -CacheRules* CacheRules::create(uint32_t debug) +std::auto_ptr CacheRules::create(uint32_t debug) { - CacheRules* pThis = NULL; + std::auto_ptr sThis; CACHE_RULES* pRules = cache_rules_create(debug); if (pRules) { - pThis = new (std::nothrow) CacheRules(pRules); + sThis = std::auto_ptr(new (std::nothrow) CacheRules(pRules)); } - return pThis; + return sThis; } // static -CacheRules* CacheRules::load(const char *zPath, uint32_t debug) +bool CacheRules::load(const char *zPath, uint32_t debug, std::vector* pRules) { - CacheRules* pThis = NULL; + bool rv = false; + + pRules->clear(); CACHE_RULES** ppRules; int32_t nRules; if (cache_rules_load(zPath, debug, &ppRules, &nRules)) { - // TODO: Handle more that one CACHE_RULES object at this level. - ss_dassert(nRules == 1); + int j = 0; - pThis = new (std::nothrow) CacheRules(ppRules[0]); + try + { + std::vector rules; + rules.reserve(nRules); + + for (int i = 0; i < nRules; ++i) + { + j = i; + CacheRules* pRules = new CacheRules(ppRules[i]); + j = i + 1; + + rules.push_back(SCacheRules(pRules)); + } + + pRules->swap(rules); + rv = true; + } + catch (const std::exception&) + { + // Free all CACHE_RULES objects that were not pushed into 'rules' above. + for (; j < nRules; ++j) + { + cache_rules_free(ppRules[j]); + } + } MXS_FREE(ppRules); } - return pThis; + return rv; } const json_t* CacheRules::json() const diff --git a/server/modules/filter/cache/rules.h b/server/modules/filter/cache/rules.h index 23cb8f816..2941946d8 100644 --- a/server/modules/filter/cache/rules.h +++ b/server/modules/filter/cache/rules.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -105,6 +106,14 @@ CACHE_RULES *cache_rules_create(uint32_t debug); */ void cache_rules_free(CACHE_RULES *rules); +/** + * Frees all rules in an array of rules *and* the array itself. + * + * @param ppRules Pointer to array of pointers to rules. + * @param nRules The number of items in the array. + */ +void cache_rules_free_array(CACHE_RULES** ppRules, int32_t nRules); + /** * Loads the caching rules from a file and returns corresponding object. * @@ -175,6 +184,8 @@ MXS_END_DECLS class CacheRules { public: + typedef std::tr1::shared_ptr SCacheRules; + ~CacheRules(); /** @@ -184,17 +195,18 @@ public: * * @return An empty rules object, or NULL in case of error. */ - static CacheRules* create(uint32_t debug); + static std::auto_ptr create(uint32_t debug); /** * Loads the caching rules from a file and returns corresponding object. * - * @param path The path of the file containing the rules. - * @param debug The debug level. + * @param path The path of the file containing the rules. + * @param debug The debug level. + * @param pRules [out] The loaded rules. * - * @return The corresponding rules object, or NULL in case of error. + * @return True, if the rules could be loaded, false otherwise. */ - static CacheRules* load(const char *zPath, uint32_t debug); + static bool load(const char *zPath, uint32_t debug, std::vector* pRules); /** * Returns the json rules object.