32#include <flow/error/error.hpp>
33#include <boost/move/make_unique.hpp>
104 public flow::log::Log_context
303 boost::movelib::unique_ptr<Capnp_heap_engine>
m_engine;
319 public flow::log::Log_context,
320 private boost::noncopyable
392 template<
typename Struct>
482template<
typename Channel_obj,
typename Msg_body_t>
484 =
Channel<Channel_obj, Msg_body_t,
491template<
typename Struct>
494 using flow::error::Runtime_error;
495 using flow::util::buffers_dump_string;
496 using flow::util::stat::fetch_add;
497 using flow::util::stat::update_hi_wmark;
498 using boost::movelib::make_unique;
502 using Capnp_word_array_array_ptr = kj::ArrayPtr<const Capnp_word_array_ptr>;
503 using Capnp_heap_engine_opts = ::capnp::ReaderOptions;
505 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
typename Struct::Reader, deserialization<Struct>, split_segs_or_null, _1);
509 constexpr Capnp_heap_engine_opts RDR_OPTIONS = { std::numeric_limits<uint64_t>::max() /
sizeof(word),
510 Capnp_heap_engine_opts{}.nestingLimit };
519 assert((!
m_engine) &&
"Do not call deserialization() more than once.");
521 if (split_segs_or_null)
523 const auto& split_segs = *split_segs_or_null;
524 if (split_segs.empty())
526 FLOW_LOG_WARNING(
"Heap_reader [" << *
this <<
"]: "
527 "Split-segment records sequence is supplied but empty, against internal protocol; "
528 "it should have not been supplied (null).");
558 const auto split_segs_it_rend = split_segs.rend();
559 for (
auto split_segs_it = split_segs.rbegin();
560 split_segs_it != split_segs_it_rend;
563 const auto& split_seg = *split_segs_it;
564 const size_t start_idx = split_seg.m_start_idx;
565 const size_t n_cont_subsegs = split_seg.m_n_cont_subsegs;
576 FLOW_LOG_WARNING(
"Heap_reader [" << *
this <<
"]: "
577 "Split-segment record (start-index [" << start_idx <<
"] "
578 "(0-based, of [" << split_segs.size() <<
"], 1-based), "
579 "# continuation sub-segs [" << n_cont_subsegs <<
"]): "
580 "The latter value must be 1+ and not exceed (+ start_idx) # of input buffers "
587 const size_t end_idx = start_idx + n_cont_subsegs + 1;
590 size_t cont_total_sz = 0;
591 for (
size_t idx = start_idx + 1; idx != end_idx; ++idx)
597 const bool first_seg = start_idx == 0;
599 const auto unused_cap =
static_cast<size_t>(subseg1.capacity() - subseg1.size() - subseg1.start());
600 if (unused_cap >= cont_total_sz)
603 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: "
604 "Split-segment record (start-index [" << start_idx <<
"] "
605 "(0-based, of [" << split_segs.size() <<
"], 1-based), "
606 "# continuation sub-segs [" << n_cont_subsegs <<
"]): "
607 "All [" << cont_total_sz <<
"] bytes across continuation sub-segs can fit into "
608 "unused capacity [" << unused_cap <<
"] of start-index-th sub-seg; copying their contents there "
609 "accordingly and deleting them.");
611 auto dest_it = subseg1.end();
612 subseg1.resize(subseg1.size() + cont_total_sz);
615 for (
auto cont_subseg_it = cont_subseg_begin_it;
616 cont_subseg_it != cont_subseg_end_it;
617 (dest_it += cont_subseg_it->size()), ++cont_subseg_it)
619 subseg1.emplace_copy(dest_it, cont_subseg_it->const_buffer());
621 assert(dest_it == subseg1.end());
649 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: "
650 "Split-segment record (start-index [" << start_idx <<
"] "
651 "(0-based, of [" << split_segs.size() <<
"], 1-based), "
652 "# continuation sub-segs [" << n_cont_subsegs <<
"]): "
653 "All [" << cont_total_sz <<
"] bytes across continuation sub-segs cannot fit into "
654 "unused capacity [" << unused_cap <<
"] of start-index-th sub-seg; "
655 "therefore creating new segment-blob of size [" <<
m_seg1_hdr_backup.size() <<
"], "
656 "copying sub-segs' contents there, and replacing sub-segments with the resulting blob. "
657 "Start-index-th sub-seg shall be saved elsewhere so as to keep frame-header alive? = "
658 "[" << first_seg <<
"].");
662 for (
auto subseg_it = subseg_begin_it;
663 subseg_it != subseg_end_it;
664 (dest_it += subseg_it->size()), ++subseg_it)
685 assert(capnp_segs.empty() &&
"m_capnp_segments should have been empty so far, pre-deserialization().");
691 const auto data_ptr = serialization_segment.const_data();
692 const auto seg_sz = serialization_segment.size();
694 if (((
reinterpret_cast<uintptr_t
>(data_ptr) %
sizeof(word)) != 0) || ((seg_sz %
sizeof(word)) != 0))
696 FLOW_LOG_WARNING(
"Heap_reader [" << *
this <<
"]: "
697 "Serialization segment [" << idx <<
"] "
699 "Heap buffer @[" <<
static_cast<const void*
>(data_ptr) <<
"] sized [" << seg_sz <<
"]: "
700 "Starting pointer is not capnp-word-aligned, and/or size is not a capnp-word-multiple. "
701 "Bug? Misuse of Heap_reader? "
702 "Either is against the API use requirements; capnp would complain and fail.");
708 FLOW_LOG_TRACE(
"Heap_reader [" << *
this <<
"]: "
709 "Serialization segment [" << idx <<
"] "
711 "Heap buffer @[" <<
static_cast<const void*
>(data_ptr) <<
"] sized [" << seg_sz <<
"]: "
712 "Feeding into capnp deserialization engine.");
713 FLOW_LOG_DATA(
"Segment contents: "
714 "[\n" << buffers_dump_string(serialization_segment.const_buffer(),
" ") <<
"].");
716 capnp_segs.emplace_back(
reinterpret_cast<const word*
>(data_ptr),
720 seg_sz /
sizeof(word));
724 m_alloc_sz += serialization_segment.capacity();
734 const Capnp_word_array_array_ptr capnp_segs_ptr{&(capnp_segs.front()), capnp_segs.size()};
735 m_engine = make_unique<Capnp_heap_engine>(capnp_segs_ptr, RDR_OPTIONS);
Owning and wrapping a pre-connected transport::Channel peer (an endpoint of an established channel ov...
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(const Heap_fixed_builder &)=delete
Disallow copy construction.
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.
Heap_fixed_builder(Heap_fixed_builder &&src)
Implements concept API.
Implements Struct_reader concept by straightforwardly interpreting a serialization by Heap_fixed_buil...
Heap_reader(const Config &config)
Implements concept API.
Struct::Reader deserialization(const Split_segments *split_segs_or_null, Error_code *err_code=nullptr)
Implements concept API.
uint64_t m_alloc_sz
Cache: sum of m_serialization_segments[].capacity() (post-reassembly-if-needed inside deserialization...
boost::movelib::unique_ptr< Capnp_heap_engine > Capnp_heap_engine_ptr
Alias to pointer to Capnp_heap_engine.
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...
::capnp::SegmentArrayMessageReader Capnp_heap_engine
Alias for the capnp SegmentArrayMessageReader deserialization engine.
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...
Segment_blob_in m_seg1_hdr_backup
Null/meaningless until deserialization() returns; once it does: if needed by the re-joining procedure...
void add_serialization_segment(Segment_blob_in &&blob)
Implements concept API.
std::vector< Capnp_word_array_ptr > m_capnp_segments
After deserialization(), capnp-targeted data structure which is essentially vector<> of each Blob::co...
kj::ArrayPtr< const ::capnp::word > Capnp_word_array_ptr
Alias to capnp type that's similar to util::Blob_const but stores word* and word count instead of uin...
@ S_DESERIALIZE_FAILED_INSUFFICIENT_SEGMENTS
Structured message deserialization: Tried to deserialize without enough input segments (e....
@ S_DESERIALIZE_FAILED_REASSEMBLY_FAILED
Structured message deserialization: Cannot reassemble large capnp-segment; internal protocol error.
@ S_DESERIALIZE_FAILED_SEGMENT_MISALIGNED
Structured message deserialization: An input segment is not aligned as required.
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...
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...
void swap(Bipc_mq_handle &val1, Bipc_mq_handle &val2)
Implements Persistent_mq_handle related concept: Swaps two objects.
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Implements Struct_builder::Config sub-concept.
size_t m_seg_and_frame_sz_cap
Cap for how large a buffer size to choose for any header+segment buffer.
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.
flow::log::Logger * m_logger_ptr
Logger to use for logging subsequently.
size_t m_frame_prefix_sz
Size of header to precede seg 1 in the first buffer allocated by the Heap_fixed_builder.
stat::Serializer_stats::Snd * m_stats
See Struct_builder::Config concept.
Implements Struct_reader::Config sub-concept.
stat::Serializer_stats::Rcv * m_stats
See Struct_reader::Config concept.
flow::log::Logger * m_logger_ptr
Logger to use for logging subsequently.
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...
size_t m_start_idx
The index into a fully-post-split Segment_bufs (or similar) containing the first component of the spl...
size_t m_n_cont_subsegs
How many elements immediately following the one at m_start_idx (but not including it!...
Receive-side (during-deserialization) stats, captured at hooks within the Struct_reader impl.
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_alloc_outstanding_sz_hi_wmark
High water-mark of m_alloc_outstanding_sz observed so far.
std::atomic< size_t > m_msgs_outstanding_hi_wmark
High water-mark of m_msgs_outstanding observed so far.
std::atomic< size_t > m_msgs_outstanding
Gauge: Currently-alive Struct_reader (usually <=> Msg_in) instances.
std::atomic< uint64_t > m_alloc_lifetime_sz
Lifetime sum of segment-blob capacity across all Struct_reader (usually <=> Msg_in) instances ever.
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...
std::atomic< size_t > m_used_outstanding_sz_hi_wmark
High water-mark of m_used_outstanding_sz observed so far.
flow::util::stat::Histogram_counter m_histo_msg_alloc_sz
Histogram tracking per-Struct_reader (usually <=> Msg_in) contribution to m_alloc_lifetime_sz.
flow::util::stat::Histogram_counter m_histo_msg_used_sz
Subset of bytes tracked in m_histo_msg_alloc_sz that contains actual capnp-serialization payload.
Send-side (during-serialization) stats, captured at hooks within the Struct_builder impl: typically e...