From 549ab7b16ab20b2e1b767147ea861ffb276f4155 Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Tue, 14 Jun 2016 10:39:42 +0100 Subject: [PATCH] Write implementation for search_file_by_hash(). Note that the postgresql backend does something like "select blah... where hash=$1 limit 1", so it only returns one match. The SRANDMEMBER used in this implementation also returns one match, but it's not deterministic I suppose. --- src/backends/redis/backend_redis.cpp | 130 ++++++++++++++++++++------- src/backends/redis/reply.hpp | 3 +- 2 files changed, 100 insertions(+), 33 deletions(-) diff --git a/src/backends/redis/backend_redis.cpp b/src/backends/redis/backend_redis.cpp index 7e3ff5d..d2d4679 100644 --- a/src/backends/redis/backend_redis.cpp +++ b/src/backends/redis/backend_redis.cpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include namespace dindb { namespace { @@ -31,6 +33,66 @@ namespace dindb { uint16_t port; uint16_t database; }; + + std::pair pair_list_to_file_record (const redis::Command::hscan_range& parRange, const mchlib::TigerHash& parHash) { + using boost::lexical_cast; + + mchlib::FileRecordData retval; + retval.hash = parHash; + std::array mime; + std::string group_key; + + for (const auto itm : parRange) { + if (itm.first == "path") + retval.abs_path = itm.second; + else if (itm.first == "hash") + assert(tiger_to_string(parHash) == itm.second); + else if (itm.first == "size") + retval.size = lexical_cast( + itm.second); + else if (itm.first == "level") + retval.level = lexical_cast( + itm.second); + else if (itm.first == "mime_type") + mime[0] = itm.second; + else if (itm.first == "mime_charset") + mime[1] = itm.second; + else if (itm.first == "is_directory") + retval.is_directory = (itm.second[0] == '0' ? false : true); + else if (itm.first == "is_symlink") + retval.is_symlink = (itm.second[0] == '0' ? false : true); + else if (itm.first == "unreadable") + retval.unreadable = (itm.second[0] == '0' ? false : true); + else if (itm.first == "hash_valid") + retval.hash_valid = (itm.second[0] == '0' ? false : true); + else if (itm.first == "group_id") + group_key = itm.second; + } + retval.mime_full = mime[0] + mime[1]; + retval.mime_type_offset = 0; + retval.mime_type_length = retval.mime_charset_offset = static_cast(mime[0].size()); + retval.mime_charset_length = static_cast(mime[1].size()); + return std::make_pair(group_key, std::move(retval)); + } + + mchlib::SetRecordDataFull pair_list_to_set_record (const redis::Command::hscan_range& parRange) { + using boost::lexical_cast; + + mchlib::SetRecordDataFull retval; + for (const auto& itm : parRange) { + if (itm.first == "name") + retval.name = itm.second; + else if (itm.first == "disk_label") + retval.disk_label = itm.second; + else if (itm.first == "fs_uuid") + retval.fs_uuid = itm.second; + else if (itm.first == "type") + retval.type = lexical_cast(itm.second[0]); + else if (itm.first == "content_type") + retval.content_type = lexical_cast(itm.second[0]); + } + return retval; + } } //unnamed namespace } //namespace dindb @@ -117,50 +179,56 @@ namespace dindb { redis::Reply insert_set_reply = m_redis.run( "HMSET", set_key, - "name", - parSetData.name, - "disk_label", - parSetData.disk_label, - "fs_uuid", - parSetData.fs_uuid, - "type", - parSetData.type, - "content_type", - parSetData.content_type + "name", parSetData.name, + "disk_label", parSetData.disk_label, + "fs_uuid", parSetData.fs_uuid, + "type", parSetData.type, + "content_type", parSetData.content_type ); for (const auto& file_data : parData) { redis::Reply file_id_reply = m_redis.run("HINCRBY", PROGRAM_NAME ":indices", "files", "1"); const std::string file_key = PROGRAM_NAME ":file:" + lexical_cast(redis::get_integer(file_id_reply)); + const std::string hash = tiger_to_string(file_data.hash); redis::Reply insert_file_reply = m_redis.run( "HMSET", file_key, - "hash", - tiger_to_string(file_data.hash), - "path", - file_data.path(), - "size", - lexical_cast(file_data.size), - "level", - lexical_cast(file_data.level), - "mime_type", - file_data.mime_type(), - "mime_charset", - file_data.mime_charset(), - "is_directory", - (file_data.is_directory ? '1' : '0'), - "is_symlink", - (file_data.is_symlink ? '1' : '0'), - "unreadable", - (file_data.unreadable ? '1' : '0'), - "hash_valid", - (file_data.hash_valid ? '1' : '0') + "hash", hash, + "path", file_data.path(), + "size", lexical_cast(file_data.size), + "level", lexical_cast(file_data.level), + "mime_type", file_data.mime_type(), + "mime_charset", file_data.mime_charset(), + "is_directory", (file_data.is_directory ? '1' : '0'), + "is_symlink", (file_data.is_symlink ? '1' : '0'), + "unreadable", (file_data.unreadable ? '1' : '0'), + "hash_valid", (file_data.hash_valid ? '1' : '0'), + "group_id", set_key + ); + + redis::Reply insert_hash_reply = m_redis.run( + "SADD", + "hash:" + hash, + file_key ); } } bool BackendRedis::search_file_by_hash (mchlib::FileRecordData& parItem, mchlib::SetRecordDataFull& parSet, const mchlib::TigerHash& parHash) { - return false; + const std::string hash_key = "hash:" + tiger_to_string(parHash); + redis::Reply hash_reply = m_redis.run("SRANDMEMBER", hash_key); + if (redis::RedisVariantType_Integer == hash_reply.which() and not redis::get_integer(hash_reply)) { + return false; + } + else { + const auto result_id = redis::get_string(hash_reply); + auto set_key_and_file_item = pair_list_to_file_record(m_redis.hscan(result_id), parHash); + parItem = std::move(set_key_and_file_item.second); + const std::string group_key = std::move(set_key_and_file_item.first); + + auto set_item = pair_list_to_set_record(m_redis.hscan(group_key)); + return true; + } } std::vector BackendRedis::locate_in_db (const std::string& parSearch, const TagList& parTags) { diff --git a/src/backends/redis/reply.hpp b/src/backends/redis/reply.hpp index 6ed6820..a1a6606 100644 --- a/src/backends/redis/reply.hpp +++ b/src/backends/redis/reply.hpp @@ -35,8 +35,7 @@ namespace redis { enum RedisVariantTypes { RedisVariantType_Integer = 0, RedisVariantType_String, - RedisVariantType_Array, - RedisVariantType_Bool + RedisVariantType_Array }; struct Reply : implem::RedisVariantType {