LCOV - code coverage report
Current view: top level - src/config - binary_loader.cpp (source / functions) Coverage Total Hit
Test: HPActor Coverage Lines: 81.7 % 82 67
Test Date: 2026-05-20 02:24:49 Functions: 100.0 % 6 6
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : // Copyright 2026 HPActor Contributors
       2                 :             : //
       3                 :             : // Licensed under the Apache License, Version 2.0 (the "License");
       4                 :             : // you may not use this file except in compliance with the License.
       5                 :             : // You may obtain a copy of the License at
       6                 :             : //
       7                 :             : //     http://www.apache.org/licenses/LICENSE-2.0
       8                 :             : //
       9                 :             : // Unless required by applicable law or agreed to in writing, software
      10                 :             : // distributed under the License is distributed on an "AS IS" BASIS,
      11                 :             : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :             : // See the License for the specific language governing permissions and
      13                 :             : // limitations under the License.
      14                 :             : 
      15                 :             : #include <hpactor/config/binary_loader.hpp>
      16                 :             : 
      17                 :             : #include <fcntl.h>
      18                 :             : #include <sys/mman.h>
      19                 :             : #include <sys/stat.h>
      20                 :             : #include <unistd.h>
      21                 :             : 
      22                 :             : namespace hpactor::config {
      23                 :             : 
      24                 :             : // -----------------------------------------------------------------------------
      25                 :             : // Binary format types (must match binary_format.hpp)
      26                 :             : // -----------------------------------------------------------------------------
      27                 :             : namespace {
      28                 :             : 
      29                 :             : constexpr uint32_t MAGIC = 0x48504154; // "HPAT"
      30                 :             : 
      31                 :             : struct RawHeader {
      32                 :             :     uint32_t magic;
      33                 :             :     uint32_t version;
      34                 :             :     uint32_t system_offset;
      35                 :             :     uint32_t dispatcher_count;
      36                 :             :     uint32_t dispatchers_offset;
      37                 :             :     uint32_t actor_count;
      38                 :             :     uint32_t actors_offset;
      39                 :             :     uint32_t string_table_offset;
      40                 :             :     uint32_t string_table_size;
      41                 :             : };
      42                 :             : 
      43                 :             : struct RawSystemDef {
      44                 :             :     uint32_t scheduler_threads;
      45                 :             :     uint32_t max_queue_depth;
      46                 :             :     uint32_t default_mailbox_size;
      47                 :             :     uint32_t enable_network;
      48                 :             :     uint16_t tcp_port;
      49                 :             :     uint16_t reserved_pad;
      50                 :             :     uint32_t spawn_timeout_ms;
      51                 :             :     uint32_t enable_http_gateway;
      52                 :             :     uint16_t http_port;
      53                 :             :     uint32_t http_max_connections;
      54                 :             :     uint32_t http_max_request_size;
      55                 :             :     uint32_t http_reply_timeout_ms;
      56                 :             :     uint32_t use_coroutines;
      57                 :             :     uint32_t version_offset;
      58                 :             :     union {
      59                 :             :         uint32_t http_bind_host;        // X-macro compatible name
      60                 :             :         uint32_t http_bind_host_offset; // string table offset (canonical)
      61                 :             :     };
      62                 :             :     uint32_t tracing_enabled;
      63                 :             :     uint32_t tracing_propagate_unsampled;
      64                 :             :     uint32_t tracing_ring_buffer_capacity;
      65                 :             :     uint32_t tracing_sampler;
      66                 :             :     uint32_t tracing_exporter;
      67                 :             :     double tracing_sample_ratio;
      68                 :             :     uint32_t tracing_export_interval_ms;
      69                 :             :     uint32_t tracing_max_export_batch_size;
      70                 :             :     uint16_t tracing_max_tracestate_len;
      71                 :             :     uint16_t tracing_pad;
      72                 :             :     uint32_t tracing_flags;
      73                 :             :     uint32_t tracing_service_name_offset;
      74                 :             :     uint32_t tracing_otlp_endpoint_offset;
      75                 :             :     uint32_t tracing_json_file_path_offset;
      76                 :             : };
      77                 :             : 
      78                 :             : struct RawDispatcher {
      79                 :             :     uint32_t name_offset;
      80                 :             :     uint16_t threads;
      81                 :             :     uint16_t cpu_affinity_count;
      82                 :             :     uint32_t cpu_affinity_offset;
      83                 :             : };
      84                 :             : 
      85                 :             : struct RawActor {
      86                 :             :     uint32_t id_offset;
      87                 :             :     uint32_t behavior_offset;
      88                 :             :     uint32_t supervisor_offset;
      89                 :             :     uint32_t dispatcher_offset;
      90                 :             :     uint8_t dispatch_policy;
      91                 :             :     uint32_t mailbox_capacity;
      92                 :             :     uint32_t slab_class_bytes;
      93                 :             :     uint32_t max_memory_kb;
      94                 :             :     uint16_t args_count;
      95                 :             :     uint32_t args_offset;
      96                 :             : };
      97                 :             : 
      98                 :             : struct RawKV {
      99                 :             :     uint32_t key_offset;
     100                 :             :     uint32_t value_offset;
     101                 :             : };
     102                 :             : 
     103                 :          39 : inline const char* str_at(const uint8_t* str_table, uint32_t offset) {
     104                 :          39 :     return offset ? reinterpret_cast<const char*>(str_table + offset) : "";
     105                 :             : }
     106                 :             : 
     107                 :             : // Assign Dst from Src when the types are directly compatible; silently skip
     108                 :             : // otherwise.  Catches mismatches like std::string = uint32_t (string is
     109                 :             : // assignable from char = int, but that's not what we want for binary offset
     110                 :             : // fields).
     111                 :             : template <typename Dst, typename Src>
     112                 :          33 : void assign_or_skip(Dst& dst, const Src& src) {
     113                 :             :     if constexpr (std::is_assignable_v<Dst&, const Src&> &&
     114                 :             :                   !(std::is_arithmetic_v<Src> && std::is_same_v<Dst, std::string>)) {
     115                 :          30 :         dst = static_cast<Dst>(src);
     116                 :             :     }
     117                 :          33 : }
     118                 :             : 
     119                 :             : } // anonymous namespace
     120                 :             : 
     121                 :             : // -----------------------------------------------------------------------------
     122                 :             : // load_binary_topology — mmap a .bin file into a TopologyModel
     123                 :             : // -----------------------------------------------------------------------------
     124                 :           3 : result<TopologyModel> load_binary_topology(const std::string& path) {
     125                 :           3 :     int fd = open(path.c_str(), O_RDONLY);
     126                 :           3 :     if (fd < 0) {
     127                 :           0 :         return result<TopologyModel>::make(error(errors::unknown));
     128                 :             :     }
     129                 :             : 
     130                 :             :     struct stat st;
     131                 :           3 :     if (fstat(fd, &st) < 0) {
     132                 :           0 :         close(fd);
     133                 :           0 :         return result<TopologyModel>::make(error(errors::unknown));
     134                 :             :     }
     135                 :             : 
     136                 :           3 :     size_t file_size = static_cast<size_t>(st.st_size);
     137                 :           3 :     void* mapped = mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0);
     138                 :           3 :     close(fd);
     139                 :             : 
     140                 :           3 :     if (mapped == MAP_FAILED) {
     141                 :           0 :         return result<TopologyModel>::make(error(errors::unknown));
     142                 :             :     }
     143                 :             : 
     144                 :           3 :     const uint8_t* base = static_cast<const uint8_t*>(mapped);
     145                 :           3 :     const RawHeader* hdr = reinterpret_cast<const RawHeader*>(base);
     146                 :             : 
     147                 :           3 :     if (hdr->magic != MAGIC) {
     148                 :           0 :         munmap(mapped, file_size);
     149                 :           0 :         return result<TopologyModel>::make(error(errors::unknown));
     150                 :             :     }
     151                 :             : 
     152                 :           3 :     const uint8_t* str_table = base + hdr->string_table_offset;
     153                 :           3 :     TopologyModel model;
     154                 :             : 
     155                 :             :     // System config
     156                 :           3 :     const RawSystemDef* rsys =
     157                 :           3 :         reinterpret_cast<const RawSystemDef*>(base + hdr->system_offset);
     158                 :           3 :     model.system.version = str_at(str_table, rsys->version_offset);
     159                 :             : 
     160                 :             : // Shared scalar fields (generated from system_toml_fields.def)
     161                 :             : // NOLINTBEGIN(cppcoreguidelines-macro-usage)
     162                 :             : #define HPACTOR_SYSTEM_TOML_FIELD(name, type, toml, def)                       \
     163                 :             :     assign_or_skip(model.system.name, rsys->name);
     164                 :             : #include <hpactor/config/system_toml_fields.def>
     165                 :             : #undef HPACTOR_SYSTEM_TOML_FIELD
     166                 :             :     // NOLINTEND(cppcoreguidelines-macro-usage)
     167                 :             : 
     168                 :             :     // SystemDef-only fields (not in the shared X-macro table)
     169                 :           3 :     model.system.default_mailbox_size = rsys->default_mailbox_size;
     170                 :           3 :     model.system.use_coroutines = rsys->use_coroutines != 0;
     171                 :             : 
     172                 :             :     // String-override: assign_or_skip skips string fields (string != uint32_t),
     173                 :             :     // so apply the string-table lookup manually.
     174                 :           3 :     model.system.http_bind_host = str_at(str_table, rsys->http_bind_host_offset);
     175                 :             : 
     176                 :             :     // Tracing config (zero-filled for older binary versions = disabled)
     177                 :           3 :     model.system.tracing.enabled = rsys->tracing_enabled != 0;
     178                 :           3 :     model.system.tracing.propagate_unsampled =
     179                 :           3 :         rsys->tracing_propagate_unsampled != 0;
     180                 :           3 :     model.system.tracing.ring_buffer_capacity = rsys->tracing_ring_buffer_capacity;
     181                 :           3 :     model.system.tracing.sampler =
     182                 :           3 :         static_cast<hpactor::tracing::SamplerKind>(rsys->tracing_sampler);
     183                 :           3 :     model.system.tracing.exporter =
     184                 :           3 :         static_cast<hpactor::tracing::TraceExporterKind>(rsys->tracing_exporter);
     185                 :           3 :     model.system.tracing.sample_ratio = rsys->tracing_sample_ratio;
     186                 :           3 :     model.system.tracing.export_interval =
     187                 :           3 :         std::chrono::milliseconds(rsys->tracing_export_interval_ms);
     188                 :           3 :     model.system.tracing.max_export_batch_size = rsys->tracing_max_export_batch_size;
     189                 :           3 :     model.system.tracing.max_tracestate_len = rsys->tracing_max_tracestate_len;
     190                 :             :     model.system.tracing.service_name =
     191                 :           3 :         str_at(str_table, rsys->tracing_service_name_offset);
     192                 :             :     model.system.tracing.otlp_endpoint =
     193                 :           3 :         str_at(str_table, rsys->tracing_otlp_endpoint_offset);
     194                 :             :     model.system.tracing.json_file_path =
     195                 :           3 :         str_at(str_table, rsys->tracing_json_file_path_offset);
     196                 :             : 
     197                 :             :     // Dispatchers
     198                 :           3 :     const RawDispatcher* dispatchers =
     199                 :           3 :         reinterpret_cast<const RawDispatcher*>(base + hdr->dispatchers_offset);
     200                 :           3 :     for (uint32_t i = 0; i < hdr->dispatcher_count; ++i) {
     201                 :           0 :         DispatcherDef def;
     202                 :           0 :         def.name = str_at(str_table, dispatchers[i].name_offset);
     203                 :           0 :         def.threads = dispatchers[i].threads;
     204                 :           0 :         if (dispatchers[i].cpu_affinity_count > 0 &&
     205                 :           0 :             dispatchers[i].cpu_affinity_offset) {
     206                 :           0 :             const uint8_t* aff = base + dispatchers[i].cpu_affinity_offset;
     207                 :           0 :             def.cpu_affinity.assign(aff, aff + dispatchers[i].cpu_affinity_count);
     208                 :             :         }
     209                 :           0 :         model.dispatchers.push_back(std::move(def));
     210                 :           0 :     }
     211                 :             : 
     212                 :             :     // Actors
     213                 :           3 :     const RawActor* actors =
     214                 :           3 :         reinterpret_cast<const RawActor*>(base + hdr->actors_offset);
     215                 :           8 :     for (uint32_t i = 0; i < hdr->actor_count; ++i) {
     216                 :           5 :         const RawActor& ra = actors[i];
     217                 :           5 :         ActorDef def;
     218                 :           5 :         def.id = str_at(str_table, ra.id_offset);
     219                 :           5 :         def.behavior = str_at(str_table, ra.behavior_offset);
     220                 :           5 :         def.supervisor = str_at(str_table, ra.supervisor_offset);
     221                 :           5 :         def.dispatcher = str_at(str_table, ra.dispatcher_offset);
     222                 :           5 :         def.dispatch_policy = static_cast<DispatchPolicy>(ra.dispatch_policy);
     223                 :           5 :         def.mailbox_capacity = ra.mailbox_capacity;
     224                 :           5 :         def.resources.slab_class_bytes = ra.slab_class_bytes;
     225                 :           5 :         def.resources.max_memory_kb = ra.max_memory_kb;
     226                 :             : 
     227                 :           5 :         if (ra.args_count > 0 && ra.args_offset) {
     228                 :           1 :             const RawKV* kvs =
     229                 :           1 :                 reinterpret_cast<const RawKV*>(base + ra.args_offset);
     230                 :           3 :             for (uint16_t j = 0; j < ra.args_count; ++j) {
     231                 :           6 :                 def.args[str_at(str_table, kvs[j].key_offset)] =
     232                 :           4 :                     str_at(str_table, kvs[j].value_offset);
     233                 :             :             }
     234                 :             :         }
     235                 :             : 
     236                 :           5 :         model.actors.push_back(std::move(def));
     237                 :           5 :     }
     238                 :             : 
     239                 :           3 :     munmap(mapped, file_size);
     240                 :           3 :     return result<TopologyModel>::make(std::move(model));
     241                 :           3 : }
     242                 :             : 
     243                 :             : } // namespace hpactor::config
        

Generated by: LCOV version 2.0-1