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-09-30 18:30:16 Functions: 39 41 95.1 %
Branches: 252 348 72.4 %

           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                 :        227 : bool BagReader::Info::UrlMeta::operator<(const BagReader::Info::UrlMeta& target) const noexcept {
      45                 :        227 :   int lindex = Url::get_sort_index(url);
      46                 :        227 :   int rindex = Url::get_sort_index(target.url);
      47                 :            : 
      48         [ +  + ]:        227 :   if (lindex < rindex) {
      49                 :          1 :     return true;
      50         [ +  + ]:        226 :   } else if (lindex > rindex) {
      51                 :          3 :     return false;
      52         [ +  + ]:        223 :   } else if (url < target.url) {
      53                 :         20 :     return true;
      54         [ +  + ]:        203 :   } else if (url > target.url) {
      55                 :        192 :     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                 :        407 : std::shared_ptr<BagReader> BagReader::create(const std::string& path, bool read_only, bool try_to_fix) {
      80         [ +  - ]:        407 :   std::string suffix_check = path;
      81                 :            : 
      82                 :        407 :   std::transform(suffix_check.begin(), suffix_check.end(), suffix_check.begin(),
      83                 :      32736 :                  [](unsigned char c) { return std::tolower(c); });
      84                 :            : 
      85   [ +  +  +  +  :        407 :   if (Helpers::has_endwith(suffix_check, ".vdb") || Helpers::has_endwith(suffix_check, ".vdbx")) {
                   +  + ]
      86         [ +  + ]:        221 :     return std::make_shared<VDBReader>(path, read_only, try_to_fix);
      87   [ +  +  +  +  :        186 :   } else if (Helpers::has_endwith(suffix_check, ".vcap") || Helpers::has_endwith(suffix_check, ".vcapx")) {
                   +  + ]
      88         [ +  + ]:        185 :     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                 :        407 : }
      94                 :            : 
      95         [ +  - ]:        425 : 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                 :        425 :   Bytes::init_memory_pool();
     101                 :        425 : }
     102                 :            : 
     103                 :        425 : BagReader::~BagReader() {
     104                 :        425 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     105                 :            : 
     106                 :            :   {
     107                 :        425 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     108                 :        425 :     plugin_interface = impl_->plugin_interface;
     109                 :        425 :   }
     110                 :            : 
     111         [ +  + ]:        425 :   if (plugin_interface) {
     112                 :          9 :     plugin_interface->register_callback({});
     113                 :            :   }
     114                 :        425 : }
     115                 :            : 
     116                 :         26 : void BagReader::bind_bag_interface(const std::shared_ptr<BagPluginInterface>& bag_interface) {
     117                 :         26 :   std::shared_ptr<BagPluginInterface> old_plugin_interface;
     118                 :            : 
     119                 :            :   {
     120         [ +  - ]:         26 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     121                 :         26 :     old_plugin_interface = impl_->plugin_interface;
     122                 :         26 :   }
     123                 :            : 
     124   [ +  +  +  -  :         26 :   if (old_plugin_interface && old_plugin_interface != bag_interface) {
                   +  + ]
     125         [ +  - ]:          3 :     old_plugin_interface->flush();
     126                 :          3 :     old_plugin_interface->register_callback({});
     127                 :            :   }
     128                 :            : 
     129         [ +  + ]:         26 :   if VLIKELY (bag_interface) {
     130                 :         24 :     bag_interface->bind_direction(BagPluginInterface::Direction::kRead);
     131                 :            : 
     132         [ +  - ]:         24 :     bag_interface->register_callback([this](const Frame& frame) {
     133                 :         36 :       std::string output_url;
     134                 :            : 
     135   [ +  -  -  + ]:         36 :       if VUNLIKELY (!convert_playback_url(frame.url, output_url)) {
     136                 :            :         return;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     137                 :            :       }
     138                 :            : 
     139         [ +  - ]:         36 :       std::shared_lock callback_lock(impl_->output_callback_mtx);
     140                 :            : 
     141         [ +  - ]:         36 :       if VLIKELY (impl_->output_callback) {
     142                 :         36 :         Frame out;
     143                 :         36 :         out.timestamp = frame.timestamp;
     144                 :         36 :         out.url = std::move(output_url);
     145         [ +  - ]:         36 :         out.ser_type = frame.ser_type;
     146                 :         36 :         out.schema_type = frame.schema_type;
     147                 :         36 :         out.action_type = frame.action_type;
     148                 :         36 :         out.data = Bytes::shallow_copy(frame.data.data(), frame.data.size());
     149                 :            : 
     150   [ +  +  -  +  :         36 :         if (out.ser_type.empty() || out.schema_type == SchemaType::kUnknown) {
                   +  + ]
     151         [ +  - ]:          6 :           fill_frame_meta(out);
     152                 :            :         }
     153                 :            : 
     154         [ +  - ]:         36 :         impl_->output_callback(out);
     155                 :         36 :       }
     156         [ +  - ]:         36 :     });
     157                 :            :   }
     158                 :            : 
     159         [ +  - ]:         26 :   std::unique_lock state_lock(impl_->playback_state_mtx);
     160                 :            : 
     161                 :         26 :   impl_->plugin_interface = bag_interface;
     162                 :         26 :   impl_->playback_url_remap.clear();
     163                 :         26 :   impl_->excluded_playback_urls.clear();
     164                 :         26 :   impl_->playback_url_rules_enabled.store(false, std::memory_order_release);
     165                 :         26 : }
     166                 :            : 
     167         [ #  # ]:          0 : void BagReader::clear_bag_interface() { bind_bag_interface(nullptr); }
     168                 :            : 
     169                 :          1 : void BagReader::register_status_callback(StatusCallback&& status_callback) { (void)status_callback; }
     170                 :            : 
     171                 :          1 : void BagReader::register_ready_callback(ReadyCallback&& ready_callback) { (void)ready_callback; }
     172                 :            : 
     173                 :          1 : void BagReader::register_finish_callback(FinishCallback&& finish_callback) { (void)finish_callback; }
     174                 :            : 
     175                 :         40 : void BagReader::register_output_callback(OutputCallback&& output_callback) {
     176         [ +  - ]:         40 :   std::unique_lock lock(impl_->output_callback_mtx);
     177                 :            : 
     178                 :         40 :   impl_->output_callback = std::move(output_callback);
     179                 :         40 : }
     180                 :            : 
     181                 :        233 : bool BagReader::open_cursor(const Config& config) {
     182                 :        233 :   impl_->cursor_opened = false;
     183                 :        233 :   impl_->cursor_eof = false;
     184                 :        233 :   impl_->cursor_fail = false;
     185                 :            : 
     186         [ +  + ]:        233 :   if VUNLIKELY (!do_open_cursor(config)) {
     187                 :          2 :     impl_->cursor_fail = true;
     188                 :          2 :     return false;
     189                 :            :   }
     190                 :            : 
     191                 :        231 :   impl_->cursor_opened = true;
     192                 :        231 :   return true;
     193                 :            : }
     194                 :            : 
     195         [ +  - ]:        193 : bool BagReader::open_cursor() { return open_cursor(Config{}); }
     196                 :            : 
     197                 :       1173 : bool BagReader::read_next(Frame& out) {
     198         [ +  + ]:       1173 :   if VUNLIKELY (impl_->cursor_fail) {
     199                 :          2 :     return false;
     200                 :            :   }
     201                 :            : 
     202         [ +  + ]:       1171 :   if VUNLIKELY (impl_->cursor_eof) {
     203                 :          1 :     return false;
     204                 :            :   }
     205                 :            : 
     206   [ +  +  +  -  :       1170 :   if (!impl_->cursor_opened && !open_cursor(Config{})) {
          -  +  +  +  -  
                +  -  - ]
     207                 :            :     return false;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     208                 :            :   }
     209                 :            : 
     210                 :       1170 :   bool is_error = false;
     211                 :            : 
     212   [ +  -  +  + ]:       1170 :   if VLIKELY (do_read_next(out, is_error)) {
     213                 :        939 :     return true;
     214                 :            :   }
     215                 :            : 
     216         [ -  + ]:        231 :   if (is_error) {
     217                 :            :     impl_->cursor_fail = true;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     218                 :            :   } else {
     219                 :        231 :     impl_->cursor_eof = true;
     220                 :            :   }
     221                 :            : 
     222                 :        231 :   return false;
     223                 :            : }
     224                 :            : 
     225                 :         12 : BagReader& BagReader::operator>>(Frame& out) {
     226                 :         12 :   read_next(out);
     227                 :            : 
     228                 :         12 :   return *this;
     229                 :            : }
     230                 :            : 
     231                 :         32 : bool BagReader::eof() const noexcept { return impl_->cursor_eof; }
     232                 :            : 
     233                 :         28 : bool BagReader::fail() const noexcept { return impl_->cursor_fail; }
     234                 :            : 
     235   [ +  +  +  + ]:         14 : BagReader::operator bool() const noexcept { return !impl_->cursor_eof && !impl_->cursor_fail; }
     236                 :            : 
     237                 :         27 : std::string BagReader::get_ser_type(const std::string& url) const {
     238         [ +  - ]:         27 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     239                 :            : 
     240         [ +  - ]:         27 :   auto iter = impl_->url_to_ser_map.find(url);
     241                 :            : 
     242         [ +  + ]:         27 :   if VLIKELY (iter != impl_->url_to_ser_map.end()) {
     243         [ +  - ]:         18 :     return iter->second;
     244                 :            :   }
     245                 :            : 
     246                 :          9 :   return {};
     247                 :         27 : }
     248                 :            : 
     249                 :         15 : SchemaType BagReader::get_schema_type(const std::string& url) const {
     250         [ +  - ]:         15 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     251                 :            : 
     252         [ +  - ]:         15 :   auto iter = impl_->url_to_schema_type_map.find(url);
     253                 :            : 
     254         [ +  + ]:         15 :   if VLIKELY (iter != impl_->url_to_schema_type_map.end()) {
     255                 :         12 :     return iter->second;
     256                 :            :   }
     257                 :            : 
     258                 :          3 :   return SchemaType::kUnknown;
     259                 :         15 : }
     260                 :            : 
     261                 :          1 : bool BagReader::do_open_cursor(const Config& config) {
     262                 :            :   (void)config;
     263                 :            : 
     264                 :          1 :   return false;
     265                 :            : }
     266                 :            : 
     267                 :            : bool BagReader::do_read_next(Frame& out, bool& is_error) {  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     268                 :            :   (void)out;
     269                 :            : 
     270                 :            :   is_error = false;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     271                 :            : 
     272                 :            :   return false;  // LCOV_EXCL_LINE GCOVR_EXCL_LINE
     273                 :            : }
     274                 :            : 
     275                 :       1920 : void BagReader::rebuild_url_meta_maps(const std::vector<Info::UrlMeta>& url_metas,
     276                 :            :                                       std::unordered_map<std::string, std::string>& ser_map,
     277                 :            :                                       std::unordered_map<std::string, SchemaType>& schema_type_map) {
     278                 :       1920 :   ser_map.clear();
     279                 :       1920 :   schema_type_map.clear();
     280         [ +  - ]:       1920 :   ser_map.reserve(url_metas.size());
     281         [ +  - ]:       1920 :   schema_type_map.reserve(url_metas.size());
     282                 :            : 
     283                 :       1920 :   std::unordered_set<std::string> ser_conflict_urls;
     284                 :       1920 :   std::unordered_set<std::string> schema_conflict_urls;
     285                 :            : 
     286         [ +  - ]:       1920 :   ser_conflict_urls.reserve(url_metas.size());
     287         [ +  - ]:       1920 :   schema_conflict_urls.reserve(url_metas.size());
     288                 :            : 
     289         [ +  + ]:       3978 :   for (const auto& meta : url_metas) {
     290         [ +  - ]:       2058 :     auto& merged_ser_type = ser_map[meta.url];
     291         [ +  - ]:       2058 :     auto& merged_schema_type = schema_type_map[meta.url];
     292                 :            : 
     293   [ +  -  +  +  :       2058 :     if (ser_conflict_urls.count(meta.url) == 0U && !meta.ser_type.empty()) {
             +  +  +  + ]
     294   [ +  +  +  +  :       2039 :       if (merged_ser_type.empty() || merged_ser_type == "Bytes") {
                   +  + ]
     295         [ +  - ]:       2034 :         merged_ser_type = meta.ser_type;
     296   [ +  -  +  +  :          5 :       } else if (meta.ser_type != "Bytes" && meta.ser_type != merged_ser_type) {
                   +  + ]
     297   [ +  -  +  -  :          2 :         CLOG_E("BagReader: URL remap collision on %s, keeping ser_type unknown. ser [%s] vs [%s].", meta.url.c_str(),
                   +  - ]
     298                 :            :                merged_ser_type.c_str(), meta.ser_type.c_str());
     299                 :          1 :         merged_ser_type.clear();
     300         [ +  - ]:          1 :         ser_conflict_urls.emplace(meta.url);
     301                 :            :       }
     302                 :            :     }
     303                 :            : 
     304   [ +  -  +  +  :       2058 :     if (schema_conflict_urls.count(meta.url) == 0U && meta.schema_type != SchemaType::kUnknown) {
             +  +  +  + ]
     305         [ +  + ]:       2006 :       if (merged_schema_type == SchemaType::kUnknown) {
     306                 :       2001 :         merged_schema_type = meta.schema_type;
     307         [ +  + ]:          5 :       } else if (merged_schema_type != meta.schema_type) {
     308                 :          1 :         const auto current_label = SchemaData::convert_type(merged_schema_type);
     309                 :          1 :         const auto new_label = SchemaData::convert_type(meta.schema_type);
     310   [ +  -  +  -  :          2 :         CLOG_E("BagReader: URL remap collision on %s, keeping schema_type unknown. schema [%.*s] vs [%.*s].",
                   +  - ]
     311                 :            :                meta.url.c_str(), static_cast<int>(current_label.size()), current_label.data(),
     312                 :            :                static_cast<int>(new_label.size()), new_label.data());
     313                 :          1 :         merged_schema_type = SchemaType::kUnknown;
     314         [ +  - ]:          1 :         schema_conflict_urls.emplace(meta.url);
     315                 :            :       }
     316                 :            :     }
     317                 :            :   }
     318                 :       1920 : }
     319                 :            : 
     320                 :        189 : void BagReader::process_output(Frame& frame) {
     321                 :        189 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     322                 :            : 
     323                 :            :   {
     324         [ +  - ]:        189 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     325                 :            : 
     326                 :        189 :     plugin_interface = impl_->plugin_interface;
     327                 :            : 
     328   [ +  +  +  -  :        189 :     if VUNLIKELY (plugin_interface && impl_->excluded_playback_urls.count(frame.url) != 0U) {
             +  +  +  + ]
     329                 :          1 :       return;
     330                 :            :     }
     331                 :            : 
     332                 :        188 :     const std::string* meta_url = &frame.url;
     333                 :            : 
     334         [ +  + ]:        188 :     if (plugin_interface) {
     335         [ +  - ]:         47 :       auto remap_iter = impl_->playback_url_remap.find(frame.url);
     336                 :            : 
     337         [ +  + ]:         47 :       if (remap_iter != impl_->playback_url_remap.end()) {
     338                 :          2 :         meta_url = &remap_iter->second;
     339                 :            :       }
     340                 :            :     }
     341                 :            : 
     342         [ +  - ]:        188 :     if (frame.ser_type.empty()) {
     343         [ +  - ]:        188 :       auto ser_iter = impl_->url_to_ser_map.find(*meta_url);
     344                 :            : 
     345         [ +  + ]:        188 :       if VLIKELY (ser_iter != impl_->url_to_ser_map.end()) {
     346         [ +  - ]:        182 :         frame.ser_type = ser_iter->second;
     347                 :            :       }
     348                 :            :     }
     349                 :            : 
     350         [ +  - ]:        188 :     if (frame.schema_type == SchemaType::kUnknown) {
     351         [ +  - ]:        188 :       auto schema_iter = impl_->url_to_schema_type_map.find(*meta_url);
     352                 :            : 
     353         [ +  + ]:        188 :       if VLIKELY (schema_iter != impl_->url_to_schema_type_map.end()) {
     354                 :        182 :         frame.schema_type = schema_iter->second;
     355                 :            :       }
     356                 :            :     }
     357         [ +  + ]:        189 :   }
     358                 :            : 
     359         [ +  + ]:        188 :   if (plugin_interface) {
     360         [ +  - ]:         47 :     plugin_interface->on_read(frame);
     361                 :            :   } else {
     362         [ +  - ]:        141 :     std::shared_lock callback_lock(impl_->output_callback_mtx);
     363                 :            : 
     364         [ +  + ]:        141 :     if VLIKELY (impl_->output_callback) {
     365         [ +  - ]:        140 :       impl_->output_callback(frame);
     366                 :            :     }
     367                 :        141 :   }
     368         [ +  + ]:        189 : }
     369                 :            : 
     370                 :        937 : void BagReader::fill_frame_meta(Frame& frame) const {
     371         [ +  - ]:        937 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     372                 :            : 
     373         [ +  - ]:        937 :   if (frame.ser_type.empty()) {
     374         [ +  - ]:        937 :     auto iter = impl_->url_to_ser_map.find(frame.url);
     375                 :            : 
     376         [ +  + ]:        937 :     if VLIKELY (iter != impl_->url_to_ser_map.end()) {
     377         [ +  - ]:        932 :       frame.ser_type = iter->second;
     378                 :            :     }
     379                 :            :   }
     380                 :            : 
     381         [ +  - ]:        937 :   if (frame.schema_type == SchemaType::kUnknown) {
     382         [ +  - ]:        937 :     auto iter = impl_->url_to_schema_type_map.find(frame.url);
     383                 :            : 
     384         [ +  + ]:        937 :     if VLIKELY (iter != impl_->url_to_schema_type_map.end()) {
     385                 :        932 :       frame.schema_type = iter->second;
     386                 :            :     }
     387                 :            :   }
     388                 :        937 : }
     389                 :            : 
     390                 :         71 : void BagReader::reset_plugin() {
     391                 :         71 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     392                 :            : 
     393                 :            :   {
     394         [ +  - ]:         71 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     395                 :         71 :     plugin_interface = impl_->plugin_interface;
     396                 :         71 :   }
     397                 :            : 
     398         [ +  + ]:         71 :   if (plugin_interface) {
     399         [ +  - ]:         18 :     plugin_interface->on_reset();
     400                 :            :   }
     401                 :         71 : }
     402                 :            : 
     403                 :         58 : void BagReader::flush_plugin() {
     404                 :         58 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     405                 :            : 
     406                 :            :   {
     407         [ +  - ]:         58 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     408                 :         58 :     plugin_interface = impl_->plugin_interface;
     409                 :         58 :   }
     410                 :            : 
     411         [ +  + ]:         58 :   if (plugin_interface) {
     412         [ +  - ]:         13 :     plugin_interface->flush();
     413                 :            :   }
     414                 :         58 : }
     415                 :            : 
     416                 :         24 : void BagReader::process_url_metas(std::vector<Info::UrlMeta>& url_metas) {
     417                 :         24 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     418                 :            : 
     419                 :            :   {
     420         [ +  - ]:         24 :     std::shared_lock state_lock(impl_->playback_state_mtx);
     421                 :         24 :     plugin_interface = impl_->plugin_interface;
     422                 :         24 :   }
     423                 :            : 
     424                 :         24 :   std::unordered_map<std::string, std::string> playback_url_remap;
     425                 :         24 :   std::unordered_set<std::string> excluded_playback_urls;
     426                 :            : 
     427         [ +  + ]:         24 :   if (plugin_interface) {
     428         [ +  - ]:         42 :     url_metas.erase(
     429         [ +  - ]:         21 :         std::remove_if(url_metas.begin(), url_metas.end(),
     430                 :        103 :                        [&plugin_interface, &playback_url_remap, &excluded_playback_urls](Info::UrlMeta& meta) {
     431         [ +  - ]:         45 :                          const std::string input_url = meta.url;
     432                 :            : 
     433   [ +  -  +  + ]:         45 :                          if VUNLIKELY (!plugin_interface->convert_url_meta(meta.url, meta.ser_type, meta.schema_type)) {
     434         [ +  - ]:          5 :                            excluded_playback_urls.emplace(input_url);
     435                 :          5 :                            return true;
     436                 :            :                          }
     437                 :            : 
     438         [ +  + ]:         40 :                          if (meta.url != input_url) {
     439   [ +  -  +  - ]:          8 :                            playback_url_remap[input_url] = meta.url;
     440                 :            :                          }
     441                 :            : 
     442                 :         40 :                          return false;
     443                 :         45 :                        }),
     444                 :         42 :         url_metas.end());
     445                 :            :   }
     446                 :            : 
     447                 :            :   {
     448         [ +  - ]:         24 :     std::unique_lock state_lock(impl_->playback_state_mtx);
     449                 :            : 
     450         [ +  - ]:         24 :     if (impl_->plugin_interface == plugin_interface) {
     451                 :         24 :       impl_->playback_url_remap = std::move(playback_url_remap);
     452                 :         24 :       impl_->excluded_playback_urls = std::move(excluded_playback_urls);
     453                 :         48 :       impl_->playback_url_rules_enabled.store(
     454   [ +  +  +  + ]:         24 :           !impl_->playback_url_remap.empty() || !impl_->excluded_playback_urls.empty(), std::memory_order_release);
     455                 :            :     }
     456                 :         24 :   }
     457                 :         24 : }
     458                 :            : 
     459                 :       1918 : void BagReader::rebuild_url_meta_lookup(const std::vector<Info::UrlMeta>& url_metas) {
     460         [ +  - ]:       1918 :   std::unique_lock state_lock(impl_->playback_state_mtx);
     461                 :            : 
     462         [ +  - ]:       1918 :   rebuild_url_meta_maps(url_metas, impl_->url_to_ser_map, impl_->url_to_schema_type_map);
     463                 :       1918 : }
     464                 :            : 
     465                 :       4311 : std::unordered_map<std::string, std::string>& BagReader::url_ser_map() { return impl_->url_to_ser_map; }
     466                 :            : 
     467                 :       4311 : std::unordered_map<std::string, SchemaType>& BagReader::url_schema_type_map() { return impl_->url_to_schema_type_map; }
     468                 :            : 
     469                 :       1042 : bool BagReader::convert_playback_url(const std::string& input_url, std::string& output_url) const {
     470         [ +  - ]:       1042 :   std::shared_lock state_lock(impl_->playback_state_mtx);
     471                 :            : 
     472   [ +  -  +  + ]:       1042 :   if VUNLIKELY (impl_->excluded_playback_urls.count(input_url) != 0U) {
     473                 :          4 :     return false;
     474                 :            :   }
     475                 :            : 
     476         [ +  - ]:       1038 :   auto iter = impl_->playback_url_remap.find(input_url);
     477                 :            : 
     478         [ +  + ]:       1038 :   if (iter != impl_->playback_url_remap.end()) {
     479         [ +  - ]:         10 :     output_url = iter->second;
     480                 :            :   } else {
     481         [ +  - ]:       1028 :     output_url = input_url;
     482                 :            :   }
     483                 :            : 
     484                 :       1038 :   return true;
     485                 :       1042 : }
     486                 :            : 
     487                 :        162 : bool BagReader::match_playback_url_filter(std::string_view input_url,
     488                 :            :                                           const std::unordered_set<std::string>& filter_urls) const {
     489         [ +  + ]:        162 :   if VUNLIKELY (!input_url.data()) {
     490                 :          1 :     return false;
     491                 :            :   }
     492                 :            : 
     493   [ +  +  +  +  :        161 :   if (filter_urls.empty() && !has_playback_url_rules()) {
                   +  + ]
     494                 :         87 :     return true;
     495                 :            :   }
     496                 :            : 
     497                 :         74 :   std::string output_url;
     498                 :            : 
     499   [ +  -  +  -  :         74 :   if VUNLIKELY (!convert_playback_url(std::string(input_url), output_url)) {
                   +  + ]
     500                 :          3 :     return false;
     501                 :            :   }
     502                 :            : 
     503   [ +  +  +  -  :         71 :   return filter_urls.empty() || filter_urls.count(output_url) != 0U;
                   +  + ]
     504                 :         74 : }
     505                 :            : 
     506                 :        554 : bool BagReader::has_playback_url_rules() const noexcept {
     507                 :        554 :   return impl_->playback_url_rules_enabled.load(std::memory_order_acquire);
     508                 :            : }
     509                 :            : 
     510                 :       1536 : ActionType BagReader::convert_action(std::string_view str) {
     511         [ +  + ]:       1536 :   if (str == "C/Req") {
     512                 :         28 :     return ActionType::kClientRequest;
     513         [ +  + ]:       1508 :   } else if (str == "C/Resp") {
     514                 :          4 :     return ActionType::kClientResponse;
     515         [ +  + ]:       1504 :   } else if (str == "S/Req") {
     516                 :          3 :     return ActionType::kServerRequest;
     517         [ +  + ]:       1501 :   } else if (str == "S/Resp") {
     518                 :          3 :     return ActionType::kServerResponse;
     519         [ +  + ]:       1498 :   } else if (str == "Pub") {
     520                 :       1423 :     return ActionType::kPublish;
     521         [ +  + ]:         75 :   } else if (str == "Sub") {
     522                 :         20 :     return ActionType::kSubscribe;
     523         [ +  + ]:         55 :   } else if (str == "Set") {
     524                 :         32 :     return ActionType::kSet;
     525         [ +  + ]:         23 :   } else if (str == "Get") {
     526                 :         16 :     return ActionType::kGet;
     527                 :            :   } else {
     528                 :          7 :     return ActionType::kUnknownAction;
     529                 :            :   }
     530                 :            : }
     531                 :            : 
     532                 :        389 : void BagReader::detach_plugin() {
     533                 :        389 :   std::shared_ptr<BagPluginInterface> plugin_interface;
     534                 :            : 
     535                 :            :   {
     536         [ +  - ]:        389 :     std::unique_lock state_lock(impl_->playback_state_mtx);
     537                 :        389 :     plugin_interface = std::move(impl_->plugin_interface);
     538                 :        389 :   }
     539                 :            : 
     540         [ +  + ]:        389 :   if (plugin_interface) {
     541         [ +  - ]:         12 :     plugin_interface->flush();
     542                 :         12 :     plugin_interface->register_callback({});
     543                 :            :   }
     544                 :        389 : }
     545                 :            : 
     546                 :            : }  // namespace vlink

Generated by: LCOV version 1.14