/workspaces/astro/sol3-sdk/cpp/sol3/core/shmem_exchange.h Source File

Space-ng SDK: /workspaces/astro/sol3-sdk/cpp/sol3/core/shmem_exchange.h Source File
Space-ng SDK
shmem_exchange.h
Go to the documentation of this file.
1 // Copyright (c) Space-ng, inc. All rights reserved.
2 
3 #pragma once
5 #include "sol3/core/msg/exchange_config.h"
7 #include "sol3/cpp/filesystem.h"
9 
10 #include <boost/asio.hpp>
11 #include <boost/asio/local/datagram_protocol.hpp>
12 
13 #include <atomic>
14 #include <cstddef>
15 #include <cstdint>
16 #include <map>
17 #include <memory>
18 #include <set>
19 #include <string>
20 #include <unordered_set>
21 #include <utility>
22 #include <vector>
23 namespace sol3::core {
24 
25 enum ExchangeCode : uint32_t {
30 };
31 
37 msg::ExchangeConfigT loadExchangeConfigFromEnv();
38 
41 msg::ExchangeConfigT loadExchangeConfigFromPath(std::string const& config_path);
42 
49 msg::ExchangeConfigT loadExchangeConfigFromSol3Root(
50  char const* app_name, cpp::fs::path const& sol3_root_path);
51 
55  public:
59 
62  ShmemExchange(Endpoint const& local_endpoint);
63 
65  ShmemExchange(msg::ExchangeConfigT exchange_config);
66 
68  ~ShmemExchange() override;
69 
70  // Non-copyable and non-movable: ShmemExchange owns IO and socket resources.
71  ShmemExchange(ShmemExchange const&) = delete;
75 
76  void start() override;
77  void stop() override;
78  bool stopped() const override;
79  void addPeer(Endpoint peer_endpoint) override;
81  uint32_t local_port,
82  Endpoint peer_endpoint,
83  uint32_t peer_port = 0) override;
84  void configure(msg::ExchangeConfigT const& config) override;
85  void registerBuffer(IBufferMutable const& buffer) override;
86  void unregisterBuffer(IBufferMutable const& buffer) override;
87  Endpoint const& localEndpoint() const override { return local_endpoint_; }
88  std::shared_ptr<IBufferConst> get(uint32_t port, uint32_t idx) const override;
89  std::shared_ptr<IBufferConst> get(
90  Endpoint const& ep, uint32_t port, uint32_t idx) const override;
91  void dispose(std::shared_ptr<IBufferConst>&& buffer) override;
92  void listPorts(std::vector<EndpointPort>& ports) const override;
94  std::map<uint32_t, std::vector<std::pair<Endpoint, uint32_t>>>& mappings)
95  const override;
97  std::map<PortIdx, std::shared_ptr<IBufferConst>>& buffers) const override;
98  Endpoint resolveEndpoint(Endpoint const& endpoint) const override;
99 
100  private:
101  struct ExchangePacket {
103  uint64_t peer_session_id;
104  } __attribute__((packed));
105 
106  static size_t constexpr kMaxRecvBuffer = 8192;
107  static size_t constexpr kMaxPayload = sizeof(uint64_t);
108  static size_t constexpr kMaxMissedPollsBeforeEvict = 4;
109  static size_t constexpr kMaxBuffers =
110  (kMaxRecvBuffer - sizeof(ExchangePacket)) / sizeof(BufferInfo);
111  // Process-lifetime peer identity for protocol sessions.
112  // Not a UUID: generated randomly at startup and changes on restart.
113  using PeerSessionId = uint64_t;
114 
115  using Socket = boost::asio::local::datagram_protocol::socket;
116  using ShmemBufferMap = std::map<PortIdx, std::shared_ptr<IBufferConst>>;
117 
118  // State information about downstream peers that are requesting
119  // buffers from this exchange.
120  struct SentState {
121  // buffers that have been registered to share.
122  ShmemBufferMap buffers_to_share;
123 
124  // A list of all peers that we're interacting with.
125  std::vector<Endpoint> peer_endpoints;
126 
127  // Track the last seen peer session id for each polling endpoint.
128  std::map<Endpoint, PeerSessionId> peer_session_ids;
129 
130  // Track which buffers we've sent to each requesting peer endpoint.
131  std::map<Endpoint, std::unordered_set<PortIdx>> sent_buffers_per_peer;
132  };
133 
134  // State information and buffers that are received from other peer endpoints
135  // in response to this exchange's explicit polling.
136  struct ReceivedState {
137  Endpoint local_endpoint;
138  // Track the last seen peer session id for each polled endpoint.
139  // Includes this exchange's endpoint.
140  std::map<Endpoint, PeerSessionId> peer_session_ids;
141 
142  // A list of all peers that we're interacting with.
143  // Includes this exchange's endpoint.
144  std::set<Endpoint> peer_endpoints;
145 
146  // Buffers that have been shared by each peer that we're polling
147  // Note: this will also include buffers that are registered with the
148  // exchange.
149  std::map<Endpoint, ShmemBufferMap> buffers_per_peer;
150 
151  // Track consecutive failed polls for each peer endpoint. Used to evict
152  // stale buffers when a preferred peer dies so fallback peers can take over.
153  std::map<Endpoint, uint32_t> peer_missed_polls;
154 
155  // Resolution mappings:
156  // - local_port != 0: explicit local-port to peer-port mappings.
157  // - local_port == 0: wildcard fallback mappings for any local port.
158  std::map<uint32_t, std::vector<std::pair<Endpoint, uint32_t>>>
159  local_port_to_peer_ports;
160 
162  std::shared_ptr<IBufferConst> buffer;
163  uint64_t generation = 0;
164  };
165 
168  std::shared_ptr<IBufferConst> buffer;
169  bool cache_needs_update = false;
170  uint64_t generation = 0;
171  };
172 
173  // Cache of resolved buffers, invalidated by resolve_generation.
174  std::map<PortIdx, ResolvedCacheEntry> resolved_buffers;
175  // Monotonically increasing counter; bumped whenever the authoritative
176  // buffer state changes, which obsoletes the resolved_buffers cache.
177  uint64_t resolve_generation = 0;
178 
179  // Bump the generation counter, invalidating all resolved_buffers entries.
180  void bumpResolvedGeneration();
181 
182  // Resolve from a mapping bucket in local_port_to_peer_ports. When
183  // mapping_local_port == 0 and mapped peer_port == 0, peer port falls back
184  // to requested_local_port.
185  std::shared_ptr<IBufferConst> resolveFromPortMappings(
186  uint32_t mapping_local_port,
187  uint32_t requested_local_port,
188  uint32_t idx) const;
189 
190  // Walk explicit port mappings, then wildcard fallback mappings
191  // (local_port_to_peer_ports[0]), then finally local endpoint, returning
192  // the first matching buffer for (port, idx).
193  std::shared_ptr<IBufferConst> resolveEntry(PortIdx local_port_idx) const;
194 
195  // Shared-lock lookup for (port, idx). Returns resolved buffer and whether
196  // the caller should schedule a deferred cache update.
197  GetResolvedResult getResolved(uint32_t port, uint32_t idx) const;
198 
199  // Exclusive-lock cache write for deferred updates from getResolved().
200  void updateResolvedCache(GetResolvedResult const& resolved);
201 
202  std::shared_ptr<IBufferConst> get(
203  Endpoint const& ep, uint32_t port, uint32_t idx) const;
204  };
205 
206  template <typename TFunction>
207  auto accessReceivedState(TFunction&& cb) const {
208  return received_state_.access(std::forward<TFunction>(cb));
209  }
210  void run();
211  void registerBuffer(std::shared_ptr<IBufferConst> const& buffer);
212  void unregisterBuffer(std::shared_ptr<IBufferConst> const& buffer);
213  void unregisterBuffer(BufferInfo const& info);
214  void startReceive();
215  void startPeerPoll();
216  void handleReceive();
217  void sendSomeBuffers(Endpoint const& sender_ep);
218  void requestPeerBuffers(Endpoint const& ep);
219  bool sendPacketOnStrand(
220  Endpoint const& ep,
222  uint8_t const* payload = nullptr,
223  size_t payload_size = 0);
224  void sendExchangePacket(
225  Endpoint const& ep,
227  void const* payload = nullptr,
228  size_t payload_size = 0);
229 
230  void handleBufferRequest(
231  Endpoint const& sender_ep,
232  std::array<char, ShmemExchange::kMaxRecvBuffer> const& msgbuf);
233  void handleIncomingBuffers(
234  Endpoint const& sender_ep,
235  std::array<char, ShmemExchange::kMaxRecvBuffer> const& msgbuf,
236  const struct msghdr& msgh);
237  void handleBufferRemoved(
238  Endpoint const& sender_ep,
239  std::array<char, ShmemExchange::kMaxRecvBuffer> const& msgbuf);
240  void handlePeerDisconnect(
241  Endpoint const& sender_ep,
242  std::array<char, ShmemExchange::kMaxRecvBuffer> const& msgbuf);
243  void sendBufferRemoved(Endpoint const& ep, PortIdx port_idx);
244  void sendDisconnect();
245 
246  PeerSessionId peer_session_id_;
247  boost::asio::io_context ctx_;
248  boost::asio::io_context::strand strand_;
249  boost::asio::steady_timer peer_poll_timer_;
250  Endpoint local_endpoint_;
251  Socket socket_;
252  cpp::ThreadSafeValue<ReceivedState> received_state_;
254  std::atomic<bool> stop_requested_{false};
255 
256  std::thread run_thread_;
257 };
258 
259 } // namespace sol3::core
Interface for registering, discovering, and disposing shared buffers.
Definition: shmem_buffer.h:112
boost::asio::local::datagram_protocol::endpoint Endpoint
Definition: shmem_buffer.h:114
Mutable view of shared memory buffer.
Definition: shmem_buffer.h:90
Definition: shmem_exchange.h:54
void start() override
Start running in a background thread.
void unregisterBuffer(IBufferMutable const &buffer) override
Unregister a previously shared mutable buffer.
Endpoint const & localEndpoint() const override
Local endpoint used by this exchange.
Definition: shmem_exchange.h:87
ShmemExchange(msg::ExchangeConfigT exchange_config)
Create an exchange from an exchange configuration.
void listPorts(std::vector< EndpointPort > &ports) const override
List all ports this exchange has received from peers or shared locally.
void mapLocalToPeer(uint32_t local_port, Endpoint peer_endpoint, uint32_t peer_port=0) override
void listResolvedBuffers(std::map< PortIdx, std::shared_ptr< IBufferConst >> &buffers) const override
IBufferExchange::Endpoint Endpoint
Definition: shmem_exchange.h:56
ShmemExchange(ShmemExchange const &)=delete
bool stopped() const override
True if the exchange has been stopped.
void registerBuffer(IBufferMutable const &buffer) override
~ShmemExchange() override
Stops and releases socket/IO resources.
ShmemExchange & operator=(ShmemExchange &&)=delete
void stop() override
Request the event loop to stop.
ShmemExchange & operator=(ShmemExchange const &)=delete
ShmemExchange(ShmemExchange &&)=delete
std::shared_ptr< IBufferConst > get(uint32_t port, uint32_t idx) const override
ShmemExchange(Endpoint const &local_endpoint)
void addPeer(Endpoint peer_endpoint) override
void dispose(std::shared_ptr< IBufferConst > &&buffer) override
Release resources associated with a previously retrieved buffer.
std::shared_ptr< IBufferConst > get(Endpoint const &ep, uint32_t port, uint32_t idx) const override
void listMappings(std::map< uint32_t, std::vector< std::pair< Endpoint, uint32_t >>> &mappings) const override
Endpoint resolveEndpoint(Endpoint const &endpoint) const override
void configure(msg::ExchangeConfigT const &config) override
auto access(TFunction &&cb) const
Shared/read-only access; executes cb(TData const&) under a shared_lock.
Definition: thread_safe_value.h:34
enum ArtifactFormat string
Camera/host holding the original file.
Definition: any_message_input.h:15
msg::ExchangeConfigT loadExchangeConfigFromSol3Root(char const *app_name, cpp::fs::path const &sol3_root_path)
msg::ExchangeConfigT loadExchangeConfigFromPath(std::string const &config_path)
msg::ExchangeConfigT loadExchangeConfigFromEnv()
boost::asio::local::datagram_protocol::endpoint Endpoint
Definition: shmem_buffer.h:28
ExchangeCode
Definition: shmem_exchange.h:25
@ buffers_request
Definition: shmem_exchange.h:26
@ buffers_response
Definition: shmem_exchange.h:27
@ peer_disconnect
Definition: shmem_exchange.h:29
@ buffer_removed
Definition: shmem_exchange.h:28
ExchangeCode what
Definition: shmem_exchange.h:0
uint64_t peer_session_id
Definition: shmem_exchange.h:1
Definition: shmem_buffer.h:41
Definition: shmem_buffer.h:62
PortIdx port_idx
Definition: shmem_exchange.h:167
uint64_t generation
Definition: shmem_exchange.h:170
std::shared_ptr< IBufferConst > buffer
Definition: shmem_exchange.h:168
bool cache_needs_update
Definition: shmem_exchange.h:169
std::shared_ptr< IBufferConst > buffer
Definition: shmem_exchange.h:162
uint64_t generation
Definition: shmem_exchange.h:163