diff --git a/src/backends/redis/CMakeLists.txt b/src/backends/redis/CMakeLists.txt index 19f75d5..19f7f05 100644 --- a/src/backends/redis/CMakeLists.txt +++ b/src/backends/redis/CMakeLists.txt @@ -51,8 +51,7 @@ configure_file( ${CMAKE_CURRENT_BINARY_DIR}/redisConfig.h ) set(LUA_SCRIPTS - "${CMAKE_SOURCE_DIR}/lib/ohm-scripts/save.lua" - "${CMAKE_SOURCE_DIR}/lib/ohm-scripts/delete.lua" + tag_if_in_set.lua ) install(TARGETS ${PROJECT_NAME} diff --git a/src/backends/redis/backend_redis.cpp b/src/backends/redis/backend_redis.cpp index 990a6e1..3bd8543 100644 --- a/src/backends/redis/backend_redis.cpp +++ b/src/backends/redis/backend_redis.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include namespace dindb { namespace { @@ -94,6 +96,23 @@ namespace dindb { } return retval; } + + std::string read_script (const dincore::SearchPaths& parSearch, const char* parName) { + const auto full_path = parSearch.first_hit(boost::string_ref(parName)); + if (full_path.empty()) { + const std::string msg = std::string("Unable to locate and load Lua script \"") + parName + "\" from any of the given search paths"; + throw std::runtime_error(msg); + } + + std::ifstream script(full_path); + std::string retval; + script.seekg(0, std::ios::end); + retval.reserve(script.tellg()); + script.seekg(0, std::ios::beg); + retval.assign(std::istreambuf_iterator(script), std::istreambuf_iterator()); + + return retval; + } } //unnamed namespace } //namespace dindb @@ -140,6 +159,7 @@ namespace YAML { namespace dindb { BackendRedis::BackendRedis(std::string&& parAddress, uint16_t parPort, uint16_t parDatabase, bool parConnect, dincore::SearchPaths&& parLuaPaths) : m_redis(std::move(parAddress), parPort), + m_tag_if_in_set(), m_lua_script_paths(std::move(parLuaPaths)), m_database(parDatabase) { @@ -166,6 +186,8 @@ namespace dindb { oss << "Error connecting to Redis: " << m_redis.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")); } void BackendRedis::disconnect() { @@ -173,6 +195,21 @@ namespace dindb { } void BackendRedis::tag_files (const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) { + using dinhelp::lexical_cast; + + auto batch = m_redis.make_batch(); + const std::string set_key = (parSet != InvalidGroupID ? PROGRAM_NAME ":set:" + lexical_cast(parSet) : ""); + for (const auto file_id : parFiles) { + for (const auto &tag : parTags) { + std::ostringstream oss; + oss << PROGRAM_NAME ":tag:" << tag; + const std::string tag_key = oss.str(); + const std::string file_key = PROGRAM_NAME ":file:" + lexical_cast(file_id); + m_tag_if_in_set.run(batch, std::make_tuple(tag_key, file_key), std::make_tuple(set_key)); + } + } + + batch.throw_if_failed(); } void BackendRedis::tag_files (const std::vector& parRegexes, const std::vector& parTags, GroupIDType parSet) { diff --git a/src/backends/redis/backend_redis.hpp b/src/backends/redis/backend_redis.hpp index d7ced97..08fb6cc 100644 --- a/src/backends/redis/backend_redis.hpp +++ b/src/backends/redis/backend_redis.hpp @@ -20,6 +20,7 @@ #include "backends/db_backend.hpp" #include "command.hpp" +#include "script.hpp" #include "dindexer-core/searchpaths.hpp" #include #include @@ -58,6 +59,7 @@ namespace dindb { private: redis::Command m_redis; + redis::Script m_tag_if_in_set; dincore::SearchPaths m_lua_script_paths; uint16_t m_database; }; diff --git a/src/backends/redis/tag_if_in_set.lua b/src/backends/redis/tag_if_in_set.lua new file mode 100644 index 0000000..6c9ec12 --- /dev/null +++ b/src/backends/redis/tag_if_in_set.lua @@ -0,0 +1,30 @@ +-- 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 . + +local tag_key = KEYS[1] +local file_key = KEYS[2] +local group_key = ARGV[1] + +if group_key == "" then + return redis.call("SADD", tag_key, file_key) +else + local found_group_key = redis.call("HGET", file_key, "group_id") + if found_group_key == group_key then + return redis.call("SADD", tag_key, file_key) + else + return nil + end +end