feat: opt-in lossless (blocking) output for nodes and fanouts
Channels drop on overflow by default. That is the right behaviour for live
sources, where a stale item is worth less than a fresh one, but it makes the
library unusable for offline batch work: items vanish with no diagnostic, and
any downstream analysis that assumes a fixed sample rate is silently invalid.
Auto-inserted fanouts were the harder half of this. They are created inside
make_network(), so user code cannot reach them to configure, and they drop
per-output inside a swallowed catch — so a pipeline whose own nodes were all
configured lossless could still lose items with nothing reported anywhere. In
the pipeline this came from, capture's 2505 frames arrived at the detector as
774 while the overflow counter read zero.
Adds:
- INode::set_lossless_output(bool), defaulted to a no-op so node types with
no output channels ignore it
- PoolNode / PoolObjectNode: route push_one_out() through push_blocking()
- FanoutNode: same, plus set_lossy_output(i) to opt a single branch back out
- StaticNetwork::set_lossless(), which reaches user nodes and fanouts alike
- StaticNetwork::drain(), a public wrapper over the existing private
drain_all_channels(), so callers can flush in-flight work before stop()
Default behaviour is unchanged; every path is off unless explicitly enabled.
Blocking output is only safe when every consumer eventually drains. A branch
that can stall indefinitely — a display node nobody is servicing — will apply
backpressure to the whole pipeline, which is what set_lossy_output() is for.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -219,6 +219,24 @@ public:
|
||||
|
||||
FanoutStorage& fanouts_storage() { return *fanouts_; }
|
||||
|
||||
// Make every node in this network push losslessly (block until the consumer
|
||||
// drains) instead of dropping on a full channel. Includes the fanout nodes
|
||||
// make_network() inserts automatically, which is the part user code cannot
|
||||
// reach: they are unnamed, and they drop silently per-output, so a network
|
||||
// whose own nodes are all lossless can still lose items at a fanout.
|
||||
//
|
||||
// Only safe when every consumer eventually drains. A branch that can stall
|
||||
// indefinitely — a display node nobody is servicing, say — will block the
|
||||
// whole pipeline through backpressure. Call before start().
|
||||
void set_lossless(bool on = true) {
|
||||
for (auto* n : user_nodes_topo_) if (n) n->set_lossless_output(on);
|
||||
for (auto* n : fanout_nodes_ptr_) if (n) n->set_lossless_output(on);
|
||||
}
|
||||
|
||||
// Block until every channel is empty. Useful before stop() so work already
|
||||
// in flight completes rather than being discarded at teardown.
|
||||
void drain() const { drain_all_channels(); }
|
||||
|
||||
private:
|
||||
struct Snapshots {
|
||||
std::vector<NodeSnapshot> nodes;
|
||||
|
||||
Reference in New Issue
Block a user