1use crate::{
26 Error as DbspError, Position, Runtime, RuntimeError,
27 circuit::{
28 cache::{CircuitCache, CircuitStoreMarker},
29 fingerprinter::Fingerprinter,
30 metadata::OperatorMeta,
31 metrics::DBSP_OPERATOR_COMMIT_LATENCY_MICROSECONDS,
32 operator_traits::{
33 BinaryOperator, BinarySinkOperator, Data, ImportOperator, NaryOperator,
34 QuaternaryOperator, SinkOperator, SourceOperator, StrictUnaryOperator, TernaryOperator,
35 TernarySinkOperator, UnaryOperator,
36 },
37 runtime::Consensus,
38 schedule::{
39 CommitProgress, DynamicScheduler, Error as SchedulerError, Executor, IterativeExecutor,
40 OnceExecutor, Scheduler,
41 },
42 trace::{CircuitEvent, SchedulerEvent},
43 },
44 circuit_cache_key,
45 ir::LABEL_MIR_NODE_ID,
46 operator::dynamic::balance::{Balancer, BalancerError, BalancerHint, PartitioningPolicy},
47 time::{Timestamp, UnitTimestamp},
48};
49#[cfg(doc)]
50use crate::{
51 InputHandle, OutputHandle,
52 algebra::{IndexedZSet, ZSet},
53 operator::{Aggregator, Fold, Generator, Max, Min, time_series::RelRange},
54 trace::Batch,
55};
56use anyhow::Error as AnyError;
57use dyn_clone::{DynClone, clone_box};
58use feldera_ir::{LirCircuit, LirNodeId};
59use feldera_samply::Span;
60use feldera_storage::{FileCommitter, StoragePath};
61use itertools::Itertools;
62use nix::{
63 sys::time::TimeValLike,
64 time::{ClockId, clock_gettime},
65};
66use pin_project_lite::pin_project;
67use serde::{Deserialize, Serialize, Serializer, de::DeserializeOwned};
68use size_of::SizeOf;
69use std::{
70 any::{Any, TypeId, type_name_of_val},
71 borrow::Cow,
72 cell::{Cell, Ref, RefCell, RefMut},
73 collections::{BTreeMap, BTreeSet, HashMap},
74 fmt::{self, Debug, Display, Write},
75 future::Future,
76 io::ErrorKind,
77 marker::PhantomData,
78 mem::{take, transmute},
79 ops::{AddAssign, Deref},
80 panic::Location,
81 pin::Pin,
82 rc::Rc,
83 sync::Arc,
84 task::{Context, Poll},
85 thread::panicking,
86 time::{Duration, Instant},
87};
88use tokio::{runtime::Runtime as TokioRuntime, task::LocalSet};
89use tracing::debug;
90use typedmap::{TypedMap, TypedMapKey};
91
92use super::dbsp_handle::Mode;
93
94const LABEL_PERSISTENT_OPERATOR_ID: &str = "persistent_id";
97
98struct StreamValue<D> {
100 val: Option<D>,
103
104 consumers: usize,
109
110 tokens: Cell<usize>,
117}
118
119impl<D> StreamValue<D> {
120 const fn empty() -> Self {
121 Self {
122 val: None,
123 consumers: 0,
124 tokens: Cell::new(0),
125 }
126 }
127
128 fn put(&mut self, val: D) {
129 debug_assert!(self.val.is_none());
133
134 if self.consumers > 0 {
137 self.tokens = Cell::new(self.consumers);
138 self.val = Some(val);
139 }
140 }
141
142 fn peek<R>(this: &R) -> &D
144 where
145 R: Deref<Target = Self>,
146 {
147 debug_assert_ne!(this.tokens.get(), 0);
148
149 this.val.as_ref().unwrap()
150 }
151
152 fn take(this: &RefCell<Self>) -> Option<D>
155 where
156 D: Clone,
157 {
158 let tokens = this.borrow().tokens.get();
159 debug_assert_ne!(tokens, 0);
160
161 if tokens == 1 {
162 Some(this.borrow_mut().val.take().unwrap())
163 } else {
164 None
165 }
166 }
167
168 fn consume_token(this: &RefCell<Self>) {
174 let this_ref = this.borrow();
175 debug_assert_ne!(this_ref.tokens.get(), 0);
176 this_ref.tokens.update(|tokens| tokens - 1);
177 if this_ref.tokens.get() == 0 {
178 drop(this_ref);
180 this.borrow_mut().val.take();
181 }
182 }
183}
184
185#[repr(transparent)]
186pub struct RefStreamValue<D>(Rc<RefCell<StreamValue<D>>>);
187
188impl<D> Clone for RefStreamValue<D> {
189 fn clone(&self) -> Self {
190 Self(self.0.clone())
191 }
192}
193
194impl<D> RefStreamValue<D> {
195 pub fn empty() -> Self {
196 Self(Rc::new(RefCell::new(StreamValue::empty())))
197 }
198
199 fn get_mut(&self) -> RefMut<'_, StreamValue<D>> {
200 self.0.borrow_mut()
201 }
202
203 fn get(&self) -> Ref<'_, StreamValue<D>> {
204 self.0.borrow()
205 }
206
207 pub fn put(&self, d: D) {
213 let mut val = self.get_mut();
214 val.put(d);
215 }
216
217 unsafe fn transmute<D2>(&self) -> RefStreamValue<D2> {
218 unsafe {
219 RefStreamValue(std::mem::transmute::<
220 Rc<RefCell<StreamValue<D>>>,
221 Rc<RefCell<StreamValue<D2>>>,
222 >(self.0.clone()))
223 }
224 }
225}
226
227pub trait StreamMetadata: DynClone + 'static {
232 fn stream_id(&self) -> StreamId;
233 fn local_node_id(&self) -> NodeId;
234 fn origin_node_id(&self) -> &GlobalNodeId;
235 fn num_consumers(&self) -> usize;
236
237 fn clear_consumer_count(&self);
239
240 fn register_consumer(&self);
243
244 fn consume_token(&self);
253}
254
255dyn_clone::clone_trait_object!(StreamMetadata);
256
257pub struct Stream<C, D> {
706 stream_id: StreamId,
708 local_node_id: NodeId,
710 origin_node_id: GlobalNodeId,
712 circuit: C,
714 val: RefStreamValue<D>,
717}
718
719impl<C, D> StreamMetadata for Stream<C, D>
720where
721 C: Clone + 'static,
722 D: 'static,
723{
724 fn stream_id(&self) -> StreamId {
725 self.stream_id
726 }
727 fn local_node_id(&self) -> NodeId {
728 self.local_node_id
729 }
730 fn origin_node_id(&self) -> &GlobalNodeId {
731 &self.origin_node_id
732 }
733 fn clear_consumer_count(&self) {
734 self.val.get_mut().consumers = 0;
735 }
736 fn num_consumers(&self) -> usize {
737 self.val.get().consumers
738 }
739 fn register_consumer(&self) {
740 self.val.get_mut().consumers += 1;
741 }
742 fn consume_token(&self) {
743 StreamValue::consume_token(self.val());
744 }
745}
746
747impl<C, D> Clone for Stream<C, D>
748where
749 C: Clone,
750{
751 fn clone(&self) -> Self {
752 Self {
753 stream_id: self.stream_id,
754 local_node_id: self.local_node_id,
755 origin_node_id: self.origin_node_id.clone(),
756 circuit: self.circuit.clone(),
757 val: self.val.clone(),
758 }
759 }
760}
761
762impl<C, D> Stream<C, D>
763where
764 C: Clone,
765{
766 pub(crate) unsafe fn transmute_payload<D2>(&self) -> Stream<C, D2> {
775 unsafe {
776 Stream {
777 stream_id: self.stream_id,
778 local_node_id: self.local_node_id,
779 origin_node_id: self.origin_node_id.clone(),
780 circuit: self.circuit.clone(),
781 val: self.val.transmute::<D2>(),
782 }
783 }
784 }
785}
786
787impl<C, D> Stream<C, D> {
788 pub fn local_node_id(&self) -> NodeId {
794 self.local_node_id
795 }
796
797 pub fn origin_node_id(&self) -> &GlobalNodeId {
803 &self.origin_node_id
804 }
805
806 pub fn stream_id(&self) -> StreamId {
807 self.stream_id
808 }
809
810 pub fn circuit(&self) -> &C {
812 &self.circuit
813 }
814
815 pub fn ptr_eq<D2>(&self, other: &Stream<C, D2>) -> bool {
816 self.stream_id() == other.stream_id()
817 }
818}
819
820impl<C, D> Stream<C, D>
822where
823 C: Circuit,
824{
825 pub(crate) fn new(circuit: C, node_id: NodeId) -> Self {
828 Self {
829 stream_id: circuit.allocate_stream_id(),
830 local_node_id: node_id,
831 origin_node_id: GlobalNodeId::child_of(&circuit, node_id),
832 circuit,
833 val: RefStreamValue::empty(),
834 }
835 }
836
837 pub fn with_value(circuit: C, node_id: NodeId, val: RefStreamValue<D>) -> Self {
839 Self {
840 stream_id: circuit.allocate_stream_id(),
841 local_node_id: node_id,
842 origin_node_id: GlobalNodeId::child_of(&circuit, node_id),
843 circuit,
844 val,
845 }
846 }
847
848 pub fn value(&self) -> RefStreamValue<D> {
849 self.val.clone()
850 }
851
852 pub fn export(&self) -> Stream<C::Parent, D>
860 where
861 C::Parent: Circuit,
862 D: 'static,
863 {
864 self.circuit()
865 .cache_get_or_insert_with(ExportId::new(self.stream_id()), || unimplemented!())
866 .clone()
867 }
868
869 pub fn set_label(&self, key: &str, val: &str) -> Self {
871 self.circuit.set_node_label(&self.origin_node_id, key, val);
872 self.clone()
873 }
874
875 pub fn get_label(&self, key: &str) -> Option<String> {
877 self.circuit.get_node_label(&self.origin_node_id, key)
878 }
879
880 pub fn set_persistent_id(&self, name: Option<&str>) -> Self {
882 if let Some(name) = name {
883 self.set_label(LABEL_PERSISTENT_OPERATOR_ID, name)
884 } else {
885 self.clone()
886 }
887 }
888
889 pub fn get_persistent_id(&self) -> Option<String> {
891 self.get_label(LABEL_PERSISTENT_OPERATOR_ID)
892 }
893}
894
895impl<C, D> Stream<C, D> {
896 fn with_origin(
898 circuit: C,
899 stream_id: StreamId,
900 node_id: NodeId,
901 origin_node_id: GlobalNodeId,
902 ) -> Self {
903 Self {
904 stream_id,
905 local_node_id: node_id,
906 origin_node_id,
907 circuit,
908 val: RefStreamValue::empty(),
909 }
910 }
911}
912
913impl<C, D> Stream<C, D> {
914 pub(crate) fn map_value<T>(&self, f: impl Fn(&D) -> T) -> T {
915 f(StreamValue::peek(&self.get()))
916 }
917
918 fn get(&self) -> Ref<'_, StreamValue<D>> {
919 self.val.get()
920 }
921
922 fn val(&self) -> &RefCell<StreamValue<D>> {
923 &self.val.0
924 }
925
926 pub(crate) fn put(&self, d: D) {
933 self.val.put(d);
934 }
935}
936
937pub struct ExportStream<C, D>
946where
947 C: Circuit,
948{
949 pub local: Stream<C, D>,
950 pub export: Stream<C::Parent, D>,
951}
952
953pub type Scope = u16;
959
960pub trait Node: Any {
963 fn local_id(&self) -> NodeId;
965
966 fn global_id(&self) -> &GlobalNodeId;
968
969 fn persistent_id(&self) -> Option<String> {
982 let worker_index = Runtime::worker_index();
983
984 match Runtime::mode() {
985 Mode::Ephemeral => Some(format!(
986 "{worker_index}-{}",
987 self.global_id().path_as_string()
988 )),
989 Mode::Persistent => self
990 .get_label(LABEL_PERSISTENT_OPERATOR_ID)
991 .map(|operator_id| format!("{worker_index}-{operator_id}")),
992 }
993 }
994
995 fn name(&self) -> Cow<'static, str>;
997
998 fn is_circuit(&self) -> bool {
999 false
1000 }
1001
1002 fn is_input(&self) -> bool;
1004
1005 fn is_async(&self) -> bool;
1009
1010 fn ready(&self) -> bool;
1014
1015 fn register_ready_callback(&mut self, _cb: Box<dyn Fn() + Send + Sync>) {}
1019
1020 fn eval<'a>(
1024 &'a mut self,
1025 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>>;
1026
1027 fn import<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
1028 Box::pin(async {})
1029 }
1030
1031 fn start_transaction(&mut self);
1033
1034 fn flush(&mut self);
1037
1038 fn is_flush_complete(&self) -> bool;
1040
1041 fn clock_start(&mut self, scope: Scope);
1051
1052 fn clock_end(&mut self, scope: Scope);
1060
1061 fn init(&mut self) {}
1062
1063 fn metadata(&self, output: &mut OperatorMeta);
1064
1065 fn fixedpoint(&self, scope: Scope) -> bool;
1066
1067 fn map_nodes_recursive(
1070 &self,
1071 _f: &mut dyn FnMut(&dyn Node) -> Result<(), DbspError>,
1072 ) -> Result<(), DbspError> {
1073 Ok(())
1074 }
1075
1076 fn map_nodes_recursive_mut(
1079 &self,
1080 _f: &mut dyn FnMut(&mut dyn Node) -> Result<(), DbspError>,
1081 ) -> Result<(), DbspError> {
1082 Ok(())
1083 }
1084
1085 fn checkpoint(
1091 &mut self,
1092 base: &StoragePath,
1093 files: &mut Vec<Arc<dyn FileCommitter>>,
1094 ) -> Result<(), DbspError>;
1095
1096 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError>;
1099
1100 fn clear_state(&mut self) -> Result<(), DbspError>;
1106
1107 fn start_compaction(&mut self);
1109
1110 fn is_compaction_complete(&self) -> bool;
1112
1113 fn start_replay(&mut self) -> Result<(), DbspError>;
1122
1123 fn is_replay_complete(&self) -> bool;
1129
1130 fn end_replay(&mut self) -> Result<(), DbspError>;
1138
1139 fn fingerprint(&self, fip: &mut Fingerprinter) {
1141 fip.hash(type_name_of_val(self));
1142 }
1143
1144 fn set_label(&mut self, key: &str, value: &str);
1146
1147 fn get_label(&self, key: &str) -> Option<&str>;
1149
1150 fn labels(&self) -> &BTreeMap<String, String>;
1151
1152 fn map_child(&self, _path: &[NodeId], _f: &mut dyn FnMut(&dyn Node)) {
1154 panic!("map_child: not a circuit node")
1155 }
1156
1157 fn map_child_mut(&self, _path: &[NodeId], _f: &mut dyn FnMut(&mut dyn Node)) {
1159 panic!("map_child_mut: not a circuit node")
1160 }
1161
1162 fn as_circuit(&self) -> Option<&dyn CircuitBase> {
1163 None
1164 }
1165
1166 fn as_any(&self) -> &dyn Any;
1167}
1168
1169#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Deserialize, Serialize)]
1171#[repr(transparent)]
1172pub struct StreamId(usize);
1173
1174impl StreamId {
1175 pub fn new(id: usize) -> Self {
1176 Self(id)
1177 }
1178
1179 pub fn id(&self) -> usize {
1181 self.0
1182 }
1183}
1184
1185impl Display for StreamId {
1186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1187 f.write_char('s')?;
1188 Debug::fmt(&self.0, f)
1189 }
1190}
1191
1192#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
1194#[repr(transparent)]
1195pub struct NodeId(usize);
1196
1197impl NodeId {
1198 pub fn new(id: usize) -> Self {
1199 Self(id)
1200 }
1201
1202 pub fn id(&self) -> usize {
1204 self.0
1205 }
1206
1207 pub fn root() -> Self {
1208 Self(0)
1209 }
1210}
1211
1212impl Display for NodeId {
1213 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1214 f.write_char('n')?;
1215 Debug::fmt(&self.0, f)
1216 }
1217}
1218
1219#[derive(Debug, Clone, Eq, Hash, PartialEq)]
1221pub struct RegionName {
1222 id: u64,
1224 pub name: Cow<'static, str>,
1225}
1226
1227impl RegionName {
1228 fn new(name: &str, id: u64) -> Self {
1229 Self {
1230 id,
1231 name: Cow::Owned(name.to_string()),
1232 }
1233 }
1234
1235 pub fn id(&self) -> u64 {
1237 self.id
1238 }
1239
1240 pub fn name(&self) -> &str {
1242 &self.name
1243 }
1244}
1245
1246impl Display for RegionName {
1247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1248 f.write_str(self.name.as_ref())?;
1249 f.write_char(':')?;
1250 write!(f, "{}", self.id)
1251 }
1252}
1253
1254#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
1262#[repr(transparent)]
1263pub struct GlobalNodeId(Vec<NodeId>);
1264
1265impl Serialize for GlobalNodeId {
1266 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1268 where
1269 S: Serializer,
1270 {
1271 let s = self.node_identifier().to_string();
1272 serializer.serialize_str(&s)
1273 }
1274}
1275
1276impl Display for GlobalNodeId {
1277 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1278 f.write_str("[")?;
1279 let path = self.path();
1280 for i in 0..path.len() {
1281 f.write_str(&path[i].0.to_string())?;
1282 if i < path.len() - 1 {
1283 f.write_str(".")?;
1284 }
1285 }
1286 f.write_str("]")
1287 }
1288}
1289
1290impl GlobalNodeId {
1291 pub fn from_path(path: &[NodeId]) -> Self {
1293 Self(path.to_owned())
1294 }
1295
1296 pub fn from_path_vec(path: Vec<NodeId>) -> Self {
1298 Self(path)
1299 }
1300
1301 pub fn root() -> Self {
1302 Self(Vec::new())
1303 }
1304
1305 pub fn child(&self, child_id: NodeId) -> Self {
1307 let mut path = Vec::with_capacity(self.path().len() + 1);
1308 for id in self.path() {
1309 path.push(*id);
1310 }
1311 path.push(child_id);
1312 Self(path)
1313 }
1314
1315 pub fn child_of<C>(circuit: &C, node_id: NodeId) -> Self
1317 where
1318 C: Circuit,
1319 {
1320 let mut ids = circuit.global_node_id().path().to_owned();
1321 ids.push(node_id);
1322 Self(ids)
1323 }
1324
1325 pub fn node_identifier(&self) -> impl Display {
1327 struct NodeIdentifier<'a>(&'a GlobalNodeId);
1328 impl<'a> Display for NodeIdentifier<'a> {
1329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1330 write!(f, "n{}", self.0.path().iter().format("_"))
1331 }
1332 }
1333 NodeIdentifier(self)
1334 }
1335
1336 pub fn local_node_id(&self) -> Option<NodeId> {
1338 self.0.last().cloned()
1339 }
1340
1341 pub fn parent_id(&self) -> Option<Self> {
1343 self.0
1344 .split_last()
1345 .map(|(_, prefix)| GlobalNodeId::from_path(prefix))
1346 }
1347
1348 pub fn is_child_of(&self, parent: &Self) -> bool {
1350 self.parent_id().as_ref() == Some(parent)
1351 }
1352
1353 pub fn path(&self) -> &[NodeId] {
1355 &self.0
1356 }
1357
1358 pub fn top_level_ancestor(&self) -> NodeId {
1367 self.0[0]
1368 }
1369
1370 pub(crate) fn path_as_string(&self) -> String {
1372 self.0
1373 .iter()
1374 .map(|node_id| node_id.0.to_string())
1375 .collect::<Vec<_>>()
1376 .join("-")
1377 }
1378
1379 pub fn lir_node_id(&self) -> LirNodeId {
1381 LirNodeId::new(&self.path_as_string())
1382 }
1383}
1384
1385type CircuitEventHandler = Box<dyn Fn(&CircuitEvent)>;
1386type SchedulerEventHandler = Box<dyn FnMut(&SchedulerEvent<'_>)>;
1387type CircuitEventHandlers = Rc<RefCell<HashMap<String, CircuitEventHandler>>>;
1388type SchedulerEventHandlers = Rc<RefCell<HashMap<String, SchedulerEventHandler>>>;
1389
1390#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
1429#[repr(transparent)]
1430pub struct OwnershipPreference(usize);
1431
1432impl OwnershipPreference {
1433 pub const fn new(val: usize) -> Self {
1436 Self(val)
1437 }
1438
1439 pub const INDIFFERENT: Self = Self::new(0);
1441
1442 pub const WEAKLY_PREFER_OWNED: Self = Self::new(40);
1448
1449 pub const PREFER_OWNED: Self = Self::new(50);
1455
1456 pub const STRONGLY_PREFER_OWNED: Self = Self::new(100);
1459
1460 pub const fn raw(&self) -> usize {
1462 self.0
1463 }
1464}
1465
1466impl Default for OwnershipPreference {
1467 #[inline]
1468 fn default() -> Self {
1469 Self::INDIFFERENT
1470 }
1471}
1472
1473impl Display for OwnershipPreference {
1474 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1475 match *self {
1476 Self::INDIFFERENT => f.write_str("Indifferent"),
1477 Self::WEAKLY_PREFER_OWNED => f.write_str("WeaklyPreferOwned"),
1478 Self::PREFER_OWNED => f.write_str("PreferOwned"),
1479 Self::STRONGLY_PREFER_OWNED => f.write_str("StronglyPreferOwned"),
1480 Self(preference) => write!(f, "Preference({preference})"),
1481 }
1482 }
1483}
1484
1485#[derive(Clone)]
1490pub struct Edge {
1491 pub from: NodeId,
1493 pub to: NodeId,
1495 pub origin: GlobalNodeId,
1499 pub stream: Option<Box<dyn StreamMetadata>>,
1502 pub ownership_preference: Option<OwnershipPreference>,
1505}
1506
1507#[allow(dead_code)]
1508impl Edge {
1509 pub(crate) fn is_dependency(&self) -> bool {
1511 self.ownership_preference.is_none()
1512 }
1513
1514 pub(crate) fn is_stream(&self) -> bool {
1516 self.stream.is_some()
1517 }
1518
1519 pub(crate) fn stream_id(&self) -> Option<StreamId> {
1520 self.stream.as_ref().map(|meta| meta.stream_id())
1521 }
1522}
1523
1524circuit_cache_key!(ExportId<C, D>(StreamId => Stream<C, D>));
1525
1526circuit_cache_key!(ReplaySource(StreamId => Box<dyn StreamMetadata>));
1529
1530pub(crate) fn register_replay_stream<C, B>(
1532 circuit: &C,
1533 stream: &Stream<C, B>,
1534 replay_stream: &Stream<C, B>,
1535) where
1536 C: Circuit,
1537 B: 'static,
1538{
1539 if TypeId::of::<()>() == TypeId::of::<C::Time>() {
1542 if !circuit.cache_contains(&ReplaySource::new(stream.stream_id())) {
1551 circuit.cache_insert(
1552 ReplaySource::new(stream.stream_id()),
1553 Box::new(replay_stream.clone()),
1554 );
1555 }
1556 }
1557}
1558
1559pub trait WithClock {
1562 type Time: Timestamp;
1565
1566 fn time(&self) -> Self::Time;
1568}
1569
1570impl WithClock for () {
1574 type Time = UnitTimestamp;
1575
1576 fn time(&self) -> Self::Time {
1577 UnitTimestamp
1578 }
1579}
1580
1581impl<P, T> WithClock for ChildCircuit<P, T>
1582where
1583 P: 'static,
1584 T: Timestamp,
1585{
1586 type Time = T;
1587
1588 fn time(&self) -> Self::Time {
1589 self.time.borrow().clone()
1590 }
1591}
1592
1593#[derive(Default, Debug, Clone, Serialize, Deserialize)]
1595pub struct CircuitMetadata {
1596 metadata: HashMap<NodeId, serde_json::Value>,
1597}
1598
1599#[derive(Default, Debug)]
1600pub struct MetadataExchangeInner {
1601 local_metadata: RefCell<CircuitMetadata>,
1603
1604 global_metadata: RefCell<Vec<CircuitMetadata>>,
1607}
1608
1609#[derive(Default, Debug, Clone)]
1619pub struct MetadataExchange {
1620 inner: Rc<MetadataExchangeInner>,
1621}
1622
1623impl MetadataExchange {
1624 fn new() -> Self {
1625 Self::default()
1626 }
1627
1628 pub fn local_metadata(&self) -> CircuitMetadata {
1630 self.inner.local_metadata.borrow().clone()
1631 }
1632
1633 pub fn set_local_operator_metadata(&self, id: NodeId, metadata: serde_json::Value) {
1635 self.inner
1636 .local_metadata
1637 .borrow_mut()
1638 .metadata
1639 .insert(id, metadata.clone());
1640 }
1641
1642 pub fn clear_local_operator_metadata(&self, id: NodeId) {
1644 self.inner.local_metadata.borrow_mut().metadata.remove(&id);
1645 }
1646
1647 pub fn set_local_operator_metadata_typed<T>(&self, id: NodeId, metadata: T)
1649 where
1650 T: Serialize,
1651 {
1652 self.inner
1653 .local_metadata
1654 .borrow_mut()
1655 .metadata
1656 .insert(id, serde_json::to_value(metadata).unwrap());
1657 }
1658
1659 pub fn get_local_operator_metadata(&self, id: NodeId) -> Option<serde_json::Value> {
1661 self.inner
1662 .local_metadata
1663 .borrow()
1664 .metadata
1665 .get(&id)
1666 .cloned()
1667 }
1668
1669 pub fn get_local_operator_metadata_typed<T>(&self, id: NodeId) -> Option<T>
1670 where
1671 T: DeserializeOwned,
1672 {
1673 self.get_local_operator_metadata(id)
1674 .map(|val| serde_json::from_value::<T>(val).unwrap())
1675 }
1676
1677 pub fn set_global_metadata(&self, global_metadata: Vec<CircuitMetadata>) {
1679 *self.inner.global_metadata.borrow_mut() = global_metadata;
1680 }
1681
1682 pub fn get_global_metadata(&self) -> Vec<CircuitMetadata> {
1683 self.inner.global_metadata.borrow().clone()
1684 }
1685
1686 pub fn get_global_operator_metadata(&self, id: NodeId) -> Vec<Option<serde_json::Value>> {
1688 self.inner
1689 .global_metadata
1690 .borrow()
1691 .iter()
1692 .map(|global_metadata| global_metadata.metadata.get(&id).cloned())
1693 .collect()
1694 }
1695
1696 pub fn get_global_operator_metadata_typed<T>(&self, id: NodeId) -> Vec<Option<T>>
1703 where
1704 T: DeserializeOwned,
1705 {
1706 self.inner
1707 .global_metadata
1708 .borrow()
1709 .iter()
1710 .map(|global_metadata| {
1711 global_metadata
1712 .metadata
1713 .get(&id)
1714 .cloned()
1715 .map(|val| serde_json::from_value::<T>(val).unwrap())
1716 })
1717 .collect()
1718 }
1719}
1720
1721pub trait CircuitBase: 'static {
1723 fn edges(&self) -> Ref<'_, Edges>;
1724
1725 fn edges_mut(&self) -> RefMut<'_, Edges>;
1726
1727 fn global_id(&self) -> &GlobalNodeId;
1731
1732 fn num_nodes(&self) -> usize;
1734
1735 fn node_ids(&self) -> Vec<NodeId>;
1737
1738 fn lookup_local_node_by_persistent_id(
1739 &self,
1740 persistent_id: &str,
1741 ) -> Result<GlobalNodeId, DbspError>;
1742
1743 fn import_nodes(&self) -> Vec<NodeId>;
1744
1745 fn clear(&mut self);
1746
1747 fn add_dependency(&self, from: NodeId, to: NodeId);
1752
1753 fn transitive_ancestors(&self) -> BTreeMap<NodeId, BTreeSet<NodeId>>;
1756
1757 fn allocate_stream_id(&self) -> StreamId;
1760
1761 fn last_stream_id(&self) -> RefCell<StreamId>;
1763
1764 fn root_scope(&self) -> Scope;
1769
1770 fn node_id(&self) -> NodeId;
1772
1773 fn global_node_id(&self) -> GlobalNodeId;
1775
1776 fn map_node_relative(&self, path: &[NodeId], f: &mut dyn FnMut(&dyn Node));
1778
1779 fn map_node_mut_relative(&self, path: &[NodeId], f: &mut dyn FnMut(&mut dyn Node));
1781
1782 fn map_nodes_recursive(
1786 &self,
1787 f: &mut dyn FnMut(&dyn Node) -> Result<(), DbspError>,
1788 ) -> Result<(), DbspError>;
1789
1790 fn map_nodes_recursive_mut(
1794 &mut self,
1795 f: &mut dyn FnMut(&mut dyn Node) -> Result<(), DbspError>,
1796 ) -> Result<(), DbspError>;
1797
1798 fn map_local_nodes(
1802 &self,
1803 f: &mut dyn FnMut(&dyn Node) -> Result<(), DbspError>,
1804 ) -> Result<(), DbspError>;
1805
1806 fn map_local_nodes_mut(
1808 &self,
1809 f: &mut dyn FnMut(&mut dyn Node) -> Result<(), DbspError>,
1810 ) -> Result<(), DbspError>;
1811
1812 fn apply_local_node_mut(&self, id: NodeId, f: &mut dyn FnMut(&mut dyn Node));
1818
1819 fn map_subcircuits(
1823 &self,
1824 f: &mut dyn FnMut(&dyn CircuitBase) -> Result<(), DbspError>,
1825 ) -> Result<(), DbspError>;
1826
1827 fn set_node_label(&self, id: &GlobalNodeId, key: &str, val: &str);
1834
1835 fn set_persistent_node_id(&self, id: &GlobalNodeId, persistent_id: Option<&str>) {
1836 if let Some(persistent_id) = persistent_id {
1837 self.set_node_label(id, LABEL_PERSISTENT_OPERATOR_ID, persistent_id);
1838 }
1839 }
1840
1841 fn set_mir_node_id(&self, id: &GlobalNodeId, mir_id: Option<&str>) {
1842 if let Some(mir_id) = mir_id {
1843 self.set_node_label(id, LABEL_MIR_NODE_ID, mir_id);
1844 }
1845 }
1846
1847 fn get_node_label(&self, id: &GlobalNodeId, key: &str) -> Option<String>;
1854
1855 fn get_persistent_node_id(&self, id: &GlobalNodeId) -> Option<String> {
1857 self.get_node_label(id, LABEL_PERSISTENT_OPERATOR_ID)
1858 }
1859
1860 fn check_fixedpoint(&self, scope: Scope) -> bool;
1861
1862 fn metadata_exchange(&self) -> &MetadataExchange;
1864
1865 fn balancer(&self) -> &Balancer;
1867
1868 fn set_auto_rebalance(&self, enable: bool) -> Result<(), DbspError>;
1870
1871 fn set_balancer_hint_by_global_id(
1878 &self,
1879 global_node_id: &GlobalNodeId,
1880 hint: BalancerHint,
1881 ) -> Result<(), DbspError>;
1882
1883 fn set_balancer_hint(&self, persistent_id: &str, hint: BalancerHint) -> Result<(), DbspError>;
1884
1885 fn get_current_balancer_policies(&self) -> BTreeMap<NodeId, PartitioningPolicy>;
1887
1888 fn get_current_balancer_policy(
1889 &self,
1890 persistent_id: &str,
1891 ) -> Result<PartitioningPolicy, DbspError>;
1892
1893 fn rebalance(&self);
1894
1895 fn start_compaction(&self);
1896
1897 fn is_compaction_complete(&self) -> bool;
1900}
1901
1902pub trait Circuit: CircuitBase + Clone + WithClock {
1915 type Parent;
1917
1918 fn parent(&self) -> Self::Parent;
1920
1921 fn root_circuit(&self) -> RootCircuit;
1923
1924 fn ptr_eq(this: &Self, other: &Self) -> bool;
1926
1927 fn circuit_event_handlers(&self) -> CircuitEventHandlers;
1929
1930 fn scheduler_event_handlers(&self) -> SchedulerEventHandlers;
1932
1933 fn log_circuit_event(&self, event: &CircuitEvent);
1935
1936 fn log_scheduler_event(&self, event: &SchedulerEvent<'_>);
1938
1939 fn map_node<T>(&self, id: &GlobalNodeId, f: &mut dyn FnMut(&dyn Node) -> T) -> T;
1946
1947 fn map_node_mut<T>(&self, id: &GlobalNodeId, f: &mut dyn FnMut(&mut dyn Node) -> T) -> T;
1954
1955 fn map_local_node_mut<T>(&self, id: NodeId, f: &mut dyn FnMut(&mut dyn Node) -> T) -> T;
1961
1962 fn cache_get_or_insert_with<K, F>(&self, key: K, f: F) -> RefMut<'_, K::Value>
1967 where
1968 K: 'static + TypedMapKey<CircuitStoreMarker>,
1969 F: FnMut() -> K::Value;
1970
1971 fn tick(&self);
1974
1975 fn clock_start(&self, scope: Scope);
1977
1978 fn clock_end(&self, scope: Scope);
1980
1981 fn ready(&self, id: NodeId) -> bool;
1984
1985 fn cache_insert<K>(&self, key: K, val: K::Value)
1990 where
1991 K: TypedMapKey<CircuitStoreMarker> + 'static;
1992
1993 fn cache_contains<K>(&self, key: &K) -> bool
1994 where
1995 K: TypedMapKey<CircuitStoreMarker> + 'static;
1996
1997 fn cache_get<K>(&self, key: &K) -> Option<K::Value>
1998 where
1999 K: TypedMapKey<CircuitStoreMarker> + 'static,
2000 K::Value: Clone;
2001
2002 fn get_replay_source(&self, stream_id: StreamId) -> Option<Box<dyn StreamMetadata>> {
2005 self.cache_get(&ReplaySource::new(stream_id))
2006 }
2007
2008 fn add_replay_edges(&self, stream_id: StreamId, replay_stream: &dyn StreamMetadata);
2011
2012 fn connect_stream<T: 'static>(
2014 &self,
2015 stream: &Stream<Self, T>,
2016 to: NodeId,
2017 ownership_preference: OwnershipPreference,
2018 );
2019
2020 fn register_ready_callback(&self, id: NodeId, cb: Box<dyn Fn() + Send + Sync>);
2021
2022 fn is_async_node(&self, id: NodeId) -> bool;
2023
2024 fn eval_node(
2028 &self,
2029 id: NodeId,
2030 ) -> impl Future<Output = Result<Option<Position>, SchedulerError>>;
2031
2032 fn eval_import_node(&self, id: NodeId) -> impl Future<Output = ()>;
2034
2035 fn flush_node(&self, id: NodeId);
2036
2037 fn is_flush_complete(&self, id: NodeId) -> bool;
2038
2039 #[track_caller]
2047 fn region<F, T>(&self, name: &str, f: F) -> T
2048 where
2049 F: FnOnce() -> T;
2050
2051 fn create_region_name(&self, name: &str, id: u64) -> RegionName {
2059 RegionName::new(name, id)
2060 }
2061
2062 #[track_caller]
2075 fn open_region(&self, name: RegionName);
2076
2077 fn close_region(&self, name: RegionName);
2083
2084 fn add_preprocessor(&self, preprocessor_node_id: NodeId);
2088
2089 fn add_source<O, Op>(&self, operator: Op) -> Stream<Self, O>
2091 where
2092 O: Data,
2093 Op: SourceOperator<O>;
2094
2095 fn add_exchange<I, SndOp, O, RcvOp>(
2123 &self,
2124 sender: SndOp,
2125 receiver: RcvOp,
2126 input_stream: &Stream<Self, I>,
2127 ) -> Stream<Self, O>
2128 where
2129 I: Data,
2130 O: Data,
2131 SndOp: SinkOperator<I>,
2132 RcvOp: SourceOperator<O>;
2133
2134 fn add_exchange_with_preference<I, SndOp, O, RcvOp>(
2137 &self,
2138 sender: SndOp,
2139 receiver: RcvOp,
2140 input_stream: &Stream<Self, I>,
2141 input_preference: OwnershipPreference,
2142 ) -> Stream<Self, O>
2143 where
2144 I: Data,
2145 O: Data,
2146 SndOp: SinkOperator<I>,
2147 RcvOp: SourceOperator<O>;
2148
2149 fn add_sink<I, Op>(&self, operator: Op, input_stream: &Stream<Self, I>) -> GlobalNodeId
2151 where
2152 I: Data,
2153 Op: SinkOperator<I>;
2154
2155 fn add_sink_with_preference<I, Op>(
2158 &self,
2159 operator: Op,
2160 input_stream: &Stream<Self, I>,
2161 input_preference: OwnershipPreference,
2162 ) -> GlobalNodeId
2163 where
2164 I: Data,
2165 Op: SinkOperator<I>;
2166
2167 fn add_binary_sink<I1, I2, Op>(
2169 &self,
2170 operator: Op,
2171 input_stream1: &Stream<Self, I1>,
2172 input_stream2: &Stream<Self, I2>,
2173 ) where
2174 I1: Data,
2175 I2: Data,
2176 Op: BinarySinkOperator<I1, I2>;
2177
2178 fn add_binary_sink_with_preference<I1, I2, Op>(
2182 &self,
2183 operator: Op,
2184 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
2185 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
2186 ) where
2187 I1: Data,
2188 I2: Data,
2189 Op: BinarySinkOperator<I1, I2>;
2190
2191 fn add_ternary_sink<I1, I2, I3, Op>(
2193 &self,
2194 operator: Op,
2195 input_stream1: &Stream<Self, I1>,
2196 input_stream2: &Stream<Self, I2>,
2197 input_stream3: &Stream<Self, I3>,
2198 ) -> GlobalNodeId
2199 where
2200 I1: Data,
2201 I2: Data,
2202 I3: Data,
2203 Op: TernarySinkOperator<I1, I2, I3>;
2204
2205 fn add_ternary_sink_with_preference<I1, I2, I3, Op>(
2208 &self,
2209 operator: Op,
2210 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
2211 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
2212 input_stream3: (&Stream<Self, I3>, OwnershipPreference),
2213 ) -> GlobalNodeId
2214 where
2215 I1: Data,
2216 I2: Data,
2217 I3: Data,
2218 Op: TernarySinkOperator<I1, I2, I3>;
2219
2220 fn add_unary_operator<I, O, Op>(
2222 &self,
2223 operator: Op,
2224 input_stream: &Stream<Self, I>,
2225 ) -> Stream<Self, O>
2226 where
2227 I: Data,
2228 O: Data,
2229 Op: UnaryOperator<I, O>;
2230
2231 fn add_unary_operator_with_preference<I, O, Op>(
2234 &self,
2235 operator: Op,
2236 input_stream: &Stream<Self, I>,
2237 input_preference: OwnershipPreference,
2238 ) -> Stream<Self, O>
2239 where
2240 I: Data,
2241 O: Data,
2242 Op: UnaryOperator<I, O>;
2243
2244 fn add_binary_operator<I1, I2, O, Op>(
2246 &self,
2247 operator: Op,
2248 input_stream1: &Stream<Self, I1>,
2249 input_stream2: &Stream<Self, I2>,
2250 ) -> Stream<Self, O>
2251 where
2252 I1: Data,
2253 I2: Data,
2254 O: Data,
2255 Op: BinaryOperator<I1, I2, O>;
2256
2257 fn add_binary_operator_with_preference<I1, I2, O, Op>(
2261 &self,
2262 operator: Op,
2263 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
2264 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
2265 ) -> Stream<Self, O>
2266 where
2267 I1: Data,
2268 I2: Data,
2269 O: Data,
2270 Op: BinaryOperator<I1, I2, O>;
2271
2272 fn add_ternary_operator<I1, I2, I3, O, Op>(
2274 &self,
2275 operator: Op,
2276 input_stream1: &Stream<Self, I1>,
2277 input_stream2: &Stream<Self, I2>,
2278 input_stream3: &Stream<Self, I3>,
2279 ) -> Stream<Self, O>
2280 where
2281 I1: Data,
2282 I2: Data,
2283 I3: Data,
2284 O: Data,
2285 Op: TernaryOperator<I1, I2, I3, O>;
2286
2287 #[allow(clippy::too_many_arguments)]
2290 fn add_ternary_operator_with_preference<I1, I2, I3, O, Op>(
2291 &self,
2292 operator: Op,
2293 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
2294 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
2295 input_stream3: (&Stream<Self, I3>, OwnershipPreference),
2296 ) -> Stream<Self, O>
2297 where
2298 I1: Data,
2299 I2: Data,
2300 I3: Data,
2301 O: Data,
2302 Op: TernaryOperator<I1, I2, I3, O>;
2303
2304 fn add_quaternary_operator<I1, I2, I3, I4, O, Op>(
2306 &self,
2307 operator: Op,
2308 input_stream1: &Stream<Self, I1>,
2309 input_stream2: &Stream<Self, I2>,
2310 input_stream3: &Stream<Self, I3>,
2311 input_stream4: &Stream<Self, I4>,
2312 ) -> Stream<Self, O>
2313 where
2314 I1: Data,
2315 I2: Data,
2316 I3: Data,
2317 I4: Data,
2318 O: Data,
2319 Op: QuaternaryOperator<I1, I2, I3, I4, O>;
2320
2321 #[allow(clippy::too_many_arguments)]
2324 fn add_quaternary_operator_with_preference<I1, I2, I3, I4, O, Op>(
2325 &self,
2326 operator: Op,
2327 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
2328 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
2329 input_stream3: (&Stream<Self, I3>, OwnershipPreference),
2330 input_stream4: (&Stream<Self, I4>, OwnershipPreference),
2331 ) -> Stream<Self, O>
2332 where
2333 I1: Data,
2334 I2: Data,
2335 I3: Data,
2336 I4: Data,
2337 O: Data,
2338 Op: QuaternaryOperator<I1, I2, I3, I4, O>;
2339
2340 fn add_nary_operator<'a, I, O, Op, Iter>(
2342 &'a self,
2343 operator: Op,
2344 input_streams: Iter,
2345 ) -> Stream<Self, O>
2346 where
2347 I: Data,
2348 O: Data,
2349 Op: NaryOperator<I, O>,
2350 Iter: IntoIterator<Item = &'a Stream<Self, I>>;
2351
2352 fn add_nary_operator_with_preference<'a, I, O, Op, Iter>(
2355 &'a self,
2356 operator: Op,
2357 input_streams: Iter,
2358 input_preference: OwnershipPreference,
2359 ) -> Stream<Self, O>
2360 where
2361 I: Data,
2362 O: Data,
2363 Op: NaryOperator<I, O>,
2364 Iter: IntoIterator<Item = &'a Stream<Self, I>>;
2365
2366 fn add_custom_node<N: Node, R>(
2372 &self,
2373 name: Cow<'static, str>,
2374 constructor: impl FnOnce(NodeId) -> (N, R),
2375 ) -> R;
2376
2377 fn add_feedback<I, O, Op>(
2427 &self,
2428 operator: Op,
2429 ) -> (Stream<Self, O>, FeedbackConnector<Self, I, O, Op>)
2430 where
2431 I: Data,
2432 O: Data,
2433 Op: StrictUnaryOperator<I, O>;
2434
2435 fn add_feedback_persistent<I, O, Op>(
2437 &self,
2438 persistent_id: Option<&str>,
2439 operator: Op,
2440 ) -> (Stream<Self, O>, FeedbackConnector<Self, I, O, Op>)
2441 where
2442 I: Data,
2443 O: Data,
2444 Op: StrictUnaryOperator<I, O>,
2445 {
2446 let (output, feedback) = self.add_feedback(operator);
2447
2448 output.set_persistent_id(persistent_id);
2449
2450 (output, feedback)
2451 }
2452
2453 fn add_feedback_with_export<I, O, Op>(
2467 &self,
2468 operator: Op,
2469 ) -> (ExportStream<Self, O>, FeedbackConnector<Self, I, O, Op>)
2470 where
2471 I: Data,
2472 O: Data,
2473 Op: StrictUnaryOperator<I, O>;
2474
2475 fn add_feedback_with_export_persistent<I, O, Op>(
2477 &self,
2478 persistent_id: Option<&str>,
2479 operator: Op,
2480 ) -> (ExportStream<Self, O>, FeedbackConnector<Self, I, O, Op>)
2481 where
2482 I: Data,
2483 O: Data,
2484 Op: StrictUnaryOperator<I, O>,
2485 {
2486 let (export, feedback) = self.add_feedback_with_export(operator);
2487
2488 export.local.set_persistent_id(persistent_id);
2489
2490 (export, feedback)
2491 }
2492
2493 fn connect_feedback_with_preference<I, O, Op>(
2494 &self,
2495 output_node_id: NodeId,
2496 operator: Rc<RefCell<Op>>,
2497 input_stream: &Stream<Self, I>,
2498 input_preference: OwnershipPreference,
2499 ) where
2500 I: Data,
2501 O: Data,
2502 Op: StrictUnaryOperator<I, O>;
2503
2504 fn iterative_subcircuit<F, T, E>(&self, child_constructor: F) -> Result<T, SchedulerError>
2518 where
2519 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<(T, E), SchedulerError>,
2520 E: Executor<IterativeCircuit<Self>>;
2521
2522 fn non_iterative_subcircuit<F, T, E>(&self, child_constructor: F) -> Result<T, SchedulerError>
2525 where
2526 F: FnOnce(&mut NonIterativeCircuit<Self>) -> Result<(T, E), SchedulerError>,
2527 E: Executor<NonIterativeCircuit<Self>>;
2528
2529 fn iterate<F, C, T>(&self, constructor: F) -> Result<T, SchedulerError>
2600 where
2601 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<(C, T), SchedulerError>,
2602 C: AsyncFn() -> Result<bool, SchedulerError> + 'static;
2603
2604 fn iterate_with_scheduler<F, C, T, S>(&self, constructor: F) -> Result<T, SchedulerError>
2609 where
2610 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<(C, T), SchedulerError>,
2611 C: AsyncFn() -> Result<bool, SchedulerError> + 'static,
2612 S: Scheduler + 'static;
2613
2614 fn fixedpoint<F, T>(&self, constructor: F) -> Result<T, SchedulerError>
2650 where
2651 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<T, SchedulerError>;
2652
2653 fn fixedpoint_with_scheduler<F, T, S>(&self, constructor: F) -> Result<T, SchedulerError>
2658 where
2659 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<T, SchedulerError>,
2660 S: Scheduler + 'static;
2661
2662 fn import_stream<I, O, Op>(
2667 &self,
2668 operator: Op,
2669 parent_stream: &Stream<Self::Parent, I>,
2670 ) -> Stream<Self, O>
2671 where
2672 Self::Parent: Circuit,
2673 I: Data,
2674 O: Data,
2675 Op: ImportOperator<I, O>;
2676
2677 fn import_stream_with_preference<I, O, Op>(
2680 &self,
2681 operator: Op,
2682 parent_stream: &Stream<Self::Parent, I>,
2683 input_preference: OwnershipPreference,
2684 ) -> Stream<Self, O>
2685 where
2686 Self::Parent: Circuit,
2687 I: Data,
2688 O: Data,
2689 Op: ImportOperator<I, O>;
2690}
2691
2692pub struct Edges {
2694 by_source: BTreeMap<NodeId, Vec<Rc<Edge>>>,
2695 by_destination: BTreeMap<NodeId, Vec<Rc<Edge>>>,
2696 by_stream: BTreeMap<Option<StreamId>, Vec<Rc<Edge>>>,
2697}
2698
2699impl Edges {
2700 fn new() -> Self {
2701 Self {
2702 by_source: BTreeMap::new(),
2703 by_destination: BTreeMap::new(),
2704 by_stream: BTreeMap::new(),
2705 }
2706 }
2707
2708 fn add_edge(&mut self, edge: Edge) {
2709 let edge = Rc::new(edge);
2710
2711 self.by_source
2712 .entry(edge.from)
2713 .or_default()
2714 .push(edge.clone());
2715 self.by_destination
2716 .entry(edge.to)
2717 .or_default()
2718 .push(edge.clone());
2719
2720 self.by_stream
2721 .entry(edge.stream.as_ref().map(|s| s.stream_id()))
2722 .or_default()
2723 .push(edge);
2724 }
2725
2726 fn extend<I>(&mut self, edges: I)
2727 where
2728 I: IntoIterator<Item = Edge>,
2729 {
2730 for edge in edges {
2731 self.add_edge(edge)
2732 }
2733 }
2734
2735 pub(crate) fn iter(&self) -> impl Iterator<Item = &Edge> {
2736 self.by_source
2737 .values()
2738 .flat_map(|edges| edges.iter().map(|edge| edge.as_ref()))
2739 }
2740
2741 pub(crate) fn get_by_stream_id(&self, stream_id: &Option<StreamId>) -> Option<&[Rc<Edge>]> {
2742 self.by_stream.get(stream_id).map(|v| v.as_slice())
2743 }
2744
2745 fn delete_stream(&mut self, stream_id: StreamId) {
2746 if let Some(edges) = self.by_stream.remove(&Some(stream_id)) {
2747 for edge in edges {
2748 if let Some(v) = self.by_source.get_mut(&edge.from) {
2749 v.retain(|e| e.stream_id() != Some(stream_id))
2750 }
2751 if let Some(v) = self.by_destination.get_mut(&edge.to) {
2752 v.retain(|e| e.stream_id() != Some(stream_id))
2753 }
2754 }
2755 }
2756 }
2757
2758 pub(crate) fn inputs_of(&self, node_id: NodeId) -> impl Iterator<Item = &Edge> {
2759 self.by_destination
2760 .get(&node_id)
2761 .into_iter()
2762 .flatten()
2763 .map(|edge| edge.as_ref())
2764 }
2765
2766 pub(crate) fn depend_on(&self, node_id: NodeId) -> impl Iterator<Item = &Edge> {
2770 self.by_source.get(&node_id).into_iter().flat_map(|edges| {
2771 edges.iter().filter_map(|edge| {
2772 if edge.is_dependency() {
2773 Some(edge.as_ref())
2774 } else {
2775 None
2776 }
2777 })
2778 })
2779 }
2780
2781 pub(crate) fn dependencies_of(&self, node_id: NodeId) -> impl Iterator<Item = &Edge> {
2785 self.by_destination
2786 .get(&node_id)
2787 .into_iter()
2788 .flat_map(|edges| {
2789 edges.iter().filter_map(|edge| {
2790 if edge.is_dependency() {
2791 Some(edge.as_ref())
2792 } else {
2793 None
2794 }
2795 })
2796 })
2797 }
2798
2799 fn clear(&mut self) {
2800 *self = Self::new();
2801 }
2802}
2803
2804struct CircuitInner<P>
2808where
2809 P: 'static,
2810{
2811 parent: P,
2812
2813 root: Option<RootCircuit>,
2815
2816 root_scope: Scope,
2817
2818 node_id: NodeId,
2820 global_node_id: GlobalNodeId,
2821 nodes: RefCell<Vec<RefCell<Box<dyn Node>>>>,
2822 edges: RefCell<Edges>,
2823 import_nodes: RefCell<Vec<NodeId>>,
2824 circuit_event_handlers: CircuitEventHandlers,
2825 scheduler_event_handlers: SchedulerEventHandlers,
2826 store: RefCell<CircuitCache>,
2827 last_stream_id: RefCell<StreamId>,
2828 metadata_exchange: MetadataExchange,
2829 balancer: Rc<Balancer>,
2830}
2831
2832impl<P> CircuitInner<P>
2833where
2834 P: 'static,
2835{
2836 #[allow(clippy::too_many_arguments)]
2837 fn new(
2838 parent: P,
2839 root: Option<RootCircuit>,
2840 root_scope: Scope,
2841 node_id: NodeId,
2842 global_node_id: GlobalNodeId,
2843 circuit_event_handlers: CircuitEventHandlers,
2844 scheduler_event_handlers: SchedulerEventHandlers,
2845 last_stream_id: RefCell<StreamId>,
2846 ) -> Self {
2847 let metadata_exchange = MetadataExchange::new();
2848
2849 Self {
2850 parent,
2851 root,
2852 root_scope,
2853 node_id,
2854 global_node_id,
2855 nodes: RefCell::new(Vec::new()),
2856 edges: RefCell::new(Edges::new()),
2857 import_nodes: RefCell::new(Vec::new()),
2858 circuit_event_handlers,
2859 scheduler_event_handlers,
2860 store: RefCell::new(TypedMap::new()),
2861 last_stream_id,
2862 metadata_exchange: metadata_exchange.clone(),
2863 balancer: Rc::new(Balancer::new(&metadata_exchange)),
2864 }
2865 }
2866
2867 fn add_edge(&self, edge: Edge) {
2868 self.edges.borrow_mut().add_edge(edge);
2869 }
2870
2871 fn add_node<N>(&self, mut node: N)
2872 where
2873 N: Node + 'static,
2874 {
2875 node.init();
2876 self.nodes
2877 .borrow_mut()
2878 .push(RefCell::new(Box::new(node) as Box<dyn Node>));
2879 }
2880
2881 fn add_import_node(&self, node_id: NodeId) {
2882 self.import_nodes.borrow_mut().push(node_id);
2883 }
2884
2885 fn import_nodes(&self) -> Vec<NodeId> {
2886 self.import_nodes.borrow().clone()
2887 }
2888
2889 fn clear(&self) {
2890 self.nodes.borrow_mut().clear();
2891 self.edges.borrow_mut().clear();
2892 self.store.borrow_mut().clear();
2893 }
2894
2895 fn register_circuit_event_handler<F>(&self, name: &str, handler: F)
2896 where
2897 F: Fn(&CircuitEvent) + 'static,
2898 {
2899 self.circuit_event_handlers.borrow_mut().insert(
2900 name.to_string(),
2901 Box::new(handler) as Box<dyn Fn(&CircuitEvent)>,
2902 );
2903 }
2904
2905 fn unregister_circuit_event_handler(&self, name: &str) -> bool {
2906 self.circuit_event_handlers
2907 .borrow_mut()
2908 .remove(name)
2909 .is_some()
2910 }
2911
2912 fn register_scheduler_event_handler<F>(&self, name: &str, handler: F)
2913 where
2914 F: FnMut(&SchedulerEvent<'_>) + 'static,
2915 {
2916 self.scheduler_event_handlers.borrow_mut().insert(
2917 name.to_string(),
2918 Box::new(handler) as Box<dyn FnMut(&SchedulerEvent<'_>)>,
2919 );
2920 }
2921
2922 fn unregister_scheduler_event_handler(&self, name: &str) -> bool {
2923 self.scheduler_event_handlers
2924 .borrow_mut()
2925 .remove(name)
2926 .is_some()
2927 }
2928
2929 fn log_circuit_event(&self, event: &CircuitEvent) {
2930 for (_, handler) in self.circuit_event_handlers.borrow().iter() {
2931 handler(event)
2932 }
2933 }
2934
2935 fn log_scheduler_event(&self, event: &SchedulerEvent<'_>) {
2936 for (_, handler) in self.scheduler_event_handlers.borrow_mut().iter_mut() {
2937 handler(event)
2938 }
2939 }
2940
2941 fn check_fixedpoint(&self, scope: Scope) -> bool {
2942 self.nodes.borrow().iter().all(|node| {
2943 node.borrow().fixedpoint(scope)
2951 })
2952 }
2953
2954 fn lookup_local_node_by_persistent_id(
2955 &self,
2956 persistent_id: &str,
2957 ) -> Result<GlobalNodeId, DbspError> {
2958 self.nodes
2959 .borrow()
2960 .iter()
2961 .find_map(|node| {
2962 if node.borrow().get_label(LABEL_PERSISTENT_OPERATOR_ID) == Some(persistent_id) {
2963 Some(node.borrow().global_id().clone())
2964 } else {
2965 None
2966 }
2967 })
2968 .ok_or_else(|| {
2969 DbspError::Runtime(RuntimeError::UnknownPersistentId(persistent_id.to_string()))
2970 })
2971 }
2972}
2973
2974pub struct ChildCircuit<P, T>
2980where
2981 P: 'static,
2982 T: Timestamp,
2983{
2984 inner: Rc<CircuitInner<P>>,
2985 time: Rc<RefCell<T>>,
2986}
2987
2988pub type RootCircuit = ChildCircuit<(), ()>;
3003
3004pub type NestedCircuit = ChildCircuit<RootCircuit, <() as Timestamp>::Nested>;
3005
3006pub type IterativeCircuit<P> = ChildCircuit<P, <<P as WithClock>::Time as Timestamp>::Nested>;
3008
3009pub type NonIterativeCircuit<P> = ChildCircuit<P, <P as WithClock>::Time>;
3011
3012impl<P, T> Clone for ChildCircuit<P, T>
3013where
3014 P: 'static,
3015 T: Timestamp,
3016{
3017 fn clone(&self) -> Self {
3018 Self {
3019 inner: self.inner.clone(),
3020 time: self.time.clone(),
3021 }
3022 }
3023}
3024
3025impl<P, T> ChildCircuit<P, T>
3026where
3027 P: 'static,
3028 T: Timestamp,
3029{
3030 fn inner(&self) -> &CircuitInner<P> {
3032 &self.inner
3033 }
3034}
3035
3036impl RootCircuit {
3037 pub fn build<F, T>(constructor: F) -> Result<(CircuitHandle, T), DbspError>
3081 where
3082 F: FnOnce(&mut RootCircuit) -> Result<T, AnyError>,
3083 {
3084 Self::build_with_scheduler::<F, T, DynamicScheduler>(constructor)
3085 }
3086
3087 pub fn build_with_scheduler<F, T, S>(constructor: F) -> Result<(CircuitHandle, T), DbspError>
3093 where
3094 F: FnOnce(&mut RootCircuit) -> Result<T, AnyError>,
3095 S: Scheduler + 'static,
3096 {
3097 let tokio_runtime = tokio::runtime::Builder::new_current_thread()
3101 .build()
3102 .map_err(|e| {
3103 DbspError::Scheduler(SchedulerError::TokioError {
3104 error: e.to_string(),
3105 })
3106 })?;
3107
3108 let mut circuit = RootCircuit::new();
3109 let res = constructor(&mut circuit).map_err(DbspError::Constructor)?;
3110 let mut executor = Box::new(<OnceExecutor<S>>::new()) as Box<dyn Executor<RootCircuit>>;
3111 executor.prepare(&circuit, None)?;
3112
3113 circuit.log_scheduler_event(&SchedulerEvent::clock_start());
3150 circuit.clock_start(0);
3151 Ok((
3152 CircuitHandle {
3153 circuit,
3154 executor,
3155 tokio_runtime,
3156 replay_info: None,
3157 },
3158 res,
3159 ))
3160 }
3161}
3162
3163impl RootCircuit {
3164 fn new() -> Self {
3167 Self {
3168 inner: Rc::new(CircuitInner::new(
3169 (),
3170 None,
3171 0,
3172 NodeId::root(),
3173 GlobalNodeId::root(),
3174 Rc::new(RefCell::new(HashMap::new())),
3175 Rc::new(RefCell::new(HashMap::new())),
3176 RefCell::new(StreamId::new(0)),
3177 )),
3178 time: Rc::new(RefCell::new(())),
3179 }
3180 }
3181}
3182
3183impl RootCircuit {
3184 pub fn register_circuit_event_handler<F>(&self, name: &str, handler: F)
3204 where
3205 F: Fn(&CircuitEvent) + 'static,
3206 {
3207 self.inner().register_circuit_event_handler(name, handler);
3208 }
3209
3210 pub fn unregister_circuit_event_handler(&self, name: &str) -> bool {
3213 self.inner().unregister_circuit_event_handler(name)
3214 }
3215
3216 pub fn register_scheduler_event_handler<F>(&self, name: &str, handler: F)
3231 where
3232 F: FnMut(&SchedulerEvent<'_>) + 'static,
3233 {
3234 self.inner().register_scheduler_event_handler(name, handler);
3235 }
3236
3237 pub fn unregister_scheduler_event_handler(&self, name: &str) -> bool {
3240 self.inner().unregister_scheduler_event_handler(name)
3241 }
3242}
3243
3244impl<P, T> ChildCircuit<P, T>
3245where
3246 P: Circuit,
3247 T: Timestamp,
3248{
3249 fn with_parent(parent: P, id: NodeId) -> Self {
3251 let global_node_id = parent.global_node_id().child(id);
3252 let circuit_handlers = parent.circuit_event_handlers();
3253 let sched_handlers = parent.scheduler_event_handlers();
3254 let root_scope = parent.root_scope() + 1;
3255 let last_stream_id = parent.last_stream_id();
3256
3257 let root = parent.root_circuit();
3258
3259 ChildCircuit {
3260 inner: Rc::new(CircuitInner::new(
3261 parent,
3262 Some(root),
3263 root_scope,
3264 id,
3265 global_node_id,
3266 circuit_handlers,
3267 sched_handlers,
3268 last_stream_id,
3269 )),
3270 time: Rc::new(RefCell::new(Timestamp::clock_start())),
3271 }
3272 }
3273
3274 pub fn is_child_of(&self, other: &P) -> bool {
3276 P::ptr_eq(&self.inner().parent, other)
3277 }
3278}
3279
3280impl<P, T> ChildCircuit<P, T>
3282where
3283 P: 'static,
3284 T: Timestamp,
3285 Self: Circuit,
3286{
3287 fn node_id(&self) -> NodeId {
3289 self.inner().node_id
3290 }
3291
3292 fn add_node<F, N, V>(&self, f: F) -> V
3298 where
3299 F: FnOnce(NodeId) -> (N, V),
3300 N: Node + 'static,
3301 {
3302 let id = self.inner().nodes.borrow().len();
3303
3304 let (node, res) = f(NodeId(id));
3307 self.inner().add_node(node);
3308 res
3309 }
3310
3311 fn add_import_node(&self, node_id: NodeId) {
3312 self.inner().add_import_node(node_id);
3313 }
3314
3315 fn try_add_node<F, N, V, E>(&self, f: F) -> Result<V, E>
3317 where
3318 F: FnOnce(NodeId) -> Result<(N, V), E>,
3319 N: Node + 'static,
3320 {
3321 let id = self.inner().nodes.borrow().len();
3322
3323 let (node, res) = f(NodeId(id))?;
3326 self.inner().add_node(node);
3327 Ok(res)
3328 }
3329
3330 fn log_circuit_event(&self, event: &CircuitEvent) {
3333 self.inner().log_circuit_event(event);
3334 }
3335
3336 pub(super) fn log_scheduler_event(&self, event: &SchedulerEvent<'_>) {
3339 self.inner().log_scheduler_event(event);
3340 }
3341}
3342
3343impl<P, T> CircuitBase for ChildCircuit<P, T>
3344where
3345 P: Clone + 'static,
3346 T: Timestamp,
3347{
3348 fn edges(&self) -> Ref<'_, Edges> {
3349 self.inner().edges.borrow()
3350 }
3351
3352 fn transitive_ancestors(&self) -> BTreeMap<NodeId, BTreeSet<NodeId>> {
3353 let edges = self.edges();
3354 let mut result = BTreeMap::new();
3355
3356 for node_id in self.node_ids() {
3358 let mut ancestors = BTreeSet::new();
3359 let mut queue = vec![node_id];
3360
3361 while let Some(current) = queue.pop() {
3363 for edge in edges.inputs_of(current) {
3364 let ancestor_node = edge.from;
3365 if ancestors.insert(ancestor_node) {
3366 queue.push(ancestor_node);
3367 }
3368 }
3369 }
3370
3371 result.insert(node_id, ancestors);
3372 }
3373
3374 result
3375 }
3376
3377 fn edges_mut(&self) -> RefMut<'_, Edges> {
3378 self.inner().edges.borrow_mut()
3379 }
3380
3381 fn num_nodes(&self) -> usize {
3382 self.inner().nodes.borrow().len()
3383 }
3384
3385 fn clear(&mut self) {
3386 self.inner().clear();
3387 }
3388
3389 fn add_dependency(&self, from: NodeId, to: NodeId) {
3390 self.log_circuit_event(&CircuitEvent::dependency(
3391 self.global_node_id().child(from),
3392 self.global_node_id().child(to),
3393 ));
3394
3395 let origin = self.global_node_id().child(from);
3396 self.inner().add_edge(Edge {
3397 from,
3398 to,
3399 origin,
3400 stream: None,
3401 ownership_preference: None,
3402 });
3403 }
3404
3405 fn map_node_relative(&self, path: &[NodeId], f: &mut dyn FnMut(&dyn Node)) {
3407 let nodes = self.inner().nodes.borrow();
3408 let node = nodes[path[0].0].borrow();
3409 if path.len() == 1 {
3410 f(node.as_ref())
3411 } else {
3412 node.map_child(&path[1..], &mut |node| f(node));
3413 }
3414 }
3415
3416 fn map_node_mut_relative(&self, path: &[NodeId], f: &mut dyn FnMut(&mut dyn Node)) {
3418 let nodes = self.inner().nodes.borrow();
3419 let mut node = nodes[path[0].0].borrow_mut();
3420 if path.len() == 1 {
3421 f(node.as_mut())
3422 } else {
3423 node.map_child_mut(&path[1..], &mut |node| f(node));
3424 }
3425 }
3426
3427 fn map_nodes_recursive(
3428 &self,
3429 f: &mut dyn FnMut(&dyn Node) -> Result<(), DbspError>,
3430 ) -> Result<(), DbspError> {
3431 for node in self.inner().nodes.borrow().iter() {
3432 f(node.borrow().as_ref())?;
3433 node.borrow().map_nodes_recursive(f)?;
3434 }
3435 Ok(())
3436 }
3437
3438 fn map_nodes_recursive_mut(
3439 &mut self,
3440 f: &mut dyn FnMut(&mut dyn Node) -> Result<(), DbspError>,
3441 ) -> Result<(), DbspError> {
3442 for node in self.inner().nodes.borrow_mut().iter_mut() {
3443 f(node.borrow_mut().as_mut())?;
3444 node.borrow_mut().map_nodes_recursive_mut(f)?;
3445 }
3446
3447 Ok(())
3448 }
3449
3450 fn map_local_nodes(
3451 &self,
3452 f: &mut dyn FnMut(&dyn Node) -> Result<(), DbspError>,
3453 ) -> Result<(), DbspError> {
3454 for node in self.inner().nodes.borrow().iter() {
3455 f(node.borrow().as_ref())?;
3456 }
3457 Ok(())
3458 }
3459
3460 fn map_local_nodes_mut(
3461 &self,
3462 f: &mut dyn FnMut(&mut dyn Node) -> Result<(), DbspError>,
3463 ) -> Result<(), DbspError> {
3464 for node in self.inner().nodes.borrow_mut().iter_mut() {
3465 f(node.borrow_mut().as_mut())?;
3466 }
3467
3468 Ok(())
3469 }
3470
3471 fn apply_local_node_mut(&self, id: NodeId, f: &mut dyn FnMut(&mut dyn Node)) {
3472 self.map_node_mut_relative(&[id], &mut |node| f(node));
3473 }
3474
3475 fn map_subcircuits(
3476 &self,
3477 f: &mut dyn FnMut(&dyn CircuitBase) -> Result<(), DbspError>,
3478 ) -> Result<(), DbspError> {
3479 for node in self.inner().nodes.borrow().iter() {
3480 let node = node.borrow();
3481 if let Some(child_circuit) = node.as_circuit() {
3482 f(child_circuit)?;
3483 }
3484 }
3485 Ok(())
3486 }
3487
3488 fn set_node_label(&self, id: &GlobalNodeId, key: &str, val: &str) {
3489 self.map_node_mut(id, &mut |node| node.set_label(key, val));
3490 }
3491
3492 fn get_node_label(&self, id: &GlobalNodeId, key: &str) -> Option<String> {
3493 self.map_node(id, &mut |node| node.get_label(key).map(str::to_string))
3494 }
3495
3496 fn global_id(&self) -> &GlobalNodeId {
3497 &self.inner().global_node_id
3498 }
3499
3500 fn node_ids(&self) -> Vec<NodeId> {
3502 self.inner()
3503 .nodes
3504 .borrow()
3505 .iter()
3506 .map(|node| node.borrow().local_id())
3507 .collect()
3508 }
3509
3510 fn lookup_local_node_by_persistent_id(
3511 &self,
3512 persistent_id: &str,
3513 ) -> Result<GlobalNodeId, DbspError> {
3514 self.inner()
3515 .lookup_local_node_by_persistent_id(persistent_id)
3516 }
3517
3518 fn import_nodes(&self) -> Vec<NodeId> {
3519 self.inner().import_nodes()
3520 }
3521
3522 fn allocate_stream_id(&self) -> StreamId {
3523 let circuit = self.inner();
3524 let mut last_stream_id = circuit.last_stream_id.borrow_mut();
3525 last_stream_id.0 += 1;
3526 *last_stream_id
3527 }
3528
3529 fn last_stream_id(&self) -> RefCell<StreamId> {
3530 self.inner().last_stream_id.clone()
3531 }
3532
3533 fn root_scope(&self) -> Scope {
3534 self.inner().root_scope
3535 }
3536
3537 fn node_id(&self) -> NodeId {
3538 self.inner().node_id
3539 }
3540
3541 fn global_node_id(&self) -> GlobalNodeId {
3542 self.inner().global_node_id.clone()
3543 }
3544
3545 fn check_fixedpoint(&self, scope: Scope) -> bool {
3546 self.inner().check_fixedpoint(scope)
3547 }
3548
3549 fn metadata_exchange(&self) -> &MetadataExchange {
3550 &self.inner().metadata_exchange
3551 }
3552
3553 fn balancer(&self) -> &Balancer {
3554 &self.inner().balancer
3555 }
3556
3557 fn set_auto_rebalance(&self, enable: bool) -> Result<(), DbspError> {
3558 self.inner().balancer.set_auto_rebalance(enable)
3559 }
3560
3561 fn set_balancer_hint_by_global_id(
3562 &self,
3563 global_node_id: &GlobalNodeId,
3564 hint: BalancerHint,
3565 ) -> Result<(), DbspError> {
3566 if global_node_id.parent_id() != Some(GlobalNodeId::root()) {
3567 return Err(DbspError::Balancer(BalancerError::NonTopLevelNode(
3568 global_node_id.clone(),
3569 )));
3570 }
3571
3572 self.inner()
3573 .balancer
3574 .set_hint(global_node_id.local_node_id().unwrap(), hint)
3575 }
3576
3577 fn set_balancer_hint(&self, persistent_id: &str, hint: BalancerHint) -> Result<(), DbspError> {
3578 let global_node_id = self.lookup_local_node_by_persistent_id(persistent_id)?;
3579 self.set_balancer_hint_by_global_id(&global_node_id, hint)
3580 }
3581
3582 fn get_current_balancer_policies(&self) -> BTreeMap<NodeId, PartitioningPolicy> {
3583 self.inner().balancer.get_policy()
3584 }
3585
3586 fn get_current_balancer_policy(
3587 &self,
3588 persistent_id: &str,
3589 ) -> Result<PartitioningPolicy, DbspError> {
3590 let global_node_id = self.lookup_local_node_by_persistent_id(persistent_id)?;
3591 let local_node_id = global_node_id.local_node_id().unwrap();
3592 self.inner()
3593 .balancer
3594 .get_policy_for_stream(local_node_id)
3595 .ok_or_else(|| {
3596 DbspError::Balancer(BalancerError::NotRegisteredWithBalancer(local_node_id))
3597 })
3598 }
3599
3600 fn rebalance(&self) {
3601 self.inner().balancer.rebalance()
3602 }
3603
3604 fn start_compaction(&self) {
3605 let _ = self.map_local_nodes_mut(&mut |node| {
3606 node.start_compaction();
3607 Ok(())
3608 });
3609 }
3610
3611 fn is_compaction_complete(&self) -> bool {
3612 let mut complete = true;
3613 let _ = self.map_local_nodes(&mut |node| {
3614 complete &= node.is_compaction_complete();
3615 Ok(())
3616 });
3617 complete
3618 }
3619}
3620
3621impl<P, T> Circuit for ChildCircuit<P, T>
3622where
3623 P: Clone + 'static,
3624 T: Timestamp,
3625{
3626 type Parent = P;
3627
3628 fn parent(&self) -> P {
3629 self.inner().parent.clone()
3630 }
3631
3632 fn root_circuit(&self) -> RootCircuit {
3633 if <dyn Any>::is::<RootCircuit>(self) {
3634 unsafe { transmute::<&Self, &RootCircuit>(self) }.clone()
3635 } else {
3636 self.inner().root.as_ref().unwrap().clone()
3637 }
3638 }
3639
3640 fn map_node<V>(&self, id: &GlobalNodeId, f: &mut dyn FnMut(&dyn Node) -> V) -> V {
3641 let path = id.path();
3642 let mut result: Option<V> = None;
3643
3644 assert!(path.starts_with(self.global_id().path()));
3645
3646 self.map_node_relative(
3647 path.strip_prefix(self.global_id().path()).unwrap(),
3648 &mut |node| result = Some(f(node)),
3649 );
3650 result.unwrap()
3651 }
3652
3653 fn map_node_mut<V>(&self, id: &GlobalNodeId, f: &mut dyn FnMut(&mut dyn Node) -> V) -> V {
3654 let path = id.path();
3655 let mut result: Option<V> = None;
3656
3657 assert!(path.starts_with(self.global_id().path()));
3658
3659 self.map_node_mut_relative(
3660 path.strip_prefix(self.global_id().path()).unwrap(),
3661 &mut |node| result = Some(f(node)),
3662 );
3663 result.unwrap()
3664 }
3665
3666 fn map_local_node_mut<V>(&self, id: NodeId, f: &mut dyn FnMut(&mut dyn Node) -> V) -> V {
3667 let mut result: Option<V> = None;
3668
3669 self.map_node_mut_relative(&[id], &mut |node| result = Some(f(node)));
3670 result.unwrap()
3671 }
3672
3673 fn ptr_eq(this: &Self, other: &Self) -> bool {
3674 Rc::ptr_eq(&this.inner, &other.inner)
3675 }
3676
3677 fn circuit_event_handlers(&self) -> CircuitEventHandlers {
3678 self.inner().circuit_event_handlers.clone()
3679 }
3680
3681 fn scheduler_event_handlers(&self) -> SchedulerEventHandlers {
3682 self.inner().scheduler_event_handlers.clone()
3683 }
3684
3685 fn log_circuit_event(&self, event: &CircuitEvent) {
3686 self.inner().log_circuit_event(event);
3687 }
3688
3689 fn log_scheduler_event(&self, event: &SchedulerEvent<'_>) {
3690 self.inner().log_scheduler_event(event);
3691 }
3692
3693 fn cache_get_or_insert_with<K, F>(&self, key: K, mut f: F) -> RefMut<'_, K::Value>
3694 where
3695 K: 'static + TypedMapKey<CircuitStoreMarker>,
3696 F: FnMut() -> K::Value,
3697 {
3698 if self.inner().store.borrow().contains_key(&key) {
3701 return RefMut::map(self.inner().store.borrow_mut(), |store| {
3702 store.get_mut(&key).unwrap()
3703 });
3704 }
3705
3706 let new = f();
3707
3708 RefMut::map(self.inner().store.borrow_mut(), |store| {
3711 store.entry(key).or_insert(new)
3712 })
3713 }
3714
3715 fn connect_stream<V: 'static>(
3716 &self,
3717 stream: &Stream<Self, V>,
3718 to: NodeId,
3719 ownership_preference: OwnershipPreference,
3720 ) {
3721 self.log_circuit_event(&CircuitEvent::stream(
3722 stream.origin_node_id().clone(),
3723 self.global_node_id().child(to),
3724 ownership_preference,
3725 ));
3726
3727 debug_assert_eq!(self.global_node_id(), stream.circuit.global_node_id());
3728 self.inner().add_edge(Edge {
3729 from: stream.local_node_id(),
3730 to,
3731 origin: stream.origin_node_id().clone(),
3732 stream: Some(Box::new(stream.clone())),
3733 ownership_preference: Some(ownership_preference),
3734 });
3735 }
3736
3737 fn tick(&self) {
3738 let mut time = self.time.borrow_mut();
3739 *time = time.advance(0);
3740 }
3741
3742 fn clock_start(&self, scope: Scope) {
3743 for node in self.inner().nodes.borrow_mut().iter_mut() {
3744 node.borrow_mut().clock_start(scope);
3745 }
3746 }
3747
3748 fn clock_end(&self, scope: Scope) {
3749 for node in self.inner().nodes.borrow_mut().iter_mut() {
3750 node.borrow_mut().clock_end(scope);
3751 }
3752
3753 let mut time = self.time.borrow_mut();
3754 *time = time.advance(scope + 1);
3755 }
3756
3757 fn ready(&self, id: NodeId) -> bool {
3758 self.inner().nodes.borrow()[id.0].borrow().ready()
3759 }
3760
3761 fn cache_insert<K>(&self, key: K, val: K::Value)
3762 where
3763 K: TypedMapKey<CircuitStoreMarker> + 'static,
3764 {
3765 self.inner().store.borrow_mut().insert(key, val);
3766 }
3767
3768 fn cache_contains<K>(&self, key: &K) -> bool
3769 where
3770 K: TypedMapKey<CircuitStoreMarker> + 'static,
3771 {
3772 self.inner().store.borrow().contains_key(key)
3773 }
3774
3775 fn cache_get<K>(&self, key: &K) -> Option<K::Value>
3776 where
3777 K: TypedMapKey<CircuitStoreMarker> + 'static,
3778 K::Value: Clone,
3779 {
3780 self.inner().store.borrow().get(key).cloned()
3781 }
3782
3783 fn register_ready_callback(&self, id: NodeId, cb: Box<dyn Fn() + Send + Sync>) {
3784 self.inner().nodes.borrow()[id.0]
3785 .borrow_mut()
3786 .register_ready_callback(cb);
3787 }
3788
3789 fn is_async_node(&self, id: NodeId) -> bool {
3790 self.inner().nodes.borrow()[id.0].borrow().is_async()
3791 }
3792
3793 #[allow(clippy::await_holding_refcell_ref)]
3795 async fn eval_node(&self, id: NodeId) -> Result<Option<Position>, SchedulerError> {
3796 let circuit = self.inner();
3797 debug_assert!(id.0 < circuit.nodes.borrow().len());
3798
3799 circuit.log_scheduler_event(&SchedulerEvent::eval_start(
3804 circuit.nodes.borrow()[id.0].borrow().as_ref(),
3805 ));
3806
3807 let span = Span::new("eval").with_category("Operator");
3808 let (result, elapsed_time) =
3809 Timed::new(circuit.nodes.borrow()[id.0].borrow_mut().eval()).await;
3810 let progress = result?;
3811 span.with_tooltip(|| {
3812 let nodes = circuit.nodes.borrow();
3813 let node = nodes[id.0].borrow();
3814 format!(
3815 "{} {} used {}μs real time, {}μs CPU time",
3816 node.name(),
3817 node.global_id().node_identifier(),
3818 elapsed_time.real.as_micros(),
3819 elapsed_time.cpu.as_micros(),
3820 )
3821 })
3822 .record();
3823
3824 circuit.log_scheduler_event(&SchedulerEvent::eval_end(
3825 circuit.nodes.borrow()[id.0].borrow().as_ref(),
3826 elapsed_time,
3827 ));
3828
3829 Ok(progress)
3830 }
3831
3832 #[allow(clippy::await_holding_refcell_ref)]
3834 async fn eval_import_node(&self, id: NodeId) {
3835 let circuit = self.inner();
3836 debug_assert!(id.0 < circuit.nodes.borrow().len());
3837 debug_assert!(circuit.import_nodes().contains(&id));
3838
3839 circuit.nodes.borrow()[id.0].borrow_mut().import().await;
3846 }
3847
3848 fn flush_node(&self, id: NodeId) {
3849 let circuit = self.inner();
3850 debug_assert!(id.0 < circuit.nodes.borrow().len());
3851
3852 circuit.nodes.borrow()[id.0].borrow_mut().flush();
3853 }
3854
3855 fn is_flush_complete(&self, id: NodeId) -> bool {
3856 let circuit = self.inner();
3857 debug_assert!(id.0 < circuit.nodes.borrow().len());
3858
3859 circuit.nodes.borrow()[id.0].borrow().is_flush_complete()
3860 }
3861
3862 #[track_caller]
3863 fn region<F, V>(&self, name: &str, f: F) -> V
3864 where
3865 F: FnOnce() -> V,
3866 {
3867 self.log_circuit_event(&CircuitEvent::push_region(name, Some(Location::caller())));
3868 let res = f();
3869 self.log_circuit_event(&CircuitEvent::pop_region());
3870 res
3871 }
3872
3873 #[track_caller]
3874 fn open_region(&self, name: RegionName) {
3875 self.log_circuit_event(&CircuitEvent::open_region(name, Some(Location::caller())));
3876 }
3877
3878 fn close_region(&self, name: RegionName) {
3879 self.log_circuit_event(&CircuitEvent::close_region(name));
3880 }
3881
3882 fn add_preprocessor(&self, preprocessor_node_id: NodeId) {
3883 for node in self.inner().nodes.borrow_mut().iter() {
3884 if node.borrow().is_input() {
3885 self.add_dependency(preprocessor_node_id, node.borrow().local_id());
3886 }
3887 }
3888 }
3889
3890 fn add_source<O, Op>(&self, operator: Op) -> Stream<Self, O>
3892 where
3893 O: Data,
3894 Op: SourceOperator<O>,
3895 {
3896 self.add_node(|id| {
3897 self.log_circuit_event(&CircuitEvent::operator(
3898 GlobalNodeId::child_of(self, id),
3899 operator.name(),
3900 operator.location(),
3901 ));
3902
3903 let node = SourceNode::new(operator, self.clone(), id);
3904 let output_stream = node.output_stream();
3905 (node, output_stream)
3906 })
3907 }
3908
3909 fn add_exchange<I, SndOp, O, RcvOp>(
3910 &self,
3911 sender: SndOp,
3912 receiver: RcvOp,
3913 input_stream: &Stream<Self, I>,
3914 ) -> Stream<Self, O>
3915 where
3916 I: Data,
3917 O: Data,
3918 SndOp: SinkOperator<I>,
3919 RcvOp: SourceOperator<O>,
3920 {
3921 let preference = sender.input_preference();
3922 self.add_exchange_with_preference(sender, receiver, input_stream, preference)
3923 }
3924
3925 fn add_exchange_with_preference<I, SndOp, O, RcvOp>(
3926 &self,
3927 sender: SndOp,
3928 receiver: RcvOp,
3929 input_stream: &Stream<Self, I>,
3930 input_preference: OwnershipPreference,
3931 ) -> Stream<Self, O>
3932 where
3933 I: Data,
3934 O: Data,
3935 SndOp: SinkOperator<I>,
3936 RcvOp: SourceOperator<O>,
3937 {
3938 let sender_id = self.add_node(|id| {
3939 self.log_circuit_event(&CircuitEvent::operator(
3940 GlobalNodeId::child_of(self, id),
3941 sender.name(),
3942 sender.location(),
3943 ));
3944
3945 let node = SinkNode::new(sender, input_stream.clone(), self.clone(), id);
3946 self.connect_stream(input_stream, id, input_preference);
3947 (node, id)
3948 });
3949
3950 let output_stream = self.add_node(|id| {
3951 self.log_circuit_event(&CircuitEvent::operator(
3952 GlobalNodeId::child_of(self, id),
3953 receiver.name(),
3954 receiver.location(),
3955 ));
3956
3957 let node = SourceNode::new(receiver, self.clone(), id);
3958 let output_stream = node.output_stream();
3959 (node, output_stream)
3960 });
3961
3962 self.add_dependency(sender_id, output_stream.local_node_id());
3963 output_stream
3964 }
3965
3966 fn add_sink<I, Op>(&self, operator: Op, input_stream: &Stream<Self, I>) -> GlobalNodeId
3967 where
3968 I: Data,
3969 Op: SinkOperator<I>,
3970 {
3971 let preference = operator.input_preference();
3972 self.add_sink_with_preference(operator, input_stream, preference)
3973 }
3974
3975 fn add_sink_with_preference<I, Op>(
3976 &self,
3977 operator: Op,
3978 input_stream: &Stream<Self, I>,
3979 input_preference: OwnershipPreference,
3980 ) -> GlobalNodeId
3981 where
3982 I: Data,
3983 Op: SinkOperator<I>,
3984 {
3985 self.add_node(|id| {
3986 let global_node_id = GlobalNodeId::child_of(self, id);
3987 self.log_circuit_event(&CircuitEvent::operator(
3990 global_node_id.clone(),
3991 operator.name(),
3992 operator.location(),
3993 ));
3994
3995 self.connect_stream(input_stream, id, input_preference);
3996 (
3997 SinkNode::new(operator, input_stream.clone(), self.clone(), id),
3998 global_node_id,
3999 )
4000 })
4001 }
4002
4003 fn add_binary_sink<I1, I2, Op>(
4005 &self,
4006 operator: Op,
4007 input_stream1: &Stream<Self, I1>,
4008 input_stream2: &Stream<Self, I2>,
4009 ) where
4010 I1: Data,
4011 I2: Data,
4012 Op: BinarySinkOperator<I1, I2>,
4013 {
4014 let (preference1, preference2) = operator.input_preference();
4015 self.add_binary_sink_with_preference(
4016 operator,
4017 (input_stream1, preference1),
4018 (input_stream2, preference2),
4019 )
4020 }
4021
4022 fn add_binary_sink_with_preference<I1, I2, Op>(
4023 &self,
4024 operator: Op,
4025 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
4026 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
4027 ) where
4028 I1: Data,
4029 I2: Data,
4030 Op: BinarySinkOperator<I1, I2>,
4031 {
4032 let (input_stream1, input_preference1) = input_stream1;
4033 let (input_stream2, input_preference2) = input_stream2;
4034
4035 self.add_node(|id| {
4036 self.log_circuit_event(&CircuitEvent::operator(
4037 GlobalNodeId::child_of(self, id),
4038 operator.name(),
4039 operator.location(),
4040 ));
4041
4042 let node = BinarySinkNode::new(
4043 operator,
4044 input_stream1.clone(),
4045 input_stream2.clone(),
4046 self.clone(),
4047 id,
4048 );
4049 self.connect_stream(input_stream1, id, input_preference1);
4050 self.connect_stream(input_stream2, id, input_preference2);
4051 (node, ())
4052 });
4053 }
4054
4055 fn add_ternary_sink<I1, I2, I3, Op>(
4057 &self,
4058 operator: Op,
4059 input_stream1: &Stream<Self, I1>,
4060 input_stream2: &Stream<Self, I2>,
4061 input_stream3: &Stream<Self, I3>,
4062 ) -> GlobalNodeId
4063 where
4064 I1: Data,
4065 I2: Data,
4066 I3: Data,
4067 Op: TernarySinkOperator<I1, I2, I3>,
4068 {
4069 let (preference1, preference2, preference3) = operator.input_preference();
4070 self.add_ternary_sink_with_preference(
4071 operator,
4072 (input_stream1, preference1),
4073 (input_stream2, preference2),
4074 (input_stream3, preference3),
4075 )
4076 }
4077
4078 fn add_ternary_sink_with_preference<I1, I2, I3, Op>(
4079 &self,
4080 operator: Op,
4081 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
4082 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
4083 input_stream3: (&Stream<Self, I3>, OwnershipPreference),
4084 ) -> GlobalNodeId
4085 where
4086 I1: Data,
4087 I2: Data,
4088 I3: Data,
4089 Op: TernarySinkOperator<I1, I2, I3>,
4090 {
4091 let (input_stream1, input_preference1) = input_stream1;
4092 let (input_stream2, input_preference2) = input_stream2;
4093 let (input_stream3, input_preference3) = input_stream3;
4094
4095 self.add_node(|id| {
4096 let global_node_id = GlobalNodeId::child_of(self, id);
4097
4098 self.log_circuit_event(&CircuitEvent::operator(
4099 GlobalNodeId::child_of(self, id),
4100 operator.name(),
4101 operator.location(),
4102 ));
4103
4104 let node = TernarySinkNode::new(
4105 operator,
4106 input_stream1.clone(),
4107 input_stream2.clone(),
4108 input_stream3.clone(),
4109 self.clone(),
4110 id,
4111 );
4112 self.connect_stream(input_stream1, id, input_preference1);
4113 self.connect_stream(input_stream2, id, input_preference2);
4114 self.connect_stream(input_stream3, id, input_preference3);
4115 (node, global_node_id)
4116 })
4117 }
4118
4119 fn add_unary_operator<I, O, Op>(
4120 &self,
4121 operator: Op,
4122 input_stream: &Stream<Self, I>,
4123 ) -> Stream<Self, O>
4124 where
4125 I: Data,
4126 O: Data,
4127 Op: UnaryOperator<I, O>,
4128 {
4129 let preference = operator.input_preference();
4130 self.add_unary_operator_with_preference(operator, input_stream, preference)
4131 }
4132
4133 fn add_unary_operator_with_preference<I, O, Op>(
4134 &self,
4135 operator: Op,
4136 input_stream: &Stream<Self, I>,
4137 input_preference: OwnershipPreference,
4138 ) -> Stream<Self, O>
4139 where
4140 I: Data,
4141 O: Data,
4142 Op: UnaryOperator<I, O>,
4143 {
4144 self.add_node(|id| {
4145 self.log_circuit_event(&CircuitEvent::operator(
4146 GlobalNodeId::child_of(self, id),
4147 operator.name(),
4148 operator.location(),
4149 ));
4150
4151 let node = UnaryNode::new(operator, input_stream.clone(), self.clone(), id);
4152 let output_stream = node.output_stream();
4153 self.connect_stream(input_stream, id, input_preference);
4154 (node, output_stream)
4155 })
4156 }
4157
4158 fn add_binary_operator<I1, I2, O, Op>(
4159 &self,
4160 operator: Op,
4161 input_stream1: &Stream<Self, I1>,
4162 input_stream2: &Stream<Self, I2>,
4163 ) -> Stream<Self, O>
4164 where
4165 I1: Data,
4166 I2: Data,
4167 O: Data,
4168 Op: BinaryOperator<I1, I2, O>,
4169 {
4170 let (pref1, pref2) = operator.input_preference();
4171 self.add_binary_operator_with_preference(
4172 operator,
4173 (input_stream1, pref1),
4174 (input_stream2, pref2),
4175 )
4176 }
4177
4178 fn add_binary_operator_with_preference<I1, I2, O, Op>(
4179 &self,
4180 operator: Op,
4181 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
4182 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
4183 ) -> Stream<Self, O>
4184 where
4185 I1: Data,
4186 I2: Data,
4187 O: Data,
4188 Op: BinaryOperator<I1, I2, O>,
4189 {
4190 let (input_stream1, input_preference1) = input_stream1;
4191 let (input_stream2, input_preference2) = input_stream2;
4192
4193 self.add_node(|id| {
4194 self.log_circuit_event(&CircuitEvent::operator(
4195 GlobalNodeId::child_of(self, id),
4196 operator.name(),
4197 operator.location(),
4198 ));
4199
4200 let node = BinaryNode::new(
4201 operator,
4202 input_stream1.clone(),
4203 input_stream2.clone(),
4204 self.clone(),
4205 id,
4206 );
4207 let output_stream = node.output_stream();
4208 self.connect_stream(input_stream1, id, input_preference1);
4209 self.connect_stream(input_stream2, id, input_preference2);
4210 (node, output_stream)
4211 })
4212 }
4213
4214 fn add_ternary_operator<I1, I2, I3, O, Op>(
4215 &self,
4216 operator: Op,
4217 input_stream1: &Stream<Self, I1>,
4218 input_stream2: &Stream<Self, I2>,
4219 input_stream3: &Stream<Self, I3>,
4220 ) -> Stream<Self, O>
4221 where
4222 I1: Data,
4223 I2: Data,
4224 I3: Data,
4225 O: Data,
4226 Op: TernaryOperator<I1, I2, I3, O>,
4227 {
4228 let (pref1, pref2, pref3) = operator.input_preference();
4229 self.add_ternary_operator_with_preference(
4230 operator,
4231 (input_stream1, pref1),
4232 (input_stream2, pref2),
4233 (input_stream3, pref3),
4234 )
4235 }
4236
4237 #[allow(clippy::too_many_arguments)]
4238 fn add_ternary_operator_with_preference<I1, I2, I3, O, Op>(
4239 &self,
4240 operator: Op,
4241 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
4242 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
4243 input_stream3: (&Stream<Self, I3>, OwnershipPreference),
4244 ) -> Stream<Self, O>
4245 where
4246 I1: Data,
4247 I2: Data,
4248 I3: Data,
4249 O: Data,
4250 Op: TernaryOperator<I1, I2, I3, O>,
4251 {
4252 let (input_stream1, input_preference1) = input_stream1;
4253 let (input_stream2, input_preference2) = input_stream2;
4254 let (input_stream3, input_preference3) = input_stream3;
4255
4256 self.add_node(|id| {
4257 self.log_circuit_event(&CircuitEvent::operator(
4258 GlobalNodeId::child_of(self, id),
4259 operator.name(),
4260 operator.location(),
4261 ));
4262
4263 let node = TernaryNode::new(
4264 operator,
4265 input_stream1.clone(),
4266 input_stream2.clone(),
4267 input_stream3.clone(),
4268 self.clone(),
4269 id,
4270 );
4271 let output_stream = node.output_stream();
4272 self.connect_stream(input_stream1, id, input_preference1);
4273 self.connect_stream(input_stream2, id, input_preference2);
4274 self.connect_stream(input_stream3, id, input_preference3);
4275 (node, output_stream)
4276 })
4277 }
4278
4279 fn add_quaternary_operator<I1, I2, I3, I4, O, Op>(
4280 &self,
4281 operator: Op,
4282 input_stream1: &Stream<Self, I1>,
4283 input_stream2: &Stream<Self, I2>,
4284 input_stream3: &Stream<Self, I3>,
4285 input_stream4: &Stream<Self, I4>,
4286 ) -> Stream<Self, O>
4287 where
4288 I1: Data,
4289 I2: Data,
4290 I3: Data,
4291 I4: Data,
4292 O: Data,
4293 Op: QuaternaryOperator<I1, I2, I3, I4, O>,
4294 {
4295 let (pref1, pref2, pref3, pref4) = operator.input_preference();
4296 self.add_quaternary_operator_with_preference(
4297 operator,
4298 (input_stream1, pref1),
4299 (input_stream2, pref2),
4300 (input_stream3, pref3),
4301 (input_stream4, pref4),
4302 )
4303 }
4304
4305 #[allow(clippy::too_many_arguments)]
4306 fn add_quaternary_operator_with_preference<I1, I2, I3, I4, O, Op>(
4307 &self,
4308 operator: Op,
4309 input_stream1: (&Stream<Self, I1>, OwnershipPreference),
4310 input_stream2: (&Stream<Self, I2>, OwnershipPreference),
4311 input_stream3: (&Stream<Self, I3>, OwnershipPreference),
4312 input_stream4: (&Stream<Self, I4>, OwnershipPreference),
4313 ) -> Stream<Self, O>
4314 where
4315 I1: Data,
4316 I2: Data,
4317 I3: Data,
4318 I4: Data,
4319 O: Data,
4320 Op: QuaternaryOperator<I1, I2, I3, I4, O>,
4321 {
4322 let (input_stream1, input_preference1) = input_stream1;
4323 let (input_stream2, input_preference2) = input_stream2;
4324 let (input_stream3, input_preference3) = input_stream3;
4325 let (input_stream4, input_preference4) = input_stream4;
4326
4327 self.add_node(|id| {
4328 self.log_circuit_event(&CircuitEvent::operator(
4329 GlobalNodeId::child_of(self, id),
4330 operator.name(),
4331 operator.location(),
4332 ));
4333
4334 let node = QuaternaryNode::new(
4335 operator,
4336 input_stream1.clone(),
4337 input_stream2.clone(),
4338 input_stream3.clone(),
4339 input_stream4.clone(),
4340 self.clone(),
4341 id,
4342 );
4343 let output_stream = node.output_stream();
4344 self.connect_stream(input_stream1, id, input_preference1);
4345 self.connect_stream(input_stream2, id, input_preference2);
4346 self.connect_stream(input_stream3, id, input_preference3);
4347 self.connect_stream(input_stream4, id, input_preference4);
4348 (node, output_stream)
4349 })
4350 }
4351
4352 fn add_nary_operator<'a, I, O, Op, Iter>(
4353 &'a self,
4354 operator: Op,
4355 input_streams: Iter,
4356 ) -> Stream<Self, O>
4357 where
4358 I: Data,
4359 O: Data,
4360 Op: NaryOperator<I, O>,
4361 Iter: IntoIterator<Item = &'a Stream<Self, I>>,
4362 {
4363 let pref = operator.input_preference();
4364 self.add_nary_operator_with_preference(operator, input_streams, pref)
4365 }
4366
4367 fn add_nary_operator_with_preference<'a, I, O, Op, Iter>(
4368 &'a self,
4369 operator: Op,
4370 input_streams: Iter,
4371 input_preference: OwnershipPreference,
4372 ) -> Stream<Self, O>
4373 where
4374 I: Data,
4375 O: Data,
4376 Op: NaryOperator<I, O>,
4377 Iter: IntoIterator<Item = &'a Stream<Self, I>>,
4378 {
4379 let input_streams: Vec<Stream<_, _>> = input_streams.into_iter().cloned().collect();
4380 self.add_node(|id| {
4381 self.log_circuit_event(&CircuitEvent::operator(
4382 GlobalNodeId::child_of(self, id),
4383 operator.name(),
4384 operator.location(),
4385 ));
4386
4387 let node = NaryNode::new(operator, input_streams.clone(), self.clone(), id);
4388 let output_stream = node.output_stream();
4389 for stream in input_streams.iter() {
4390 self.connect_stream(stream, id, input_preference);
4391 }
4392 (node, output_stream)
4393 })
4394 }
4395
4396 #[track_caller]
4397 fn add_custom_node<N: Node, R>(
4398 &self,
4399 name: Cow<'static, str>,
4400 constructor: impl FnOnce(NodeId) -> (N, R),
4401 ) -> R {
4402 self.add_node(|id| {
4403 self.log_circuit_event(&CircuitEvent::operator(
4406 GlobalNodeId::child_of(self, id),
4407 name,
4408 Some(Location::caller()),
4409 ));
4410 let (node, res) = constructor(id);
4411 (node, res)
4412 })
4413 }
4414
4415 fn add_feedback<I, O, Op>(
4416 &self,
4417 operator: Op,
4418 ) -> (Stream<Self, O>, FeedbackConnector<Self, I, O, Op>)
4419 where
4420 I: Data,
4421 O: Data,
4422 Op: StrictUnaryOperator<I, O>,
4423 {
4424 self.add_node(|id| {
4425 self.log_circuit_event(&CircuitEvent::strict_operator_output(
4426 GlobalNodeId::child_of(self, id),
4427 operator.name(),
4428 operator.location(),
4429 ));
4430
4431 let operator = Rc::new(RefCell::new(operator));
4432 let connector = FeedbackConnector::new(id, self.clone(), operator.clone());
4433 let output_node = FeedbackOutputNode::new(operator, self.clone(), id);
4434 let local = output_node.output_stream();
4435 (output_node, (local, connector))
4436 })
4437 }
4438
4439 fn add_feedback_with_export<I, O, Op>(
4440 &self,
4441 operator: Op,
4442 ) -> (ExportStream<Self, O>, FeedbackConnector<Self, I, O, Op>)
4443 where
4444 I: Data,
4445 O: Data,
4446 Op: StrictUnaryOperator<I, O>,
4447 {
4448 self.add_node(|id| {
4449 self.log_circuit_event(&CircuitEvent::strict_operator_output(
4450 GlobalNodeId::child_of(self, id),
4451 operator.name(),
4452 operator.location(),
4453 ));
4454
4455 let operator = Rc::new(RefCell::new(operator));
4456 let connector = FeedbackConnector::new(id, self.clone(), operator.clone());
4457 let output_node = FeedbackOutputNode::with_export(operator, self.clone(), id);
4458 let local = output_node.output_stream();
4459 let export = output_node.export_stream.clone().unwrap();
4460 (output_node, (ExportStream { local, export }, connector))
4461 })
4462 }
4463
4464 fn connect_feedback_with_preference<I, O, Op>(
4468 &self,
4469 output_node_id: NodeId,
4470 operator: Rc<RefCell<Op>>,
4471 input_stream: &Stream<Self, I>,
4472 input_preference: OwnershipPreference,
4473 ) where
4474 I: Data,
4475 O: Data,
4476 Op: StrictUnaryOperator<I, O>,
4477 {
4478 self.add_node(|id| {
4479 self.log_circuit_event(&CircuitEvent::strict_operator_input(
4480 GlobalNodeId::child_of(self, id),
4481 output_node_id,
4482 ));
4483
4484 let output_node = FeedbackInputNode::new(operator, input_stream.clone(), id);
4485 self.connect_stream(input_stream, id, input_preference);
4486 self.add_dependency(output_node_id, id);
4487 (output_node, ())
4488 })
4489 }
4490
4491 fn iterative_subcircuit<F, V, E>(&self, child_constructor: F) -> Result<V, SchedulerError>
4492 where
4493 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<(V, E), SchedulerError>,
4494 E: Executor<IterativeCircuit<Self>>,
4495 {
4496 self.try_add_node(|id| {
4497 let global_id = GlobalNodeId::child_of(self, id);
4498 self.log_circuit_event(&CircuitEvent::subcircuit(global_id.clone(), true));
4499 let mut child_circuit = ChildCircuit::with_parent(self.clone(), id);
4500 let (res, executor) = child_constructor(&mut child_circuit)?;
4501 let child = <ChildNode<IterativeCircuit<Self>>>::new::<E>(child_circuit, 1, executor);
4502 self.log_circuit_event(&CircuitEvent::subcircuit_complete(global_id));
4503 Ok((child, res))
4504 })
4505 }
4506
4507 fn non_iterative_subcircuit<F, V, E>(&self, child_constructor: F) -> Result<V, SchedulerError>
4508 where
4509 F: FnOnce(&mut NonIterativeCircuit<Self>) -> Result<(V, E), SchedulerError>,
4510 E: Executor<NonIterativeCircuit<Self>>,
4511 {
4512 self.try_add_node(|id| {
4513 let global_id = GlobalNodeId::child_of(self, id);
4514 self.log_circuit_event(&CircuitEvent::subcircuit(global_id.clone(), false));
4515 let mut child_circuit = ChildCircuit::with_parent(self.clone(), id);
4516 let (res, executor) = child_constructor(&mut child_circuit)?;
4517 let child =
4518 <ChildNode<NonIterativeCircuit<Self>>>::new::<E>(child_circuit, 0, executor);
4519 self.log_circuit_event(&CircuitEvent::subcircuit_complete(global_id));
4520 Ok((child, res))
4521 })
4522 }
4523
4524 fn iterate<F, C, V>(&self, constructor: F) -> Result<V, SchedulerError>
4525 where
4526 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<(C, V), SchedulerError>,
4527 C: AsyncFn() -> Result<bool, SchedulerError> + 'static,
4528 {
4529 self.iterate_with_scheduler::<F, C, V, DynamicScheduler>(constructor)
4530 }
4531
4532 fn iterate_with_scheduler<F, C, V, S>(&self, constructor: F) -> Result<V, SchedulerError>
4537 where
4538 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<(C, V), SchedulerError>,
4539 C: AsyncFn() -> Result<bool, SchedulerError> + 'static,
4540 S: Scheduler + 'static,
4541 {
4542 self.iterative_subcircuit(|child| {
4543 let (termination_check, res) = constructor(child)?;
4544 let mut executor = <IterativeExecutor<_, S>>::new(termination_check);
4545 executor.prepare(child, None)?;
4546 Ok((res, executor))
4547 })
4548 }
4549
4550 fn fixedpoint<F, V>(&self, constructor: F) -> Result<V, SchedulerError>
4551 where
4552 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<V, SchedulerError>,
4553 {
4554 self.fixedpoint_with_scheduler::<F, V, DynamicScheduler>(constructor)
4555 }
4556
4557 fn fixedpoint_with_scheduler<F, V, S>(&self, constructor: F) -> Result<V, SchedulerError>
4558 where
4559 F: FnOnce(&mut IterativeCircuit<Self>) -> Result<V, SchedulerError>,
4560 S: Scheduler + 'static,
4561 {
4562 self.iterative_subcircuit(|child| {
4563 let res = constructor(child)?;
4564 let child_clone = child.clone();
4565
4566 let consensus = Consensus::new("fixed point");
4567
4568 let termination_check = async move || {
4569 let local_fixedpoint = child_clone.inner().check_fixedpoint(0);
4571 consensus.check(local_fixedpoint).await
4572 };
4573 let mut executor = <IterativeExecutor<_, S>>::new(termination_check);
4574 executor.prepare(child, None)?;
4575 Ok((res, executor))
4576 })
4577 }
4578
4579 fn import_stream<I, O, Op>(&self, operator: Op, parent_stream: &Stream<P, I>) -> Stream<Self, O>
4580 where
4581 Self::Parent: Circuit,
4582 I: Data,
4583 O: Data,
4584 Op: ImportOperator<I, O>,
4585 {
4586 let preference = operator.input_preference();
4587 self.import_stream_with_preference(operator, parent_stream, preference)
4588 }
4589
4590 fn import_stream_with_preference<I, O, Op>(
4591 &self,
4592 operator: Op,
4593 parent_stream: &Stream<P, I>,
4594 input_preference: OwnershipPreference,
4595 ) -> Stream<Self, O>
4596 where
4597 Self::Parent: Circuit,
4598 I: Data,
4599 O: Data,
4600 Op: ImportOperator<I, O>,
4601 {
4602 assert!(self.is_child_of(parent_stream.circuit()));
4603
4604 let output_stream = self.add_node(|id| {
4605 let node_id = self.global_node_id().child(id);
4606 self.log_circuit_event(&CircuitEvent::operator(
4607 node_id.clone(),
4608 operator.name(),
4609 operator.location(),
4610 ));
4611 let node = ImportNode::new(operator, self.clone(), parent_stream.clone(), id);
4612 self.parent()
4614 .connect_stream(parent_stream, self.node_id(), input_preference);
4615 self.parent().log_circuit_event(&CircuitEvent::stream(
4617 parent_stream.origin_node_id().clone(),
4618 node_id.clone(),
4619 input_preference,
4620 ));
4621 let output_stream = node.output_stream();
4622 (node, output_stream)
4623 });
4624
4625 self.add_import_node(output_stream.local_node_id());
4626
4627 output_stream
4628 }
4629
4630 fn add_replay_edges(&self, stream_id: StreamId, replay_stream: &dyn StreamMetadata) {
4631 let mut edges = self.edges_mut();
4632 let mut new_edges = Vec::new();
4633
4634 let Some(edges_to_replay) = edges.get_by_stream_id(&Some(stream_id)) else {
4635 return;
4636 };
4637
4638 for edge in edges_to_replay {
4639 new_edges.push(Edge {
4646 from: replay_stream.local_node_id(),
4647 to: edge.to,
4648 origin: replay_stream.origin_node_id().clone(),
4649 stream: Some(clone_box(replay_stream)),
4650 ownership_preference: edge.ownership_preference,
4651 });
4652 }
4653
4654 edges.extend(new_edges);
4655 }
4656}
4657struct ImportNode<C, I, O, Op>
4658where
4659 C: Circuit,
4660{
4661 id: GlobalNodeId,
4662 operator: Op,
4663 parent_stream: Stream<C::Parent, I>,
4664 output_stream: Stream<C, O>,
4665 labels: BTreeMap<String, String>,
4666}
4667
4668impl<C, I, O, Op> ImportNode<C, I, O, Op>
4669where
4670 C: Circuit,
4671 C::Parent: Circuit,
4672 I: Clone + 'static,
4673 O: Clone + 'static,
4674 Op: ImportOperator<I, O>,
4675{
4676 fn new(operator: Op, circuit: C, parent_stream: Stream<C::Parent, I>, id: NodeId) -> Self {
4677 assert!(Circuit::ptr_eq(&circuit.parent(), parent_stream.circuit()));
4678
4679 Self {
4680 id: circuit.global_node_id().child(id),
4681 operator,
4682 parent_stream,
4683 output_stream: Stream::new(circuit, id),
4684 labels: BTreeMap::new(),
4685 }
4686 }
4687
4688 fn output_stream(&self) -> Stream<C, O> {
4689 self.output_stream.clone()
4690 }
4691}
4692
4693impl<C, I, O, Op> Node for ImportNode<C, I, O, Op>
4694where
4695 C: Circuit,
4696 C::Parent: Circuit,
4697 I: Clone + 'static,
4698 O: Clone + 'static,
4699 Op: ImportOperator<I, O>,
4700{
4701 fn name(&self) -> Cow<'static, str> {
4702 self.operator.name()
4703 }
4704
4705 fn local_id(&self) -> NodeId {
4706 self.id.local_node_id().unwrap()
4707 }
4708
4709 fn global_id(&self) -> &GlobalNodeId {
4710 &self.id
4711 }
4712
4713 fn is_async(&self) -> bool {
4714 self.operator.is_async()
4715 }
4716
4717 fn is_input(&self) -> bool {
4718 self.operator.is_input()
4719 }
4720
4721 fn ready(&self) -> bool {
4722 self.operator.ready()
4723 }
4724
4725 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
4726 self.operator.register_ready_callback(cb);
4727 }
4728
4729 fn eval<'a>(
4730 &'a mut self,
4731 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
4732 Box::pin(async {
4733 self.output_stream.put(self.operator.eval().await);
4734 Ok(self.operator.flush_progress())
4735 })
4736 }
4737
4738 #[allow(clippy::await_holding_refcell_ref)]
4741 fn import<'a>(&'a mut self) -> Pin<Box<dyn Future<Output = ()> + 'a>> {
4742 Box::pin(async {
4743 match StreamValue::take(self.parent_stream.val()) {
4744 None => {
4745 self.operator
4746 .import(StreamValue::peek(&self.parent_stream.get()))
4747 .await
4748 }
4749 Some(val) => self.operator.import_owned(val).await,
4750 }
4751
4752 StreamValue::consume_token(self.parent_stream.val());
4753 })
4754 }
4755
4756 fn start_transaction(&mut self) {
4757 self.operator.start_transaction();
4758 }
4759
4760 fn flush(&mut self) {
4761 self.operator.flush();
4762 }
4763
4764 fn is_flush_complete(&self) -> bool {
4765 self.operator.is_flush_complete()
4766 }
4767
4768 fn clock_start(&mut self, scope: Scope) {
4769 self.operator.clock_start(scope);
4770 }
4771
4772 fn clock_end(&mut self, scope: Scope) {
4773 self.operator.clock_end(scope);
4774 }
4775
4776 fn init(&mut self) {
4777 self.operator.init(&self.id);
4778 }
4779
4780 fn metadata(&self, output: &mut OperatorMeta) {
4781 self.operator.metadata(output);
4782 }
4783
4784 fn fixedpoint(&self, scope: Scope) -> bool {
4785 self.operator.fixedpoint(scope)
4786 }
4787
4788 fn checkpoint(
4789 &mut self,
4790 base: &StoragePath,
4791 files: &mut Vec<Arc<dyn FileCommitter>>,
4792 ) -> Result<(), DbspError> {
4793 self.operator
4794 .checkpoint(base, self.persistent_id().as_deref(), files)
4795 }
4796
4797 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
4798 self.operator.restore(base, self.persistent_id().as_deref())
4799 }
4800
4801 fn start_compaction(&mut self) {
4802 self.operator.start_compaction()
4803 }
4804
4805 fn is_compaction_complete(&self) -> bool {
4806 self.operator.is_compaction_complete()
4807 }
4808
4809 fn clear_state(&mut self) -> Result<(), DbspError> {
4810 self.operator.clear_state()
4811 }
4812
4813 fn start_replay(&mut self) -> Result<(), DbspError> {
4814 self.operator.start_replay()
4815 }
4816
4817 fn end_replay(&mut self) -> Result<(), DbspError> {
4818 self.operator.end_replay()
4819 }
4820
4821 fn is_replay_complete(&self) -> bool {
4822 self.operator.is_replay_complete()
4823 }
4824
4825 fn set_label(&mut self, key: &str, value: &str) {
4826 self.labels.insert(key.to_string(), value.to_string());
4827 }
4828
4829 fn get_label(&self, key: &str) -> Option<&str> {
4830 self.labels.get(key).map(|s| s.as_str())
4831 }
4832
4833 fn labels(&self) -> &BTreeMap<String, String> {
4834 &self.labels
4835 }
4836
4837 fn as_any(&self) -> &dyn Any {
4838 self
4839 }
4840}
4841
4842struct SourceNode<C, O, Op> {
4843 id: GlobalNodeId,
4844 operator: Op,
4845 output_stream: Stream<C, O>,
4846 labels: BTreeMap<String, String>,
4847}
4848
4849impl<C, O, Op> SourceNode<C, O, Op>
4850where
4851 Op: SourceOperator<O>,
4852 C: Circuit,
4853{
4854 fn new(operator: Op, circuit: C, id: NodeId) -> Self {
4855 Self {
4856 id: circuit.global_node_id().child(id),
4857 operator,
4858 output_stream: Stream::new(circuit, id),
4859 labels: BTreeMap::new(),
4860 }
4861 }
4862
4863 fn output_stream(&self) -> Stream<C, O> {
4864 self.output_stream.clone()
4865 }
4866}
4867
4868impl<C, O, Op> Node for SourceNode<C, O, Op>
4869where
4870 C: Circuit,
4871 O: Clone + 'static,
4872 Op: SourceOperator<O>,
4873{
4874 fn name(&self) -> Cow<'static, str> {
4875 self.operator.name()
4876 }
4877
4878 fn local_id(&self) -> NodeId {
4879 self.id.local_node_id().unwrap()
4880 }
4881
4882 fn global_id(&self) -> &GlobalNodeId {
4883 &self.id
4884 }
4885
4886 fn is_async(&self) -> bool {
4887 self.operator.is_async()
4888 }
4889
4890 fn is_input(&self) -> bool {
4891 self.operator.is_input()
4892 }
4893
4894 fn ready(&self) -> bool {
4895 self.operator.ready()
4896 }
4897
4898 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
4899 self.operator.register_ready_callback(cb);
4900 }
4901
4902 fn eval<'a>(
4903 &'a mut self,
4904 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
4905 Box::pin(async {
4906 self.output_stream.put(self.operator.eval().await);
4907 Ok(self.operator.flush_progress())
4908 })
4909 }
4910
4911 fn start_transaction(&mut self) {
4912 self.operator.start_transaction();
4913 }
4914
4915 fn flush(&mut self) {
4916 self.operator.flush();
4917 }
4918
4919 fn is_flush_complete(&self) -> bool {
4920 self.operator.is_flush_complete()
4921 }
4922
4923 fn clock_start(&mut self, scope: Scope) {
4924 self.operator.clock_start(scope);
4925 }
4926
4927 fn clock_end(&mut self, scope: Scope) {
4928 self.operator.clock_end(scope);
4929 }
4930
4931 fn init(&mut self) {
4932 self.operator.init(&self.id);
4933 }
4934
4935 fn metadata(&self, output: &mut OperatorMeta) {
4936 self.operator.metadata(output);
4937 }
4938
4939 fn fixedpoint(&self, scope: Scope) -> bool {
4940 self.operator.fixedpoint(scope)
4941 }
4942
4943 fn checkpoint(
4944 &mut self,
4945 base: &StoragePath,
4946 files: &mut Vec<Arc<dyn FileCommitter>>,
4947 ) -> Result<(), DbspError> {
4948 self.operator
4949 .checkpoint(base, self.persistent_id().as_deref(), files)
4950 }
4951
4952 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
4953 self.operator.restore(base, self.persistent_id().as_deref())
4954 }
4955
4956 fn start_compaction(&mut self) {
4957 self.operator.start_compaction()
4958 }
4959
4960 fn is_compaction_complete(&self) -> bool {
4961 self.operator.is_compaction_complete()
4962 }
4963
4964 fn clear_state(&mut self) -> Result<(), DbspError> {
4965 self.operator.clear_state()
4966 }
4967
4968 fn start_replay(&mut self) -> Result<(), DbspError> {
4969 self.operator.start_replay()
4970 }
4971
4972 fn is_replay_complete(&self) -> bool {
4973 self.operator.is_replay_complete()
4974 }
4975
4976 fn end_replay(&mut self) -> Result<(), DbspError> {
4977 self.operator.end_replay()
4978 }
4979
4980 fn set_label(&mut self, key: &str, value: &str) {
4981 self.labels.insert(key.to_string(), value.to_string());
4982 }
4983
4984 fn get_label(&self, key: &str) -> Option<&str> {
4985 self.labels.get(key).map(|s| s.as_str())
4986 }
4987
4988 fn labels(&self) -> &BTreeMap<String, String> {
4989 &self.labels
4990 }
4991
4992 fn as_any(&self) -> &dyn Any {
4993 self
4994 }
4995}
4996
4997struct UnaryNode<C, I, O, Op> {
4998 id: GlobalNodeId,
4999 operator: Op,
5000 input_stream: Stream<C, I>,
5001 output_stream: Stream<C, O>,
5002 labels: BTreeMap<String, String>,
5003}
5004
5005impl<C, I, O, Op> UnaryNode<C, I, O, Op>
5006where
5007 Op: UnaryOperator<I, O>,
5008 C: Circuit,
5009{
5010 fn new(operator: Op, input_stream: Stream<C, I>, circuit: C, id: NodeId) -> Self {
5011 Self {
5012 id: circuit.global_node_id().child(id),
5013 operator,
5014 input_stream,
5015 output_stream: Stream::new(circuit, id),
5016 labels: BTreeMap::new(),
5017 }
5018 }
5019
5020 fn output_stream(&self) -> Stream<C, O> {
5021 self.output_stream.clone()
5022 }
5023}
5024
5025impl<C, I, O, Op> Node for UnaryNode<C, I, O, Op>
5026where
5027 C: Circuit,
5028 I: Clone + 'static,
5029 O: Clone + 'static,
5030 Op: UnaryOperator<I, O>,
5031{
5032 fn name(&self) -> Cow<'static, str> {
5033 self.operator.name()
5034 }
5035
5036 fn local_id(&self) -> NodeId {
5037 self.id.local_node_id().unwrap()
5038 }
5039
5040 fn global_id(&self) -> &GlobalNodeId {
5041 &self.id
5042 }
5043
5044 fn is_async(&self) -> bool {
5045 self.operator.is_async()
5046 }
5047
5048 fn is_input(&self) -> bool {
5049 self.operator.is_input()
5050 }
5051
5052 fn ready(&self) -> bool {
5053 self.operator.ready()
5054 }
5055
5056 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
5057 self.operator.register_ready_callback(cb);
5058 }
5059
5060 #[allow(clippy::await_holding_refcell_ref)]
5062 fn eval<'a>(
5063 &'a mut self,
5064 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
5065 Box::pin(async {
5066 self.output_stream
5067 .put(match StreamValue::take(self.input_stream.val()) {
5068 Some(v) => self.operator.eval_owned(v).await,
5069 None => {
5070 self.operator
5071 .eval(StreamValue::peek(&self.input_stream.get()))
5072 .await
5073 }
5074 });
5075 StreamValue::consume_token(self.input_stream.val());
5076 Ok(self.operator.flush_progress())
5077 })
5078 }
5079
5080 fn start_transaction(&mut self) {
5081 self.operator.start_transaction();
5082 }
5083
5084 fn flush(&mut self) {
5085 self.operator.flush();
5086 }
5087
5088 fn is_flush_complete(&self) -> bool {
5089 self.operator.is_flush_complete()
5090 }
5091
5092 fn clock_start(&mut self, scope: Scope) {
5093 self.operator.clock_start(scope);
5094 }
5095
5096 fn clock_end(&mut self, scope: Scope) {
5097 self.operator.clock_end(scope);
5098 }
5099
5100 fn init(&mut self) {
5101 self.operator.init(&self.id);
5102 }
5103
5104 fn metadata(&self, output: &mut OperatorMeta) {
5105 self.operator.metadata(output);
5106 }
5107
5108 fn fixedpoint(&self, scope: Scope) -> bool {
5109 self.operator.fixedpoint(scope)
5110 }
5111
5112 fn checkpoint(
5113 &mut self,
5114 base: &StoragePath,
5115 files: &mut Vec<Arc<dyn FileCommitter>>,
5116 ) -> Result<(), DbspError> {
5117 self.operator
5118 .checkpoint(base, self.persistent_id().as_deref(), files)
5119 }
5120
5121 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
5122 self.operator.restore(base, self.persistent_id().as_deref())
5123 }
5124
5125 fn start_compaction(&mut self) {
5126 self.operator.start_compaction()
5127 }
5128
5129 fn is_compaction_complete(&self) -> bool {
5130 self.operator.is_compaction_complete()
5131 }
5132
5133 fn clear_state(&mut self) -> Result<(), DbspError> {
5134 self.operator.clear_state()
5135 }
5136
5137 fn start_replay(&mut self) -> Result<(), DbspError> {
5138 self.operator.start_replay()
5139 }
5140
5141 fn is_replay_complete(&self) -> bool {
5142 self.operator.is_replay_complete()
5143 }
5144
5145 fn end_replay(&mut self) -> Result<(), DbspError> {
5146 self.operator.end_replay()
5147 }
5148
5149 fn set_label(&mut self, key: &str, value: &str) {
5150 self.labels.insert(key.to_string(), value.to_string());
5151 }
5152
5153 fn get_label(&self, key: &str) -> Option<&str> {
5154 self.labels.get(key).map(|s| s.as_str())
5155 }
5156
5157 fn labels(&self) -> &BTreeMap<String, String> {
5158 &self.labels
5159 }
5160
5161 fn as_any(&self) -> &dyn Any {
5162 self
5163 }
5164}
5165
5166struct SinkNode<C, I, Op> {
5167 id: GlobalNodeId,
5168 operator: Op,
5169 input_stream: Stream<C, I>,
5170 labels: BTreeMap<String, String>,
5171}
5172
5173impl<C, I, Op> SinkNode<C, I, Op>
5174where
5175 Op: SinkOperator<I>,
5176 C: Circuit,
5177{
5178 fn new(operator: Op, input_stream: Stream<C, I>, circuit: C, id: NodeId) -> Self {
5179 Self {
5180 id: circuit.global_node_id().child(id),
5181 operator,
5182 input_stream,
5183 labels: BTreeMap::new(),
5184 }
5185 }
5186}
5187
5188impl<C, I, Op> Node for SinkNode<C, I, Op>
5189where
5190 C: Circuit,
5191 I: Clone + 'static,
5192 Op: SinkOperator<I>,
5193{
5194 fn name(&self) -> Cow<'static, str> {
5195 self.operator.name()
5196 }
5197
5198 fn local_id(&self) -> NodeId {
5199 self.id.local_node_id().unwrap()
5200 }
5201
5202 fn global_id(&self) -> &GlobalNodeId {
5203 &self.id
5204 }
5205
5206 fn is_async(&self) -> bool {
5207 self.operator.is_async()
5208 }
5209
5210 fn is_input(&self) -> bool {
5211 self.operator.is_input()
5212 }
5213
5214 fn ready(&self) -> bool {
5215 self.operator.ready()
5216 }
5217
5218 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
5219 self.operator.register_ready_callback(cb);
5220 }
5221
5222 #[allow(clippy::await_holding_refcell_ref)]
5224 fn eval<'a>(
5225 &'a mut self,
5226 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
5227 Box::pin(async {
5228 match StreamValue::take(self.input_stream.val()) {
5229 Some(v) => self.operator.eval_owned(v).await,
5230 None => {
5231 self.operator
5232 .eval(StreamValue::peek(&self.input_stream.get()))
5233 .await
5234 }
5235 };
5236 StreamValue::consume_token(self.input_stream.val());
5237
5238 Ok(self.operator.flush_progress())
5239 })
5240 }
5241
5242 fn start_transaction(&mut self) {
5243 self.operator.start_transaction();
5244 }
5245
5246 fn flush(&mut self) {
5247 self.operator.flush();
5248 }
5249
5250 fn is_flush_complete(&self) -> bool {
5251 self.operator.is_flush_complete()
5252 }
5253
5254 fn clock_start(&mut self, scope: Scope) {
5255 self.operator.clock_start(scope);
5256 }
5257
5258 fn clock_end(&mut self, scope: Scope) {
5259 self.operator.clock_end(scope);
5260 }
5261
5262 fn init(&mut self) {
5263 self.operator.init(&self.id);
5264 }
5265
5266 fn metadata(&self, output: &mut OperatorMeta) {
5267 self.operator.metadata(output);
5268 }
5269
5270 fn fixedpoint(&self, scope: Scope) -> bool {
5271 self.operator.fixedpoint(scope)
5272 }
5273
5274 fn checkpoint(
5275 &mut self,
5276 base: &StoragePath,
5277 files: &mut Vec<Arc<dyn FileCommitter>>,
5278 ) -> Result<(), DbspError> {
5279 self.operator
5280 .checkpoint(base, self.persistent_id().as_deref(), files)
5281 }
5282
5283 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
5284 self.operator.restore(base, self.persistent_id().as_deref())
5285 }
5286
5287 fn start_compaction(&mut self) {
5288 self.operator.start_compaction()
5289 }
5290
5291 fn is_compaction_complete(&self) -> bool {
5292 self.operator.is_compaction_complete()
5293 }
5294
5295 fn clear_state(&mut self) -> Result<(), DbspError> {
5296 self.operator.clear_state()
5297 }
5298
5299 fn start_replay(&mut self) -> Result<(), DbspError> {
5300 self.operator.start_replay()
5301 }
5302
5303 fn is_replay_complete(&self) -> bool {
5304 self.operator.is_replay_complete()
5305 }
5306
5307 fn end_replay(&mut self) -> Result<(), DbspError> {
5308 self.operator.end_replay()
5309 }
5310
5311 fn set_label(&mut self, key: &str, value: &str) {
5312 self.labels.insert(key.to_string(), value.to_string());
5313 }
5314
5315 fn get_label(&self, key: &str) -> Option<&str> {
5316 self.labels.get(key).map(|s| s.as_str())
5317 }
5318
5319 fn labels(&self) -> &BTreeMap<String, String> {
5320 &self.labels
5321 }
5322
5323 fn as_any(&self) -> &dyn Any {
5324 self
5325 }
5326}
5327
5328struct BinarySinkNode<C, I1, I2, Op> {
5329 id: GlobalNodeId,
5330 operator: Op,
5331 input_stream1: Stream<C, I1>,
5332 input_stream2: Stream<C, I2>,
5333 is_alias: bool,
5335 labels: BTreeMap<String, String>,
5336}
5337
5338impl<C, I1, I2, Op> BinarySinkNode<C, I1, I2, Op>
5339where
5340 I1: Clone,
5341 I2: Clone,
5342 Op: BinarySinkOperator<I1, I2>,
5343 C: Circuit,
5344{
5345 fn new(
5346 operator: Op,
5347 input_stream1: Stream<C, I1>,
5348 input_stream2: Stream<C, I2>,
5349 circuit: C,
5350 id: NodeId,
5351 ) -> Self {
5352 let is_alias = input_stream1.ptr_eq(&input_stream2);
5353 Self {
5354 id: circuit.global_node_id().child(id),
5355 operator,
5356 input_stream1,
5357 input_stream2,
5358 is_alias,
5359 labels: BTreeMap::new(),
5360 }
5361 }
5362}
5363
5364impl<C, I1, I2, Op> Node for BinarySinkNode<C, I1, I2, Op>
5365where
5366 C: Circuit,
5367 I1: Clone + 'static,
5368 I2: Clone + 'static,
5369 Op: BinarySinkOperator<I1, I2>,
5370{
5371 fn name(&self) -> Cow<'static, str> {
5372 self.operator.name()
5373 }
5374
5375 fn local_id(&self) -> NodeId {
5376 self.id.local_node_id().unwrap()
5377 }
5378
5379 fn global_id(&self) -> &GlobalNodeId {
5380 &self.id
5381 }
5382
5383 fn is_async(&self) -> bool {
5384 self.operator.is_async()
5385 }
5386
5387 fn is_input(&self) -> bool {
5388 self.operator.is_input()
5389 }
5390
5391 fn ready(&self) -> bool {
5392 self.operator.ready()
5393 }
5394
5395 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
5396 self.operator.register_ready_callback(cb);
5397 }
5398
5399 #[allow(clippy::await_holding_refcell_ref)]
5401 fn eval<'a>(
5402 &'a mut self,
5403 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
5404 Box::pin(async {
5405 if self.is_alias {
5406 {
5407 let val1 = self.input_stream1.get();
5408 let val2 = self.input_stream2.get();
5409 self.operator
5410 .eval(
5411 Cow::Borrowed(StreamValue::peek(&val1)),
5412 Cow::Borrowed(StreamValue::peek(&val2)),
5413 )
5414 .await;
5415 }
5416
5417 StreamValue::consume_token(self.input_stream1.val());
5418 StreamValue::consume_token(self.input_stream2.val());
5419 } else {
5420 let val1 = StreamValue::take(self.input_stream1.val());
5421 let val2 = StreamValue::take(self.input_stream2.val());
5422
5423 match (val1, val2) {
5424 (Some(val1), Some(val2)) => {
5425 self.operator.eval(Cow::Owned(val1), Cow::Owned(val2)).await;
5426 }
5427 (Some(val1), None) => {
5428 self.operator
5429 .eval(
5430 Cow::Owned(val1),
5431 Cow::Borrowed(StreamValue::peek(&self.input_stream2.get())),
5432 )
5433 .await;
5434 }
5435 (None, Some(val2)) => {
5436 self.operator
5437 .eval(
5438 Cow::Borrowed(StreamValue::peek(&self.input_stream1.get())),
5439 Cow::Owned(val2),
5440 )
5441 .await;
5442 }
5443 (None, None) => {
5444 self.operator
5445 .eval(
5446 Cow::Borrowed(StreamValue::peek(&self.input_stream1.get())),
5447 Cow::Borrowed(StreamValue::peek(&self.input_stream2.get())),
5448 )
5449 .await;
5450 }
5451 }
5452
5453 StreamValue::consume_token(self.input_stream1.val());
5454 StreamValue::consume_token(self.input_stream2.val());
5455 };
5456
5457 Ok(self.operator.flush_progress())
5458 })
5459 }
5460
5461 fn start_transaction(&mut self) {
5462 self.operator.start_transaction();
5463 }
5464
5465 fn flush(&mut self) {
5466 self.operator.flush();
5467 }
5468
5469 fn is_flush_complete(&self) -> bool {
5470 self.operator.is_flush_complete()
5471 }
5472
5473 fn clock_start(&mut self, scope: Scope) {
5474 self.operator.clock_start(scope);
5475 }
5476
5477 fn clock_end(&mut self, scope: Scope) {
5478 self.operator.clock_end(scope);
5479 }
5480
5481 fn init(&mut self) {
5482 self.operator.init(&self.id);
5483 }
5484
5485 fn metadata(&self, output: &mut OperatorMeta) {
5486 self.operator.metadata(output);
5487 }
5488
5489 fn fixedpoint(&self, scope: Scope) -> bool {
5490 self.operator.fixedpoint(scope)
5491 }
5492
5493 fn checkpoint(
5494 &mut self,
5495 base: &StoragePath,
5496 files: &mut Vec<Arc<dyn FileCommitter>>,
5497 ) -> Result<(), DbspError> {
5498 self.operator
5499 .checkpoint(base, self.persistent_id().as_deref(), files)
5500 }
5501
5502 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
5503 self.operator.restore(base, self.persistent_id().as_deref())
5504 }
5505
5506 fn start_compaction(&mut self) {
5507 self.operator.start_compaction()
5508 }
5509
5510 fn is_compaction_complete(&self) -> bool {
5511 self.operator.is_compaction_complete()
5512 }
5513
5514 fn clear_state(&mut self) -> Result<(), DbspError> {
5515 self.operator.clear_state()
5516 }
5517
5518 fn start_replay(&mut self) -> Result<(), DbspError> {
5519 self.operator.start_replay()
5520 }
5521
5522 fn is_replay_complete(&self) -> bool {
5523 self.operator.is_replay_complete()
5524 }
5525
5526 fn end_replay(&mut self) -> Result<(), DbspError> {
5527 self.operator.end_replay()
5528 }
5529
5530 fn set_label(&mut self, key: &str, value: &str) {
5531 self.labels.insert(key.to_string(), value.to_string());
5532 }
5533
5534 fn get_label(&self, key: &str) -> Option<&str> {
5535 self.labels.get(key).map(|s| s.as_str())
5536 }
5537
5538 fn labels(&self) -> &BTreeMap<String, String> {
5539 &self.labels
5540 }
5541
5542 fn as_any(&self) -> &dyn Any {
5543 self
5544 }
5545}
5546
5547struct TernarySinkNode<C, I1, I2, I3, Op> {
5548 id: GlobalNodeId,
5549 operator: Op,
5550 input_stream1: Stream<C, I1>,
5551 input_stream2: Stream<C, I2>,
5552 input_stream3: Stream<C, I3>,
5553 labels: BTreeMap<String, String>,
5554}
5555
5556impl<C, I1, I2, I3, Op> TernarySinkNode<C, I1, I2, I3, Op>
5557where
5558 I1: Clone,
5559 I2: Clone,
5560 I3: Clone,
5561 Op: TernarySinkOperator<I1, I2, I3>,
5562 C: Circuit,
5563{
5564 fn new(
5565 operator: Op,
5566 input_stream1: Stream<C, I1>,
5567 input_stream2: Stream<C, I2>,
5568 input_stream3: Stream<C, I3>,
5569 circuit: C,
5570 id: NodeId,
5571 ) -> Self {
5572 assert!(!input_stream1.ptr_eq(&input_stream2));
5573 assert!(!input_stream1.ptr_eq(&input_stream3));
5574 assert!(!input_stream2.ptr_eq(&input_stream3));
5575
5576 Self {
5577 id: circuit.global_node_id().child(id),
5578 operator,
5579 input_stream1,
5580 input_stream2,
5581 input_stream3,
5582 labels: BTreeMap::new(),
5583 }
5584 }
5585}
5586
5587impl<C, I1, I2, I3, Op> Node for TernarySinkNode<C, I1, I2, I3, Op>
5588where
5589 C: Circuit,
5590 I1: Clone + 'static,
5591 I2: Clone + 'static,
5592 I3: Clone + 'static,
5593 Op: TernarySinkOperator<I1, I2, I3>,
5594{
5595 fn name(&self) -> Cow<'static, str> {
5596 self.operator.name()
5597 }
5598
5599 fn local_id(&self) -> NodeId {
5600 self.id.local_node_id().unwrap()
5601 }
5602
5603 fn global_id(&self) -> &GlobalNodeId {
5604 &self.id
5605 }
5606
5607 fn is_async(&self) -> bool {
5608 self.operator.is_async()
5609 }
5610
5611 fn is_input(&self) -> bool {
5612 self.operator.is_input()
5613 }
5614
5615 fn ready(&self) -> bool {
5616 self.operator.ready()
5617 }
5618
5619 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
5620 self.operator.register_ready_callback(cb);
5621 }
5622
5623 #[allow(clippy::await_holding_refcell_ref)]
5625 fn eval<'a>(
5626 &'a mut self,
5627 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
5628 Box::pin(async {
5629 let val1 = StreamValue::take(self.input_stream1.val()).map(|val| Cow::Owned(val));
5630 let r1 = self.input_stream1.get();
5631 let val2 = StreamValue::take(self.input_stream2.val()).map(|val| Cow::Owned(val));
5632 let r2 = self.input_stream2.get();
5633 let val3 = StreamValue::take(self.input_stream3.val()).map(|val| Cow::Owned(val));
5634 let r3 = self.input_stream3.get();
5635
5636 self.operator
5637 .eval(
5638 val1.unwrap_or_else(|| Cow::Borrowed(StreamValue::peek(&r1))),
5639 val2.unwrap_or_else(|| Cow::Borrowed(StreamValue::peek(&r2))),
5640 val3.unwrap_or_else(|| Cow::Borrowed(StreamValue::peek(&r3))),
5641 )
5642 .await;
5643
5644 drop(r1);
5645 drop(r2);
5646 drop(r3);
5647
5648 StreamValue::consume_token(self.input_stream1.val());
5649 StreamValue::consume_token(self.input_stream2.val());
5650 StreamValue::consume_token(self.input_stream3.val());
5651
5652 Ok(self.operator.flush_progress())
5653 })
5654 }
5655
5656 fn start_transaction(&mut self) {
5657 self.operator.start_transaction();
5658 }
5659
5660 fn flush(&mut self) {
5661 self.operator.flush();
5662 }
5663
5664 fn is_flush_complete(&self) -> bool {
5665 self.operator.is_flush_complete()
5666 }
5667
5668 fn clock_start(&mut self, scope: Scope) {
5669 self.operator.clock_start(scope);
5670 }
5671
5672 fn clock_end(&mut self, scope: Scope) {
5673 self.operator.clock_end(scope);
5674 }
5675
5676 fn init(&mut self) {
5677 self.operator.init(&self.id);
5678 }
5679
5680 fn metadata(&self, output: &mut OperatorMeta) {
5681 self.operator.metadata(output);
5682 }
5683
5684 fn fixedpoint(&self, scope: Scope) -> bool {
5685 self.operator.fixedpoint(scope)
5686 }
5687
5688 fn checkpoint(
5689 &mut self,
5690 base: &StoragePath,
5691 files: &mut Vec<Arc<dyn FileCommitter>>,
5692 ) -> Result<(), DbspError> {
5693 self.operator
5694 .checkpoint(base, self.persistent_id().as_deref(), files)
5695 }
5696
5697 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
5698 self.operator.restore(base, self.persistent_id().as_deref())
5699 }
5700
5701 fn start_compaction(&mut self) {
5702 self.operator.start_compaction()
5703 }
5704
5705 fn is_compaction_complete(&self) -> bool {
5706 self.operator.is_compaction_complete()
5707 }
5708
5709 fn clear_state(&mut self) -> Result<(), DbspError> {
5710 self.operator.clear_state()
5711 }
5712
5713 fn start_replay(&mut self) -> Result<(), DbspError> {
5714 self.operator.start_replay()
5715 }
5716
5717 fn is_replay_complete(&self) -> bool {
5718 self.operator.is_replay_complete()
5719 }
5720
5721 fn end_replay(&mut self) -> Result<(), DbspError> {
5722 self.operator.end_replay()
5723 }
5724
5725 fn set_label(&mut self, key: &str, value: &str) {
5726 self.labels.insert(key.to_string(), value.to_string());
5727 }
5728
5729 fn get_label(&self, key: &str) -> Option<&str> {
5730 self.labels.get(key).map(|s| s.as_str())
5731 }
5732
5733 fn labels(&self) -> &BTreeMap<String, String> {
5734 &self.labels
5735 }
5736
5737 fn as_any(&self) -> &dyn Any {
5738 self
5739 }
5740}
5741
5742struct BinaryNode<C, I1, I2, O, Op> {
5743 id: GlobalNodeId,
5744 operator: Op,
5745 input_stream1: Stream<C, I1>,
5746 input_stream2: Stream<C, I2>,
5747 output_stream: Stream<C, O>,
5748 is_alias: bool,
5750 labels: BTreeMap<String, String>,
5751}
5752
5753impl<C, I1, I2, O, Op> BinaryNode<C, I1, I2, O, Op>
5754where
5755 Op: BinaryOperator<I1, I2, O>,
5756 C: Circuit,
5757{
5758 fn new(
5759 operator: Op,
5760 input_stream1: Stream<C, I1>,
5761 input_stream2: Stream<C, I2>,
5762 circuit: C,
5763 id: NodeId,
5764 ) -> Self {
5765 let is_alias = input_stream1.ptr_eq(&input_stream2);
5766 Self {
5767 id: circuit.global_node_id().child(id),
5768 operator,
5769 input_stream1,
5770 input_stream2,
5771 is_alias,
5772 output_stream: Stream::new(circuit, id),
5773 labels: BTreeMap::new(),
5774 }
5775 }
5776
5777 fn output_stream(&self) -> Stream<C, O> {
5778 self.output_stream.clone()
5779 }
5780}
5781
5782impl<C, I1, I2, O, Op> Node for BinaryNode<C, I1, I2, O, Op>
5783where
5784 C: Circuit,
5785 I1: Clone + 'static,
5786 I2: Clone + 'static,
5787 O: Clone + 'static,
5788 Op: BinaryOperator<I1, I2, O>,
5789{
5790 fn name(&self) -> Cow<'static, str> {
5791 self.operator.name()
5792 }
5793
5794 fn local_id(&self) -> NodeId {
5795 self.id.local_node_id().unwrap()
5796 }
5797
5798 fn global_id(&self) -> &GlobalNodeId {
5799 &self.id
5800 }
5801
5802 fn is_async(&self) -> bool {
5803 self.operator.is_async()
5804 }
5805
5806 fn is_input(&self) -> bool {
5807 self.operator.is_input()
5808 }
5809
5810 fn ready(&self) -> bool {
5811 self.operator.ready()
5812 }
5813
5814 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
5815 self.operator.register_ready_callback(cb);
5816 }
5817
5818 #[allow(clippy::await_holding_refcell_ref)]
5820 fn eval<'a>(
5821 &'a mut self,
5822 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
5823 Box::pin(async {
5824 if self.is_alias {
5829 {
5830 let val1 = self.input_stream1.get();
5831 let val2 = self.input_stream2.get();
5832
5833 self.output_stream.put(
5834 self.operator
5835 .eval(StreamValue::peek(&val1), StreamValue::peek(&val2))
5836 .await,
5837 );
5838 }
5839 StreamValue::consume_token(self.input_stream1.val());
5842 StreamValue::consume_token(self.input_stream2.val());
5843 } else {
5844 let val1 = StreamValue::take(self.input_stream1.val());
5845 let val2 = StreamValue::take(self.input_stream2.val());
5846
5847 self.output_stream.put(match (val1, val2) {
5848 (Some(val1), Some(val2)) => self.operator.eval_owned(val1, val2).await,
5849 (Some(val1), None) => {
5850 self.operator
5851 .eval_owned_and_ref(val1, StreamValue::peek(&self.input_stream2.get()))
5852 .await
5853 }
5854 (None, Some(val2)) => {
5855 self.operator
5856 .eval_ref_and_owned(StreamValue::peek(&self.input_stream1.get()), val2)
5857 .await
5858 }
5859 (None, None) => {
5860 self.operator
5861 .eval(
5862 StreamValue::peek(&self.input_stream1.get()),
5863 StreamValue::peek(&self.input_stream2.get()),
5864 )
5865 .await
5866 }
5867 });
5868 StreamValue::consume_token(self.input_stream1.val());
5869 StreamValue::consume_token(self.input_stream2.val());
5870 }
5871 Ok(self.operator.flush_progress())
5872 })
5873 }
5874
5875 fn start_transaction(&mut self) {
5876 self.operator.start_transaction();
5877 }
5878
5879 fn flush(&mut self) {
5880 self.operator.flush();
5881 }
5882
5883 fn is_flush_complete(&self) -> bool {
5884 self.operator.is_flush_complete()
5885 }
5886
5887 fn clock_start(&mut self, scope: Scope) {
5888 self.operator.clock_start(scope);
5889 }
5890
5891 fn clock_end(&mut self, scope: Scope) {
5892 self.operator.clock_end(scope);
5893 }
5894
5895 fn init(&mut self) {
5896 self.operator.init(&self.id);
5897 }
5898
5899 fn metadata(&self, output: &mut OperatorMeta) {
5900 self.operator.metadata(output);
5901 }
5902
5903 fn fixedpoint(&self, scope: Scope) -> bool {
5904 self.operator.fixedpoint(scope)
5905 }
5906
5907 fn checkpoint(
5908 &mut self,
5909 base: &StoragePath,
5910 files: &mut Vec<Arc<dyn FileCommitter>>,
5911 ) -> Result<(), DbspError> {
5912 self.operator
5913 .checkpoint(base, self.persistent_id().as_deref(), files)
5914 }
5915
5916 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
5917 self.operator.restore(base, self.persistent_id().as_deref())
5918 }
5919
5920 fn start_compaction(&mut self) {
5921 self.operator.start_compaction()
5922 }
5923
5924 fn is_compaction_complete(&self) -> bool {
5925 self.operator.is_compaction_complete()
5926 }
5927
5928 fn clear_state(&mut self) -> Result<(), DbspError> {
5929 self.operator.clear_state()
5930 }
5931
5932 fn start_replay(&mut self) -> Result<(), DbspError> {
5933 self.operator.start_replay()
5934 }
5935
5936 fn is_replay_complete(&self) -> bool {
5937 self.operator.is_replay_complete()
5938 }
5939
5940 fn end_replay(&mut self) -> Result<(), DbspError> {
5941 self.operator.end_replay()
5942 }
5943
5944 fn set_label(&mut self, key: &str, value: &str) {
5945 self.labels.insert(key.to_string(), value.to_string());
5946 }
5947
5948 fn get_label(&self, key: &str) -> Option<&str> {
5949 self.labels.get(key).map(|s| s.as_str())
5950 }
5951
5952 fn labels(&self) -> &BTreeMap<String, String> {
5953 &self.labels
5954 }
5955
5956 fn as_any(&self) -> &dyn Any {
5957 self
5958 }
5959}
5960
5961struct TernaryNode<C, I1, I2, I3, O, Op> {
5962 id: GlobalNodeId,
5963 operator: Op,
5964 input_stream1: Stream<C, I1>,
5965 input_stream2: Stream<C, I2>,
5966 input_stream3: Stream<C, I3>,
5967 output_stream: Stream<C, O>,
5968 labels: BTreeMap<String, String>,
5969}
5970
5971impl<C, I1, I2, I3, O, Op> TernaryNode<C, I1, I2, I3, O, Op>
5972where
5973 I1: Clone,
5974 I2: Clone,
5975 I3: Clone,
5976 Op: TernaryOperator<I1, I2, I3, O>,
5977 C: Circuit,
5978{
5979 fn new(
5980 operator: Op,
5981 input_stream1: Stream<C, I1>,
5982 input_stream2: Stream<C, I2>,
5983 input_stream3: Stream<C, I3>,
5984 circuit: C,
5985 id: NodeId,
5986 ) -> Self {
5987 Self {
5988 id: circuit.global_node_id().child(id),
5989 operator,
5990 input_stream1,
5991 input_stream2,
5992 input_stream3,
5993 output_stream: Stream::new(circuit, id),
5996 labels: BTreeMap::new(),
5997 }
5998 }
5999
6000 fn output_stream(&self) -> Stream<C, O> {
6001 self.output_stream.clone()
6002 }
6003}
6004
6005impl<C, I1, I2, I3, O, Op> Node for TernaryNode<C, I1, I2, I3, O, Op>
6006where
6007 C: Circuit,
6008 I1: Clone + 'static,
6009 I2: Clone + 'static,
6010 I3: Clone + 'static,
6011 O: Clone + 'static,
6012 Op: TernaryOperator<I1, I2, I3, O>,
6013{
6014 fn name(&self) -> Cow<'static, str> {
6015 self.operator.name()
6016 }
6017
6018 fn local_id(&self) -> NodeId {
6019 self.id.local_node_id().unwrap()
6020 }
6021
6022 fn global_id(&self) -> &GlobalNodeId {
6023 &self.id
6024 }
6025
6026 fn is_async(&self) -> bool {
6027 self.operator.is_async()
6028 }
6029
6030 fn is_input(&self) -> bool {
6031 self.operator.is_input()
6032 }
6033
6034 fn ready(&self) -> bool {
6035 self.operator.ready()
6036 }
6037
6038 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
6039 self.operator.register_ready_callback(cb);
6040 }
6041
6042 #[allow(clippy::await_holding_refcell_ref)]
6044 fn eval<'a>(
6045 &'a mut self,
6046 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
6047 Box::pin(async {
6048 {
6049 self.output_stream.put(
6050 self.operator
6051 .eval(
6052 Cow::Borrowed(StreamValue::peek(&self.input_stream1.get())),
6053 Cow::Borrowed(StreamValue::peek(&self.input_stream2.get())),
6054 Cow::Borrowed(StreamValue::peek(&self.input_stream3.get())),
6055 )
6056 .await,
6057 );
6058 }
6059
6060 StreamValue::consume_token(self.input_stream1.val());
6061 StreamValue::consume_token(self.input_stream2.val());
6062 StreamValue::consume_token(self.input_stream3.val());
6063
6064 Ok(self.operator.flush_progress())
6065 })
6066 }
6067
6068 fn start_transaction(&mut self) {
6069 self.operator.start_transaction();
6070 }
6071
6072 fn flush(&mut self) {
6073 self.operator.flush();
6074 }
6075
6076 fn is_flush_complete(&self) -> bool {
6077 self.operator.is_flush_complete()
6078 }
6079
6080 fn clock_start(&mut self, scope: Scope) {
6081 self.operator.clock_start(scope);
6082 }
6083
6084 fn clock_end(&mut self, scope: Scope) {
6085 self.operator.clock_end(scope);
6086 }
6087
6088 fn init(&mut self) {
6089 self.operator.init(&self.id);
6090 }
6091
6092 fn metadata(&self, output: &mut OperatorMeta) {
6093 self.operator.metadata(output);
6094 }
6095
6096 fn fixedpoint(&self, scope: Scope) -> bool {
6097 self.operator.fixedpoint(scope)
6098 }
6099
6100 fn checkpoint(
6101 &mut self,
6102 base: &StoragePath,
6103 files: &mut Vec<Arc<dyn FileCommitter>>,
6104 ) -> Result<(), DbspError> {
6105 self.operator
6106 .checkpoint(base, self.persistent_id().as_deref(), files)
6107 }
6108
6109 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
6110 self.operator.restore(base, self.persistent_id().as_deref())
6111 }
6112
6113 fn start_compaction(&mut self) {
6114 self.operator.start_compaction()
6115 }
6116
6117 fn is_compaction_complete(&self) -> bool {
6118 self.operator.is_compaction_complete()
6119 }
6120
6121 fn clear_state(&mut self) -> Result<(), DbspError> {
6122 self.operator.clear_state()
6123 }
6124
6125 fn start_replay(&mut self) -> Result<(), DbspError> {
6126 self.operator.start_replay()
6127 }
6128
6129 fn is_replay_complete(&self) -> bool {
6130 self.operator.is_replay_complete()
6131 }
6132
6133 fn end_replay(&mut self) -> Result<(), DbspError> {
6134 self.operator.end_replay()
6135 }
6136
6137 fn set_label(&mut self, key: &str, value: &str) {
6138 self.labels.insert(key.to_string(), value.to_string());
6139 }
6140
6141 fn get_label(&self, key: &str) -> Option<&str> {
6142 self.labels.get(key).map(|s| s.as_str())
6143 }
6144
6145 fn labels(&self) -> &BTreeMap<String, String> {
6146 &self.labels
6147 }
6148
6149 fn as_any(&self) -> &dyn Any {
6150 self
6151 }
6152}
6153
6154struct QuaternaryNode<C, I1, I2, I3, I4, O, Op> {
6155 id: GlobalNodeId,
6156 operator: Op,
6157 input_stream1: Stream<C, I1>,
6158 input_stream2: Stream<C, I2>,
6159 input_stream3: Stream<C, I3>,
6160 input_stream4: Stream<C, I4>,
6161 output_stream: Stream<C, O>,
6162 labels: BTreeMap<String, String>,
6163 }
6171
6172impl<C, I1, I2, I3, I4, O, Op> QuaternaryNode<C, I1, I2, I3, I4, O, Op>
6173where
6174 I1: Clone,
6175 I2: Clone,
6176 I3: Clone,
6177 I4: Clone,
6178 Op: QuaternaryOperator<I1, I2, I3, I4, O>,
6179 C: Circuit,
6180{
6181 fn new(
6182 operator: Op,
6183 input_stream1: Stream<C, I1>,
6184 input_stream2: Stream<C, I2>,
6185 input_stream3: Stream<C, I3>,
6186 input_stream4: Stream<C, I4>,
6187 circuit: C,
6188 id: NodeId,
6189 ) -> Self {
6190 Self {
6197 id: circuit.global_node_id().child(id),
6198 operator,
6199 input_stream1,
6200 input_stream2,
6201 input_stream3,
6202 input_stream4,
6203 output_stream: Stream::new(circuit, id),
6207 labels: BTreeMap::new(),
6208 }
6209 }
6210
6211 fn output_stream(&self) -> Stream<C, O> {
6212 self.output_stream.clone()
6213 }
6214}
6215
6216impl<C, I1, I2, I3, I4, O, Op> Node for QuaternaryNode<C, I1, I2, I3, I4, O, Op>
6217where
6218 C: Circuit,
6219 I1: Clone + 'static,
6220 I2: Clone + 'static,
6221 I3: Clone + 'static,
6222 I4: Clone + 'static,
6223 O: Clone + 'static,
6224 Op: QuaternaryOperator<I1, I2, I3, I4, O>,
6225{
6226 fn name(&self) -> Cow<'static, str> {
6227 self.operator.name()
6228 }
6229
6230 fn local_id(&self) -> NodeId {
6231 self.id.local_node_id().unwrap()
6232 }
6233
6234 fn global_id(&self) -> &GlobalNodeId {
6235 &self.id
6236 }
6237
6238 fn is_async(&self) -> bool {
6239 self.operator.is_async()
6240 }
6241
6242 fn is_input(&self) -> bool {
6243 self.operator.is_input()
6244 }
6245
6246 fn ready(&self) -> bool {
6247 self.operator.ready()
6248 }
6249
6250 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
6251 self.operator.register_ready_callback(cb);
6252 }
6253
6254 #[allow(clippy::await_holding_refcell_ref)]
6256 fn eval<'a>(
6257 &'a mut self,
6258 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
6259 Box::pin(async {
6260 {
6261 self.output_stream.put(
6262 self.operator
6263 .eval(
6264 Cow::Borrowed(StreamValue::peek(&self.input_stream1.get())),
6265 Cow::Borrowed(StreamValue::peek(&self.input_stream2.get())),
6266 Cow::Borrowed(StreamValue::peek(&self.input_stream3.get())),
6267 Cow::Borrowed(StreamValue::peek(&self.input_stream4.get())),
6268 )
6269 .await,
6270 );
6271 }
6272
6273 StreamValue::consume_token(self.input_stream1.val());
6274 StreamValue::consume_token(self.input_stream2.val());
6275 StreamValue::consume_token(self.input_stream3.val());
6276 StreamValue::consume_token(self.input_stream4.val());
6277
6278 Ok(self.operator.flush_progress())
6279 })
6280 }
6281
6282 fn start_transaction(&mut self) {
6283 self.operator.start_transaction();
6284 }
6285
6286 fn flush(&mut self) {
6287 self.operator.flush();
6288 }
6289
6290 fn is_flush_complete(&self) -> bool {
6291 self.operator.is_flush_complete()
6292 }
6293
6294 fn clock_start(&mut self, scope: Scope) {
6295 self.operator.clock_start(scope);
6296 }
6297
6298 fn clock_end(&mut self, scope: Scope) {
6299 self.operator.clock_end(scope);
6300 }
6301
6302 fn init(&mut self) {
6303 self.operator.init(&self.id);
6304 }
6305
6306 fn metadata(&self, output: &mut OperatorMeta) {
6307 self.operator.metadata(output);
6308 }
6309
6310 fn fixedpoint(&self, scope: Scope) -> bool {
6311 self.operator.fixedpoint(scope)
6312 }
6313
6314 fn checkpoint(
6315 &mut self,
6316 base: &StoragePath,
6317 files: &mut Vec<Arc<dyn FileCommitter>>,
6318 ) -> Result<(), DbspError> {
6319 self.operator
6320 .checkpoint(base, self.persistent_id().as_deref(), files)
6321 }
6322
6323 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
6324 self.operator.restore(base, self.persistent_id().as_deref())
6325 }
6326
6327 fn start_compaction(&mut self) {
6328 self.operator.start_compaction()
6329 }
6330
6331 fn is_compaction_complete(&self) -> bool {
6332 self.operator.is_compaction_complete()
6333 }
6334
6335 fn clear_state(&mut self) -> Result<(), DbspError> {
6336 self.operator.clear_state()
6337 }
6338
6339 fn start_replay(&mut self) -> Result<(), DbspError> {
6340 self.operator.start_replay()
6341 }
6342
6343 fn is_replay_complete(&self) -> bool {
6344 self.operator.is_replay_complete()
6345 }
6346
6347 fn end_replay(&mut self) -> Result<(), DbspError> {
6348 self.operator.end_replay()
6349 }
6350
6351 fn set_label(&mut self, key: &str, value: &str) {
6352 self.labels.insert(key.to_string(), value.to_string());
6353 }
6354
6355 fn get_label(&self, key: &str) -> Option<&str> {
6356 self.labels.get(key).map(|s| s.as_str())
6357 }
6358
6359 fn labels(&self) -> &BTreeMap<String, String> {
6360 &self.labels
6361 }
6362
6363 fn as_any(&self) -> &dyn Any {
6364 self
6365 }
6366}
6367
6368struct NaryNode<C, I, O, Op>
6369where
6370 I: Clone + 'static,
6371{
6372 id: GlobalNodeId,
6373 operator: Op,
6374 input_streams: Vec<Stream<C, I>>,
6377 output_stream: Stream<C, O>,
6380 labels: BTreeMap<String, String>,
6381}
6382
6383impl<C, I, O, Op> NaryNode<C, I, O, Op>
6384where
6385 I: Clone + 'static,
6386 Op: NaryOperator<I, O>,
6387 C: Circuit,
6388{
6389 fn new<Iter>(operator: Op, input_streams: Iter, circuit: C, id: NodeId) -> Self
6390 where
6391 Iter: IntoIterator<Item = Stream<C, I>>,
6392 {
6393 let mut input_streams: Vec<_> = input_streams.into_iter().collect();
6394 input_streams.shrink_to_fit();
6406 Self {
6407 id: circuit.global_node_id().child(id),
6408 operator,
6409 input_streams,
6410 output_stream: Stream::new(circuit, id),
6412 labels: BTreeMap::new(),
6413 }
6414 }
6415
6416 fn output_stream(&self) -> Stream<C, O> {
6417 self.output_stream.clone()
6418 }
6419}
6420
6421impl<C, I, O, Op> Node for NaryNode<C, I, O, Op>
6422where
6423 C: Circuit,
6424 I: Clone,
6425 O: Clone + 'static,
6426 Op: NaryOperator<I, O>,
6427{
6428 fn name(&self) -> Cow<'static, str> {
6429 self.operator.name()
6430 }
6431
6432 fn local_id(&self) -> NodeId {
6433 self.id.local_node_id().unwrap()
6434 }
6435
6436 fn global_id(&self) -> &GlobalNodeId {
6437 &self.id
6438 }
6439
6440 fn is_async(&self) -> bool {
6441 self.operator.is_async()
6442 }
6443
6444 fn is_input(&self) -> bool {
6445 self.operator.is_input()
6446 }
6447
6448 fn ready(&self) -> bool {
6449 self.operator.ready()
6450 }
6451
6452 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
6453 self.operator.register_ready_callback(cb);
6454 }
6455
6456 fn eval<'a>(
6457 &'a mut self,
6458 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
6459 Box::pin(async {
6460 let refs = self
6461 .input_streams
6462 .iter()
6463 .map(|stream| stream.get())
6464 .collect::<Vec<_>>();
6465
6466 self.output_stream.put(
6467 self.operator
6468 .eval(refs.iter().map(|r| Cow::Borrowed(StreamValue::peek(r))))
6469 .await,
6470 );
6471
6472 std::mem::drop(refs);
6473
6474 for i in self.input_streams.iter() {
6475 StreamValue::consume_token(i.val());
6476 }
6477 Ok(self.operator.flush_progress())
6478 })
6479 }
6480
6481 fn start_transaction(&mut self) {
6482 self.operator.start_transaction();
6483 }
6484
6485 fn flush(&mut self) {
6486 self.operator.flush();
6487 }
6488
6489 fn is_flush_complete(&self) -> bool {
6490 self.operator.is_flush_complete()
6491 }
6492
6493 fn clock_start(&mut self, scope: Scope) {
6494 self.operator.clock_start(scope);
6495 }
6496
6497 fn clock_end(&mut self, scope: Scope) {
6498 self.operator.clock_end(scope);
6499 }
6500
6501 fn init(&mut self) {
6502 self.operator.init(&self.id);
6503 }
6504
6505 fn metadata(&self, output: &mut OperatorMeta) {
6506 self.operator.metadata(output);
6507 }
6508
6509 fn fixedpoint(&self, scope: Scope) -> bool {
6510 self.operator.fixedpoint(scope)
6511 }
6512
6513 fn checkpoint(
6514 &mut self,
6515 base: &StoragePath,
6516 files: &mut Vec<Arc<dyn FileCommitter>>,
6517 ) -> Result<(), DbspError> {
6518 self.operator
6519 .checkpoint(base, self.persistent_id().as_deref(), files)
6520 }
6521
6522 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
6523 self.operator.restore(base, self.persistent_id().as_deref())
6524 }
6525
6526 fn start_compaction(&mut self) {
6527 self.operator.start_compaction()
6528 }
6529
6530 fn is_compaction_complete(&self) -> bool {
6531 self.operator.is_compaction_complete()
6532 }
6533
6534 fn clear_state(&mut self) -> Result<(), DbspError> {
6535 self.operator.clear_state()
6536 }
6537
6538 fn start_replay(&mut self) -> Result<(), DbspError> {
6539 self.operator.start_replay()
6540 }
6541
6542 fn is_replay_complete(&self) -> bool {
6543 self.operator.is_replay_complete()
6544 }
6545
6546 fn end_replay(&mut self) -> Result<(), DbspError> {
6547 self.operator.end_replay()
6548 }
6549
6550 fn set_label(&mut self, key: &str, value: &str) {
6551 self.labels.insert(key.to_string(), value.to_string());
6552 }
6553
6554 fn get_label(&self, key: &str) -> Option<&str> {
6555 self.labels.get(key).map(|s| s.as_str())
6556 }
6557
6558 fn labels(&self) -> &BTreeMap<String, String> {
6559 &self.labels
6560 }
6561
6562 fn as_any(&self) -> &dyn Any {
6563 self
6564 }
6565}
6566
6567struct FeedbackOutputNode<C, I, O, Op>
6573where
6574 C: Circuit,
6575{
6576 id: GlobalNodeId,
6577 operator: Rc<RefCell<Op>>,
6578 output_stream: Stream<C, O>,
6579 export_stream: Option<Stream<C::Parent, O>>,
6580 phantom_input: PhantomData<I>,
6581 labels: BTreeMap<String, String>,
6582}
6583
6584impl<C, I, O, Op> FeedbackOutputNode<C, I, O, Op>
6585where
6586 C: Circuit,
6587 Op: StrictUnaryOperator<I, O>,
6588{
6589 fn new(operator: Rc<RefCell<Op>>, circuit: C, id: NodeId) -> Self {
6590 Self {
6591 id: circuit.global_node_id().child(id),
6592 operator,
6593 output_stream: Stream::new(circuit.clone(), id),
6594 export_stream: None,
6595 phantom_input: PhantomData,
6596 labels: BTreeMap::new(),
6597 }
6598 }
6599
6600 fn with_export(operator: Rc<RefCell<Op>>, circuit: C, id: NodeId) -> Self {
6601 let mut result = Self::new(operator, circuit.clone(), id);
6602 result.export_stream = Some(Stream::with_origin(
6603 circuit.parent(),
6604 circuit.allocate_stream_id(),
6605 circuit.node_id(),
6606 GlobalNodeId::child_of(&circuit, id),
6607 ));
6608 result
6609 }
6610
6611 fn output_stream(&self) -> Stream<C, O> {
6612 self.output_stream.clone()
6613 }
6614}
6615
6616impl<C, I, O, Op> Node for FeedbackOutputNode<C, I, O, Op>
6617where
6618 C: Circuit,
6619 I: Data,
6620 O: Clone + 'static,
6621 Op: StrictUnaryOperator<I, O>,
6622{
6623 fn local_id(&self) -> NodeId {
6624 self.id.local_node_id().unwrap()
6625 }
6626
6627 fn global_id(&self) -> &GlobalNodeId {
6628 &self.id
6629 }
6630
6631 fn name(&self) -> Cow<'static, str> {
6632 self.operator.borrow().name()
6633 }
6634
6635 fn is_async(&self) -> bool {
6636 self.operator.borrow().is_async()
6637 }
6638
6639 fn is_input(&self) -> bool {
6640 self.operator.borrow().is_input()
6641 }
6642
6643 fn ready(&self) -> bool {
6644 self.operator.borrow().ready()
6645 }
6646
6647 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
6648 self.operator.borrow_mut().register_ready_callback(cb);
6649 }
6650
6651 fn eval<'a>(
6652 &'a mut self,
6653 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
6654 Box::pin(async {
6655 self.output_stream
6656 .put(self.operator.borrow_mut().get_output());
6657 Ok(None)
6658 })
6659 }
6660
6661 fn start_transaction(&mut self) {
6662 self.operator.borrow_mut().start_transaction();
6663 }
6664
6665 fn flush(&mut self) {
6666 self.operator.borrow_mut().flush();
6667 }
6668
6669 fn is_flush_complete(&self) -> bool {
6670 self.operator.borrow().is_flush_complete()
6671 }
6672
6673 fn clock_start(&mut self, scope: Scope) {
6674 self.operator.borrow_mut().clock_start(scope)
6675 }
6676
6677 fn clock_end(&mut self, scope: Scope) {
6678 if scope == 0
6679 && let Some(export_stream) = &mut self.export_stream
6680 {
6681 export_stream.put(self.operator.borrow_mut().get_final_output());
6682 }
6683 self.operator.borrow_mut().clock_end(scope);
6684 }
6685
6686 fn init(&mut self) {
6687 self.operator.borrow_mut().init(&self.id);
6688 }
6689
6690 fn metadata(&self, _output: &mut OperatorMeta) {
6691 }
6694
6695 fn fixedpoint(&self, scope: Scope) -> bool {
6696 self.operator.borrow().fixedpoint(scope)
6697 }
6698
6699 fn checkpoint(
6700 &mut self,
6701 base: &StoragePath,
6702 files: &mut Vec<Arc<dyn FileCommitter>>,
6703 ) -> Result<(), DbspError> {
6704 self.operator
6705 .borrow_mut()
6706 .checkpoint(base, self.persistent_id().as_deref(), files)
6707 }
6708
6709 fn restore(&mut self, base: &StoragePath) -> Result<(), DbspError> {
6710 self.operator
6711 .borrow_mut()
6712 .restore(base, self.persistent_id().as_deref())
6713 }
6714
6715 fn start_compaction(&mut self) {
6716 self.operator.borrow_mut().start_compaction()
6717 }
6718
6719 fn is_compaction_complete(&self) -> bool {
6720 self.operator.borrow().is_compaction_complete()
6721 }
6722
6723 fn clear_state(&mut self) -> Result<(), DbspError> {
6724 self.operator.borrow_mut().clear_state()
6725 }
6726
6727 fn start_replay(&mut self) -> Result<(), DbspError> {
6728 self.operator.borrow_mut().start_replay()
6729 }
6730
6731 fn is_replay_complete(&self) -> bool {
6732 self.operator.borrow().is_replay_complete()
6733 }
6734
6735 fn end_replay(&mut self) -> Result<(), DbspError> {
6736 self.operator.borrow_mut().end_replay()
6737 }
6738
6739 fn set_label(&mut self, key: &str, value: &str) {
6740 self.labels.insert(key.to_string(), value.to_string());
6741 }
6742
6743 fn get_label(&self, key: &str) -> Option<&str> {
6744 self.labels.get(key).map(|s| s.as_str())
6745 }
6746
6747 fn labels(&self) -> &BTreeMap<String, String> {
6748 &self.labels
6749 }
6750
6751 fn as_any(&self) -> &dyn Any {
6752 self
6753 }
6754}
6755
6756struct FeedbackInputNode<C, I, O, Op> {
6758 id: GlobalNodeId,
6760 operator: Rc<RefCell<Op>>,
6761 input_stream: Stream<C, I>,
6762 phantom_output: PhantomData<O>,
6763 labels: BTreeMap<String, String>,
6764}
6765
6766impl<C, I, O, Op> FeedbackInputNode<C, I, O, Op>
6767where
6768 Op: StrictUnaryOperator<I, O>,
6769 C: Circuit,
6770{
6771 fn new(operator: Rc<RefCell<Op>>, input_stream: Stream<C, I>, id: NodeId) -> Self {
6772 Self {
6773 id: input_stream.circuit().global_node_id().child(id),
6774 operator,
6775 input_stream,
6776 phantom_output: PhantomData,
6777 labels: BTreeMap::new(),
6778 }
6779 }
6780}
6781
6782impl<C, I, O, Op> Node for FeedbackInputNode<C, I, O, Op>
6783where
6784 Op: StrictUnaryOperator<I, O>,
6785 I: Data,
6786 O: 'static,
6787 C: Clone + 'static,
6788{
6789 fn name(&self) -> Cow<'static, str> {
6790 self.operator.borrow().name()
6791 }
6792
6793 fn local_id(&self) -> NodeId {
6794 self.id.local_node_id().unwrap()
6795 }
6796
6797 fn global_id(&self) -> &GlobalNodeId {
6798 &self.id
6799 }
6800
6801 fn is_async(&self) -> bool {
6802 self.operator.borrow().is_async()
6803 }
6804
6805 fn is_input(&self) -> bool {
6806 self.operator.borrow().is_input()
6807 }
6808
6809 fn ready(&self) -> bool {
6810 self.operator.borrow().ready()
6811 }
6812
6813 fn register_ready_callback(&mut self, cb: Box<dyn Fn() + Send + Sync>) {
6814 self.operator.borrow_mut().register_ready_callback(cb);
6815 }
6816
6817 #[allow(clippy::await_holding_refcell_ref)]
6819 fn eval<'a>(
6820 &'a mut self,
6821 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
6822 Box::pin(async {
6823 match StreamValue::take(self.input_stream.val()) {
6824 Some(v) => self.operator.borrow_mut().eval_strict_owned(v).await,
6825 None => {
6826 self.operator
6827 .borrow_mut()
6828 .eval_strict(StreamValue::peek(&self.input_stream.get()))
6829 .await
6830 }
6831 };
6832
6833 StreamValue::consume_token(self.input_stream.val());
6834
6835 Ok(None)
6836 })
6837 }
6838
6839 fn start_transaction(&mut self) {
6840 self.operator.borrow_mut().start_transaction();
6841 }
6842
6843 fn flush(&mut self) {
6844 self.operator.borrow_mut().flush_input();
6845 }
6846
6847 fn is_flush_complete(&self) -> bool {
6848 self.operator.borrow().is_flush_input_complete()
6849 }
6850
6851 fn clock_start(&mut self, _scope: Scope) {}
6854
6855 fn clock_end(&mut self, _scope: Scope) {}
6856
6857 fn init(&mut self) {
6858 self.operator.borrow_mut().init(&self.id);
6859 }
6860
6861 fn metadata(&self, output: &mut OperatorMeta) {
6862 self.operator.borrow().metadata(output)
6863 }
6864
6865 fn fixedpoint(&self, scope: Scope) -> bool {
6866 self.operator.borrow().fixedpoint(scope)
6867 }
6868
6869 fn checkpoint(
6870 &mut self,
6871 _base: &StoragePath,
6872 _files: &mut Vec<Arc<dyn FileCommitter>>,
6873 ) -> Result<(), DbspError> {
6874 Ok(())
6881 }
6882
6883 fn restore(&mut self, _base: &StoragePath) -> Result<(), DbspError> {
6884 Ok(())
6886 }
6887
6888 fn start_compaction(&mut self) {}
6889
6890 fn is_compaction_complete(&self) -> bool {
6891 true
6892 }
6893
6894 fn clear_state(&mut self) -> Result<(), DbspError> {
6895 Ok(())
6896 }
6897
6898 fn start_replay(&mut self) -> Result<(), DbspError> {
6899 self.operator.borrow_mut().start_replay()
6900 }
6901
6902 fn is_replay_complete(&self) -> bool {
6903 self.operator.borrow().is_replay_complete()
6904 }
6905
6906 fn end_replay(&mut self) -> Result<(), DbspError> {
6907 self.operator.borrow_mut().end_replay()
6908 }
6909
6910 fn set_label(&mut self, key: &str, value: &str) {
6911 self.labels.insert(key.to_string(), value.to_string());
6912 }
6913
6914 fn get_label(&self, key: &str) -> Option<&str> {
6915 self.labels.get(key).map(|s| s.as_str())
6916 }
6917
6918 fn labels(&self) -> &BTreeMap<String, String> {
6919 &self.labels
6920 }
6921
6922 fn as_any(&self) -> &dyn Any {
6923 self
6924 }
6925}
6926
6927pub struct FeedbackConnector<C, I, O, Op> {
6935 output_node_id: NodeId,
6936 circuit: C,
6937 operator: Rc<RefCell<Op>>,
6938 phantom_input: PhantomData<I>,
6939 phantom_output: PhantomData<O>,
6940}
6941
6942impl<C, I, O, Op> FeedbackConnector<C, I, O, Op>
6943where
6944 Op: StrictUnaryOperator<I, O>,
6945{
6946 fn new(output_node_id: NodeId, circuit: C, operator: Rc<RefCell<Op>>) -> Self {
6947 Self {
6948 output_node_id,
6949 circuit,
6950 operator,
6951 phantom_input: PhantomData,
6952 phantom_output: PhantomData,
6953 }
6954 }
6955}
6956
6957impl<C, I, O, Op> FeedbackConnector<C, I, O, Op>
6958where
6959 Op: StrictUnaryOperator<I, O>,
6960 I: Data,
6961 O: Data,
6962 C: Circuit,
6963{
6964 pub fn operator_mut(&self) -> RefMut<'_, Op> {
6965 self.operator.borrow_mut()
6966 }
6967
6968 pub fn connect(self, input_stream: &Stream<C, I>) {
6973 self.connect_with_preference(input_stream, OwnershipPreference::INDIFFERENT)
6974 }
6975
6976 pub fn connect_with_preference(
6977 self,
6978 input_stream: &Stream<C, I>,
6979 input_preference: OwnershipPreference,
6980 ) {
6981 self.circuit.connect_feedback_with_preference(
6982 self.output_node_id,
6983 self.operator,
6984 input_stream,
6985 input_preference,
6986 )
6987 }
6988}
6989
6990struct ChildNode<C>
6992where
6993 C: Circuit,
6994{
6995 id: GlobalNodeId,
6996 circuit: C,
6997 executor: Box<dyn Executor<C>>,
6998 labels: BTreeMap<String, String>,
6999 nesting_depth: Scope,
7000}
7001
7002impl<C> Drop for ChildNode<C>
7003where
7004 C: Circuit,
7005{
7006 fn drop(&mut self) {
7007 self.circuit.clear();
7010 }
7011}
7012
7013impl<C> ChildNode<C>
7014where
7015 C: Circuit,
7016{
7017 fn new<E>(circuit: C, nesting_depth: Scope, executor: E) -> Self
7018 where
7019 E: Executor<C>,
7020 {
7021 Self {
7022 id: circuit.global_node_id(),
7023 circuit,
7024 executor: Box::new(executor) as Box<dyn Executor<C>>,
7025 labels: BTreeMap::new(),
7026 nesting_depth,
7027 }
7028 }
7029}
7030
7031impl<C> Node for ChildNode<C>
7032where
7033 C: Circuit,
7034{
7035 fn name(&self) -> Cow<'static, str> {
7036 Cow::Borrowed("Subcircuit")
7037 }
7038
7039 fn local_id(&self) -> NodeId {
7040 self.id.local_node_id().unwrap()
7041 }
7042
7043 fn global_id(&self) -> &GlobalNodeId {
7044 &self.id
7045 }
7046
7047 fn is_circuit(&self) -> bool {
7048 true
7049 }
7050
7051 fn is_async(&self) -> bool {
7052 false
7053 }
7054
7055 fn is_input(&self) -> bool {
7056 false
7057 }
7058
7059 fn ready(&self) -> bool {
7060 true
7061 }
7062
7063 fn eval<'a>(
7064 &'a mut self,
7065 ) -> Pin<Box<dyn Future<Output = Result<Option<Position>, SchedulerError>> + 'a>> {
7066 Box::pin(async {
7067 for node_id in self.circuit.import_nodes() {
7070 self.circuit.eval_import_node(node_id).await;
7071 }
7072 self.executor.transaction(&self.circuit).await?;
7073 Ok(None)
7074 })
7075 }
7076
7077 fn start_transaction(&mut self) {
7078 }
7080
7081 fn flush(&mut self) {
7082 self.executor.flush();
7083 }
7084
7085 fn is_flush_complete(&self) -> bool {
7086 self.executor.is_flush_complete()
7087 }
7088
7089 fn clock_start(&mut self, scope: Scope) {
7090 self.circuit.clock_start(scope + self.nesting_depth);
7091 }
7092
7093 fn clock_end(&mut self, scope: Scope) {
7094 self.circuit.clock_end(scope + self.nesting_depth);
7095 }
7096
7097 fn metadata(&self, _meta: &mut OperatorMeta) {}
7098
7099 fn fixedpoint(&self, scope: Scope) -> bool {
7100 self.circuit.check_fixedpoint(scope + self.nesting_depth)
7101 }
7102
7103 fn map_nodes_recursive(
7104 &self,
7105 f: &mut dyn FnMut(&dyn Node) -> Result<(), DbspError>,
7106 ) -> Result<(), DbspError> {
7107 self.circuit.map_nodes_recursive(f)
7108 }
7109
7110 fn checkpoint(
7111 &mut self,
7112 _base: &StoragePath,
7113 _files: &mut Vec<Arc<dyn FileCommitter>>,
7114 ) -> Result<(), DbspError> {
7115 Ok(())
7116 }
7117
7118 fn restore(&mut self, _base: &StoragePath) -> Result<(), DbspError> {
7119 Ok(())
7120 }
7121
7122 fn start_compaction(&mut self) {
7123 self.circuit.start_compaction();
7124 }
7125
7126 fn is_compaction_complete(&self) -> bool {
7127 self.circuit.is_compaction_complete()
7128 }
7129
7130 fn clear_state(&mut self) -> Result<(), DbspError> {
7131 self.circuit
7132 .map_local_nodes_mut(&mut |node| node.clear_state())
7133 }
7134
7135 fn start_replay(&mut self) -> Result<(), DbspError> {
7136 Ok(())
7137 }
7138
7139 fn is_replay_complete(&self) -> bool {
7140 true
7141 }
7142
7143 fn end_replay(&mut self) -> Result<(), DbspError> {
7144 Ok(())
7145 }
7146
7147 fn set_label(&mut self, key: &str, value: &str) {
7148 self.labels.insert(key.to_string(), value.to_string());
7149 }
7150
7151 fn get_label(&self, key: &str) -> Option<&str> {
7152 self.labels.get(key).map(|s| s.as_str())
7153 }
7154
7155 fn labels(&self) -> &BTreeMap<String, String> {
7156 &self.labels
7157 }
7158
7159 fn map_child(&self, path: &[NodeId], f: &mut dyn FnMut(&dyn Node)) {
7160 self.circuit.map_node_relative(path, f);
7161 }
7162
7163 fn map_child_mut(&self, path: &[NodeId], f: &mut dyn FnMut(&mut dyn Node)) {
7164 self.circuit.map_node_mut_relative(path, f);
7165 }
7166
7167 fn as_any(&self) -> &dyn Any {
7168 self
7169 }
7170
7171 fn as_circuit(&self) -> Option<&dyn CircuitBase> {
7172 Some(&self.circuit)
7173 }
7174}
7175
7176pub struct CircuitHandle {
7182 circuit: RootCircuit,
7183 executor: Box<dyn Executor<RootCircuit>>,
7184 tokio_runtime: TokioRuntime,
7185 replay_info: Option<BootstrapInfo>,
7186}
7187
7188impl Drop for CircuitHandle {
7189 fn drop(&mut self) {
7190 self.circuit
7191 .log_scheduler_event(&SchedulerEvent::clock_end());
7192
7193 if !panicking() {
7197 self.circuit.clock_end(0)
7198 }
7199
7200 self.circuit.clear();
7205 }
7206}
7207
7208#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
7210pub struct BootstrapInfo {
7211 pub replay_sources: BTreeMap<NodeId, StreamId>,
7213
7214 #[allow(dead_code)]
7216 pub need_backfill: BTreeMap<NodeId, Option<String>>,
7217}
7218
7219impl CircuitHandle {
7220 pub fn transaction(&self) -> Result<(), DbspError> {
7222 self.tokio_runtime
7223 .block_on(async {
7224 let local_set = LocalSet::new();
7225 local_set
7226 .run_until(async { self.executor.transaction(&self.circuit).await })
7227 .await
7228 })
7229 .map_err(DbspError::Scheduler)
7230 }
7231
7232 pub fn start_transaction(&self) -> Result<(), DbspError> {
7237 self.tokio_runtime
7238 .block_on(async {
7239 let local_set = LocalSet::new();
7240 local_set
7241 .run_until(async { self.executor.start_transaction(&self.circuit).await })
7242 .await
7243 })
7244 .map_err(DbspError::Scheduler)
7245 }
7246
7247 pub fn start_commit_transaction(&self) -> Result<(), DbspError> {
7252 self.executor
7253 .start_commit_transaction()
7254 .map_err(DbspError::Scheduler)
7255 }
7256
7257 pub fn is_commit_complete(&self) -> bool {
7258 self.executor.is_commit_complete()
7259 }
7260
7261 pub fn commit_progress(&self) -> CommitProgress {
7262 self.executor.commit_progress()
7263 }
7264
7265 pub fn step(&self) -> Result<(), DbspError> {
7267 self.tokio_runtime
7268 .block_on(async {
7269 let local_set = LocalSet::new();
7270 local_set
7271 .run_until(async { self.executor.step(&self.circuit).await })
7272 .await
7273 })
7274 .map_err(DbspError::Scheduler)
7275 }
7276
7277 pub fn checkpoint(
7278 &mut self,
7279 base: &StoragePath,
7280 files: &mut Vec<Arc<dyn FileCommitter>>,
7281 ) -> Result<(), DbspError> {
7282 self.circuit
7315 .map_nodes_recursive_mut(&mut |node: &mut dyn Node| {
7316 let _span = Span::new("operator")
7317 .with_category("Checkpoint")
7318 .with_tooltip(|| format!("{} {}", node.name(), node.global_id()));
7319 DBSP_OPERATOR_COMMIT_LATENCY_MICROSECONDS
7320 .record_callback(|| node.checkpoint(base, files))
7321 })
7322 }
7323
7324 pub fn restore(&mut self, base: &StoragePath) -> Result<Option<BootstrapInfo>, DbspError> {
7347 let mut replay_sources: BTreeMap<NodeId, StreamId> = BTreeMap::new();
7349
7350 let mut need_backfill: BTreeSet<GlobalNodeId> = BTreeSet::new();
7352
7353 if Runtime::mode() == Mode::Persistent {
7361 let backend = Runtime::storage_backend()?;
7362 crate::circuit::checkpointer::Checkpointer::verify_checkpoint_intact(
7363 backend.as_ref(),
7364 base,
7365 )?;
7366 }
7367
7368 self.circuit.map_nodes_recursive_mut(
7373 &mut |node: &mut dyn Node| match node.restore(base) {
7374 Err(e) if Runtime::mode() == Mode::Ephemeral => Err(e),
7375 Err(DbspError::Storage(ioerror)) if ioerror.kind() == ErrorKind::NotFound => {
7376 need_backfill.insert(node.global_id().clone());
7377 Ok(())
7378 }
7379 Err(DbspError::IO(ioerror)) if ioerror.kind() == ErrorKind::NotFound => {
7380 need_backfill.insert(node.global_id().clone());
7381 Ok(())
7382 }
7383 Err(e) => Err(e),
7384 Ok(()) => Ok(()),
7385 },
7386 )?;
7387
7388 let additional_need_backfill: BTreeSet<GlobalNodeId> =
7390 self.invalidate_balancer_clusters(&need_backfill);
7391 if Runtime::worker_index() == 0 {
7392 debug!(
7393 "CircuitHandle::restore: additional need backfill: {:?}",
7394 additional_need_backfill
7395 );
7396 }
7397 need_backfill.extend(additional_need_backfill);
7398
7399 debug!(
7400 "worker {}: CircuitHandle::restore: found {} operators that require backfill: {:?}",
7401 Runtime::worker_index(),
7402 need_backfill.len(),
7403 need_backfill.iter().cloned().collect::<Vec<GlobalNodeId>>()
7404 );
7405
7406 let need_backfill = need_backfill
7410 .into_iter()
7411 .map(|gid| gid.top_level_ancestor())
7412 .collect::<BTreeSet<_>>();
7413
7414 let mut participate_in_backfill = need_backfill.clone();
7420
7421 let mut participate_in_backfill_new = need_backfill.clone();
7423
7424 while !participate_in_backfill_new.is_empty() {
7425 participate_in_backfill_new = self.compute_replay_nodes_step(
7426 &mut replay_sources,
7427 &need_backfill,
7428 participate_in_backfill_new,
7429 &mut participate_in_backfill,
7430 )?;
7431 }
7432
7433 debug!(
7434 "worker {}: CircuitHandle::restore: replaying {} operators: {:?}\n backfilling {} operators: {:?}\n replay circuit consists of {} operators: {:?}",
7435 Runtime::worker_index(),
7436 replay_sources.len(),
7437 replay_sources.keys().cloned().collect::<Vec<NodeId>>(),
7438 need_backfill.len(),
7439 need_backfill.iter().cloned().collect::<Vec<NodeId>>(),
7440 participate_in_backfill.len(),
7441 participate_in_backfill
7442 .iter()
7443 .cloned()
7444 .collect::<Vec<NodeId>>()
7445 );
7446
7447 let replay_nodes = replay_sources.keys().cloned().collect::<BTreeSet<_>>();
7448
7449 assert!(
7450 replay_nodes
7451 .intersection(&need_backfill)
7452 .collect::<Vec<_>>()
7453 .is_empty()
7454 );
7455
7456 let nodes_to_backfill = participate_in_backfill
7459 .difference(&replay_nodes)
7460 .cloned()
7461 .collect::<BTreeSet<_>>();
7462
7463 if !participate_in_backfill.is_empty() {
7464 for node_id in replay_nodes.iter() {
7466 self.circuit
7467 .map_local_node_mut(*node_id, &mut |node| node.start_replay())?;
7468 }
7469
7470 for node_id in nodes_to_backfill.iter() {
7472 self.circuit
7473 .map_local_node_mut(*node_id, &mut |node| node.clear_state())?;
7474 }
7475
7476 self.executor
7478 .prepare(&self.circuit, Some(&participate_in_backfill))?;
7479
7480 let need_backfill = nodes_to_backfill
7525 .iter()
7526 .map(|node_id| {
7527 let pid = self.circuit.map_local_node_mut(*node_id, &mut |node| {
7528 node.get_label(LABEL_PERSISTENT_OPERATOR_ID)
7529 .map(|s| s.to_string())
7530 });
7531
7532 (*node_id, pid)
7533 })
7534 .collect::<BTreeMap<_, _>>();
7535
7536 let replay_info = BootstrapInfo {
7537 replay_sources: replay_sources.clone(),
7538 need_backfill,
7539 };
7540
7541 self.replay_info = Some(replay_info.clone());
7542
7543 Ok(Some(replay_info))
7544 } else {
7545 Ok(None)
7546 }
7547 }
7548
7549 fn invalidate_balancer_clusters(
7579 &self,
7580 need_backfill: &BTreeSet<GlobalNodeId>,
7581 ) -> BTreeSet<GlobalNodeId> {
7582 let need_backfill_node_ids: BTreeSet<NodeId> = need_backfill
7584 .iter()
7585 .map(|gid| gid.top_level_ancestor())
7586 .collect();
7587
7588 let additional_need_backfill = self
7590 .circuit
7591 .balancer()
7592 .invalidate_clusters_for_bootstrapping(&need_backfill_node_ids);
7593
7594 let nodes_to_add = self.propagate_need_backfill_forward(
7597 additional_need_backfill
7598 .difference(&need_backfill_node_ids)
7599 .cloned()
7600 .collect(),
7601 );
7602
7603 nodes_to_add
7605 .into_iter()
7606 .map(|node_id| GlobalNodeId::root().child(node_id))
7607 .collect()
7608 }
7609
7610 fn propagate_need_backfill_forward(
7612 &self,
7613 mut need_backfill: BTreeSet<NodeId>,
7614 ) -> BTreeSet<NodeId> {
7615 let mut worklist: Vec<NodeId> = need_backfill.iter().cloned().collect();
7617 let mut visited = BTreeSet::new();
7618
7619 while let Some(node_id) = worklist.pop() {
7620 if visited.contains(&node_id) {
7621 continue;
7622 }
7623 visited.insert(node_id);
7624
7625 let successors: Vec<NodeId> = self
7627 .circuit
7628 .edges()
7629 .by_source
7630 .get(&node_id)
7631 .into_iter()
7632 .flat_map(|edges| edges.iter().map(|edge| edge.to))
7633 .collect();
7634
7635 for successor in successors {
7636 if !visited.contains(&successor) {
7637 worklist.push(successor);
7638 need_backfill.insert(successor);
7639 }
7640 }
7641
7642 let dependencies: Vec<NodeId> = self
7644 .circuit
7645 .edges()
7646 .by_destination
7647 .get(&node_id)
7648 .into_iter()
7649 .flat_map(|edges| edges.iter())
7650 .filter(|edge| edge.is_dependency())
7651 .map(|edge| edge.from)
7652 .collect();
7653
7654 for dependency in dependencies {
7655 if !visited.contains(&dependency) {
7656 worklist.push(dependency);
7657 need_backfill.insert(dependency);
7658 }
7659 }
7660 }
7661
7662 need_backfill
7663 }
7664
7665 fn compute_replay_nodes_step(
7676 &self,
7677 replay_sources: &mut BTreeMap<NodeId, StreamId>,
7678 need_backfill: &BTreeSet<NodeId>,
7679 participate_in_backfill_new: BTreeSet<NodeId>,
7680 participate_in_backfill: &mut BTreeSet<NodeId>,
7681 ) -> Result<BTreeSet<NodeId>, DbspError> {
7682 let mut inputs = BTreeSet::new();
7683
7684 for node_id in participate_in_backfill_new.iter() {
7685 let node_inputs = self
7694 .circuit
7695 .edges()
7696 .by_destination
7697 .get(node_id)
7698 .iter()
7699 .flat_map(|edges| edges.iter())
7700 .filter(|edge| edge.is_stream())
7701 .map(|edge| {
7702 (Some(edge.stream_id().unwrap()), edge.from)
7706 })
7707 .collect::<Vec<_>>();
7708
7709 for input in node_inputs.into_iter() {
7710 inputs.insert(input);
7711 }
7712
7713 for edge in self.circuit.edges().dependencies_of(*node_id) {
7715 inputs.insert((None, edge.from));
7716 }
7717
7718 for edge in self.circuit.edges().depend_on(*node_id) {
7720 inputs.insert((None, edge.to));
7721 }
7722 }
7723
7724 let mut participate_in_backfill_new = BTreeSet::new();
7725
7726 let mut replay_streams = BTreeMap::new();
7727
7728 for (stream_id, mut node_id) in inputs.into_iter() {
7729 if let Some(stream_id) = stream_id
7734 && let Some(replay_source) = self.circuit.get_replay_source(stream_id)
7735 {
7736 if !need_backfill.contains(&replay_source.local_node_id()) {
7739 replay_streams.insert(stream_id, replay_source.clone());
7740 node_id = replay_source.local_node_id();
7748 }
7749 }
7750
7751 if !participate_in_backfill.contains(&node_id) {
7752 participate_in_backfill.insert(node_id);
7754 participate_in_backfill_new.insert(node_id);
7755 }
7756 }
7757
7758 for (original_stream, replay_stream) in replay_streams.into_iter() {
7760 replay_sources
7761 .entry(replay_stream.local_node_id())
7762 .or_insert_with(|| {
7763 self.circuit
7764 .add_replay_edges(original_stream, replay_stream.as_ref());
7765 replay_stream.stream_id()
7766 });
7767 }
7768
7769 Ok(participate_in_backfill_new)
7770 }
7771
7772 pub fn is_replay_complete(&self) -> bool {
7774 let Some(replay_info) = self.replay_info.as_ref() else {
7775 return true;
7776 };
7777
7778 let all_complete = replay_info.replay_sources.keys().all(|node_id| {
7782 self.circuit
7783 .map_local_node_mut(*node_id, &mut |node| node.is_replay_complete())
7784 });
7785
7786 all_complete && self.is_commit_complete()
7787 }
7788
7789 pub fn complete_replay(&mut self) -> Result<(), DbspError> {
7795 let Some(replay_info) = self.replay_info.take() else {
7798 return Ok(());
7799 };
7800
7801 for (node_id, stream_id) in replay_info.replay_sources.iter() {
7803 self.circuit
7804 .map_local_node_mut(*node_id, &mut |node| node.end_replay())?;
7805 self.circuit.edges_mut().delete_stream(*stream_id);
7806 }
7807
7808 self.executor.prepare(&self.circuit, None)?;
7810
7811 Ok(())
7837 }
7838
7839 pub fn fingerprint(&self) -> u64 {
7840 let mut fip = Fingerprinter::default();
7841 let _ = self.circuit.map_nodes_recursive(&mut |node: &dyn Node| {
7842 node.fingerprint(&mut fip);
7843 Ok(())
7844 });
7845 fip.finish()
7846 }
7847
7848 pub fn register_scheduler_event_handler<F>(&self, name: &str, handler: F)
7858 where
7859 F: FnMut(&SchedulerEvent<'_>) + 'static,
7860 {
7861 self.circuit.register_scheduler_event_handler(name, handler);
7862 }
7863
7864 pub fn unregister_scheduler_event_handler(&self, name: &str) -> bool {
7870 self.circuit.unregister_scheduler_event_handler(name)
7871 }
7872
7873 pub fn lir(&self) -> LirCircuit {
7875 (&self.circuit as &dyn CircuitBase).to_lir()
7876 }
7877
7878 pub fn set_auto_rebalance(&self, enable: bool) -> Result<(), DbspError> {
7879 self.circuit.set_auto_rebalance(enable)
7880 }
7881
7882 pub fn set_balancer_hint_by_global_id(
7883 &self,
7884 global_node_id: &GlobalNodeId,
7885 hint: BalancerHint,
7886 ) -> Result<(), DbspError> {
7887 self.circuit
7888 .set_balancer_hint_by_global_id(global_node_id, hint)
7889 }
7890
7891 pub fn set_balancer_hint(
7892 &self,
7893 persistent_id: &str,
7894 hint: BalancerHint,
7895 ) -> Result<(), DbspError> {
7896 self.circuit.set_balancer_hint(persistent_id, hint)
7897 }
7898
7899 pub fn get_current_balancer_policies(&self) -> BTreeMap<GlobalNodeId, PartitioningPolicy> {
7900 self.circuit
7901 .get_current_balancer_policies()
7902 .into_iter()
7903 .map(|(node_id, policy)| (GlobalNodeId::root().child(node_id), policy))
7904 .collect()
7905 }
7906
7907 pub fn get_current_balancer_policy(
7908 &self,
7909 persistent_id: &str,
7910 ) -> Result<PartitioningPolicy, DbspError> {
7911 self.circuit.get_current_balancer_policy(persistent_id)
7912 }
7913
7914 pub fn rebalance(&self) {
7915 self.circuit.rebalance()
7916 }
7917
7918 pub fn start_compaction(&self) {
7919 self.circuit.start_compaction()
7920 }
7921
7922 pub fn is_compaction_complete(&self) -> bool {
7923 self.circuit.is_compaction_complete()
7924 }
7925}
7926
7927#[derive(Copy, Clone, Debug, Default, SizeOf)]
7929pub struct ElapsedTime {
7930 pub real: Duration,
7932
7933 pub cpu: Duration,
7939}
7940
7941impl AddAssign for ElapsedTime {
7942 fn add_assign(&mut self, rhs: Self) {
7943 self.real += rhs.real;
7944 self.cpu += rhs.cpu;
7945 }
7946}
7947
7948pin_project! {
7949 #[derive(Debug)]
7960 pub struct Timed<T> {
7961 #[pin]
7963 task: T,
7964
7965 elapsed: ElapsedTime,
7967 }
7968}
7969
7970impl<T> Timed<T> {
7971 fn new(task: T) -> Self {
7972 Self {
7973 task,
7974 elapsed: ElapsedTime::default(),
7975 }
7976 }
7977}
7978
7979pub struct ThreadCpuTime(pub Duration);
7981
7982impl ThreadCpuTime {
7983 pub fn now() -> Self {
7985 let nanos = clock_gettime(ClockId::CLOCK_THREAD_CPUTIME_ID)
7986 .unwrap()
7987 .num_nanoseconds();
7988 Self(Duration::from_nanos(nanos.max(0).cast_unsigned()))
7989 }
7990
7991 pub fn elapsed(&self) -> Duration {
7999 Self::now().0.saturating_sub(self.0)
8000 }
8001}
8002
8003impl<T> Future for Timed<T>
8004where
8005 T: Future,
8006{
8007 type Output = (T::Output, ElapsedTime);
8008
8009 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
8010 let this = self.project();
8011 let start = Instant::now();
8012 let start_cputime = ThreadCpuTime::now();
8013 let ret = this.task.poll(cx);
8014 this.elapsed.real += start.elapsed();
8015 this.elapsed.cpu += start_cputime.elapsed();
8016 ret.map(|value| (value, take(&mut *this.elapsed)))
8017 }
8018}
8019
8020#[cfg(test)]
8021mod tests {
8022 use crate::{
8023 Circuit, Error as DbspError, RootCircuit,
8024 circuit::schedule::{DynamicScheduler, Scheduler},
8025 monitor::TraceMonitor,
8026 operator::{Generator, Z1},
8027 };
8028 use anyhow::anyhow;
8029 use std::{cell::RefCell, ops::Deref, rc::Rc, vec::Vec};
8030
8031 #[test]
8032 fn sum_circuit_dynamic() {
8033 sum_circuit::<DynamicScheduler>();
8034 }
8035 fn sum_circuit<S>()
8037 where
8038 S: Scheduler + 'static,
8039 {
8040 let actual_output: Rc<RefCell<Vec<isize>>> = Rc::new(RefCell::new(Vec::with_capacity(100)));
8041 let actual_output_clone = actual_output.clone();
8042 let circuit = RootCircuit::build_with_scheduler::<_, _, S>(|circuit| {
8043 TraceMonitor::new_panic_on_error().attach(circuit, "monitor");
8044 let mut n: isize = 0;
8045 let source = circuit.add_source(Generator::new(move || {
8046 let result = n;
8047 n += 1;
8048 result
8049 }));
8050 let integrator = source.integrate();
8051 integrator.inspect(|n| println!("{}", n));
8052 integrator.inspect(move |n| actual_output_clone.borrow_mut().push(*n));
8053 Ok(())
8054 })
8055 .unwrap()
8056 .0;
8057
8058 for _ in 0..100 {
8059 circuit.transaction().unwrap();
8060 }
8061
8062 let mut sum = 0;
8063 let mut expected_output: Vec<isize> = Vec::with_capacity(100);
8064 for i in 0..100 {
8065 sum += i;
8066 expected_output.push(sum);
8067 }
8068 assert_eq!(&expected_output, actual_output.borrow().deref());
8069 }
8070
8071 #[test]
8072 fn recursive_sum_circuit_dynamic() {
8073 recursive_sum_circuit::<DynamicScheduler>()
8074 }
8075
8076 fn recursive_sum_circuit<S>()
8077 where
8078 S: Scheduler + 'static,
8079 {
8080 let actual_output: Rc<RefCell<Vec<usize>>> = Rc::new(RefCell::new(Vec::with_capacity(100)));
8081 let actual_output_clone = actual_output.clone();
8082
8083 let circuit = RootCircuit::build_with_scheduler::<_, _, S>(|circuit| {
8084 TraceMonitor::new_panic_on_error().attach(circuit, "monitor");
8085
8086 let mut n: usize = 0;
8087 let source = circuit.add_source(Generator::new(move || {
8088 let result = n;
8089 n += 1;
8090 result
8091 }));
8092 let (z1_output, z1_feedback) = circuit.add_feedback(Z1::new(0));
8093 let plus = source
8094 .apply2(&z1_output, |n1: &usize, n2: &usize| *n1 + *n2)
8095 .inspect(move |n| actual_output_clone.borrow_mut().push(*n));
8096 z1_feedback.connect(&plus);
8097 Ok(())
8098 })
8099 .unwrap()
8100 .0;
8101
8102 for _ in 0..100 {
8103 circuit.transaction().unwrap();
8104 }
8105
8106 let mut sum = 0;
8107 let mut expected_output: Vec<usize> = Vec::with_capacity(100);
8108 for i in 0..100 {
8109 sum += i;
8110 expected_output.push(sum);
8111 }
8112 assert_eq!(&expected_output, actual_output.borrow().deref());
8113 }
8114
8115 #[test]
8116 fn factorial_dynamic() {
8117 factorial::<DynamicScheduler>();
8118 }
8119
8120 fn factorial<S>()
8126 where
8127 S: Scheduler + 'static,
8128 {
8129 let actual_output: Rc<RefCell<Vec<usize>>> = Rc::new(RefCell::new(Vec::with_capacity(100)));
8130 let actual_output_clone = actual_output.clone();
8131
8132 let circuit = RootCircuit::build_with_scheduler::<_, _, S>(|circuit| {
8133 TraceMonitor::new_panic_on_error().attach(circuit, "monitor");
8134
8135 let mut n: usize = 0;
8136 let source = circuit.add_source(Generator::new(move || {
8137 n += 1;
8138 n
8139 }));
8140 let fact = circuit
8141 .iterate_with_condition_and_scheduler::<_, _, S>(|child| {
8142 let mut counter = 0;
8143 let countdown = source.delta0(child).apply_mut(move |parent_val| {
8144 if *parent_val > 0 {
8145 counter = *parent_val;
8146 };
8147 let res = counter;
8148 counter -= 1;
8149 res
8150 });
8151 let (z1_output, z1_feedback) = child.add_feedback_with_export(Z1::new(1));
8152 let mul = countdown.apply2(&z1_output.local, |n1: &usize, n2: &usize| n1 * n2);
8153 z1_feedback.connect(&mul);
8154 Ok((countdown.condition(|n| *n <= 1), z1_output.export))
8155 })
8156 .unwrap();
8157 fact.inspect(move |n| actual_output_clone.borrow_mut().push(*n));
8158 Ok(())
8159 })
8160 .unwrap()
8161 .0;
8162
8163 for _ in 1..10 {
8164 circuit.transaction().unwrap();
8165 }
8166
8167 let mut expected_output: Vec<usize> = Vec::with_capacity(10);
8168 for i in 1..10 {
8169 expected_output.push(my_factorial(i));
8170 }
8171 assert_eq!(&expected_output, actual_output.borrow().deref());
8172 }
8173
8174 fn my_factorial(n: usize) -> usize {
8175 if n == 1 { 1 } else { n * my_factorial(n - 1) }
8176 }
8177
8178 #[test]
8181 fn open_close_region() {
8182 const REGION: &str = "my_region";
8183
8184 let monitor = TraceMonitor::new_panic_on_error();
8185 let region: Rc<RefCell<Option<super::RegionName>>> = Rc::new(RefCell::new(None));
8186
8187 let _circuit = RootCircuit::build({
8188 let monitor = monitor.clone();
8189 let region = region.clone();
8190 move |circuit| {
8191 monitor.attach(circuit, "monitor");
8192
8193 let r = circuit.create_region_name(REGION, 0);
8194
8195 circuit.open_region(r.clone());
8196 let source1 = circuit.add_source(Generator::new(|| 1_i32));
8197 circuit.close_region(r.clone());
8198
8199 circuit.open_region(r.clone());
8200 let source2 = circuit.add_source(Generator::new(|| 2_i32));
8201 circuit.close_region(r.clone());
8202
8203 circuit.open_region(r.clone());
8204 source1
8205 .apply2(&source2, |a: &i32, b: &i32| a + b)
8206 .inspect(|_| {});
8207 circuit.close_region(r.clone());
8208
8209 *region.borrow_mut() = Some(r);
8210 Ok(())
8211 }
8212 })
8213 .unwrap()
8214 .0;
8215
8216 let region = region.borrow();
8218 assert_eq!(
8219 monitor.count_nodes_in_region(region.as_ref().unwrap()),
8220 Some(4)
8221 );
8222 }
8223
8224 #[test]
8228 fn separate_create_region_same_name() {
8229 const REGION: &str = "my_region";
8230
8231 let monitor = TraceMonitor::new_panic_on_error();
8232 let r1: Rc<RefCell<Option<super::RegionName>>> = Rc::new(RefCell::new(None));
8234 let r2: Rc<RefCell<Option<super::RegionName>>> = Rc::new(RefCell::new(None));
8235
8236 let _circuit = RootCircuit::build({
8237 let monitor = monitor.clone();
8238 let r1 = r1.clone();
8239 let r2 = r2.clone();
8240 move |circuit| {
8241 monitor.attach(circuit, "monitor");
8242
8243 let region1 = circuit.create_region_name(REGION, 0);
8244 let region2 = circuit.create_region_name(REGION, 1);
8245
8246 circuit.open_region(region1.clone());
8247 circuit.add_source(Generator::new(|| 1_i32));
8248 circuit.close_region(region1.clone());
8249
8250 circuit.open_region(region2.clone());
8251 circuit.add_source(Generator::new(|| 2_i32));
8252 circuit.close_region(region2.clone());
8253
8254 *r1.borrow_mut() = Some(region1);
8255 *r2.borrow_mut() = Some(region2);
8256 Ok(())
8257 }
8258 })
8259 .unwrap()
8260 .0;
8261
8262 let r1 = r1.borrow();
8263 let r2 = r2.borrow();
8264 assert_eq!(monitor.count_regions_with_name(REGION), 2);
8266 assert_eq!(monitor.count_nodes_in_region(r1.as_ref().unwrap()), Some(1));
8267 assert_eq!(monitor.count_nodes_in_region(r2.as_ref().unwrap()), Some(1));
8268 }
8269
8270 #[test]
8271 fn init_circuit_constructor_error() {
8272 match RootCircuit::build(|_circuit| Err::<(), _>(anyhow!("constructor failed"))) {
8273 Err(DbspError::Constructor(msg)) => assert_eq!(msg.to_string(), "constructor failed"),
8274 _ => panic!(),
8275 }
8276 }
8277}