1use super::*;
4
5impl GraphInner {
6 pub fn add_observer(
7 &self,
8 port: &str,
9 cb: unsafe extern "C" fn(*mut c_void, crate::ffi::LMFlowPacket),
10 user: *mut c_void,
11 observe_timestamp_bounds: bool,
12 ) -> Result<()> {
13 let edge = *self
14 .output_by_name
15 .get(port)
16 .ok_or_else(|| Error::NotFound(format!("graph output port `{port}` does not exist")))?;
17 if observe_timestamp_bounds {
18 self.edges[edge]
19 .has_timestamp_bound_subscriber
20 .store(true, Ordering::Relaxed);
21 }
22 self.edges[edge]
23 .observers
24 .lock()
25 .expect("observer list lock poisoned")
26 .push(Observer::C {
27 cb,
28 user,
29 observe_timestamp_bounds,
30 });
31 Ok(())
32 }
33
34 pub fn add_observer_fn(
37 &self,
38 port: &str,
39 callback: Arc<dyn Fn(&Packet) + Send + Sync>,
40 observe_timestamp_bounds: bool,
41 ) -> Result<()> {
42 let edge = *self
43 .output_by_name
44 .get(port)
45 .ok_or_else(|| Error::NotFound(format!("graph output port `{port}` does not exist")))?;
46 if observe_timestamp_bounds {
47 self.edges[edge]
48 .has_timestamp_bound_subscriber
49 .store(true, Ordering::Relaxed);
50 }
51 self.edges[edge]
52 .observers
53 .lock()
54 .expect("observer list lock poisoned")
55 .push(Observer::Rust {
56 callback,
57 observe_timestamp_bounds,
58 });
59 Ok(())
60 }
61
62 pub fn nodes_len(&self) -> usize {
63 self.nodes.len()
64 }
65
66 pub fn node_name_at(&self, i: usize) -> Option<&str> {
67 self.nodes.get(i).map(|node| node.name.as_str())
68 }
69
70 pub fn node_input_ports_len(&self, node: usize) -> usize {
71 self.nodes.get(node).map_or(0, |value| value.in_ports.len())
72 }
73
74 pub fn node_input_port_name_at(&self, node: usize, port: usize) -> Option<&str> {
75 self.nodes.get(node)?.in_ports.name(port)
76 }
77
78 pub fn input_port_name_at(&self, i: usize) -> Option<&str> {
79 self.graph_inputs
80 .get(i)
81 .map(|&edge| self.edges[edge].name.as_str())
82 }
83
84 pub fn output_port_name_at(&self, i: usize) -> Option<&str> {
85 self.graph_outputs
86 .get(i)
87 .map(|&edge| self.edges[edge].name.as_str())
88 }
89
90 pub fn num_input_ports(&self) -> usize {
91 self.graph_inputs.len()
92 }
93
94 pub fn num_output_ports(&self) -> usize {
95 self.graph_outputs.len()
96 }
97
98 pub fn edge_id_by_name(&self, name: &str) -> Option<EdgeId> {
99 self.edge_by_name.get(name).copied()
100 }
101
102 pub fn input_edge_by_name(&self, name: &str) -> Option<EdgeId> {
103 self.input_by_name.get(name).copied()
104 }
105
106 pub fn queue_depth_by_name(&self, name: &str) -> Option<usize> {
107 Some(self.queue_depth(self.edge_id_by_name(name)?))
108 }
109
110 pub fn dropped_by_name(&self, name: &str) -> Option<u64> {
111 Some(self.edges[self.edge_id_by_name(name)?].dropped_count())
112 }
113
114 pub fn send_by_edge(&self, edge: EdgeId, packet: Packet, blocking: bool) -> Result<()> {
115 self.send(edge, packet, blocking)
116 }
117
118 pub(crate) fn watermark_backpressure_stats(
119 &self,
120 edge: EdgeId,
121 ) -> WatermarkBackpressureStatsSnapshot {
122 let edge = &self.edges[edge];
123 let stats = edge.watermark_backpressure.snapshot(self.epoch_us());
124 WatermarkBackpressureStatsSnapshot {
125 port_name: edge.name.clone(),
126 packet_limit: self.shared.config.max_queued_packets,
127 total_queued_packets: self.shared.total_queued(),
128 blocked: stats.blocked,
129 active_waiters: stats.active_waiters,
130 blocked_for_us: stats.blocked_for_us,
131 block_events: stats.block_events,
132 total_blocked_us: stats.total_blocked_us,
133 }
134 }
135
136 pub fn close_edge_pub(&self, edge: EdgeId) {
137 self.close_edge(edge);
138 self.set_state_draining_if_all_inputs_closed();
139 }
140
141 pub fn state_pub(&self) -> State {
142 self.state()
143 }
144
145 pub fn dump_pub(&self) -> String {
146 self.dump()
147 }
148
149 pub fn node_stats_pub(&self, i: usize) -> Option<NodeStatsSnapshot> {
150 self.node_stats(i)
151 }
152
153 pub fn side_packets_mut(&self) -> &Mutex<BTreeMap<String, Packet>> {
154 &self.side_packets
155 }
156
157 pub fn start_pub(self: &Arc<Self>) -> Result<()> {
158 self.start()
159 }
160
161 pub fn wait_done_pub(&self) -> Result<()> {
162 self.wait_done(None)
163 }
164
165 pub fn pump_step_pub(&self) -> bool {
166 let generation = self.wakeup_generation.load(Ordering::Acquire);
167 let progressed = self.pump_step();
168 if !progressed {
169 self.wakeup_pending.store(false, Ordering::Release);
170 if self.wakeup_generation.load(Ordering::Acquire) != generation
171 || self.delegated_tasks_pending()
172 {
173 self.request_wakeup();
174 }
175 }
176 progressed
177 }
178
179 pub fn all_nodes_closed_pub(&self) -> bool {
180 self.all_nodes_closed()
181 }
182
183 pub fn graph_inputs(&self) -> &[EdgeId] {
184 &self.graph_inputs
185 }
186
187 pub(crate) fn remaining_for_poller(
188 &self,
189 deadline: Option<std::time::Instant>,
190 ) -> Option<std::time::Duration> {
191 self.remaining(deadline)
192 }
193
194 pub(crate) fn wait_activity_since_pub(&self, before: u64, duration: std::time::Duration) {
195 self.wait_activity_since(before, duration);
196 }
197
198 pub(crate) fn activity_gen_pub(&self) -> u64 {
199 self.activity_gen()
200 }
201
202 pub(crate) fn is_idle_pub(&self) -> bool {
203 self.is_idle()
204 }
205
206 pub fn pause(&self) {
207 self.paused.store(true, Ordering::SeqCst);
208 }
209
210 pub fn resume(&self) {
212 self.paused.store(false, Ordering::SeqCst);
213 for node in 0..self.nodes.len() {
214 self.schedule_node(node);
215 }
216 self.notify_activity();
217 }
218
219 pub fn is_paused(&self) -> bool {
220 self.paused.load(Ordering::SeqCst)
221 }
222
223 pub fn executor_names(&self) -> Vec<&str> {
224 self.executors
225 .iter()
226 .map(|executor| executor.name())
227 .collect()
228 }
229
230 pub(super) fn executor_stats(&self, name: &str) -> Option<ExecutorStatsSnapshot> {
231 let executor = self
232 .executors
233 .iter()
234 .find(|executor| executor.name() == name)?;
235 let stats = executor.stats();
236 let capacity = if executor.is_delegating() {
237 1
238 } else {
239 executor.num_threads()
240 };
241 let mut queued_counts = std::collections::BTreeMap::<NodeId, usize>::new();
242 for node in executor.queued_nodes() {
243 *queued_counts.entry(node).or_default() += 1;
244 }
245 let mut queued_nodes = queued_counts.into_iter().collect::<Vec<_>>();
246 queued_nodes.sort_by(|(left_node, left_count), (right_node, right_count)| {
247 right_count.cmp(left_count).then_with(|| {
248 self.nodes[*left_node]
249 .name
250 .cmp(&self.nodes[*right_node].name)
251 })
252 });
253 Some(ExecutorStatsSnapshot {
254 queued: stats.queued,
255 running: stats.running,
256 peak_queued: stats.peak_queued,
257 completed: stats.completed,
258 total_wait_us: stats.total_wait_us,
259 total_execution_us: stats.total_execution_us,
260 queued_for_us: stats.queued_for_us,
261 saturated: stats.queued > 0 && stats.running >= capacity,
262 queued_nodes: queued_nodes
263 .into_iter()
264 .take(5)
265 .map(|(node, count)| format!("{} ({count})", self.nodes[node].name))
266 .collect(),
267 })
268 }
269
270 pub(crate) fn shutdown_executors_pub(&self) {
271 self.shutdown_executors();
272 }
273
274 pub(super) fn shutdown_executors(&self) {
276 for executor in &self.executors {
277 executor.shutdown();
278 }
279 }
280}