zenoh_flow/runtime/dataflow/instance/
mod.rs

1//
2// Copyright (c) 2021 - 2023 ZettaScale Technology
3//
4// This program and the accompanying materials are made available under the
5// terms of the Eclipse Public License 2.0 which is available at
6// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
7// which is available at https://www.apache.org/licenses/LICENSE-2.0.
8//
9// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
10//
11// Contributors:
12//   ZettaScale Zenoh Team, <zenoh@zettascale.tech>
13//
14
15pub mod builtin;
16pub mod runners;
17
18use self::runners::connector::{ZenohReceiver, ZenohSender};
19use self::runners::Runner;
20use super::DataFlow;
21use crate::io::{Inputs, Outputs};
22use crate::model::record::{LinkRecord, ZFConnectorKind};
23use crate::prelude::{Context, Node};
24use crate::runtime::InstanceContext;
25use crate::types::NodeId;
26use crate::zfresult::ErrorKind;
27use crate::Result;
28use crate::{bail, zferror};
29use std::collections::HashMap;
30use std::ops::Deref;
31use std::sync::Arc;
32use uhlc::HLC;
33
34/// A `DataFlowInstance` is an instance of a data flow that is ready to be run.
35///
36/// All Zenoh-Flow daemons involved in the deployment of an instance of a data flow will create this
37/// structure to manage the nodes they are responsible for. Each daemon will keep in that structure
38/// only their view of the instance.
39pub struct DataFlowInstance {
40    pub(crate) _instance_context: Arc<InstanceContext>,
41    pub(crate) data_flow: DataFlow,
42    pub(crate) runners: HashMap<NodeId, Runner>,
43}
44
45impl Deref for DataFlowInstance {
46    type Target = DataFlow;
47
48    fn deref(&self) -> &Self::Target {
49        &self.data_flow
50    }
51}
52
53impl DataFlowInstance {
54    /// Retrieve the `NodeId` of the `Sink`s of this data flow instance running on the current
55    /// daemon.
56    ///
57    /// CAVEAT: It is possible (and likely) that not all `Sink`s run on a single daemon. Hence, this
58    /// list will be a subset of the list of all `Sink`s of this data flow.
59    pub fn get_sinks(&self) -> Vec<NodeId> {
60        self.sink_constructors.keys().cloned().collect()
61    }
62
63    /// Retrieve the `NodeId` of the `Source`s of this data flow instance running on the current
64    /// daemon.
65    ///
66    /// CAVEAT: It is possible (and likely) that not all `Source`s run on a single daemon. Hence,
67    /// this list will be a subset of the list of all `Source`s of this data flow.
68    pub fn get_sources(&self) -> Vec<NodeId> {
69        self.source_constructors.keys().cloned().collect()
70    }
71
72    /// Retrieve the `NodeId` of the `Operator`s of this data flow instance running on the current
73    /// daemon.
74    ///
75    /// CAVEAT: It is possible (and likely) that not all `Operator`s run on a single daemon. Hence,
76    /// this list will be a subset of the list of all `Operator`s of this data flow.
77    pub fn get_operators(&self) -> Vec<NodeId> {
78        self.operator_constructors.keys().cloned().collect()
79    }
80
81    /// Retrieve the `NodeId` of the `ZFConnector`s of this data flow instance running on the
82    /// current daemon.
83    ///
84    /// CAVEAT: It is possible (and likely) that not all `ZFConnector`s run on a single daemon.
85    /// Hence, this list will be a subset of the list of all `ZFConnector`s of this data flow.
86    pub fn get_connectors(&self) -> Vec<NodeId> {
87        self.connectors.keys().cloned().collect()
88    }
89
90    /// Start the node whose id matches the one provided.
91    ///
92    /// Start means launching as many tasks as necessary to run continuously the `Node`, input
93    /// and/or output callbacks.
94    ///
95    /// Start is idempotent, if the node is already running, nothing will happen.
96    ///
97    /// # Error
98    ///
99    /// This method can return an error if the provided `node_id` is not found.
100    pub fn start_node(&mut self, node_id: &NodeId) -> Result<()> {
101        if let Some(runner) = self.runners.get_mut(node_id) {
102            runner.start();
103            return Ok(());
104        }
105
106        bail!(
107            ErrorKind::NodeNotFound(node_id.clone()),
108            "Node < {} > not found",
109            node_id
110        )
111    }
112
113    /// Stop the node whose id matches the one provided.
114    ///
115    /// Stop means canceling all the tasks that were launched. Note that `stop` does not interrupt a
116    /// currently running task. The task will effectively be stopped the next time it encounters an
117    /// `await`.
118    ///
119    /// Stop is idempotent, if the node is not running, nothing will happen.
120    ///
121    /// # Error
122    ///
123    /// This method can return an error if the provided `node_id` is not found.
124    pub async fn stop_node(&mut self, node_id: &NodeId) -> Result<()> {
125        if let Some(runner) = self.runners.get_mut(node_id) {
126            return runner.stop().await;
127        }
128
129        bail!(
130            ErrorKind::NodeNotFound(node_id.clone()),
131            "Node < {} > not found",
132            node_id
133        )
134    }
135
136    /// Given a `DataFlow` and an `HLC`, try to instantiate the data flow by generating all the
137    /// nodes (via their factories) and all the connections --- _running on the daemon_.
138    ///
139    /// # Error
140    ///
141    /// This function can return an error if:
142    /// - some links are missing which resulted in some missing connections,
143    /// - a factory failed to generate a node.
144    pub async fn try_instantiate(data_flow: DataFlow, hlc: Arc<HLC>) -> Result<Self> {
145        let instance_context = Arc::new(InstanceContext {
146            flow_id: data_flow.flow.clone(),
147            instance_id: data_flow.uuid,
148            runtime: data_flow.context.clone(),
149        });
150
151        let mut node_ids: Vec<NodeId> = Vec::with_capacity(
152            data_flow.source_constructors.len()
153                + data_flow.operator_constructors.len()
154                + data_flow.sink_constructors.len()
155                + data_flow.connectors.len(),
156        );
157
158        node_ids.append(
159            &mut data_flow
160                .source_constructors
161                .keys()
162                .cloned()
163                .collect::<Vec<_>>(),
164        );
165        node_ids.append(
166            &mut data_flow
167                .operator_constructors
168                .keys()
169                .cloned()
170                .collect::<Vec<_>>(),
171        );
172        node_ids.append(
173            &mut data_flow
174                .sink_constructors
175                .keys()
176                .cloned()
177                .collect::<Vec<_>>(),
178        );
179        node_ids.append(&mut data_flow.connectors.keys().cloned().collect::<Vec<_>>());
180
181        let mut links = create_links(&node_ids, &data_flow.links, hlc.clone())?;
182
183        let context = Context::new(&instance_context);
184
185        let mut runners = HashMap::with_capacity(data_flow.source_constructors.len());
186        for (source_id, source_constructor) in &data_flow.source_constructors {
187            let (_, outputs) = links.remove(source_id).ok_or_else(|| {
188                zferror!(
189                    ErrorKind::IOError,
190                    "Links for Source < {} > were not created.",
191                    &source_id
192                )
193            })?;
194
195            let source = (source_constructor.constructor)(
196                context.clone(),
197                source_constructor.configuration.clone(),
198                outputs,
199            )
200            .await?;
201
202            let runner = Runner::new(source);
203            runners.insert(source_id.clone(), runner);
204        }
205
206        for (operator_id, operator_constructor) in &data_flow.operator_constructors {
207            let (inputs, outputs) = links.remove(operator_id).ok_or_else(|| {
208                zferror!(
209                    ErrorKind::IOError,
210                    "Links for Operator < {} > were not created.",
211                    &operator_id
212                )
213            })?;
214
215            let operator = (operator_constructor.constructor)(
216                context.clone(),
217                operator_constructor.configuration.clone(),
218                inputs,
219                outputs,
220            )
221            .await?;
222
223            let runner = Runner::new(operator);
224            runners.insert(operator_id.clone(), runner);
225        }
226
227        for (sink_id, sink_constructor) in &data_flow.sink_constructors {
228            let (inputs, _) = links.remove(sink_id).ok_or_else(|| {
229                zferror!(
230                    ErrorKind::IOError,
231                    "Links for Sink < {} > were not created.",
232                    &sink_id
233                )
234            })?;
235
236            let sink = (sink_constructor.constructor)(
237                context.clone(),
238                sink_constructor.configuration.clone(),
239                inputs,
240            )
241            .await?;
242
243            let runner = Runner::new(sink);
244            runners.insert(sink_id.clone(), runner);
245        }
246
247        for (connector_id, connector_record) in &data_flow.connectors {
248            let node = match &connector_record.kind {
249                ZFConnectorKind::Sender => {
250                    let (inputs, _) = links.remove(connector_id).ok_or_else(|| {
251                        zferror!(
252                            ErrorKind::IOError,
253                            "Links for Sink < {} > were not created.",
254                            connector_id
255                        )
256                    })?;
257                    Arc::new(
258                        ZenohSender::new(connector_record, instance_context.clone(), inputs)
259                            .await?,
260                    ) as Arc<dyn Node>
261                }
262                ZFConnectorKind::Receiver => {
263                    let (_, outputs) = links.remove(connector_id).ok_or_else(|| {
264                        zferror!(
265                            ErrorKind::IOError,
266                            "Links for Source < {} > were not created.",
267                            &connector_id
268                        )
269                    })?;
270                    Arc::new(
271                        ZenohReceiver::new(connector_record, instance_context.clone(), outputs)
272                            .await?,
273                    ) as Arc<dyn Node>
274                }
275            };
276
277            let runner = Runner::new(node);
278            runners.insert(connector_id.clone(), runner);
279        }
280
281        Ok(DataFlowInstance {
282            _instance_context: instance_context,
283            data_flow,
284            runners,
285        })
286    }
287}
288
289/// Creates the [`Link`](`Link`) between the `nodes` using `links`.
290///
291/// # Errors
292/// An error variant is returned in case of:
293/// -  port id is duplicated.
294pub(crate) fn create_links(
295    nodes: &[NodeId],
296    links: &[LinkRecord],
297    hlc: Arc<HLC>,
298) -> Result<HashMap<NodeId, (Inputs, Outputs)>> {
299    let mut io: HashMap<NodeId, (Inputs, Outputs)> = HashMap::with_capacity(nodes.len());
300
301    for link_desc in links {
302        let upstream_node = link_desc.from.node.clone();
303        let downstream_node = link_desc.to.node.clone();
304
305        // Nodes have been filtered based on their runtime. If the runtime of either one of the node
306        // is not equal to that of the current runtime, the channels should not be created.
307        if !nodes.contains(&upstream_node) || !nodes.contains(&downstream_node) {
308            continue;
309        }
310
311        // FIXME Introduce a user-configurable maximum capacity on the links. This also requires
312        // implementing a dropping policy.
313        let (tx, rx) = flume::unbounded();
314        let from = link_desc.from.output.clone();
315        let to = link_desc.to.input.clone();
316
317        match io.get_mut(&upstream_node) {
318            Some((_, outputs)) => outputs.insert(from.clone(), tx),
319            None => {
320                let inputs = Inputs::new();
321                let mut outputs = Outputs::new(hlc.clone());
322                outputs.insert(from.clone(), tx);
323
324                io.insert(upstream_node, (inputs, outputs));
325            }
326        }
327
328        match io.get_mut(&downstream_node) {
329            Some((inputs, _)) => inputs.insert(to.clone(), rx),
330            None => {
331                let outputs = Outputs::new(hlc.clone());
332
333                let mut inputs = Inputs::new();
334                inputs.insert(to.clone(), rx);
335
336                io.insert(downstream_node, (inputs, outputs));
337            }
338        }
339    }
340
341    Ok(io)
342}