Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
blob_stream_mq_snd.hpp
Go to the documentation of this file.
1/* Flow-IPC: Core
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
22#include <boost/move/make_unique.hpp>
23#include <experimental/propagate_const>
24#include <ostream>
25#include <string>
26#include <utility>
27
28namespace ipc::transport
29{
30
31// Types.
32
33/**
34 * Implements Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message queue)
35 * of that type, such as a POSIX or bipc MQ. This allows for high-performance, potentially zero-copy (except
36 * for copying into the transport MQ) of discrete messages, each containing a binary blob.
37 * This is a low-level (core) transport mechanism; higher-level (structured)
38 * transport mechanisms may use Blob_stream_mq_sender (and Blob_stream_mq_receiver) to enable their work.
39 *
40 * ### Informal comparison to other core transport mechanisms ###
41 * It is intended for transmission of relatively short messages -- rough guidance
42 * being for max length being in the 10s-of-KiB range. With a modern Linux kernel on server hardware from about 2014
43 * to 2020, our performance tests show that its raw speed for messages of aforementioned size is comparable to
44 * non-zero-copy mechanism based on Unix domain sockets. Technically we found `Blob_stream_mq_*<Posix_mq_handle>`
45 * to be somewhat faster; and `Blob_stream_*<Bipc_mq_handle>` (internally, SHM-based) somewhat slower.
46 * However, for best perf, it is recommended to send handles to SHM areas containing arbitrarily long structured
47 * messages (such as ones [de]serialized using zero-copy builders: capnp and the like).
48 * This further reduces the importance of relative perf compared to
49 * other low-level transports (which, as noted, is pretty close regardless -- though this is bound to stop being true
50 * for much longer messages, if the send-SHM-handles technique were to *not* be used).
51 *
52 * @see Native_socket_stream which also implements Blob_sender (and Blob_receiver) in its degraded mode (where
53 * one does not transmit native handles, only blobs).
54 *
55 * ### Relationship between `Blob_stream_mq_*`, the underlying MQ resource, and its Shared_name ###
56 * If one is familiar with MQs (doesn't matter whether POSIX or bipc -- their persistence semantics are identical),
57 * it is easy to become confused as to what `Blob_stream_mq_*` is modeling. To explain it then:
58 *
59 * - Think of the MQ itself as a file -- albeit in RAM -- a bulky thing that can store a certain number of bytes.
60 * - Think of its Shared_name as a directory entry, essentially a file name in a certain directory in the file system.
61 * - Think of a Persistent_mq_handle (the actual type being a template param; namely as of this writing
62 * Posix_mq_handle or Bipc_mq_handle) as a file handle. They can be opened for reading, writing, or both.
63 * More than 1 can be opened simultaneously.
64 * - Writing through this handle *pushes* a message but really writes those bytes somewhere in the "file" (MQ)
65 * in RAM. Any handle can be used for this; one can write through handle X and then right after that read through
66 * same handle X if desired.
67 * - Reading, similarly, *pops* a message by reading bytes from the "file."
68 * - One can open handle X, close handle X, wait 5 minutes, and from even another process open handle Y
69 * to the same name: the "stuff" (un-popped messages) will still be there.
70 *
71 * So that's MQs. However, `Blob_stream_mq_*` -- implementing Blob_sender and Blob_receiver as they do -- emphatically
72 * does *not* model that kind of free-for-all access (read/write, through 3+ handles if desired). Instead it models
73 * a *one-direction pipe*. So: there is up to 1 (exactly 1, if you want it to be useful) Blob_stream_mq_sender
74 * per Shared_name. It *only* writes (pushes). There is up to 1 (exactly 1, if...) Blob_stream_mq_receiver
75 * per Shared_name. It *only* reads (pops). Therefore trying to create a 2nd `_sender`, when 1 already exists --
76 * in *any* process -- is an error and does not work (an error is emitted from ctor; see its doc header).
77 * Same thing for `_receiver`.
78 *
79 * Moreover it is not a persistent pipe, either, even though the underlying MQ is quite capable of persistence
80 * (until reboot at any rate). Per Blob_sender/Blob_receiver concept, when a destructor for *either*
81 * the 1 Blob_stream_mq_sender *or* the 1 Blob_stream_mq_receiver is called (whichever happens first):
82 * - The Shared_name "directory entry" is deleted. The MQ becomes anonymous: creating an MQ with the same name
83 * will begin working -- and will create a totally new MQ.
84 * - (Caveat/corner case: In practice this is only useful after *both* destructors have run.
85 * Indeed MQ creation is possible after 1, but not the other, has executed; but then that "the other" will
86 * sadly delete the new, same-named MQ. So don't.)
87 * - The MQ handle is closed.
88 *
89 * Then once the other peer object (whether receiver or sender) dtor also executes:
90 * - (There is no "directory entry" to delete any longer.)
91 * - The MQ handle is closed.
92 *
93 * That last step brings the ref-count of things referring to the underlying MQ "file" (in RAM) to 0. Hence
94 * the MQ "file" (in RAM) is deleted (RAM is freed, becoming usable by other stuff, like maybe the general heap).
95 *
96 * That is how the Blob_sender/Blob_receiver one-direction pipe concept is satisfied, even though a general MQ
97 * has greater capabilities. That's not to say one should not use those; just not what this class is for;
98 * but one can use Posix_mq_handle/Bipc_mq_handle directly if necessary.
99 *
100 * ### Cleanup ###
101 * As just described, the two `Blob_stream_mq_*` classes are fairly aggressive about deleting the underlying MQ
102 * RAM resource. It is, generally, important not to leave those lying around post-use, as they can take non-trivial
103 * RAM.
104 *
105 * However, MQs (being kernel-persistent at least) require an even greater amount of care in cleanup than that.
106 * Assuming buglessness of the classes themselves and a graceful shutdown of the program -- including on clean
107 * exception handling, wherein the stack fully unwinds, and the destructors all run -- there is no problem.
108 *
109 * However, if something (a hard crash perhaps) prevents a Blob_stream_mq_sender or Blob_stream_mq_receiver dtor
110 * from running, the MQ "file" (in RAM) shall leak. It is your responsibility to implement a contingency for such
111 * leaks. (Note that, beyond RAM, there are limits on the number of MQs -- and certain other internally used
112 * kernel-persistent objects -- that exist system-wide. If reached -- which is not hard -- then things will
113 * screech to a halt, until something cleans up the leaks.) We provide 2 techniques to aid this.
114 *
115 * - You can maintain a *persistent* registry of created MQ streams. In that case you'll have a list of
116 * `mq.absolute_name()`s (where `mq` is passed to our and the receiver peer's ctors). After any potential
117 * abort, in another instance (process) of the application, invoke Blob_stream_mq_base::remove_persistent()
118 * on each such name.
119 * - To avoid the persistent registry, a much easier, though less surgical/definitive, technique is to maintain
120 * a prefix-based naming convention for `mq.absolute_name()`. Then: After any potential abort, in another
121 * instance (process) of the application, invoke remove_each_persistent_with_name_prefix<Blob_stream_mq_base>(),
122 * passing in the applicable Shared_name prefix. Having done so, the leaks (if any) should be cleaned.
123 *
124 * ipc::session uses the 2nd technique.
125 *
126 * ### Reusing the same absolute_name() for a new MQ and one-direction pipe ###
127 * Formally, as pointed out in various docs, this is possible no later than the return of the later of the
128 * Blob_stream_mq_sender and Blob_stream_mq_receiver dtors. Informally, we recommend against this if it can be avoided.
129 * Sure, it's fine if you can guarantee no process -- even *another* process -- would try to do so until
130 * in fact both of those dtors has run. This may not be trivial; it might even require more IPC to coordinate!
131 * It is better to segregate these things via unique names, using a namespace from something like a PID which
132 * will not, within reason, repeat before reboot. ipc::session uses this technique for various kernel-persistent
133 * resources including (not limited to) these MQs.
134 *
135 * ### Thread safety ###
136 * We add no more thread safety guarantees than those mandated by Blob_sender concept.
137 *
138 * @internal
139 * ### Implementation design/rationale ###
140 * Internally this class template uses the pImpl idiom (see https://en.cppreference.com/w/cpp/language/pimpl
141 * for an excellent overview), except it is what I (ygoldfel) term "pImpl-lite". That is: it is pImpl that achieves
142 * performant and easily-coded move-semantics -- in the face of fairly complex async impl details --
143 * but does *not* achieve a stable ABI (the thing where one can change impl method bodies without recompiling
144 * the code/changing the binary signature of the class). Long story short:
145 *
146 * See Native_socket_stream's "Implementation design/rationale" for why they chose pImpl-lite. The same applies here.
147 * (Historically that guy originally used strict-pImpl, but with the later introduction of a required function
148 * *template* API, not conducive to elision via `Function<>`, it was converted to pImpl-lite, same as we always
149 * had to be due to our innate templateness.)
150 *
151 * @see Blob_stream_mq_sender_impl doc header.
152 *
153 * @endinternal
154 *
155 * @tparam Persistent_mq_handle
156 * See Persistent_mq_handle concept doc header.
157 *
158 * @see Blob_sender: implemented concept.
159 */
160template<typename Persistent_mq_handle>
161class Blob_stream_mq_sender : public Blob_stream_mq_base<Persistent_mq_handle>
162{
163private:
164 // Types.
165
166 /// Short-hand for the impl type we're wrapping. Cannot simply forward-declare as in pImpl; we do pImpl-lite.
168
169public:
170 // Types.
171
172 /// Short-hand for template arg for underlying MQ handle type.
173 using Mq = typename Impl::Mq;
174
175 /// Short-hand for our base with `static` goodies at least.
177
178 /// Useful for generic programming, the `sync_io`-pattern counterpart to `*this` type.
180 /// You may disregard.
182
183 /// Implements Blob_sender concept API.
185
186 // Constants.
187
188 /// Implements concept API. Equals `Mq::S_RESOURCE_TYPE_ID`.
190
191 // Constructors/destructor.
192
193 /**
194 * Constructs the sender by taking over an already-opened MQ handle.
195 * Note that this op does not implement any concept; Blob_sender concept does not define how a Blob_sender
196 * is created in this explicit fashion.
197 *
198 * No traffic must have occurred on `mq_moved` up to this call. Otherwise behavior is undefined.
199 *
200 * If this fails (sets `*err_code` to truthy if not null; throws if null), all transmission calls on `*this`
201 * will fail with the post-value in `*err_code` emitted. In particular, error::Code::S_BLOB_STREAM_MQ_SENDER_EXISTS
202 * is that code, if the reason for failure was that another Blob_stream_mq_sender to
203 * `mq_moved.absolute_name()` has already been created in this or other process. See class doc header for
204 * discussion of the relationship between Blob_stream_mq_sender, Blob_stream_mq_receiver, the underlying MQ
205 * at a given Shared_name, and that Shared_name as registered in the OS.
206 * In short: there is to be up to 1 Blob_stream_mq_sender and up to 1 Blob_stream_mq_receiver for a given
207 * named persistent MQ. In this way, it is one single-direction pipe with 2 peers, like half of
208 * Native_socket_stream pipe: it is not a MQ with
209 * back-and-forth traffic nor multiple senders or multiple receivers. The underlying MQ supports such things;
210 * but that is not what the Blob_sender/Blob_receiver concepts model.
211 *
212 * Along those same lines note that the dtor (at the latest -- which happens if no fatal error occurs throughout)
213 * will not only close the MQ handle acquired from `mq_moved` but will execute `Mq::remove_persistent(name)`,
214 * where `name == mq_moved.absolute_name()` pre-this-ctor.
215 *
216 * ### Leaks of persistent resources ###
217 * If something prevents the destructor from running -- a hard crash, say -- the underlying MQ and/or the name
218 * may be leaked. External measures taken by ipc::session machinery are likely necessary to subsequently clean up
219 * the resource which, depending on the parameters passed to the #Mq ctor when originally creating the MQ,
220 * may use non-trivial RAM.
221 *
222 * ### Performance ###
223 * The taking over of `mq_moved` should be thought of as light-weight.
224 *
225 * @param logger_ptr
226 * Logger to use for subsequently logging.
227 * @param mq_moved
228 * An MQ handle to an MQ with no traffic on it so far. Unless an error is emitted, `mq_moved` becomes
229 * nullified upon return from this ctor. `*this` owns the MQ handle from this point on and is reponsible
230 * for closing it.
231 * @param nickname_str
232 * Human-readable nickname of the new object, as of this writing for use in `operator<<(ostream)` and
233 * logging only.
234 * @param err_code
235 * See `flow::Error_code` docs for error reporting semantics. #Error_code generated:
236 * error::Code::S_BLOB_STREAM_MQ_SENDER_EXISTS (another Blob_stream_mq_sender exists),
237 * system codes (other errors, all to do with the creation of a separate internally used tiny SHM pool
238 * used to prevent duplicate Blob_stream_mq_sender in the system).
239 */
240 explicit Blob_stream_mq_sender(flow::log::Logger* logger_ptr, util::String_view nickname_str,
241 Mq&& mq_moved, Error_code* err_code = nullptr);
242
243 /**
244 * Implements Blob_sender API, per its concept contract.
245 * All the notes for that concept's core-adopting ctor apply.
246 *
247 * @param sync_io_core_in_peer_state_moved
248 * See above.
249 */
250 explicit Blob_stream_mq_sender(Sync_io_obj&& sync_io_core_in_peer_state_moved);
251
252 /**
253 * Implements Blob_sender API, per its concept contract.
254 * All the notes for that concept's default ctor apply.
255 */
257
258 /**
259 * Move-constructs from `src`; `src` becomes as-if default-cted (therefore in NULL state).
260 * Implements Blob_sender API, per its concept contract.
261 *
262 * @param src
263 * See above.
264 */
266
267 /// Copy construction is disallowed.
269
270 /**
271 * Implements Blob_sender API. All the notes for the concept's destructor apply but as a reminder:
272 *
273 * Destroys this peer endpoint which will end the one-direction pipe and cancel any pending
274 * completion handlers by invoking it ASAP with error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER.
275 * As of this writing these are the completion handlers that would therefore be called:
276 * - The handler passed to async_end_sending() if not yet invoked.
277 * Since it is not valid to call async_end_sending() more than once, there is at most 1 of these.
278 *
279 * ### Fate of underlying MQ and its `.absolute_name()` ###
280 * No later than the return of this destructor:
281 * - The MQ name, namely `mq_moved.absolute_name()` from ctor, shall have been deleted.
282 * Therefore one will be able to util::Create a new #Mq; whereas before the dtor is called and returns
283 * it may (most likely will) not be possible to do so. This shall decrease the ref-count for the underlying
284 * MQ resource to at most 2. (Its ref-count is ever at most 3: 1 from the OS-registered Shared_name in the
285 * file system; 1 from `*this` Blob_stream_mq_sender; and 1 from the peer Blob_stream_mq_receiver).
286 * - The ref-count for the underlying MQ resource shall further decrease from 2 to 1 (if the counterpart
287 * Blob_stream_mq_sender still lives) or from 1 to 0 (if not). In the latter case the MQ itself shall be
288 * deleted, its bulk resources (in RAM) freed.
289 *
290 * While indeed util::Create of a new #Mq is possible after this dtor returns:
291 * - In practice it should only be done after *both* (sender and receiver) dtors have returned.
292 * Otherwise the later of the 2 will delete the new underlying MQ too: probably not what you want.
293 * - Even having accomplished that, it is still best not to reuse names if possible, at least not anytime soon.
294 * See class doc header for brief discussion.
295 */
297
298 // Methods.
299
300 /**
301 * Move-assigns from `src`; `*this` acts as if destructed; `src` becomes as-if default-cted (therefore in NULL state).
302 * No-op if `&src == this`.
303 * Implements Blob_sender API, per its concept contract.
304 *
305 * @see ~Blob_stream_mq_sender().
306 *
307 * @param src
308 * See above.
309 * @return See above.
310 */
312
313 /// Copy assignment is disallowed.
315
316 /**
317 * Implements Blob_sender API per contract. Note this value equals "remote" peer's value for the same call
318 * at any given time which is *not* a concept requirement and may be untrue of other concept co-implementing classes.
319 *
320 * @return See above.
321 */
322 size_t send_blob_max_size() const;
323
324 /**
325 * Implements Blob_sender API per contract. Reminder: It's not thread-safe
326 * to call this concurrently with other transmission methods on the same `*this`.
327 *
328 * Reminder: `blob.size() == 0` results in undefined behavior (assertion may trip).
329 *
330 * @param blob
331 * See above. Reminder: The memory area described by this arg need only be valid until this
332 * method returns. Perf reminder: That area will not be copied except for rare circumstances.
333 * @param err_code
334 * See above. Reminder: In rare circumstances, an error emitted here may represent something
335 * detected during handling of a *preceding* send_blob() call but after it returned.
336 * #Error_code generated:
337 * error::Code::S_INVALID_ARGUMENT (`blob.size()` exceeds max_msg_size()),
338 * error::Code::S_SENDS_FINISHED_CANNOT_SEND (`*end_sending()` was called earlier),
339 * system codes (but never would-block), indicating the underlying transport is hosed for that
340 * specific reason, as detected during outgoing-direction processing.
341 * @return See above.
342 */
343 bool send_blob(const util::Blob_const& blob, Error_code* err_code = nullptr);
344
345 /**
346 * Implements Blob_sender API per contract.
347 * Reminder: It's not thread-safe to call this concurrently with other transmission methods on
348 * the same `*this`.
349 *
350 * #Error_code generated and passed to `on_done_func()`:
351 * system codes (but never would-block) (same as for send_blob()),
352 * error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER (destructor called, canceling all pending ops;
353 * spiritually identical to `boost::asio::error::operation_aborted`),
354 *
355 * Reminder: In rare circumstances, an error emitted there may represent something
356 * detected during handling of a preceding send_blob() call but after it returned.
357 *
358 * @tparam Task_err
359 * See above.
360 * @param on_done_func
361 * See above. Reminder: any moved/copied version of this callback's associated captured state will
362 * be freed soon after it returns.
363 * @return See above. Reminder: If and only if it returns `false`, we're in NULL state, or `*end_sending()` has
364 * already been called; and `on_done_func()` will never be called.
365 */
366 template<typename Task_err>
367 bool async_end_sending(Task_err&& on_done_func);
368
369 /**
370 * Implements Blob_sender API per contract. Reminder: It is equivalent to async_end_sending()
371 * but with a no-op `on_done_func`.
372 *
373 * @return See above. Reminder: If and only if it returns `false`, we're in NULL state, or `*end_sending()` has
374 * already been called.
375 */
376 bool end_sending();
377
378 /**
379 * Implements Blob_sender API per contract.
380 *
381 * @param period
382 * See above.
383 * @return See above.
384 */
385 bool auto_ping(util::Fine_duration period = boost::chrono::seconds{2});
386
387 /**
388 * Implements Blob_sender API per contract.
389 *
390 * Thread-safe: can be called concurrently with any other method including `send_*()`.
391 * The returned copy is a consistent snapshot.
392 *
393 * @return Stats snapshot by value.
394 */
396
397 /**
398 * Implements Blob_sender API per contract.
399 *
400 * Thread-safe: can be called concurrently with any other method including `send_*()`.
401 */
403
404 /**
405 * Returns nickname, a brief string suitable for logging. This is included in the output by the `ostream<<`
406 * operator as well. This method is thread-safe in that it always returns the same value.
407 *
408 * If this object is default-cted (or moved-from), this will return a value equal to "".
409 *
410 * @return See above.
411 */
412 const std::string& nickname() const;
413
414 /**
415 * Returns name equal to `mq.absolute_name()`, where `mq` was passed to ctor, at the time it was passed to ctor.
416 *
417 * If this object is default-cted (or moved-from), this will return Shared_name::S_EMPTY.
418 *
419 * @return See above. Always the same value except across move-assignment.
420 */
421 const Shared_name& absolute_name() const;
422
423private:
424 // Types.
425
426 /// Short-hand for `const`-respecting wrapper around #Impl for the pImpl idiom.
427 using Impl_ptr = std::experimental::propagate_const<boost::movelib::unique_ptr<Impl>>;
428
429 // Friends.
430
431 /// Friend of Blob_stream_mq_sender.
432 template<typename Persistent_mq_handle2>
433 friend std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_sender<Persistent_mq_handle2>& val);
434
435 // Data.
436
437 /// The true implementation of this class. See also our class doc header.
439}; // class Blob_stream_mq_sender
440
441// Free functions: in *_fwd.hpp.
442
443// Template initializers.
444
445template<typename Persistent_mq_handle>
447
448// Template implementations (strict pImpl-idiom style (albeit pImpl-lite due to template-ness)).
449
450// The performant move semantics we get delightfully free with pImpl; they'll just move-to/from the unique_ptr m_impl.
451
452template<typename Persistent_mq_handle>
454template<typename Persistent_mq_handle>
456 (Blob_stream_mq_sender&&) = default;
457
458// The NULL state ctor comports with how null m_impl is treated all over below.
459template<typename Persistent_mq_handle>
461
462// The rest is strict forwarding to m_impl, once PEER state is established (non-null m_impl).
463
464template<typename Persistent_mq_handle>
466 (flow::log::Logger* logger_ptr, util::String_view nickname_str, Mq&& mq, Error_code* err_code) :
467 m_impl(boost::movelib::make_unique<Impl>
468 (logger_ptr, nickname_str, std::move(mq), err_code))
469{
470 // Yay.
471}
472
473template<typename Persistent_mq_handle>
475 (Sync_io_obj&& sync_io_core_in_peer_state_moved) :
476
477 m_impl(boost::movelib::make_unique<Impl>
478 (std::move(sync_io_core_in_peer_state_moved)))
479{
480 // Yay.
481}
482
483// It's only explicitly defined to formally document it.
484template<typename Persistent_mq_handle>
486
487template<typename Persistent_mq_handle>
489{
490 return m_impl ? m_impl->send_blob_max_size() : 0;
491}
492
493template<typename Persistent_mq_handle>
495{
496 return m_impl ? (m_impl->send_blob(blob, err_code), true)
497 : false;
498}
499
500template<typename Persistent_mq_handle>
501template<typename Task_err>
503{
504 return m_impl ? m_impl->async_end_sending(std::move(on_done_func)) : false;
505}
506
507template<typename Persistent_mq_handle>
509{
510 return m_impl ? m_impl->end_sending() : false;
511}
512
513template<typename Persistent_mq_handle>
515{
516 return m_impl ? m_impl->auto_ping(period) : false;
517}
518
519template<typename Persistent_mq_handle>
521{
522 return m_impl ? m_impl->blob_send_stats()
523 /* The histogram's structure will be based on a silly msg max size, and that is okay.
524 * Contract is struct is filled with zeroes, and that will hold. */
525 : Blob_snd_stats{1};
526}
527
528template<typename Persistent_mq_handle>
530{
531 if (m_impl) { m_impl->blob_send_stats_reset(); }
532}
533
534template<typename Persistent_mq_handle>
536{
537 return m_impl ? m_impl->absolute_name() : Shared_name::S_EMPTY;
538}
539
540template<typename Persistent_mq_handle>
542{
543 return m_impl ? m_impl->nickname() : util::EMPTY_STRING;
544}
545
546// `friend`ship needed for this "non-method method":
547
548template<typename Persistent_mq_handle>
549std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_sender<Persistent_mq_handle>& val)
550{
551 return val.m_impl ? (os << *val.m_impl) : (os << "null");
552}
553
554} // namespace ipc::transport
Base of Blob_stream_mq_sender and Blob_stream_mq_receiver containing certain static facilities,...
Internal, non-movable pImpl-lite implementation of Blob_stream_mq_sender class template.
typename Base::Mq Mq
Short-hand for template arg for underlying MQ handle type.
Implements Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message q...
~Blob_stream_mq_sender()
Implements Blob_sender API.
bool end_sending()
Implements Blob_sender API per contract.
size_t send_blob_max_size() const
Implements Blob_sender API per contract.
static const Shared_name S_RESOURCE_TYPE_ID
Implements concept API. Equals Mq::S_RESOURCE_TYPE_ID.
bool auto_ping(util::Fine_duration period=boost::chrono::seconds{2})
Implements Blob_sender API per contract.
Blob_stream_mq_sender & operator=(Blob_stream_mq_sender &&src)
Move-assigns from src; *this acts as if destructed; src becomes as-if default-cted (therefore in NULL...
Blob_stream_mq_sender & operator=(const Blob_stream_mq_sender &)=delete
Copy assignment is disallowed.
transport::stat::Blob_snd_stats Blob_snd_stats
Implements Blob_sender concept API.
const Shared_name & absolute_name() const
Returns name equal to mq.absolute_name(), where mq was passed to ctor, at the time it was passed to c...
std::experimental::propagate_const< boost::movelib::unique_ptr< Impl > > Impl_ptr
Short-hand for const-respecting wrapper around Impl for the pImpl idiom.
Blob_stream_mq_sender()
Implements Blob_sender API, per its concept contract.
void blob_send_stats_reset()
Implements Blob_sender API per contract.
const std::string & nickname() const
Returns nickname, a brief string suitable for logging.
friend std::ostream & operator<<(std::ostream &os, const Blob_stream_mq_sender< Persistent_mq_handle2 > &val)
Friend of Blob_stream_mq_sender.
Blob_stream_mq_sender(const Blob_stream_mq_sender &)=delete
Copy construction is disallowed.
Blob_snd_stats blob_send_stats() const
Implements Blob_sender API per contract.
bool send_blob(const util::Blob_const &blob, Error_code *err_code=nullptr)
Implements Blob_sender API per contract.
typename Impl::Mq Mq
Short-hand for template arg for underlying MQ handle type.
Blob_stream_mq_sender(Blob_stream_mq_sender &&src)
Move-constructs from src; src becomes as-if default-cted (therefore in NULL state).
bool async_end_sending(Task_err &&on_done_func)
Implements Blob_sender API per contract.
Impl_ptr m_impl
The true implementation of this class. See also our class doc header.
Dummy type for use as a template param to Channel when either the blobs pipe or handles pipe is disab...
Definition: channel.hpp:1137
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
static const Shared_name S_EMPTY
A (default-cted) Shared_name. May be useful for functions returning const Shared_name&.
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
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.
Definition: batch.hpp:431
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
Definition: util_fwd.hpp:114
const std::string EMPTY_STRING
A (default-cted) string. May be useful for functions returning const std::string&.
Definition: util.cpp:39
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:131
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:112
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313
Cumulative stats from the outgoing-direction (send) pipe of a Blob_sender or Native_handle_sender con...