28#include <boost/move/make_unique.hpp>
43 flow::log::Log_context(config.m_logger_ptr,
Log_component::S_TRANSPORT),
45 m_seg_and_frame_sz_cap((config.m_seg_and_frame_sz_cap / sizeof(::
capnp::word)) * sizeof(::
capnp::word)),
48 (m_seg_and_frame_sz_cap,
49 config.m_frame_prefix_sz,
52 config.m_segment_sz_init,
55 FLOW_LOG_TRACE(
"Heap_fixed_builder [" << *
this <<
"]: Fixed-size builder started: "
70 FLOW_LOG_TRACE(
"Heap_fixed_builder [" << *
this <<
"]: Fixed-size builder being destroyed.");
95 FLOW_LOG_TRACE(
"Heap_fixed_builder [" << *
this <<
"]: Fixed-size builder being destroyed "
96 "(move-assigned-over).");
100 static_cast<flow::log::Log_context&
>(*this) = std::move(src);
110 assert(
m_engine &&
"Are you operating on a moved-from `*this`?");
122 if (flow::error::exec_void_and_throw_on_error
124 {
emit_serialization(target_blobs, hdr_blob, split_segs, session, actual_err_code); },
125 err_code,
"Heap_fixed_builder::emit_serialization()"))
131 assert(
m_engine &&
"Are you operating on a moved-from `*this`?");
138 target_blobs->clear();
145 m_engine->emit_segment_blobs(&blob_ptrs);
147 const auto n_blobs = blob_ptrs.size();
148 assert((n_blobs != 0) &&
"Empty serialization? What went wrong?");
149 auto n_blobs_with_subsegs = n_blobs;
150 target_blobs->reserve(n_blobs);
152 for (
size_t idx = 0; idx != n_blobs; ++idx)
154 auto& blob = *(blob_ptrs[idx]);
155 const auto buf = blob.mutable_buffer();
156 const auto seg_sz = buf.size();
165 hdr_sz_or_0 = blob.start();
166 *hdr_blob =
Blob_mutable{
static_cast<void*
>(blob.begin() - hdr_sz_or_0), hdr_sz_or_0};
173 FLOW_LOG_TRACE(
"Heap_fixed_builder [" << *
this <<
"]: "
174 "Serialization segment [" << idx <<
"] (0-based, of [" << n_blobs <<
"], 1-based): "
175 "Heap buffer @[" << buf.data() <<
"] sized [" << seg_sz <<
"]; "
176 "with header/prefix (if any) sized [" << hdr_sz_or_0 <<
"].");
178 target_blobs->emplace_back(buf);
181 if ((seg_sz + hdr_sz_or_0) > seg_and_hdr_sz_cap)
185 FLOW_LOG_WARNING(
"Heap_fixed_builder [" << *
this <<
"]: "
186 "Serialization segment [" << idx <<
"] (0-based, of [" << n_blobs <<
"], 1-based): "
187 "Heap buffer @[" << buf.data() <<
"] "
188 "sized [" << seg_sz <<
"] plus frame header [" << hdr_sz_or_0 <<
"]: exceeded limit "
189 "[" << seg_and_hdr_sz_cap <<
"]. Seg-split not requested (why not? bug?) so: "
190 "Emitting error; will not return serialization.");
207 auto last_subseg_ptr =
static_cast<uint8_t*
>(buf.data());
208 auto last_subseg_sz =
static_cast<size_t>(seg_and_hdr_sz_cap - hdr_sz_or_0);
209 target_blobs->back() =
Blob_const{last_subseg_ptr, last_subseg_sz};
210 const size_t seg_minus_subseg1_sz = seg_sz - last_subseg_sz;
214 size_t n_full_cont_subsegs = seg_minus_subseg1_sz / seg_and_hdr_sz_cap;
215 size_t n_cont_subsegs = n_full_cont_subsegs;
218 const size_t partial_cont_subseg_sz_or_0 = seg_minus_subseg1_sz % seg_and_hdr_sz_cap;
219 (partial_cont_subseg_sz_or_0 != 0) && (++n_cont_subsegs);
222 target_blobs->reserve(n_blobs_with_subsegs += n_cont_subsegs);
226 for (; n_full_cont_subsegs != 0; --n_full_cont_subsegs)
228 last_subseg_ptr += last_subseg_sz;
229 last_subseg_sz = seg_and_hdr_sz_cap;
230 target_blobs->emplace_back(last_subseg_ptr, last_subseg_sz);
233 if (partial_cont_subseg_sz_or_0 != 0)
235 last_subseg_ptr += last_subseg_sz;
236 target_blobs->emplace_back(last_subseg_ptr, partial_cont_subseg_sz_or_0);
239 split_segs->emplace_back(
Split_segment{ target_blobs->size() - n_cont_subsegs - 1,
241 FLOW_LOG_TRACE(
"Heap_fixed_builder [" << *
this <<
"]: "
242 "Serialization segment [" << idx <<
"] (0-based, of [" << n_blobs <<
"], 1-based): "
243 "Heap buffer @[" << buf.data() <<
"] "
244 "sized [" << seg_sz <<
"] plus frame header [" << hdr_sz_or_0 <<
"]: exceeded limit "
245 "[" << seg_and_hdr_sz_cap <<
"]. Seg-split requested; therefore split into "
246 "[" << (n_cont_subsegs + 1) <<
"] sub-segments sized "
247 "init[" << (seg_and_hdr_sz_cap - hdr_sz_or_0) <<
"], N x full[" << seg_and_hdr_sz_cap <<
"], "
248 "partial[" << partial_cont_subseg_sz_or_0 <<
"].");
258 assert(
m_engine &&
"Are you operating on a moved-from `*this`?");
265 return os <<
'@' << &val;
271 flow::log::Log_context(config.m_logger_ptr,
Log_component::S_TRANSPORT),
272 m_stats(config.m_stats),
276 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: Heap reader started: "
283 using flow::util::stat::fetch_sub;
287 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: Reader being destroyed including: "
289 << (
m_engine ?
"no stats kept." :
"no deserialization yet attempted."));
297 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: Reader being destroyed including: "
299 "last deserialization reports [" << (
m_engine->sizeInWords() *
sizeof(::capnp::word)) <<
"] "
300 "input heap space total.");
305 const auto prev_msgs_outstanding =
308 assert((prev_msgs_outstanding >= 1)
309 &&
"Bug: rcv-stats msgs_outstanding gauge underflow at Heap_reader dtor.");
312 const auto prev_alloc_outstanding_sz =
315 assert((prev_alloc_outstanding_sz >=
m_alloc_sz)
316 &&
"Bug: rcv-stats alloc-bytes_outstanding gauge underflow at Heap_reader dtor.");
319 const auto prev_used_outstanding_sz =
322 assert((prev_used_outstanding_sz >=
m_used_sz)
323 &&
"Bug: rcv-stats used-bytes_outstanding gauge underflow at Heap_reader dtor.");
328 using flow::util::Blob;
329 using Ptr =
const void*;
331 static_assert(std::is_nothrow_move_constructible_v<Segment_blob_in>,
332 "Segment_blob_in (as of this writing Basic_blob) move-ct must be noexcept for vector to move them "
333 "instead of copying on realloc; this is critical not just for performance, but because callers "
334 "may routinely rely on a given segment not moving in memory across add_serialization_segment()s.");
336 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: "
338 "Heap buffer @[" <<
static_cast<Ptr
>(blob.const_data()) <<
"] "
339 "max-sized [" << blob.capacity() <<
"], "
340 "actual serialization sized [" << blob.size() <<
"].");
345 Ptr seg1_ptr =
nullptr;
352 &&
"Bug: vector realloc moved a segment blob's buffer, presumably via unintended Basic_blob copy; "
353 "make sure Basic_blob/Segment_blob_in is coded properly for by-value storage in containers.");
358 return os <<
'@' << &val;
368 return os << val.cStr();
A capnp::MessageBuilder used by Heap_fixed_builder: similar to a capnp::MallocMessageBuilder (albeit ...
~Simplest possible impl of Struct_builder concept that represents the capnp payload directly in heap ...
Capnp_msg_builder_interface * payload_msg_builder()
Implements concept API.
size_t m_seg_and_frame_sz_cap
See ctor.
size_t n_serialization_segments() const
Implements concept API.
Heap_fixed_builder()
Implements concept API.
boost::movelib::unique_ptr< Capnp_heap_engine > m_engine
The capnp builder engine which really does the work including owning the needed allocated segments so...
~Heap_fixed_builder()
Implements concept API. In this impl: frees all segments allocated on-demand so far.
void emit_serialization(Segment_bufs *target_blobs, util::Blob_mutable *hdr_blob, Split_segments *split_segs, const Session &session, Error_code *err_code=nullptr) const
Implements concept API.
Heap_fixed_builder & operator=(const Heap_fixed_builder &)=delete
Disallow copy assignment.
Implements Struct_reader concept by straightforwardly interpreting a serialization by Heap_fixed_buil...
Heap_reader(const Config &config)
Implements concept API.
uint64_t m_alloc_sz
Cache: sum of m_serialization_segments[].capacity() (post-reassembly-if-needed inside deserialization...
uint64_t m_used_sz
Cache: analogously to m_alloc_sz: sum of m_serialization_segments[].size().
~Heap_reader()
Implements concept API. In this impl: frees all segments allocated via add_serialization_segment() so...
stat::Serializer_stats::Rcv *const m_stats
See Config::m_stats: cumulative stat::Serializer_stats::Rcv pointee *this shall update; null OK (no s...
std::vector< Segment_blob_in > m_serialization_segments
Before deserialization(): the serialization payloads supplied so far, as divided up into (sub-)segmen...
Capnp_heap_engine_ptr m_engine
The capnp reader engine, as set in the deserialization() call and corresponding to the Struct::Reader...
void add_serialization_segment(Segment_blob_in &&blob)
Implements concept API.
Small group of miscellaneous utilities to ease work with capnp (Cap'n Proto), joining its capnp names...
@ S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG
Structured message serialization (e.g., when sending over channel): A user-mutated datum (list/blob/s...
Reader< ipc::shm::classic::Pool_arena > Reader
Convenience alias: transport::struc::shm::Reader that works with boost.ipc.shm pools from ipc::shm::c...
Sub-module of Flow-IPC module ipc::transport providing transmission of structured messages specifical...
std::vector< Split_segment > Split_segments
A simple data structure describing the segments (if any) in a Segment_bufs (or similar) structure whi...
std::vector< flow::util::Blob_sans_log_context * > Segment_ptrs
Sequence of 1+ segment descriptions, each representing a live writable segment (of a capnp serializat...
const Null_session NULL_SESSION
The only necessary value of empty-type Null_session.
std::ostream & operator<<(std::ostream &os, const Heap_fixed_builder &val)
Prints string representation of the given Heap_fixed_builder to the given ostream.
flow::util::Blob_sans_log_context Segment_blob_in
Short-hand for a high-performance blob structure that represents an IPC-incoming (sub-)segment 1+ of ...
std::vector< util::Blob_const > Segment_bufs
Simpler cousin of Segment_ptrs, this represents the IPC-transmissible representation of a capnp seria...
std::ostream & operator<<(std::ostream &os, const Generic_msg_batch_in< Msg_resource_t, NO_HNDLS > &val)
Prints string representation of the given Generic_msg_batch_in to the given ostream.
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Implements Struct_builder::Config sub-concept.
size_t m_segment_sz_init
Seg 1 size; a value exceeding m_seg_and_frame_sz_cap - m_frame_prefix_sz is clamped to that.
size_t m_frame_prefix_sz
Size of header to precede seg 1 in the first buffer allocated by the Heap_fixed_builder.
Implements Struct_reader::Config sub-concept.
size_t m_n_segments_est
Best guess for how many times you expect to call add_serialization_segment(); or 0 if you have no gue...
Value for Struct_builder::Session when no extra information is needed when serializing Struct_builder...
Simple structure describing how a pre-split single segment was turned into 2+ post-split component su...
std::atomic< size_t > m_used_outstanding_sz
Gauge: Subset of m_alloc_outstanding_sz that contains actual capnp-serialization payload.
std::atomic< size_t > m_msgs_outstanding
Gauge: Currently-alive Struct_reader (usually <=> Msg_in) instances.
std::atomic< size_t > m_alloc_outstanding_sz
Gauge: Of bytes tracked by m_alloc_lifetime_sz, how many are currently allocated as opposed to now-fr...