From 10deb9f07b675d27b0e96f26ee8d29110b7fb387 Mon Sep 17 00:00:00 2001 From: Johan Wikman Date: Thu, 24 Nov 2016 11:43:29 +0200 Subject: [PATCH] Cache: Introduce StorageFactory and Storage The storage module is abstracted with StorageFactory that is capable of creating Storage instances. The latter contains the data and provides the behaviour for using the actual storage implementation, which sits behing a C API, conveniently. --- server/modules/filter/cache/CMakeLists.txt | 2 +- server/modules/filter/cache/cachefilter.cc | 29 ++-- server/modules/filter/cache/storage.cc | 104 ++++-------- server/modules/filter/cache/storage.h | 36 +++- server/modules/filter/cache/storagefactory.cc | 154 ++++++++++++++++++ server/modules/filter/cache/storagefactory.h | 44 +++++ 6 files changed, 267 insertions(+), 102 deletions(-) create mode 100644 server/modules/filter/cache/storagefactory.cc create mode 100644 server/modules/filter/cache/storagefactory.h diff --git a/server/modules/filter/cache/CMakeLists.txt b/server/modules/filter/cache/CMakeLists.txt index 2592217bd..9934207f5 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 cachefilter.cc rules.cc storage.cc) + add_library(cache SHARED cachefilter.cc rules.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/cachefilter.cc b/server/modules/filter/cache/cachefilter.cc index 458a36060..ed97c4fb9 100644 --- a/server/modules/filter/cache/cachefilter.cc +++ b/server/modules/filter/cache/cachefilter.cc @@ -25,6 +25,7 @@ #include #include "rules.h" #include "storage.h" +#include "storagefactory.h" static char VERSION_STRING[] = "V1.0.0"; @@ -124,8 +125,8 @@ typedef struct cache_instance const char *name; // The name of the instance; the section name in the config. CACHE_CONFIG config; // The configuration of the cache instance. CACHE_RULES *rules; // The rules of the cache instance. - CACHE_STORAGE_MODULE *module; // The storage module. - CACHE_STORAGE *storage; // The storage API. + StorageFactory *factory; // The storage factory. + Storage *storage; // The storage instance to use. HASHTABLE *pending; // Pending items; being fetched from the backend. SPINLOCK pending_lock; // Lock used for protecting 'pending'. } CACHE_INSTANCE; @@ -154,8 +155,7 @@ static void cache_response_state_reset(CACHE_RESPONSE_STATE *state); typedef struct cache_session_data { CACHE_INSTANCE *instance; /**< The cache instance the session is associated with. */ - CACHE_STORAGE_API *api; /**< The storage API to be used. */ - CACHE_STORAGE *storage; /**< The storage to be used with this session data. */ + Storage *storage; /**< The storage to be used with this session data. */ DOWNSTREAM down; /**< The previous filter or equivalent. */ UPSTREAM up; /**< The next filter or equivalent. */ CACHE_RESPONSE_STATE res; /**< The response state. */ @@ -268,22 +268,22 @@ static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER if (cinstance && pending) { - CACHE_STORAGE_MODULE *module = cache_storage_open(config.storage); + StorageFactory *factory = StorageFactory::Open(config.storage); - if (module) + if (factory) { uint32_t ttl = config.ttl; int argc = config.storage_argc; char** argv = config.storage_argv; - CACHE_STORAGE *storage = module->api->createInstance(name, ttl, argc, argv); + Storage *storage = factory->createStorage(name, ttl, argc, argv); if (storage) { cinstance->name = name; cinstance->config = config; cinstance->rules = rules; - cinstance->module = module; + cinstance->factory = factory; cinstance->storage = storage; cinstance->pending = pending; @@ -293,7 +293,7 @@ static FILTER *createInstance(const char *name, char **options, FILTER_PARAMETER { MXS_ERROR("Could not create storage instance for '%s'.", name); cache_rules_free(rules); - cache_storage_close(module); + delete factory; MXS_FREE(cinstance); hashtable_free(pending); cinstance = NULL; @@ -722,7 +722,6 @@ static CACHE_SESSION_DATA *cache_session_data_create(CACHE_INSTANCE *instance, if ((mysql_session->db[0] == 0) || default_db) { data->instance = instance; - data->api = instance->module->api; data->storage = instance->storage; data->session = session; data->state = CACHE_EXPECTING_NOTHING; @@ -1202,13 +1201,13 @@ static cache_result_t get_cached_response(CACHE_SESSION_DATA *csdata, const GWBUF *query, GWBUF **value) { - cache_result_t result = csdata->api->getKey(csdata->storage, csdata->default_db, query, csdata->key); + cache_result_t result = csdata->storage->getKey(csdata->default_db, query, csdata->key); if (result == CACHE_RESULT_OK) { uint32_t flags = CACHE_FLAGS_INCLUDE_STALE; - result = csdata->api->getValue(csdata->storage, csdata->key, flags, value); + result = csdata->storage->getValue(csdata->key, flags, value); } else { @@ -1250,15 +1249,13 @@ static void store_result(CACHE_SESSION_DATA *csdata) { csdata->res.data = data; - cache_result_t result = csdata->api->putValue(csdata->storage, - csdata->key, - csdata->res.data); + cache_result_t result = csdata->storage->putValue(csdata->key, csdata->res.data); if (result != CACHE_RESULT_OK) { MXS_ERROR("Could not store cache item, deleting it."); - result = csdata->api->delValue(csdata->storage, csdata->key); + result = csdata->storage->delValue(csdata->key); if ((result != CACHE_RESULT_OK) || (result != CACHE_RESULT_NOT_FOUND)) { diff --git a/server/modules/filter/cache/storage.cc b/server/modules/filter/cache/storage.cc index 165905dd1..2d724866a 100644 --- a/server/modules/filter/cache/storage.cc +++ b/server/modules/filter/cache/storage.cc @@ -12,85 +12,37 @@ */ #include "storage.h" -#include -#include -#include -#include -#include -CACHE_STORAGE_MODULE* cache_storage_open(const char *name) + +Storage::Storage(CACHE_STORAGE_API* pApi, CACHE_STORAGE* pStorage) + : m_pApi(pApi) + , m_pStorage(pStorage) { - CACHE_STORAGE_MODULE* module = (CACHE_STORAGE_MODULE*)MXS_CALLOC(1, sizeof(CACHE_STORAGE_MODULE)); - - if (module) - { - char path[MAXPATHLEN + 1]; - sprintf(path, "%s/lib%s.so", get_libdir(), name); - - void *handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); - - if (handle) - { - module->handle = handle; - - void *f = dlsym(module->handle, CACHE_STORAGE_ENTRY_POINT); - - if (f) - { - module->api = ((CacheGetStorageAPIFN)f)(); - - if (module->api) - { - if (!(module->api->initialize)()) - { - MXS_ERROR("Initialization of %s failed.", path); - - (void)dlclose(module->handle); - MXS_FREE(module); - module = NULL; - } - } - else - { - MXS_ERROR("Could not obtain API object from %s.", name); - - (void)dlclose(module->handle); - MXS_FREE(module); - module = NULL; - } - } - else - { - const char* s = dlerror(); - MXS_ERROR("Could not look up symbol %s from %s: %s", - name, CACHE_STORAGE_ENTRY_POINT, s ? s : ""); - MXS_FREE(module); - module = NULL; - } - } - else - { - const char* s = dlerror(); - MXS_ERROR("Could not load %s: %s", name, s ? s : ""); - MXS_FREE(module); - module = NULL; - } - } - - return module; + ss_dassert(m_pApi); + ss_dassert(m_pStorage); } - -void cache_storage_close(CACHE_STORAGE_MODULE *module) +cache_result_t Storage::getKey(const char* zDefaultDb, + const GWBUF* pQuery, + char* pKey) { - if (module) - { - if (dlclose(module->handle) != 0) - { - const char *s = dlerror(); - MXS_ERROR("Could not close module %s: ", s ? s : ""); - } - - MXS_FREE(module); - } + return m_pApi->getKey(m_pStorage, zDefaultDb, pQuery, pKey); +} + +cache_result_t Storage::getValue(const char* pKey, + uint32_t flags, + GWBUF** ppValue) +{ + return m_pApi->getValue(m_pStorage, pKey, flags, ppValue); +} + +cache_result_t Storage::putValue(const char* pKey, + const GWBUF* pValue) +{ + return m_pApi->putValue(m_pStorage, pKey, pValue); +} + +cache_result_t Storage::delValue(const char* pKey) +{ + return m_pApi->delValue(m_pStorage, pKey); } diff --git a/server/modules/filter/cache/storage.h b/server/modules/filter/cache/storage.h index f0d2f8bef..a2eadfaaf 100644 --- a/server/modules/filter/cache/storage.h +++ b/server/modules/filter/cache/storage.h @@ -17,17 +17,35 @@ #include #include "cache_storage_api.h" -MXS_BEGIN_DECLS - -typedef struct cache_storage_module_t +class Storage { - void* handle; - CACHE_STORAGE_API* api; -} CACHE_STORAGE_MODULE; +public: + ~Storage(); -CACHE_STORAGE_MODULE* cache_storage_open(const char *name); -void cache_storage_close(CACHE_STORAGE_MODULE *module); + cache_result_t getKey(const char* zDefaultDb, + const GWBUF* pQuery, + char* pKey); -MXS_END_DECLS + cache_result_t getValue(const char* pKey, + uint32_t flags, + GWBUF** ppValue); + + cache_result_t putValue(const char* pKey, + const GWBUF* pValue); + + cache_result_t delValue(const char* pKey); + +private: + friend class StorageFactory; + + Storage(CACHE_STORAGE_API* pApi, CACHE_STORAGE* pStorage); + + Storage(const Storage&); + Storage& operator = (const Storage&); + +private: + CACHE_STORAGE_API* m_pApi; + CACHE_STORAGE* m_pStorage; +}; #endif diff --git a/server/modules/filter/cache/storagefactory.cc b/server/modules/filter/cache/storagefactory.cc new file mode 100644 index 000000000..9b088da76 --- /dev/null +++ b/server/modules/filter/cache/storagefactory.cc @@ -0,0 +1,154 @@ +/* + * 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 "storagefactory.h" +#include +#include +#include +#include +#include +#include +#include "storage.h" + + +namespace +{ + +bool open_cache_storage(const char* zName, void** pHandle, CACHE_STORAGE_API** ppApi) +{ + bool rv = false; + + char path[MAXPATHLEN + 1]; + sprintf(path, "%s/lib%s.so", get_libdir(), zName); + + void* handle = dlopen(path, RTLD_NOW | RTLD_LOCAL); + + if (handle) + { + void* f = dlsym(handle, CACHE_STORAGE_ENTRY_POINT); + + if (f) + { + CACHE_STORAGE_API* pApi = ((CacheGetStorageAPIFN)f)(); + + if (pApi) + { + if ((pApi->initialize)()) + { + *pHandle = handle; + *ppApi = pApi; + + rv = true; + } + else + { + MXS_ERROR("Initialization of %s failed.", path); + + (void)dlclose(handle); + } + } + else + { + MXS_ERROR("Could not obtain API object from %s.", zName); + + (void)dlclose(handle); + } + } + else + { + const char* s = dlerror(); + MXS_ERROR("Could not look up symbol %s from %s: %s", + zName, CACHE_STORAGE_ENTRY_POINT, s ? s : ""); + } + } + else + { + const char* s = dlerror(); + MXS_ERROR("Could not load %s: %s", zName, s ? s : ""); + } + + return rv; +} + + +void close_cache_storage(void* handle, CACHE_STORAGE_API* pApi) +{ + // TODO: pApi->finalize(); + + if (dlclose(handle) != 0) + { + const char *s = dlerror(); + MXS_ERROR("Could not close module %s: ", s ? s : ""); + } +} + +} + +StorageFactory::StorageFactory(void* handle, CACHE_STORAGE_API* pApi) + : m_handle(handle) + , m_pApi(pApi) +{ + ss_dassert(handle); + ss_dassert(pApi); +} + +StorageFactory::~StorageFactory() +{ + close_cache_storage(m_handle, m_pApi); + m_handle = 0; + m_pApi = 0; +} + +//static +StorageFactory* StorageFactory::Open(const char* zName) +{ + StorageFactory* pFactory = 0; + + void* handle; + CACHE_STORAGE_API* pApi; + + if (open_cache_storage(zName, &handle, &pApi)) + { + pFactory = new (std::nothrow) StorageFactory(handle, pApi); + + if (!pFactory) + { + close_cache_storage(handle, pApi); + } + } + + return pFactory; +} + +Storage* StorageFactory::createStorage(const char* zName, + uint32_t ttl, + int argc, char* argv[]) +{ + ss_dassert(m_handle); + ss_dassert(m_pApi); + + Storage* pStorage = 0; + CACHE_STORAGE* pRawStorage = m_pApi->createInstance(zName, ttl, argc, argv); + + if (pRawStorage) + { + pStorage = new (std::nothrow) Storage(m_pApi, pRawStorage); + + if (!pStorage) + { + m_pApi->freeInstance(pRawStorage); + } + } + + return pStorage; +} diff --git a/server/modules/filter/cache/storagefactory.h b/server/modules/filter/cache/storagefactory.h new file mode 100644 index 000000000..e87f57742 --- /dev/null +++ b/server/modules/filter/cache/storagefactory.h @@ -0,0 +1,44 @@ +#pragma once +#ifndef _MAXSCALE_FILTER_CACHE_STORAGEFACTORY_H +#define _MAXSCALE_FILTER_CACHE_STORAGEFACTORY_H +/* + * 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 "cache_storage_api.h" + +class Storage; + +class StorageFactory +{ +public: + ~StorageFactory(); + + static StorageFactory* Open(const char* zName); + + Storage* createStorage(const char* zName, + uint32_t ttl, + int argc, char* argv[]); + +private: + StorageFactory(void* handle, CACHE_STORAGE_API* pApi); + + StorageFactory(const StorageFactory&); + StorageFactory& operator = (const StorageFactory&); + +private: + void* m_handle; + CACHE_STORAGE_API* m_pApi; +}; + +#endif