Changes
Tracks the slick-stream-buffer and slick-queue v2.0.0 releases and applies the same fix here:
compile-time configuration moves from macros to a Traits template parameter.
Breaking
- Compile-time configuration is now a
Traitstemplate parameter, and that parameter is
slick::queue_traits- the traits of the shared record queue the multiplexer is built on,
not a traits type of its own.slick::stream_buffer_multiplexeris an alias for
basic_stream_buffer_multiplexer<>, so code namingslick::stream_buffer_multiplexer,
::producer_buffer,::recordor::multiplex_recordis unaffected.
slick::default_queue_traitsfollowsNDEBUG, so name a traits struct explicitly to pin the
configuration across build types. SLICK_STREAM_BUFFER_MULTIPLEXER_ENABLE_LOSS_DETECTIONis ignored; it warns and does nothing.
It gated astd::atomicmember of a header-only class, sosizeofdiffered across a
-DNDEBUGboundary and two translation units that disagreed silently violated the ODR. A
template argument is part of the mangled name, so the same disagreement is now an ordinary
link error instead.Traits::enable_loss_detectionswitches both terms ofmultiplexer.loss_count()together -
the shared queue's wrap loss and multiplexer-level loss - and both read 0 when it is off.
They are one flag rather than two becauseloss_count()sums them: a half-configured pair
would return a partial total that reads like a complete one. Records are skipped correctly
either way; only the counters are silent.producer_bufferis no longer movable; its move constructor and move assignment were public
and defaulted in 1.x and are now deleted. A registered producer is reachable both by the
shared_ptradd_producer()returns and by a raw pointer in the multiplexer's dense lookup
table, so moving one out emptied theshared_ptrmembers of an object both still pointed at,
and the nextconsume()orread()dereferenced a null buffer. Nothing needs to move one: it
is constructed in place and only ever held byshared_ptr.producer_buffer::consume()is no longernoexcept: it propagates thestd::length_error
thatslick::stream_buffer::consume()now throws for a record of 4 GiB or more. It is thrown
before any state moves, so nothing is published to either the producer's ring or the shared
record queue and the bytes stay readable.producer_buffer::loss_count()now reads 0 unless the caller reads that producer's ring
throughstream_buffer().read<Traits>()with aTraitswhosecount_lossis true. The
multiplexer's own dereference deliberately does not count: it jumps a fresh cursor to one
exact sequence, andread()'s counter measures the gap a sequential scan skipped, which
every later lapped dereference would add all over again.cmake_minimum_requiredraised to 3.21 (PROJECT_IS_TOP_LEVELneeds it, so the stated 3.10
could never configure), and the C++20 requirement now travels with the target via
target_compile_features(... INTERFACE cxx_std_20)instead ofCMAKE_CXX_STANDARD, which
applied only to this build and left installed consumers compiling the headers under whatever
standard they happened to use.- The installed
slick-stream-buffer-multiplexerConfig.cmakerequires its dependencies with
find_dependency(... CONFIG)instead of falling back toFetchContent. A config file runs
inside a consumer'sfind_package(), where git-cloning a dependency hides a missing install
behind a network fetch and can pull a different version than the one this package was
installed against - and the pins it carried were still v1.
Changed
- Requires slick-stream-buffer >= 2.0.0 and slick-queue >= 2.0.0, and includes
<slick/queue.hpp>rather than the deprecated<slick/queue.h>shim. recordandmultiplex_recordare also spelledslick::multiplexer_recordand
slick::multiplex_recordat namespace scope, so the shared-queue element type stays one type
across everyTraitsconfiguration - two differently-configured multiplexers mapping one
segment must agree on it.loss_count()is documented more precisely: only its multiplexer-level term is filtered by
producer registration. Shared-queue wrap loss is counted before anyproducer_idis known -
a lapped slot has already been overwritten - so an instance registering a subset of producers
sees wrap loss for producers it ignores, and the total is an upper bound on what it missed.
The behaviour is unchanged from 1.x; the previous wording claimed the filter applied to both.dereference()reads through traits withdetect_resetoff. The trait resynchronizes a
cursor that outlived areset(); this cursor is built from the record's own sequence one
statement earlier and outlives nothing, and the exact-sequence check already rejects what the
rewind would return - so it cost an acquire load ofnext_seq_per dereference and bought no
accuracy.
Added
stream_buffer_multiplexer::remove(shm_name), the explicit stale-segment recovery step for a
name a dead run left behind. One call covers both kinds of segment this class creates - the
shared record queue and a producer'sstream_buffer- since both areslick::shmsegments
underneath.get_producer_buffers(), returning every registered producer keyed byproducer_idas a
const producer_map&- the registration table itself, so enumerating allocates nothing. The
order is the hash map's andconstdoes not propagate to the handles; the new public
producer_mapalias lets callers name the type without spelling the container.find_producer()overloads, public and documented.