LCOV - code coverage report
Current view: top level - src/extension - bag_reader.cc (source / functions) Hit Total Coverage
Test: vlink Lines: 284 285 99.6 %
Date: 2026-07-26 14:05:51 Functions: 39 41 95.1 %
Branches: 249 342 72.8 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (C) 2026 by Thun Lu. All rights reserved.
       3                 :            :  * Author: Thun Lu <thun.lu@zohomail.cn>
       4                 :            :  * Repo:   https://github.com/thun-res/vlink
       5                 :            :  *  _    __   __      _           __
       6                 :            :  * | |  / /  / /     (_) ____    / /__
       7                 :            :  * | | / /  / /     / / / __ \  / //_/
       8                 :            :  * | |/ /  / /___  / / / / / / / ,<
       9                 :            :  * |___/  /_____/ /_/ /_/ /_/ /_/|_|
      10                 :            :  *
      11                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
      12                 :            :  * you may not use this file except in compliance with the License.
      13                 :            :  * You may obtain a copy of the License at
      14                 :            :  *
      15                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
      16                 :            :  *
      17                 :            :  * Unless required by applicable law or agreed to in writing, software
      18                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      19                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      20                 :            :  * See the License for the specific language governing permissions and
      21                 :            :  * limitations under the License.
      22                 :            :  */
      23                 :            : 
      24                 :            : #include "./extension/bag_reader.h"
      25                 :            : 
      26                 :            : #include <algorithm>
      27                 :            : #include <memory>
      28                 :            : #include <shared_mutex>
      29                 :            : #include <string>
      30                 :            : #include <unordered_map>
      31                 :            : #include <unordered_set>
      32                 :            : #include <utility>
      33                 :            : 
      34                 :            : #include "./base/helpers.h"
      35                 :            : #include "./base/logger.h"
      36                 :            : #include "./extension/bag_plugin_interface.h"
      37                 :            : #include "./extension/vcap_reader.h"
      38                 :            : #include "./extension/vdb_reader.h"
      39                 :            : #include "./impl/url.h"
      40                 :            : 
      41                 :            : namespace vlink {
      42                 :            : 
      43                 :            : // UrlMeta
      44                 :        209 : bool BagReader::Info::UrlMeta::operator<(const BagReader::Info::UrlMeta& target) const noexcept {
      45                 :        209 :   int lindex = Url::get_sort_index(url);
      46                 :        209 :   int rindex = Url::get_sort_index(target.url);
      47                 :            : 
      48         [ +  + ]:        209 :   if (lindex < rindex) {
      49                 :          1 :     return true;
      50         [ +  + ]:        208 :   } else if (lindex > rindex) {
      51                 :          3 :     return false;
      52         [ +  + ]:        205 :   } else if (url < target.url) {
      53                 :         16 :     return true;
      54         [ +  + ]:        189 :   } else if (url > target.url) {
      55                 :        178 :     return false;
      56                 :            :   }
      57                 :            : 
      58                 :         11 :   return index < target.index;
      59                 :            : }
      60                 :            : 
      61                 :            : // BagReader::Impl
      62                 :            : struct BagReader::Impl final {
      63                 :            :   BagReader::OutputCallback output_callback;
      64                 :            :   std::shared_ptr<BagPluginInterface> plugin_interface;
      65                 :            :   std::unordered_map<std::string, std::string> playback_url_remap;
      66                 :            :   std::unordered_set<std::string> excluded_playback_urls;
      67                 :            :   std::unordered_map<std::string, std::string> url_to_ser_map;
      68                 :            :   std::unordered_map<std::string, SchemaType> url_to_schema_type_map;
      69                 :            :   std::atomic_bool playback_url_rules_enabled{false};
      70                 :            :   mutable std::shared_mutex playback_state_mtx;
      71                 :            :   mutable std::shared_mutex output_callback_mtx;
      72                 :            : 
      73                 :            :   bool cursor_opened{false};
      74                 :            :   bool cursor_eof{false};
      75                 :            :   bool cursor_fail{false};
      76                 :            : };
      77                 :            : 
      78                 :            : // BagReader
      79                 :        188 : std::shared_ptr<BagReader> BagReader::create(const std::string& path, bool read_only, bool try_to_fix) {
      80         [ +  - ]:        188 :   std::string suffix_check = path;
      81                 :            : 
      82                 :        188 :   std::transform(suffix_check.begin(), suffix_check.end(), suffix_check.begin(),
      83                 :      14818 :                  [](unsigned char c) { return std::tolower(c); });
      84                 :            : 
      85   [ +  +  +  +  :        188 :   if (Helpers::has_endwith(suffix_check, ".vdb") || Helpers::has_endwith(suffix_check, ".vdbx")) {
                   +  + ]
      86         [ +  + ]:        109 :     return std::make_shared<VDBReader>(path, read_only, try_to_fix);
      87   [ +  +  +  +  :         79 :   } else if (Helpers::has_endwith(suffix_check, ".vcap") || Helpers::has_endwith(suffix_check, ".vcapx")) {
                   +  + ]
      88         [ +  + ]:         78 :     return std::make_shared<VCAPReader>(path, read_only, try_to_fix);
      89                 :            :   } else {
      90   [ +  -  +  - ]:          2 :     CLOG_E("BagReader: Unknown bag suffix, path=%s", path.c_str());
      91                 :          1 :     return nullptr;
      92                 :            :   }
      93                 :        188 : }
      94                 :            : 
      95         [ +  - ]:        206 : BagReader::BagReader(const std::string& path, bool read_only, bool try_to_fix) : impl_(std::make_unique<Impl>()) {
      96                 :            :   (void)path;
      97                 :            :   (void)read_only;
      98                 :            :   (void)try_to_fix;
      99                 :            : 
     100                 :        206 :   Bytes::init_memory_pool();
     101                 :        206 : }
     102                 :            : 
     103                 :        206 : BagReader::~BagReader() {
     104                 :        206 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     105                 :            : 
     106                 :            :   {
     107                 :        206 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     108                 :        206 :     plugin_interface = impl_->plugin_interface;
     109                 :        206 :   }
     110                 :            : 
     111         [ +  + ]:        206 :   if (plugin_interface) {
     112                 :          9 :     plugin_interface->register_callback({});
     113                 :            :   }
     114                 :        206 : }
     115                 :            : 
     116                 :        170 : void BagReader::detach_plugin() {
     117                 :        170 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     118                 :            : 
     119                 :            :   {
     120         [ +  - ]:        170 :     std::unique_lock state_lock(impl_->playback_state_mtx);
     121                 :        170 :     plugin_interface = std::move(impl_->plugin_interface);
     122                 :        170 :   }
     123                 :            : 
     124         [ +  + ]:        170 :   if (plugin_interface) {
     125         [ +  - ]:         12 :     plugin_interface->flush();
     126                 :         12 :     plugin_interface->register_callback({});
     127                 :            :   }
     128                 :        170 : }
     129                 :            : 
     130                 :         44 : void BagReader::reset_plugin() {
     131                 :         44 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     132                 :            : 
     133                 :            :   {
     134         [ +  - ]:         44 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     135                 :         44 :     plugin_interface = impl_->plugin_interface;
     136                 :         44 :   }
     137                 :            : 
     138         [ +  + ]:         44 :   if (plugin_interface) {
     139         [ +  - ]:         18 :     plugin_interface->on_reset();
     140                 :            :   }
     141                 :         44 : }
     142                 :            : 
     143                 :         31 : void BagReader::flush_plugin() {
     144                 :         31 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     145                 :            : 
     146                 :            :   {
     147         [ +  - ]:         31 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     148                 :         31 :     plugin_interface = impl_->plugin_interface;
     149                 :         31 :   }
     150                 :            : 
     151         [ +  + ]:         31 :   if (plugin_interface) {
     152         [ +  - ]:         13 :     plugin_interface->flush();
     153                 :            :   }
     154                 :         31 : }
     155                 :            : 
     156                 :         26 : void BagReader::bind_bag_interface(const std::shared_ptr<BagPluginInterface>& bag_interface) {
     157                 :         26 :   std::shared_ptr<BagPluginInterface> old_plugin_interface;
     158                 :            : 
     159                 :            :   {
     160         [ +  - ]:         26 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     161                 :         26 :     old_plugin_interface = impl_->plugin_interface;
     162                 :         26 :   }
     163                 :            : 
     164   [ +  +  +  -  :         26 :   if (old_plugin_interface && old_plugin_interface != bag_interface) {
                   +  + ]
     165         [ +  - ]:          3 :     old_plugin_interface->flush();
     166                 :          3 :     old_plugin_interface->register_callback({});
     167                 :            :   }
     168                 :            : 
     169         [ +  + ]:         26 :   if VLIKELY (bag_interface) {
     170                 :         24 :     bag_interface->bind_direction(BagPluginInterface::Direction::kRead);
     171                 :            : 
     172         [ +  - ]:         24 :     bag_interface->register_callback([this](const Frame& frame) {
     173                 :         36 :       std::string output_url;
     174                 :            : 
     175   [ +  -  -  + ]:         36 :       if VUNLIKELY (!convert_playback_url(frame.url, output_url)) {
     176                 :            :         return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     177                 :            :       }
     178                 :            : 
     179         [ +  - ]:         36 :       std::shared_lock callback_lock(impl_->output_callback_mtx);
     180                 :            : 
     181         [ +  - ]:         36 :       if VLIKELY (impl_->output_callback) {
     182                 :         36 :         Frame out;
     183                 :         36 :         out.timestamp = frame.timestamp;
     184                 :         36 :         out.url = std::move(output_url);
     185         [ +  - ]:         36 :         out.ser_type = frame.ser_type;
     186                 :         36 :         out.schema_type = frame.schema_type;
     187                 :         36 :         out.action_type = frame.action_type;
     188                 :         36 :         out.data = Bytes::shallow_copy(frame.data.data(), frame.data.size());
     189                 :            : 
     190   [ +  +  -  +  :         36 :         if (out.ser_type.empty() || out.schema_type == SchemaType::kUnknown) {
                   +  + ]
     191         [ +  - ]:          6 :           fill_frame_meta(out);
     192                 :            :         }
     193                 :            : 
     194         [ +  - ]:         36 :         impl_->output_callback(out);
     195                 :         36 :       }
     196         [ +  - ]:         36 :     });
     197                 :            :   }
     198                 :            : 
     199         [ +  - ]:         26 :   std::unique_lock state_lock(impl_->playback_state_mtx);
     200                 :            : 
     201                 :         26 :   impl_->plugin_interface = bag_interface;
     202                 :         26 :   impl_->playback_url_remap.clear();
     203                 :         26 :   impl_->excluded_playback_urls.clear();
     204                 :         26 :   impl_->playback_url_rules_enabled.store(false, std::memory_order_release);
     205                 :         26 : }
     206                 :            : 
     207         [ #  # ]:          0 : void BagReader::clear_bag_interface() { bind_bag_interface(nullptr); }
     208                 :            : 
     209                 :          1 : void BagReader::register_status_callback(StatusCallback&& status_callback) { (void)status_callback; }
     210                 :            : 
     211                 :          1 : void BagReader::register_ready_callback(ReadyCallback&& ready_callback) { (void)ready_callback; }
     212                 :            : 
     213                 :          1 : void BagReader::register_finish_callback(FinishCallback&& finish_callback) { (void)finish_callback; }
     214                 :            : 
     215                 :         29 : void BagReader::register_output_callback(OutputCallback&& output_callback) {
     216         [ +  - ]:         29 :   std::unique_lock lock(impl_->output_callback_mtx);
     217                 :            : 
     218                 :         29 :   impl_->output_callback = std::move(output_callback);
     219                 :         29 : }
     220                 :            : 
     221                 :        111 : bool BagReader::open_cursor(const Config& config) {
     222                 :        111 :   impl_->cursor_opened = false;
     223                 :        111 :   impl_->cursor_eof = false;
     224                 :        111 :   impl_->cursor_fail = false;
     225                 :            : 
     226         [ +  + ]:        111 :   if VUNLIKELY (!do_open_cursor(config)) {
     227                 :          2 :     impl_->cursor_fail = true;
     228                 :          2 :     return false;
     229                 :            :   }
     230                 :            : 
     231                 :        109 :   impl_->cursor_opened = true;
     232                 :        109 :   return true;
     233                 :            : }
     234                 :            : 
     235         [ +  - ]:         82 : bool BagReader::open_cursor() { return open_cursor(Config{}); }
     236                 :            : 
     237                 :        285 : bool BagReader::read_next(Frame& out) {
     238         [ +  + ]:        285 :   if VUNLIKELY (impl_->cursor_fail) {
     239                 :          2 :     return false;
     240                 :            :   }
     241                 :            : 
     242         [ +  + ]:        283 :   if VUNLIKELY (impl_->cursor_eof) {
     243                 :          1 :     return false;
     244                 :            :   }
     245                 :            : 
     246   [ +  +  +  -  :        282 :   if (!impl_->cursor_opened && !open_cursor(Config{})) {
          -  +  +  +  -  
                +  -  - ]
     247                 :            :     return false;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     248                 :            :   }
     249                 :            : 
     250                 :        282 :   bool is_error = false;
     251                 :            : 
     252   [ +  -  +  + ]:        282 :   if VLIKELY (do_read_next(out, is_error)) {
     253                 :        173 :     return true;
     254                 :            :   }
     255                 :            : 
     256         [ -  + ]:        109 :   if (is_error) {
     257                 :            :     impl_->cursor_fail = true;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     258                 :            :   } else {
     259                 :        109 :     impl_->cursor_eof = true;
     260                 :            :   }
     261                 :            : 
     262                 :        109 :   return false;
     263                 :            : }
     264                 :            : 
     265                 :         12 : BagReader& BagReader::operator>>(Frame& out) {
     266                 :         12 :   read_next(out);
     267                 :            : 
     268                 :         12 :   return *this;
     269                 :            : }
     270                 :            : 
     271                 :         21 : bool BagReader::eof() const noexcept { return impl_->cursor_eof; }
     272                 :            : 
     273                 :         13 : bool BagReader::fail() const noexcept { return impl_->cursor_fail; }
     274                 :            : 
     275   [ +  +  +  + ]:         14 : BagReader::operator bool() const noexcept { return !impl_->cursor_eof && !impl_->cursor_fail; }
     276                 :            : 
     277                 :          1 : bool BagReader::do_open_cursor(const Config& config) {
     278                 :            :   (void)config;
     279                 :            : 
     280                 :          1 :   return false;
     281                 :            : }
     282                 :            : 
     283                 :            : bool BagReader::do_read_next(Frame& out, bool& is_error) {  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     284                 :            :   (void)out;
     285                 :            : 
     286                 :            :   is_error = false;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     287                 :            : 
     288                 :            :   return false;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     289                 :            : }
     290                 :            : 
     291                 :        121 : void BagReader::process_output(Frame& frame) {
     292                 :        121 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     293                 :            : 
     294                 :            :   {
     295         [ +  - ]:        121 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     296                 :            : 
     297                 :        121 :     plugin_interface = impl_->plugin_interface;
     298                 :            : 
     299   [ +  +  +  -  :        121 :     if VUNLIKELY (plugin_interface && impl_->excluded_playback_urls.count(frame.url) != 0U) {
             +  +  +  + ]
     300                 :          1 :       return;
     301                 :            :     }
     302                 :            : 
     303                 :        120 :     const std::string* meta_url = &frame.url;
     304                 :            : 
     305         [ +  + ]:        120 :     if (plugin_interface) {
     306         [ +  - ]:         47 :       auto remap_iter = impl_->playback_url_remap.find(frame.url);
     307                 :            : 
     308         [ +  + ]:         47 :       if (remap_iter != impl_->playback_url_remap.end()) {
     309                 :          2 :         meta_url = &remap_iter->second;
     310                 :            :       }
     311                 :            :     }
     312                 :            : 
     313         [ +  - ]:        120 :     if (frame.ser_type.empty()) {
     314         [ +  - ]:        120 :       auto ser_iter = impl_->url_to_ser_map.find(*meta_url);
     315                 :            : 
     316         [ +  + ]:        120 :       if VLIKELY (ser_iter != impl_->url_to_ser_map.end()) {
     317         [ +  - ]:        114 :         frame.ser_type = ser_iter->second;
     318                 :            :       }
     319                 :            :     }
     320                 :            : 
     321         [ +  - ]:        120 :     if (frame.schema_type == SchemaType::kUnknown) {
     322         [ +  - ]:        120 :       auto schema_iter = impl_->url_to_schema_type_map.find(*meta_url);
     323                 :            : 
     324         [ +  + ]:        120 :       if VLIKELY (schema_iter != impl_->url_to_schema_type_map.end()) {
     325                 :        114 :         frame.schema_type = schema_iter->second;
     326                 :            :       }
     327                 :            :     }
     328         [ +  + ]:        121 :   }
     329                 :            : 
     330         [ +  + ]:        120 :   if (plugin_interface) {
     331         [ +  - ]:         47 :     plugin_interface->on_read(frame);
     332                 :            :   } else {
     333         [ +  - ]:         73 :     std::shared_lock callback_lock(impl_->output_callback_mtx);
     334                 :            : 
     335         [ +  + ]:         73 :     if VLIKELY (impl_->output_callback) {
     336         [ +  - ]:         72 :       impl_->output_callback(frame);
     337                 :            :     }
     338                 :         73 :   }
     339         [ +  + ]:        121 : }
     340                 :            : 
     341                 :        171 : void BagReader::fill_frame_meta(Frame& frame) const {
     342         [ +  - ]:        171 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     343                 :            : 
     344         [ +  - ]:        171 :   if (frame.ser_type.empty()) {
     345         [ +  - ]:        171 :     auto iter = impl_->url_to_ser_map.find(frame.url);
     346                 :            : 
     347         [ +  + ]:        171 :     if VLIKELY (iter != impl_->url_to_ser_map.end()) {
     348         [ +  - ]:        166 :       frame.ser_type = iter->second;
     349                 :            :     }
     350                 :            :   }
     351                 :            : 
     352         [ +  - ]:        171 :   if (frame.schema_type == SchemaType::kUnknown) {
     353         [ +  - ]:        171 :     auto iter = impl_->url_to_schema_type_map.find(frame.url);
     354                 :            : 
     355         [ +  + ]:        171 :     if VLIKELY (iter != impl_->url_to_schema_type_map.end()) {
     356                 :        166 :       frame.schema_type = iter->second;
     357                 :            :     }
     358                 :            :   }
     359                 :        171 : }
     360                 :            : 
     361                 :        843 : std::unordered_map<std::string, std::string>& BagReader::url_ser_map() { return impl_->url_to_ser_map; }
     362                 :            : 
     363                 :        843 : std::unordered_map<std::string, SchemaType>& BagReader::url_schema_type_map() { return impl_->url_to_schema_type_map; }
     364                 :            : 
     365                 :         26 : std::string BagReader::get_ser_type(const std::string& url) const {
     366         [ +  - ]:         26 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     367                 :            : 
     368         [ +  - ]:         26 :   auto iter = impl_->url_to_ser_map.find(url);
     369                 :            : 
     370         [ +  + ]:         26 :   if VLIKELY (iter != impl_->url_to_ser_map.end()) {
     371         [ +  - ]:         17 :     return iter->second;
     372                 :            :   }
     373                 :            : 
     374                 :          9 :   return {};
     375                 :         26 : }
     376                 :            : 
     377                 :         14 : SchemaType BagReader::get_schema_type(const std::string& url) const {
     378         [ +  - ]:         14 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     379                 :            : 
     380         [ +  - ]:         14 :   auto iter = impl_->url_to_schema_type_map.find(url);
     381                 :            : 
     382         [ +  + ]:         14 :   if VLIKELY (iter != impl_->url_to_schema_type_map.end()) {
     383                 :         11 :     return iter->second;
     384                 :            :   }
     385                 :            : 
     386                 :          3 :   return SchemaType::kUnknown;
     387                 :         14 : }
     388                 :            : 
     389                 :         24 : void BagReader::process_url_metas(std::vector<Info::UrlMeta>& url_metas) {
     390                 :         24 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     391                 :            : 
     392                 :            :   {
     393         [ +  - ]:         24 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     394                 :         24 :     plugin_interface = impl_->plugin_interface;
     395                 :         24 :   }
     396                 :            : 
     397                 :         24 :   std::unordered_map<std::string, std::string> playback_url_remap;
     398                 :         24 :   std::unordered_set<std::string> excluded_playback_urls;
     399                 :            : 
     400         [ +  + ]:         24 :   if (plugin_interface) {
     401         [ +  - ]:         42 :     url_metas.erase(
     402         [ +  - ]:         21 :         std::remove_if(url_metas.begin(), url_metas.end(),
     403                 :        103 :                        [&plugin_interface, &playback_url_remap, &excluded_playback_urls](Info::UrlMeta& meta) {
     404         [ +  - ]:         45 :                          const std::string input_url = meta.url;
     405                 :            : 
     406   [ +  -  +  + ]:         45 :                          if VUNLIKELY (!plugin_interface->convert_url_meta(meta.url, meta.ser_type, meta.schema_type)) {
     407         [ +  - ]:          5 :                            excluded_playback_urls.emplace(input_url);
     408                 :          5 :                            return true;
     409                 :            :                          }
     410                 :            : 
     411         [ +  + ]:         40 :                          if (meta.url != input_url) {
     412   [ +  -  +  - ]:          8 :                            playback_url_remap[input_url] = meta.url;
     413                 :            :                          }
     414                 :            : 
     415                 :         40 :                          return false;
     416                 :         45 :                        }),
     417                 :         42 :         url_metas.end());
     418                 :            :   }
     419                 :            : 
     420                 :            :   {
     421         [ +  - ]:         24 :     std::unique_lock state_lock(impl_->playback_state_mtx);
     422                 :            : 
     423         [ +  - ]:         24 :     if (impl_->plugin_interface == plugin_interface) {
     424                 :         24 :       impl_->playback_url_remap = std::move(playback_url_remap);
     425                 :         24 :       impl_->excluded_playback_urls = std::move(excluded_playback_urls);
     426                 :         48 :       impl_->playback_url_rules_enabled.store(
     427   [ +  +  +  + ]:         24 :           !impl_->playback_url_remap.empty() || !impl_->excluded_playback_urls.empty(), std::memory_order_release);
     428                 :            :     }
     429                 :         24 :   }
     430                 :         24 : }
     431                 :            : 
     432                 :        276 : bool BagReader::convert_playback_url(const std::string& input_url, std::string& output_url) const {
     433         [ +  - ]:        276 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     434                 :            : 
     435   [ +  -  +  + ]:        276 :   if VUNLIKELY (impl_->excluded_playback_urls.count(input_url) != 0U) {
     436                 :          4 :     return false;
     437                 :            :   }
     438                 :            : 
     439         [ +  - ]:        272 :   auto iter = impl_->playback_url_remap.find(input_url);
     440                 :            : 
     441         [ +  + ]:        272 :   if (iter != impl_->playback_url_remap.end()) {
     442         [ +  - ]:         10 :     output_url = iter->second;
     443                 :            :   } else {
     444         [ +  - ]:        262 :     output_url = input_url;
     445                 :            :   }
     446                 :            : 
     447                 :        272 :   return true;
     448                 :        276 : }
     449                 :            : 
     450                 :        133 : bool BagReader::match_playback_url_filter(std::string_view input_url,
     451                 :            :                                           const std::unordered_set<std::string>& filter_urls) const {
     452         [ +  + ]:        133 :   if VUNLIKELY (!input_url.data()) {
     453                 :          1 :     return false;
     454                 :            :   }
     455                 :            : 
     456   [ +  +  +  +  :        132 :   if (filter_urls.empty() && !has_playback_url_rules()) {
                   +  + ]
     457                 :         58 :     return true;
     458                 :            :   }
     459                 :            : 
     460                 :         74 :   std::string output_url;
     461                 :            : 
     462   [ +  -  +  -  :         74 :   if VUNLIKELY (!convert_playback_url(std::string(input_url), output_url)) {
                   +  + ]
     463                 :          3 :     return false;
     464                 :            :   }
     465                 :            : 
     466   [ +  +  +  -  :         71 :   return filter_urls.empty() || filter_urls.count(output_url) != 0U;
                   +  + ]
     467                 :         74 : }
     468                 :            : 
     469                 :        128 : bool BagReader::has_playback_url_rules() const noexcept {
     470                 :        128 :   return impl_->playback_url_rules_enabled.load(std::memory_order_acquire);
     471                 :            : }
     472                 :            : 
     473                 :        298 : void BagReader::rebuild_url_meta_lookup(const std::vector<Info::UrlMeta>& url_metas) {
     474         [ +  - ]:        298 :   std::unique_lock state_lock(impl_->playback_state_mtx);
     475                 :            : 
     476         [ +  - ]:        298 :   rebuild_url_meta_maps(url_metas, impl_->url_to_ser_map, impl_->url_to_schema_type_map);
     477                 :        298 : }
     478                 :            : 
     479                 :        300 : void BagReader::rebuild_url_meta_maps(const std::vector<Info::UrlMeta>& url_metas,
     480                 :            :                                       std::unordered_map<std::string, std::string>& ser_map,
     481                 :            :                                       std::unordered_map<std::string, SchemaType>& schema_type_map) {
     482                 :        300 :   ser_map.clear();
     483                 :        300 :   schema_type_map.clear();
     484         [ +  - ]:        300 :   ser_map.reserve(url_metas.size());
     485         [ +  - ]:        300 :   schema_type_map.reserve(url_metas.size());
     486                 :            : 
     487                 :        300 :   std::unordered_set<std::string> ser_conflict_urls;
     488                 :        300 :   std::unordered_set<std::string> schema_conflict_urls;
     489                 :            : 
     490         [ +  - ]:        300 :   ser_conflict_urls.reserve(url_metas.size());
     491         [ +  - ]:        300 :   schema_conflict_urls.reserve(url_metas.size());
     492                 :            : 
     493         [ +  + ]:        729 :   for (const auto& meta : url_metas) {
     494         [ +  - ]:        429 :     auto& merged_ser_type = ser_map[meta.url];
     495         [ +  - ]:        429 :     auto& merged_schema_type = schema_type_map[meta.url];
     496                 :            : 
     497   [ +  -  +  +  :        429 :     if (ser_conflict_urls.count(meta.url) == 0U && !meta.ser_type.empty()) {
             +  +  +  + ]
     498   [ +  +  +  +  :        418 :       if (merged_ser_type.empty() || merged_ser_type == "Bytes") {
                   +  + ]
     499         [ +  - ]:        413 :         merged_ser_type = meta.ser_type;
     500   [ +  -  +  +  :          5 :       } else if (meta.ser_type != "Bytes" && meta.ser_type != merged_ser_type) {
                   +  + ]
     501   [ +  -  +  - ]:          2 :         CLOG_E("BagReader: URL remap collision on %s, keeping ser_type unknown. ser [%s] vs [%s].", meta.url.c_str(),
     502                 :            :                merged_ser_type.c_str(), meta.ser_type.c_str());
     503                 :          1 :         merged_ser_type.clear();
     504         [ +  - ]:          1 :         ser_conflict_urls.emplace(meta.url);
     505                 :            :       }
     506                 :            :     }
     507                 :            : 
     508   [ +  -  +  +  :        429 :     if (schema_conflict_urls.count(meta.url) == 0U && meta.schema_type != SchemaType::kUnknown) {
             +  +  +  + ]
     509         [ +  + ]:        380 :       if (merged_schema_type == SchemaType::kUnknown) {
     510                 :        375 :         merged_schema_type = meta.schema_type;
     511         [ +  + ]:          5 :       } else if (merged_schema_type != meta.schema_type) {
     512                 :          1 :         const auto current_label = SchemaData::convert_type(merged_schema_type);
     513                 :          1 :         const auto new_label = SchemaData::convert_type(meta.schema_type);
     514   [ +  -  +  - ]:          2 :         CLOG_E("BagReader: URL remap collision on %s, keeping schema_type unknown. schema [%.*s] vs [%.*s].",
     515                 :            :                meta.url.c_str(), static_cast<int>(current_label.size()), current_label.data(),
     516                 :            :                static_cast<int>(new_label.size()), new_label.data());
     517                 :          1 :         merged_schema_type = SchemaType::kUnknown;
     518         [ +  - ]:          1 :         schema_conflict_urls.emplace(meta.url);
     519                 :            :       }
     520                 :            :     }
     521                 :            :   }
     522                 :        300 : }
     523                 :            : 
     524                 :        323 : ActionType BagReader::convert_action(std::string_view str) {
     525         [ +  + ]:        323 :   if (str == "C/Req") {
     526                 :         27 :     return ActionType::kClientRequest;
     527         [ +  + ]:        296 :   } else if (str == "C/Resp") {
     528                 :          4 :     return ActionType::kClientResponse;
     529         [ +  + ]:        292 :   } else if (str == "S/Req") {
     530                 :          3 :     return ActionType::kServerRequest;
     531         [ +  + ]:        289 :   } else if (str == "S/Resp") {
     532                 :          3 :     return ActionType::kServerResponse;
     533         [ +  + ]:        286 :   } else if (str == "Pub") {
     534                 :        240 :     return ActionType::kPublish;
     535         [ +  + ]:         46 :   } else if (str == "Sub") {
     536                 :          6 :     return ActionType::kSubscribe;
     537         [ +  + ]:         40 :   } else if (str == "Set") {
     538                 :         31 :     return ActionType::kSet;
     539         [ +  + ]:          9 :   } else if (str == "Get") {
     540                 :          2 :     return ActionType::kGet;
     541                 :            :   } else {
     542                 :          7 :     return ActionType::kUnknownAction;
     543                 :            :   }
     544                 :            : }
     545                 :            : 
     546                 :            : }  // namespace vlink

Generated by: LCOV version 1.14