From afb2e6884925de024aa1c45fd4b37f8dc6f6e269 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Tue, 12 Jul 2016 16:42:27 +0100 Subject: [PATCH] Implement locate_in_db() by hash. --- src/backends/redis/backend_redis.cpp | 2 +- src/backends/redis/find.cpp | 63 ++++++++++++++++++++++++++++ src/backends/redis/find.hpp | 1 + src/backends/redis/incredis.cpp | 6 ++- src/backends/redis/incredis.hpp | 1 + 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/backends/redis/backend_redis.cpp b/src/backends/redis/backend_redis.cpp index e20c1c6..3bcf4e1 100644 --- a/src/backends/redis/backend_redis.cpp +++ b/src/backends/redis/backend_redis.cpp @@ -250,7 +250,7 @@ namespace dindb { } std::vector BackendRedis::locate_in_db (const mchlib::TigerHash& parSearch, const TagList& parTags) { - return std::vector(); + return dindb::locate_in_db(m_redis, parSearch, parTags); } std::vector BackendRedis::locate_sets_in_db (const std::string& parSearch, bool parCaseInsensitive) { diff --git a/src/backends/redis/find.cpp b/src/backends/redis/find.cpp index 6f750c6..b41cb12 100644 --- a/src/backends/redis/find.cpp +++ b/src/backends/redis/find.cpp @@ -20,9 +20,13 @@ #include "helpers/lexical_cast.hpp" #include "dindexerConfig.h" #include "dindexer-core/split_tags.hpp" +#include "dindexer-machinery/tiger.hpp" #include #include #include +#include +#include +#include namespace dindb { namespace { @@ -62,6 +66,20 @@ namespace dindb { ++id_index; } } + + //See: http://stackoverflow.com/questions/12552277/whats-the-best-way-to-iterate-over-two-or-more-containers-simultaneously/12553437#12553437 + //(referenced from http://stackoverflow.com/questions/16982190/c-use-boost-range-transformed-adaptor-with-binary-function) + //What became of this? http://marc.info/?l=boost-users&m=129619765731342 + template + auto zip_range (Conts&... parConts) -> decltype(boost::make_iterator_range( + boost::make_zip_iterator(boost::make_tuple(parConts.begin()...)), + boost::make_zip_iterator(boost::make_tuple(parConts.end()...))) + ) { + return { + boost::make_zip_iterator(boost::make_tuple(parConts.begin()...)), + boost::make_zip_iterator(boost::make_tuple(parConts.end()...)) + }; + } } //unnamed namespace std::vector find_all_sets (redis::IncRedis& parRedis) { @@ -104,4 +122,49 @@ namespace dindb { store_matching_paths(batch, retval, ids, search, parTags); return retval; } + + std::vector locate_in_db (redis::IncRedis& parRedis, const mchlib::TigerHash& parSearch, const TagList& parTags) { + using boost::adaptors::filtered; + using boost::adaptors::transformed; + using boost::tuple; + using boost::make_tuple; + using redis::get_string; + using redis::Reply; + using std::vector; + using dinhelp::lexical_cast; + + const auto hash_key = PROGRAM_NAME ":hash:" + mchlib::tiger_to_string(parSearch, false); + const auto file_ids = parRedis.smembers(hash_key); + + vector ids; + if (file_ids) { + auto batch = parRedis.make_batch(); + for (auto&& file_id : *file_ids) { + if (not file_id) + continue; + + const auto file_key = PROGRAM_NAME ":file:" + *file_id; + ids.emplace_back(std::move(*file_id)); + batch.hmget(file_key, "path", "group_id", "tags"); + } + batch.throw_if_failed(); + + assert(batch.replies().size() == ids.size()); + return boost::copy_range>( + zip_range(batch.replies(), ids) | + transformed([](const tuple& r) + { return make_tuple(redis::get_array(r.get<0>()), r.get<1>()); } + ) | + filtered([&parTags](const tuple, std::string>& t) + { return parTags.empty() or all_tags_match(parTags, get_string(t.get<0>()[2])); } + ) | + transformed([&ids](const tuple, std::string>& t) + { return LocatedItem{ get_string(t.get<0>()[0]), lexical_cast(t.get<1>()), lexical_cast(get_string(t.get<0>()[1])) }; } + ) + ); + } + else { + return std::vector(); + } + } } //namespace dindb diff --git a/src/backends/redis/find.hpp b/src/backends/redis/find.hpp index 969c9f4..5e1293c 100644 --- a/src/backends/redis/find.hpp +++ b/src/backends/redis/find.hpp @@ -28,6 +28,7 @@ namespace redis { namespace dindb { std::vector find_all_sets ( redis::IncRedis& parRedis ); std::vector locate_in_db ( redis::IncRedis& parRedis, const std::string& parSearch, const TagList& parTags ); + std::vector locate_in_db ( redis::IncRedis& parRedis, const mchlib::TigerHash& parSearch, const TagList& parTags ); } //namespace dindb #endif diff --git a/src/backends/redis/incredis.cpp b/src/backends/redis/incredis.cpp index 2ab7cbb..2e7ca88 100644 --- a/src/backends/redis/incredis.cpp +++ b/src/backends/redis/incredis.cpp @@ -24,7 +24,7 @@ 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_list optional_string_list ( const Reply& parReply ); IncRedis::opt_string optional_string (const Reply& parReply) { assert(parReply.which() == RedisVariantType_Nil or parReply.which() == RedisVariantType_String); @@ -115,6 +115,10 @@ namespace redis { return optional_string(m_command.run("SRANDMEMBER", parKey)); } + auto IncRedis::smembers (boost::string_ref parKey) -> opt_string_list { + return optional_string_list(m_command.run("SMEMBERS", parKey)); + } + bool IncRedis::script_flush() { const auto ret = get(m_command.run("SCRIPT", "FLUSH")); return ret.is_ok(); diff --git a/src/backends/redis/incredis.hpp b/src/backends/redis/incredis.hpp index e464485..5ea6727 100644 --- a/src/backends/redis/incredis.hpp +++ b/src/backends/redis/incredis.hpp @@ -74,6 +74,7 @@ namespace redis { //Set opt_string_list srandmember ( boost::string_ref parKey, int parCount ); opt_string srandmember ( boost::string_ref parKey ); + opt_string_list smembers ( boost::string_ref parKey ); //Script bool script_flush ( void );