From d0242e2721964b9066a9d7d75bc9a3d243385f33 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Tue, 12 Jul 2016 10:43:32 +0100 Subject: [PATCH] New IncRedis class. Makes high-level access to Redis easier. --- src/backends/redis/CMakeLists.txt | 1 + src/backends/redis/backend_redis.cpp | 56 ++++++++-------- src/backends/redis/backend_redis.hpp | 4 +- src/backends/redis/incredis.cpp | 97 ++++++++++++++++++++++++++++ src/backends/redis/incredis.hpp | 59 +++++++++++++++++ 5 files changed, 187 insertions(+), 30 deletions(-) create mode 100644 src/backends/redis/incredis.cpp create mode 100644 src/backends/redis/incredis.hpp diff --git a/src/backends/redis/CMakeLists.txt b/src/backends/redis/CMakeLists.txt index 096d0a2..1966159 100644 --- a/src/backends/redis/CMakeLists.txt +++ b/src/backends/redis/CMakeLists.txt @@ -19,6 +19,7 @@ add_library(${PROJECT_NAME} SHARED tag.cpp delete.cpp find.cpp + incredis.cpp ) target_include_directories(${PROJECT_NAME} SYSTEM diff --git a/src/backends/redis/backend_redis.cpp b/src/backends/redis/backend_redis.cpp index ec11d96..7f98628 100644 --- a/src/backends/redis/backend_redis.cpp +++ b/src/backends/redis/backend_redis.cpp @@ -107,7 +107,7 @@ namespace dindb { m_redis.connect(); m_redis.wait_for_connect(); if (m_redis.is_connected()) { - auto batch = m_redis.make_batch(); + auto batch = m_redis.command().make_batch(); batch.run("SELECT", lexical_cast(m_database)); batch.run("CLIENT", "SETNAME", PROGRAM_NAME "_v" STRINGIZE(VERSION_MAJOR) "." STRINGIZE(VERSION_MINOR) "." STRINGIZE(VERSION_PATCH)); batch.run("SCRIPT", "FLUSH"); @@ -115,13 +115,13 @@ namespace dindb { } else { std::ostringstream oss; - oss << "Error connecting to Redis: " << m_redis.connection_error(); + oss << "Error connecting to Redis: " << m_redis.command().connection_error(); throw std::runtime_error(oss.str()); } - m_tag_if_in_set = m_redis.make_script(read_script(m_lua_script_paths, "tag_if_in_set.lua")); - m_dele_tag_if_in_set = m_redis.make_script(read_script(m_lua_script_paths, "dele_tag_if_in_set.lua")); - m_dele_hash = m_redis.make_script(read_script(m_lua_script_paths, "dele_hash.lua")); + m_tag_if_in_set = m_redis.command().make_script(read_script(m_lua_script_paths, "tag_if_in_set.lua")); + m_dele_tag_if_in_set = m_redis.command().make_script(read_script(m_lua_script_paths, "dele_tag_if_in_set.lua")); + m_dele_hash = m_redis.command().make_script(read_script(m_lua_script_paths, "dele_hash.lua")); } void BackendRedis::disconnect() { @@ -129,47 +129,47 @@ namespace dindb { } void BackendRedis::tag_files (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) { - dindb::tag_files(m_redis, m_tag_if_in_set, parFiles, parTags, parSet); + dindb::tag_files(m_redis.command(), m_tag_if_in_set, parFiles, parTags, parSet); } void BackendRedis::tag_files (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) { - dindb::tag_files(m_redis, m_tag_if_in_set, parRegexes, parTags, parSet); + dindb::tag_files(m_redis.command(), m_tag_if_in_set, parRegexes, parTags, parSet); } void BackendRedis::delete_tags (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) { - dindb::delete_tags(m_redis, m_dele_tag_if_in_set, parFiles, parTags, parSet); + dindb::delete_tags(m_redis.command(), m_dele_tag_if_in_set, parFiles, parTags, parSet); } void BackendRedis::delete_tags (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) { - dindb::delete_tags(m_redis, m_dele_tag_if_in_set, parRegexes, parTags, parSet); + dindb::delete_tags(m_redis.command(), m_dele_tag_if_in_set, parRegexes, parTags, parSet); } void BackendRedis::delete_all_tags (const std::vector& parFiles, GroupIDType parSet) { - dindb::delete_all_tags(m_redis, m_dele_tag_if_in_set, parFiles, parSet); + dindb::delete_all_tags(m_redis.command(), m_dele_tag_if_in_set, parFiles, parSet); } void BackendRedis::delete_all_tags (const std::vector& parRegexes, GroupIDType parSet) { - dindb::delete_all_tags(m_redis, m_dele_tag_if_in_set, parRegexes, parSet); + dindb::delete_all_tags(m_redis.command(), m_dele_tag_if_in_set, parRegexes, parSet); } void BackendRedis::delete_group (const std::vector& parIDs, ConfirmDeleCallback parConf) { - delete_group_from_db(m_redis, m_dele_tag_if_in_set, m_dele_hash, parIDs, parConf); + delete_group_from_db(m_redis.command(), m_dele_tag_if_in_set, m_dele_hash, parIDs, parConf); } void BackendRedis::write_files (const std::vector& parData, const mchlib::SetRecordDataFull& parSetData, const std::string& parSignature) { using dinhelp::lexical_cast; using boost::string_ref; - redis::Reply set_id_reply = m_redis.run("HINCRBY", PROGRAM_NAME ":indices", "set", "1"); - redis::Reply file_id_reply = m_redis.run("HINCRBY", PROGRAM_NAME ":indices", "files", lexical_cast(parData.size())); + const auto data_size = static_cast(parData.size()); + const auto group_id_int = m_redis.hincrby(PROGRAM_NAME ":indices", "set", 1); + const auto file_id_int = m_redis.hincrby(PROGRAM_NAME ":indices", "files", data_size); - const auto group_id = lexical_cast(redis::get_integer(set_id_reply)); + const auto group_id = lexical_cast(group_id_int); const std::string set_key = PROGRAM_NAME ":set:" + group_id; - const auto casted_data_size = static_cast(parData.size()); - assert(redis::get_integer(file_id_reply) >= casted_data_size); - const auto base_file_id = redis::get_integer(file_id_reply) - casted_data_size + 1; + assert(file_id_int >= data_size); + const auto base_file_id = file_id_int - data_size + 1; - auto batch = m_redis.make_batch(); + auto batch = m_redis.command().make_batch(); batch.run( "HMSET", @@ -183,7 +183,7 @@ namespace dindb { "file_count", lexical_cast(parData.size()) ); - for (auto z = base_file_id; z < casted_data_size + 1; ++z) { + for (auto z = base_file_id; z < data_size + 1; ++z) { const std::string file_key = PROGRAM_NAME ":file:" + lexical_cast(z); const auto& file_data = parData[z - base_file_id]; const std::string hash = tiger_to_string(file_data.hash); @@ -217,29 +217,29 @@ namespace dindb { using boost::empty; const std::string hash_key = PROGRAM_NAME ":hash:" + tiger_to_string(parHash); - redis::Reply hash_reply = m_redis.run("SRANDMEMBER", hash_key); - if (redis::RedisVariantType_Nil == hash_reply.which() or (redis::RedisVariantType_Integer == hash_reply.which() and not redis::get_integer(hash_reply))) { + auto hash_reply = m_redis.srandmember(hash_key); + if (not hash_reply) { return false; } else { - const auto result_id = redis::get_string(hash_reply); - auto set_key_and_file_item = redis::range_as(m_redis.hscan(result_id)); + const auto result_id = std::move(*hash_reply); + auto set_key_and_file_item = redis::range_as(m_redis.command().hscan(result_id)); parItem = std::move(set_key_and_file_item.second); const std::string group_key = std::move(set_key_and_file_item.first); - auto scan_range = m_redis.hscan(group_key); + auto scan_range = m_redis.command().hscan(group_key); if (empty(scan_range)) { return false; } else { - parSet = redis::range_as(m_redis.hscan(group_key)); + parSet = redis::range_as(m_redis.command().hscan(group_key)); return true; } } } std::vector BackendRedis::locate_in_db (const std::string& parSearch, const TagList& parTags) { - return dindb::locate_in_db(m_redis, parSearch, parTags); + return dindb::locate_in_db(m_redis.command(), parSearch, parTags); } std::vector BackendRedis::locate_in_db (const mchlib::TigerHash& parSearch, const TagList& parTags) { @@ -255,7 +255,7 @@ namespace dindb { } std::vector BackendRedis::find_all_sets() { - return dindb::find_all_sets(m_redis); + return dindb::find_all_sets(m_redis.command()); } std::vector> BackendRedis::find_set_details (const std::vector& parSets) { diff --git a/src/backends/redis/backend_redis.hpp b/src/backends/redis/backend_redis.hpp index a3ed3dc..4959d87 100644 --- a/src/backends/redis/backend_redis.hpp +++ b/src/backends/redis/backend_redis.hpp @@ -19,7 +19,7 @@ #define idB2F92EE07A004D5293FD0657EEE8F75B #include "backends/db_backend.hpp" -#include "command.hpp" +#include "incredis.hpp" #include "script.hpp" #include "dindexer-core/searchpaths.hpp" #include @@ -58,7 +58,7 @@ namespace dindb { virtual std::vector find_paths_starting_by ( GroupIDType parGroupID, uint16_t parLevel, boost::string_ref parPath ) override; private: - redis::Command m_redis; + redis::IncRedis m_redis; redis::Script m_tag_if_in_set; redis::Script m_dele_tag_if_in_set; redis::Script m_dele_hash; diff --git a/src/backends/redis/incredis.cpp b/src/backends/redis/incredis.cpp new file mode 100644 index 0000000..1487c4d --- /dev/null +++ b/src/backends/redis/incredis.cpp @@ -0,0 +1,97 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "dindexer". If not, see . + */ + +#include "incredis.hpp" +#include "helpers/compatibility.h" +#include "helpers/lexical_cast.hpp" +#include +#include +#include + +namespace redis { + namespace { + inline IncRedis::opt_string optional_string ( const Reply& parReply ) a_always_inline; + inline IncRedis::opt_string_list optional_string_list ( const Reply& parReply ) a_always_inline; + + IncRedis::opt_string optional_string (const Reply& parReply) { + assert(parReply.which() == RedisVariantType_Nil or parReply.which() == RedisVariantType_String); + if (RedisVariantType_Nil == parReply.which()) + return boost::none; + else + return get_string(parReply); + } + + IncRedis::opt_string_list optional_string_list (const Reply& parReply) { + assert(parReply.which() == RedisVariantType_Nil or parReply.which() == RedisVariantType_Array); + if (RedisVariantType_Nil == parReply.which()) { + return boost::none; + } + else { + auto replies = get_array(parReply); + IncRedis::opt_string_list::value_type retval; + retval.reserve(replies.size()); + for (const auto& rep : replies) { + retval.emplace_back(optional_string(rep)); + } + return IncRedis::opt_string_list(std::move(retval)); + } + } + } + IncRedis::IncRedis (std::string &&parAddress, uint16_t parPort) : + m_command(std::move(parAddress), parPort) + { + } + + IncRedis::IncRedis (std::string&& parSocket) : + m_command(std::move(parSocket)) + { + } + + void IncRedis::connect() { + m_command.connect(); + } + + void IncRedis::wait_for_connect() { + m_command.wait_for_connect(); + } + + void IncRedis::disconnect() { + m_command.disconnect(); + } + + void IncRedis::wait_for_disconnect() { + m_command.wait_for_disconnect(); + } + + auto IncRedis::hget (boost::string_ref parKey, boost::string_ref parField) -> opt_string { + return optional_string(m_command.run("HGET", parKey, parField)); + } + + int IncRedis::hincrby (boost::string_ref parKey, boost::string_ref parField, int parInc) { + const auto inc = dinhelp::lexical_cast(parInc); + auto reply = m_command.run("HINCRBY", parKey, parField, inc); + return get_integer(reply); + } + + auto IncRedis::srandmember (boost::string_ref parKey, int parCount) -> opt_string_list { + return optional_string_list(m_command.run("SRANDMEMBER", parKey, dinhelp::lexical_cast(parCount))); + } + + auto IncRedis::srandmember (boost::string_ref parKey) -> opt_string { + return optional_string(m_command.run("SRANDMEMBER", parKey)); + } +} //namespace redis diff --git a/src/backends/redis/incredis.hpp b/src/backends/redis/incredis.hpp new file mode 100644 index 0000000..809b1de --- /dev/null +++ b/src/backends/redis/incredis.hpp @@ -0,0 +1,59 @@ +/* Copyright 2015, 2016, Michele Santullo + * This file is part of "dindexer". + * + * "dindexer" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "dindexer" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "dindexer". If not, see . + */ + +#ifndef id7D338900114548A890B1EECE0C4D3C4C +#define id7D338900114548A890B1EECE0C4D3C4C + +#include "command.hpp" +#include +#include +#include +#include + +namespace redis { + class IncRedis { + public: + typedef boost::optional opt_string; + typedef boost::optional> opt_string_list; + + IncRedis ( std::string&& parAddress, uint16_t parPort ); + explicit IncRedis ( std::string&& parSocket ); + ~IncRedis ( void ) noexcept = default; + + void connect ( void ); + void wait_for_connect ( void ); + void disconnect ( void ); + void wait_for_disconnect ( void ); + bool is_connected ( void ) const { return m_command.is_connected(); } + + Command& command ( void ) { return m_command; } + const Command& command ( void ) const { return m_command; } + + //Hash + opt_string hget ( boost::string_ref parKey, boost::string_ref parField ); + int hincrby ( boost::string_ref parKey, boost::string_ref parField, int parInc ); + + //Set + opt_string_list srandmember ( boost::string_ref parKey, int parCount ); + opt_string srandmember ( boost::string_ref parKey ); + + private: + Command m_command; + }; +} //namespace redis + +#endif