From 21a9cb6866afe3354bee60d852ebffc7ef3a8355 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 25 Aug 2025 13:06:07 +0100 Subject: Insert new entities and log entry in a transaction If no new entities are required, no transaction is created. --- src/ingestor.cpp | 53 +++++++++++++++++++++++++++++++++++------------------ src/ingestor.hpp | 6 +++++- src/util.hpp | 6 +++--- 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/src/ingestor.cpp b/src/ingestor.cpp index 1b54a64..f824c80 100644 --- a/src/ingestor.cpp +++ b/src/ingestor.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -55,7 +56,9 @@ namespace WebStat { Ingestor::Ingestor(const std::string_view hostname, DB::ConnectionPtr dbconn) : hostnameId {crc32(hostname)}, dbconn {std::move(dbconn)} { - storeEntities(std::make_tuple(std::make_pair(hostnameId, hostname))); + storeEntities({ + std::make_pair(hostnameId, hostname), + }); } Ingestor::ScanResult @@ -92,7 +95,11 @@ namespace WebStat { if (auto result = scanLogLine(line)) { linesParsed++; const auto values = crc32ScanValues(result->values()); - storeEntities(values); + std::optional dbtx; + if (const auto newEnts = newEntities(values); newEnts.front()) { + dbtx.emplace(*dbconn); + storeEntities(newEnts); + } storeLogLine(values); } else { @@ -102,32 +109,42 @@ namespace WebStat { } template - size_t - Ingestor::storeEntities(const std::tuple & values) const + Ingestor::NewEntities + Ingestor::newEntities(const std::tuple & values) const { - return visitSum( - [this](const X & entity) -> size_t { - auto insertIfReqd = [this](auto && entity) -> size_t { - if (existingEntities.contains(entity.first)) { - return 0; + Ingestor::NewEntities rtn; + auto next = rtn.begin(); + visit( + [this, &next](const X & entity) { + auto addNewIfReqd = [&next, this](auto && entity) mutable { + if (!existingEntities.contains(entity.first)) { + *next++ = entity; } - auto insert = dbconn->modify(SQL::ENTITY_INSERT, SQL::ENTITY_INSERT_OPTS); - insert->bindParamI(0, entity.first); - insert->bindParamS(1, entity.second); - insert->execute(); - existingEntities.emplace(entity.first); - return 1; + return 0; }; if constexpr (std::is_same_v) { - return insertIfReqd(entity); + addNewIfReqd(entity); } else if constexpr (std::is_same_v>) { - entity.transform(insertIfReqd).value_or(0); + entity.transform(addNewIfReqd); } - return 0; }, values); + return rtn; + } + + void + Ingestor::storeEntities(const std::span> values) const + { + std::ranges::for_each( + values | std::views::take_while(&std::optional::has_value), [this](auto && entity) { + auto insert = dbconn->modify(SQL::ENTITY_INSERT, SQL::ENTITY_INSERT_OPTS); + insert->bindParamI(0, entity->first); + insert->bindParamS(1, entity->second); + insert->execute(); + existingEntities.emplace(entity->first); + }); } template diff --git a/src/ingestor.hpp b/src/ingestor.hpp index 7141515..040331f 100644 --- a/src/ingestor.hpp +++ b/src/ingestor.hpp @@ -6,6 +6,7 @@ #include #include #include +#include namespace WebStat { class Ingestor { @@ -33,7 +34,10 @@ namespace WebStat { size_t linesDiscarded = 0; private: - template size_t storeEntities(const std::tuple &) const; + static constexpr size_t MAX_NEW_ENTITIES = 6; + void storeEntities(std::span>) const; + using NewEntities = std::array, MAX_NEW_ENTITIES>; + template NewEntities newEntities(const std::tuple &) const; mutable std::flat_set existingEntities; uint32_t hostnameId; diff --git a/src/util.hpp b/src/util.hpp index 0ed260c..dcdc654 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -5,11 +5,11 @@ namespace WebStat { template auto - visitSum(auto && visitor, const std::tuple & values) + visit(auto && visitor, const std::tuple & values) { - return std::apply( + std::apply( [&](auto &&... value) { - return (visitor(value) + ...); + (visitor(value), ...); }, values); } -- cgit v1.2.3