MXS-797 Add initial version of RocksDB storage
RocksDB is cloned from github and version v4.9 (latest at the time of this writing) is checked out. RocksDB can only be compiled as C++11, which means that RocksDB and hence storage_rocksdb can be built only if the GCC version is >= 4.7. The actual storage implementation is quite straightforward. - The key is a SHA512 of the entire query. That will be changed so that the database/table name is stored in the beginning of the key unhashed as that will cause cached items from the same table to be stored together. Assumption is that if you access something from a particular table, chances are you will access something else as well. - When the SO is loaded, the initialization function will created a subdirectory storage_rocksdb under the MaxScale cache directory. - For each instance, the RocksDB cache is created into a directory whose name is the same as the cache filter name in the configuration file, under that directory. - The storage API's get and put functions are then mapped directly on top of RockDB's equivalent functions.
This commit is contained in:
2
server/modules/filter/cache/CMakeLists.txt
vendored
2
server/modules/filter/cache/CMakeLists.txt
vendored
@ -2,3 +2,5 @@ add_library(cache SHARED cache.c storage.c)
|
||||
target_link_libraries(cache maxscale-common)
|
||||
set_target_properties(cache PROPERTIES VERSION "1.0.0")
|
||||
install_module(cache experimental)
|
||||
|
||||
add_subdirectory(storage)
|
||||
|
1
server/modules/filter/cache/storage/CMakeLists.txt
vendored
Normal file
1
server/modules/filter/cache/storage/CMakeLists.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(storage_rocksdb)
|
31
server/modules/filter/cache/storage/storage_rocksdb/BuildRocksDB.cmake
vendored
Normal file
31
server/modules/filter/cache/storage/storage_rocksdb/BuildRocksDB.cmake
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
# Build RocksDB
|
||||
|
||||
if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7)))
|
||||
message(STATUS "GCC >= 4.7, RocksDB is built.")
|
||||
|
||||
set(ROCKSDB_REPO "https://github.com/facebook/rocksdb.git"
|
||||
CACHE STRING "RocksDB Git repository")
|
||||
|
||||
# Release 4.9 of RocksDB
|
||||
set(ROCKSDB_TAG "v4.9"
|
||||
CACHE STRING "RocksDB Git tag")
|
||||
|
||||
set(ROCKSDB_SUBPATH "/server/modules/filter/cache/storage/storage_rocksdb/RocksDB-prefix/src/RocksDB")
|
||||
set(ROCKSDB_ROOT ${CMAKE_BINARY_DIR}${ROCKSDB_SUBPATH})
|
||||
|
||||
ExternalProject_Add(RocksDB
|
||||
GIT_REPOSITORY ${ROCKSDB_REPO}
|
||||
GIT_TAG ${ROCKSDB_TAG}
|
||||
CONFIGURE_COMMAND ""
|
||||
BINARY_DIR ${ROCKSDB_ROOT}
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND make DISABLE_JEMALLOC=1 EXTRA_CXXFLAGS=-fPIC static_lib
|
||||
INSTALL_COMMAND "")
|
||||
|
||||
set(ROCKSDB_BUILT TRUE CACHE INTERNAL "")
|
||||
set(ROCKSDB_INCLUDE_DIR ${ROCKSDB_ROOT}/include)
|
||||
set(ROCKSDB_LIB_DIR ${ROCKSDB_ROOT})
|
||||
set(ROCKSDB_LIB librocksdb.a)
|
||||
else()
|
||||
message(STATUS "RocksDB requires GCC >= 4.7, only ${CMAKE_CXX_COMPILER_VERSION} available.")
|
||||
endif()
|
24
server/modules/filter/cache/storage/storage_rocksdb/CMakeLists.txt
vendored
Normal file
24
server/modules/filter/cache/storage/storage_rocksdb/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
include(BuildRocksDB.cmake)
|
||||
|
||||
if (ROCKSDB_BUILT)
|
||||
message(STATUS "RocksDB is built, storage_rocksdb will be built.")
|
||||
|
||||
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-std=c++11 ${CMAKE_CXX_FLAGS_DEBUG}")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-std=c++11 ${CMAKE_CXX_FLAGS_RELEASE}")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-std=c++11 ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
|
||||
|
||||
include_directories(${ROCKSDB_INCLUDE_DIR})
|
||||
link_directories(${ROCKSDB_LIB_DIR})
|
||||
|
||||
add_library(storage_rocksdb SHARED
|
||||
rocksdbstorage.cc
|
||||
storage_rocksdb.cc
|
||||
)
|
||||
target_link_libraries(storage_rocksdb maxscale-common ${ROCKSDB_LIB})
|
||||
set_target_properties(storage_rocksdb PROPERTIES VERSION "1.0.0")
|
||||
set_target_properties(storage_rocksdb PROPERTIES LINK_FLAGS -Wl,-z,defs)
|
||||
install_module(storage_rocksdb experimental)
|
||||
else()
|
||||
message("RocksDB not built, storage_rocksdb cannot be built.")
|
||||
endif()
|
166
server/modules/filter/cache/storage/storage_rocksdb/rocksdbstorage.cc
vendored
Normal file
166
server/modules/filter/cache/storage/storage_rocksdb/rocksdbstorage.cc
vendored
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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 "rocksdbstorage.h"
|
||||
#include <openssl/sha.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <gwdirs.h>
|
||||
|
||||
using std::string;
|
||||
using std::unique_ptr;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
const size_t ROCKSDB_KEY_LENGTH = SHA512_DIGEST_LENGTH;
|
||||
string u_storageDirectory;
|
||||
|
||||
}
|
||||
|
||||
//private
|
||||
RocksDBStorage::RocksDBStorage(unique_ptr<rocksdb::DBWithTTL>& sDb,
|
||||
const string& name,
|
||||
const string& path,
|
||||
uint32_t ttl)
|
||||
: m_sDb(std::move(sDb))
|
||||
, m_name(name)
|
||||
, m_path(path)
|
||||
, m_ttl(ttl)
|
||||
{
|
||||
}
|
||||
|
||||
RocksDBStorage::~RocksDBStorage()
|
||||
{
|
||||
}
|
||||
|
||||
//static
|
||||
bool RocksDBStorage::Initialize()
|
||||
{
|
||||
bool initialized = true;
|
||||
|
||||
u_storageDirectory = get_cachedir();
|
||||
u_storageDirectory += "/storage_rocksdb";
|
||||
|
||||
if (mkdir(u_storageDirectory.c_str(), S_IRWXU) == 0)
|
||||
{
|
||||
MXS_NOTICE("Created storage directory %s.", u_storageDirectory.c_str());
|
||||
}
|
||||
else if (errno != EEXIST)
|
||||
{
|
||||
initialized = false;
|
||||
char errbuf[STRERROR_BUFLEN];
|
||||
|
||||
MXS_ERROR("Failed to create storage directory %s: %s",
|
||||
u_storageDirectory.c_str(),
|
||||
strerror_r(errno, errbuf, sizeof(errbuf)));
|
||||
}
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
|
||||
//static
|
||||
RocksDBStorage* RocksDBStorage::Create(const char* zName, uint32_t ttl, int argc, char* argv[])
|
||||
{
|
||||
ss_dassert(zName);
|
||||
|
||||
string path(u_storageDirectory);
|
||||
|
||||
path += "/";
|
||||
path += zName;
|
||||
|
||||
rocksdb::Options options;
|
||||
options.create_if_missing = true;
|
||||
rocksdb::DBWithTTL* pDb;
|
||||
|
||||
rocksdb::Status status = rocksdb::DBWithTTL::Open(options, path, &pDb, ttl);
|
||||
|
||||
RocksDBStorage* pStorage = nullptr;
|
||||
|
||||
if (status.ok())
|
||||
{
|
||||
unique_ptr<rocksdb::DBWithTTL> sDb(pDb);
|
||||
|
||||
pStorage = new RocksDBStorage(sDb, zName, path, ttl);
|
||||
}
|
||||
else
|
||||
{
|
||||
MXS_ERROR("Could not open RocksDB database %s using path %s: %s",
|
||||
zName, path.c_str(), status.ToString().c_str());
|
||||
}
|
||||
|
||||
return pStorage;
|
||||
}
|
||||
|
||||
cache_result_t RocksDBStorage::getKey(const GWBUF* pQuery, char* pKey)
|
||||
{
|
||||
// ss_dassert(gwbuf_is_contiguous(pQuery));
|
||||
const uint8_t* pData = static_cast<const uint8_t*>(GWBUF_DATA(pQuery));
|
||||
size_t len = MYSQL_GET_PACKET_LEN(pData) - 1; // Subtract 1 for packet type byte.
|
||||
|
||||
const uint8_t* pSql = &pData[5]; // Symbolic constant for 5?
|
||||
|
||||
memset(pKey, 0, CACHE_KEY_MAXLEN);
|
||||
|
||||
SHA512(pSql, len, reinterpret_cast<unsigned char*>(pKey));
|
||||
|
||||
return CACHE_RESULT_OK;
|
||||
}
|
||||
|
||||
cache_result_t RocksDBStorage::getValue(const char* pKey, GWBUF** ppResult)
|
||||
{
|
||||
rocksdb::Slice key(pKey, ROCKSDB_KEY_LENGTH);
|
||||
string value;
|
||||
|
||||
rocksdb::Status status = m_sDb->Get(rocksdb::ReadOptions(), key, &value);
|
||||
|
||||
cache_result_t result = CACHE_RESULT_ERROR;
|
||||
|
||||
switch (status.code())
|
||||
{
|
||||
case rocksdb::Status::kOk:
|
||||
{
|
||||
*ppResult = gwbuf_alloc(value.length());
|
||||
|
||||
if (*ppResult)
|
||||
{
|
||||
memcpy(GWBUF_DATA(*ppResult), value.data(), value.length());
|
||||
|
||||
result = CACHE_RESULT_OK;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case rocksdb::Status::kNotFound:
|
||||
result = CACHE_RESULT_NOT_FOUND;
|
||||
break;
|
||||
|
||||
default:
|
||||
MXS_ERROR("Failed to look up value: %s", status.ToString().c_str());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cache_result_t RocksDBStorage::putValue(const char* pKey, const GWBUF* pValue)
|
||||
{
|
||||
// ss_dassert(gwbuf_is_contiguous(pValue));
|
||||
|
||||
rocksdb::Slice key(pKey, ROCKSDB_KEY_LENGTH);
|
||||
rocksdb::Slice value(static_cast<const char*>(GWBUF_DATA(pValue)), GWBUF_LENGTH(pValue));
|
||||
|
||||
rocksdb::Status status = m_sDb->Put(rocksdb::WriteOptions(), key, value);
|
||||
|
||||
return status.ok() ? CACHE_RESULT_OK : CACHE_RESULT_ERROR;
|
||||
}
|
50
server/modules/filter/cache/storage/storage_rocksdb/rocksdbstorage.h
vendored
Normal file
50
server/modules/filter/cache/storage/storage_rocksdb/rocksdbstorage.h
vendored
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef _ROCKSDBSTORAGE_H
|
||||
#define _ROCKSDBSTORAGE_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 "storage_rocksdb.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <rocksdb/utilities/db_ttl.h>
|
||||
#include "../../cache_storage_api.h"
|
||||
|
||||
class RocksDBStorage
|
||||
{
|
||||
public:
|
||||
static bool Initialize();
|
||||
|
||||
static RocksDBStorage* Create(const char* zName, uint32_t ttl, int argc, char* argv[]);
|
||||
~RocksDBStorage();
|
||||
|
||||
cache_result_t getKey(const GWBUF* pQuery, char* pKey);
|
||||
cache_result_t getValue(const char* pKey, GWBUF** ppResult);
|
||||
cache_result_t putValue(const char* pKey, const GWBUF* pValue);
|
||||
|
||||
private:
|
||||
RocksDBStorage(std::unique_ptr<rocksdb::DBWithTTL>& sDb,
|
||||
const std::string& name,
|
||||
const std::string& path,
|
||||
uint32_t ttl);
|
||||
|
||||
RocksDBStorage(const RocksDBStorage&) = delete;
|
||||
RocksDBStorage& operator = (const RocksDBStorage&) = delete;
|
||||
|
||||
private:
|
||||
std::unique_ptr<rocksdb::DBWithTTL> m_sDb;
|
||||
std::string m_name;
|
||||
std::string m_path;
|
||||
uint32_t m_ttl;
|
||||
};
|
||||
|
||||
#endif
|
151
server/modules/filter/cache/storage/storage_rocksdb/storage_rocksdb.cc
vendored
Normal file
151
server/modules/filter/cache/storage/storage_rocksdb/storage_rocksdb.cc
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* 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 "storage_rocksdb.h"
|
||||
#include "../../cache_storage_api.h"
|
||||
#include "rocksdbstorage.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool initialize()
|
||||
{
|
||||
return RocksDBStorage::Initialize();
|
||||
}
|
||||
|
||||
CACHE_STORAGE* createInstance(const char* zName, uint32_t ttl, int argc, char* argv[])
|
||||
{
|
||||
CACHE_STORAGE* pStorage = 0;
|
||||
|
||||
try
|
||||
{
|
||||
pStorage = reinterpret_cast<CACHE_STORAGE*>(RocksDBStorage::Create(zName, ttl, argc, argv));
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
MXS_OOM();
|
||||
}
|
||||
catch (const std::exception& x)
|
||||
{
|
||||
MXS_ERROR("Standard exception caught: %s", x.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
MXS_ERROR("Unknown exception caught.");
|
||||
}
|
||||
|
||||
return pStorage;
|
||||
}
|
||||
|
||||
void freeInstance(CACHE_STORAGE* pInstance)
|
||||
{
|
||||
delete reinterpret_cast<RocksDBStorage*>(pInstance);
|
||||
}
|
||||
|
||||
cache_result_t getKey(CACHE_STORAGE* pStorage,
|
||||
const GWBUF* pQuery,
|
||||
char* pKey)
|
||||
{
|
||||
cache_result_t result = CACHE_RESULT_ERROR;
|
||||
|
||||
try
|
||||
{
|
||||
result = reinterpret_cast<RocksDBStorage*>(pStorage)->getKey(pQuery, pKey);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
MXS_OOM();
|
||||
}
|
||||
catch (const std::exception& x)
|
||||
{
|
||||
MXS_ERROR("Standard exception caught: %s", x.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
MXS_ERROR("Unknown exception caught.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cache_result_t getValue(CACHE_STORAGE* pStorage, const char* pKey, GWBUF** ppResult)
|
||||
{
|
||||
cache_result_t result = CACHE_RESULT_ERROR;
|
||||
|
||||
try
|
||||
{
|
||||
result = reinterpret_cast<RocksDBStorage*>(pStorage)->getValue(pKey, ppResult);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
MXS_OOM();
|
||||
}
|
||||
catch (const std::exception& x)
|
||||
{
|
||||
MXS_ERROR("Standard exception caught: %s", x.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
MXS_ERROR("Unknown exception caught.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cache_result_t putValue(CACHE_STORAGE* pStorage,
|
||||
const char* pKey,
|
||||
const GWBUF* pValue)
|
||||
{
|
||||
cache_result_t result = CACHE_RESULT_ERROR;
|
||||
|
||||
try
|
||||
{
|
||||
result = reinterpret_cast<RocksDBStorage*>(pStorage)->putValue(pKey, pValue);
|
||||
}
|
||||
catch (const std::bad_alloc&)
|
||||
{
|
||||
MXS_OOM();
|
||||
}
|
||||
catch (const std::exception& x)
|
||||
{
|
||||
MXS_ERROR("Standard exception caught: %s", x.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
MXS_ERROR("Unknown exception caught.");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
CACHE_STORAGE_API* CacheGetStorageAPI()
|
||||
{
|
||||
static CACHE_STORAGE_API api =
|
||||
{
|
||||
initialize,
|
||||
createInstance,
|
||||
freeInstance,
|
||||
getKey,
|
||||
getValue,
|
||||
putValue
|
||||
};
|
||||
|
||||
return &api;
|
||||
}
|
||||
|
||||
}
|
19
server/modules/filter/cache/storage/storage_rocksdb/storage_rocksdb.h
vendored
Normal file
19
server/modules/filter/cache/storage/storage_rocksdb/storage_rocksdb.h
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
#ifndef _STORAGE_ROCKSDB_H
|
||||
#define _STORAGE_ROCKSDB_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.
|
||||
*/
|
||||
|
||||
#define MXS_MODULE_NAME "storage_rocksdb"
|
||||
#include <log_manager.h>
|
||||
|
||||
#endif
|
Reference in New Issue
Block a user