diff --git a/src/backends/redis/CMakeLists.txt b/src/backends/redis/CMakeLists.txt index 95cd5e5..941b141 100644 --- a/src/backends/redis/CMakeLists.txt +++ b/src/backends/redis/CMakeLists.txt @@ -5,6 +5,7 @@ set(DINDEXER_REDIS_SCRIPTS_PATH "${CMAKE_INSTALL_PREFIX}/${bare_name}/redis" CAC find_package(hiredis 0.11.0 REQUIRED) find_package(CryptoPP 5.6) find_package(libev 4.0 REQUIRED) +find_package(Boost 1.53.0 REQUIRED COMPONENTS regex) add_library(${PROJECT_NAME} SHARED backend_redis.cpp @@ -23,6 +24,7 @@ target_include_directories(${PROJECT_NAME} SYSTEM PRIVATE ${HIREDIS_INCLUDE_DIRS} PRIVATE ${CMAKE_SOURCE_DIR}/lib/better-enums PRIVATE ${LIBEV_INCLUDE_DIRS} + PRIVATE ${Boost_INCLUDE_DIRS} ) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} @@ -33,6 +35,7 @@ target_link_libraries(${PROJECT_NAME} PUBLIC ${bare_name}-core PRIVATE ${HIREDIS_LIBRARIES} PRIVATE ${LIBEV_LIBRARIES} + PRIVATE ${Boost_LIBRARIES} ) target_compile_definitions(${PROJECT_NAME} diff --git a/src/backends/redis/tag.cpp b/src/backends/redis/tag.cpp index efb7fe4..6562b37 100644 --- a/src/backends/redis/tag.cpp +++ b/src/backends/redis/tag.cpp @@ -22,7 +22,7 @@ #include "dindexer-core/split_tags.hpp" #include #include -#include +#include #include #include @@ -41,13 +41,13 @@ namespace dindb { return PROGRAM_NAME ":file:" + dinhelp::lexical_cast(parID); } - std::vector compile_regexes (const std::vector& parRegexes) { - std::vector retval; + std::vector compile_regexes (const std::vector& parRegexes) { + std::vector retval; retval.reserve(parRegexes.size()); for (const auto& str : parRegexes) { - retval.emplace_back(std::regex( + retval.emplace_back(boost::regex( str, - std::regex_constants::optimize | std::regex_constants::nosubs | std::regex_constants::ECMAScript + boost::regex_constants::optimize | boost::regex_constants::nosubs | boost::regex_constants::perl )); } assert(retval.size() == parRegexes.size()); @@ -83,7 +83,7 @@ namespace dindb { auto batch = parRedis.make_batch(); for (const auto ®ex : regexes) { - if (not std::regex_search(path, regex)) + if (not boost::regex_search(path, regex)) continue; for (const auto &tag : parTags) { @@ -92,10 +92,17 @@ namespace dindb { const std::string tag_key = oss.str(); parTagIfInSet.run(batch, std::make_tuple(tag_key, file_key), std::make_tuple(set_key)); } + break; } batch.throw_if_failed(); } } + + template + T id_from_redis_key (const std::string& parKey) { + assert(not parKey.empty()); + return dinhelp::lexical_cast(dincore::split_and_trim(parKey, ':').back()); + } } //unnamed namespace void tag_files (redis::Command& parRedis, redis::Script& parTagIfInSet, const std::vector& parFiles, const std::vector& parTags, GroupIDType parSet) { @@ -135,6 +142,51 @@ namespace dindb { } void delete_all_tags (redis::Command& parRedis, redis::Script& parDeleIfInSet, const std::vector& parRegexes, GroupIDType parSet) { + using dinhelp::lexical_cast; + + const std::string set_key = (parSet != InvalidGroupID ? PROGRAM_NAME ":set:" + lexical_cast(parSet) : ""); + const auto regexes = compile_regexes(parRegexes); + + std::set dele_tags; + std::vector ids; + + for (const auto& itm : parRedis.scan(PROGRAM_NAME ":file:*")) { + const auto& file_key = itm; + auto file_reply = parRedis.run("HMGET", file_key, "path", "tags", "group_id"); + auto& file_replies = redis::get_array(file_reply); + assert(file_replies.size() == 3); + const auto group_id = id_from_redis_key(redis::get_string(file_replies[2])); + if (parSet != InvalidGroupID and parSet != group_id) + continue; + + const auto path = redis::get_string(file_replies[0]); + const auto tags_str = (file_replies[1].which() == redis::RedisVariantType_Nil ? std::string() : redis::get_string(file_replies[1])); + const auto tags = dincore::split_tags(tags_str); + const auto file_id = id_from_redis_key(file_key); + + for (const auto ®ex : regexes) { + if (not boost::regex_search(path, regex)) + continue; + + ids.push_back(file_id); + + for (const auto &tag : tags) { + dele_tags.insert(std::string(tag.data(), tag.size())); + } + break; + } + } + + std::vector dele_tags_vec; + dele_tags_vec.reserve(dele_tags.size()); + std::transform( + dele_tags.begin(), + dele_tags.end(), + std::back_inserter(dele_tags_vec), + [](const std::string& parS) { return boost::string_ref(parS); } + ); + + delete_tags(parRedis, parDeleIfInSet, ids, dele_tags_vec, parSet); } } //namespace dindb