Flow-IPC 1.0.0
Flow-IPC project: Full implementation reference.
heap_serializer.cpp
Go to the documentation of this file.
1/* Flow-IPC: Structured Transport
2 * Copyright (c) 2023 Akamai Technologies, Inc.; and other contributors.
3 * Each commit is copyright by its respective author or author's employer.
4 *
5 * Licensed under the MIT License:
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE. */
24
25/// @file
26
28#include <boost/move/make_unique.hpp>
29
31{
32
33// Static initializers.
34
36
37// Heap_fixed_builder implementations.
38
40
42 flow::log::Log_context(config.m_logger_ptr, Log_component::S_TRANSPORT),
43
44 m_segment_sz(config.m_segment_sz),
45 // The builder engine launched here. In the future mutators will cause it to allocate in heap on-demand.
46 m_engine(boost::movelib::make_unique<Capnp_heap_engine>
47 (get_logger(),
48 config.m_segment_sz, config.m_frame_prefix_sz, config.m_frame_postfix_sz))
49{
50 FLOW_LOG_TRACE("Heap_fixed_builder [" << *this << "]: Fixed-size builder started: "
51 "segment size limit [" << m_segment_sz << "].");
52 assert(m_segment_sz != 0);
53}
54
56
58{
59 FLOW_LOG_TRACE("Heap_fixed_builder [" << *this << "]: Fixed-size builder being destroyed.");
60 // @todo Maybe have Heap_fixed_builder_capnp_message_builder log something useful in its dtor?
61}
62
64
66{
67 assert(m_engine && "Are you operating on a moved-from `*this`?");
68
69 return m_engine.get();
70}
71
72void Heap_fixed_builder::emit_serialization(Segment_ptrs* target_blobs, [[maybe_unused]] const Session& session,
73 Error_code* err_code) const
74{
75 using util::Blob_const;
76
77 if (flow::error::exec_void_and_throw_on_error
78 ([&](Error_code* actual_err_code) { emit_serialization(target_blobs, session, actual_err_code); },
79 err_code, "Heap_fixed_builder::emit_serialization()"))
80 {
81 return;
82 }
83 // If got here: err_code is not null.
84
85 assert(m_engine && "Are you operating on a moved-from `*this`?");
86
87 /* Reminder: concept API says emit_serialization() can be called >1 times. We do allow that in the below.
88 * Keep in mind that mutations can be executed in-between, so whatever caching for perf one imagines has
89 * to not mess up in the face of that. */
90
91 Segment_ptrs& blob_ptrs = *target_blobs;
92
93 size_t n_blobs = blob_ptrs.size();
94 m_engine->emit_segment_blobs(&blob_ptrs); // It appends, like we must. Just be careful in remembering that below.
95 n_blobs = blob_ptrs.size() - n_blobs;
96 assert((n_blobs > 0) && "Empty serialization? What went wrong?");
97
98 for (size_t abs_idx = blob_ptrs.size() - n_blobs, idx = 0;
99 idx != n_blobs;
100 ++abs_idx, ++idx)
101 {
102 const auto blob = blob_ptrs[abs_idx];
103 const auto seg_size = blob->size();
104
105 FLOW_LOG_TRACE("Heap_fixed_builder [" << *this << "]: "
106 "Serialization segment [" << idx << "] (0 based, of [" << n_blobs << "], 1-based): "
107 "Heap buffer @[" << static_cast<const void*>(blob->begin()) << "] sized [" << seg_size << "].");
108
109 // Check for the one error condition: a too-large segment.
110 if (seg_size > m_segment_sz)
111 {
112 FLOW_LOG_WARNING("Heap_fixed_builder [" << *this << "]: "
113 "Serialization segment [" << idx << "] (0 based, of [" << n_blobs << "], 1-based): "
114 "Heap buffer @[" << static_cast<const void*>(blob->begin()) << "] "
115 "sized [" << seg_size << "]: exceeded limit "
116 "[" << m_segment_sz << "]. Emitting error; will not return serialization.");
118 return;
119 }
120 // else
121 } // for (blob : blob_ptrs, starting from first appended one)
122 // Got here: no error. Done and done.
123} // Heap_fixed_builder::emit_serialization()
124
126{
127 assert(m_engine && "Are you operating on a moved-from `*this`?");
128
129 return m_engine->n_segments();
130}
131
132std::ostream& operator<<(std::ostream& os, const Heap_fixed_builder& val)
133{
134 return os << '@' << &val;
135}
136
137// Heap_reader implementations.
138
140 flow::log::Log_context(config.m_logger_ptr, Log_component::S_TRANSPORT)
141{
142 FLOW_LOG_TRACE("Heap_reader [" << *this << "]: Heap reader started: "
143 "expecting [" << config.m_n_segments_est << "] segments (0 if unknown).");
145}
146
148{
149 if (!m_engine)
150 {
151 FLOW_LOG_TRACE("Heap_reader [" << *this << "]: Reader being destroyed including: "
152 "serialization containing [" << m_serialization_segments.size() << "] segments; "
153 "no deserialization yet attempted.");
154 }
155 else
156 {
157 // This *might* be perf-pricey, to some extent, so definitely be careful with the log level.
158 FLOW_LOG_TRACE("Heap_reader [" << *this << "]: Reader being destroyed including: "
159 "serialization containing [" << m_serialization_segments.size() << "] segments; "
160 "last deserialization reports [" << (m_engine->sizeInWords() * sizeof(::capnp::word)) << "] "
161 "input heap space total.");
162 }
163}
164
165flow::util::Blob* Heap_reader::add_serialization_segment(size_t max_sz)
166{
167 using flow::util::Blob;
168
169 const auto blob = new Blob(get_logger(), max_sz);
170 m_serialization_segments.emplace_back(blob);
171
172 FLOW_LOG_TRACE("Heap_reader [" << *this << "]: "
173 "Serialization segment [" << (m_serialization_segments.size() - 1) << "] (0-based) added/owned: "
174 "Heap buffer @[" << static_cast<const void*>(m_serialization_segments.back()->const_data()) << "] "
175 "max-sized [" << max_sz << "].");
176
177 return blob;
178}
179
180std::ostream& operator<<(std::ostream& os, const Heap_reader& val)
181{
182 return os << '@' << &val;
183}
184
185} // namespace ipc::transport::struc
186
187namespace capnp
188{
189
190std::ostream& operator<<(std::ostream& os, const Text::Reader& val)
191{
192 return os << val.cStr();
193}
194
195} // namespace capnp
A capnp::MessageBuilder used by Heap_fixed_builder: similar to a capnp::MallocMessageBuilder with the...
Implements Struct_builder concept by straightforwardly allocating fixed-size segments on-demand in th...
Capnp_msg_builder_interface * payload_msg_builder()
Implements concept API.
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...
void emit_serialization(Segment_ptrs *target_blobs, const Session &session, Error_code *err_code=0) const
Implements concept API.
~Heap_fixed_builder()
Implements concept API.
Heap_fixed_builder & operator=(const Heap_fixed_builder &)=delete
Disallow copy assignment.
size_t m_segment_sz
See ctor. We only store it to be able to emit S_INTERNAL_ERROR_SERIALIZE_LEAF_TOO_BIG in emit_seriali...
Implements Struct_reader concept by straightforwardly interpreting a serialization by Heap_fixed_buil...
Heap_reader(const Config &config)
Implements concept API.
std::vector< boost::movelib::unique_ptr< flow::util::Blob > > m_serialization_segments
The actual serialization supplied so far, as divided up into segments (Blobs – byte arrays).
~Heap_reader()
Implements concept API.
flow::util::Blob * add_serialization_segment(size_t max_sz)
Implements concept API.
Capnp_heap_engine_ptr m_engine
The capnp reader engine, as set in the deserialization() call and corresponding to the Struct::Reader...
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 (e....
Reader< ipc::shm::classic::Pool_arena > Reader
Convenience alias: transport::struc::shm::Reader that works with boost.ipc.shm pools from ipc::shm::c...
Definition: classic_fwd.hpp:39
Sub-module of Flow-IPC module ipc::transport providing transmission of structured messages specifical...
Definition: channel.cpp:31
std::vector< flow::util::Blob * > Segment_ptrs
Sequence of 1+ Blob pointers to blobs which must stay alive while these pointers may be dereferenced,...
Definition: struc_fwd.hpp:122
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.
std::ostream & operator<<(std::ostream &os, const Bipc_mq_handle &val)
Prints string representation of the given Bipc_mq_handle to the given ostream.
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.
Definition: util_fwd.hpp:128
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
Definition: common.hpp:322
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:297
Implements Struct_builder::Config sub-concept.
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...