Skip to content

Commit b00b2f5

Browse files
Make operator process one packet at a time asynchronously, use async mutex, drop lock before multiplexing, remove unneeded poison error handling, split model on core side, and add context to load_model error case.
1 parent 788b47d commit b00b2f5

File tree

12 files changed

+172
-212
lines changed

12 files changed

+172
-212
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ std_instead_of_core = { level = "allow", priority = 127 } # we shou
160160
string_add = { level = "allow", priority = 127 } # simple concat ok
161161
string_lit_chars_any = { level = "allow", priority = 127 } # favor readability until a perf case comes up
162162
use_debug = { level = "warn", priority = 127 } # debug print
163+
wildcard_enum_match_arm = { level = "allow", priority = 127 } # allow wildcard match arm in enums
163164

164165
# temporary
165166
single_call_fn = { level = "allow", priority = 127 } # remove once more models need pointer serializers/deserializers

cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
"getrandom",
8080
"wasi",
8181
"patchelf",
82-
"itertools"
82+
"itertools",
83+
"colinianking"
8384
],
8485
"useGitignore": false,
8586
"ignorePaths": [

src/core/error.rs

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,8 @@ use serde_json;
66
use serde_yaml;
77
use std::{
88
backtrace::{Backtrace, BacktraceStatus},
9-
error::Error,
109
fmt::{self, Formatter},
1110
io, path,
12-
sync::PoisonError,
1311
};
1412
use tokio::task;
1513

@@ -73,16 +71,6 @@ impl From<path::StripPrefixError> for OrcaError {
7371
}
7472
}
7573
}
76-
impl<T> From<PoisonError<T>> for OrcaError {
77-
fn from(_: PoisonError<T>) -> Self {
78-
Self {
79-
kind: Kind::PoisonError {
80-
source: Box::<dyn Error + Send + Sync>::from("PoisonError"),
81-
backtrace: Some(Backtrace::capture()),
82-
},
83-
}
84-
}
85-
}
8674
impl From<serde_json::Error> for OrcaError {
8775
fn from(error: serde_json::Error) -> Self {
8876
Self {
@@ -142,7 +130,6 @@ impl fmt::Debug for OrcaError {
142130
| Kind::GlobPatternError { backtrace, .. }
143131
| Kind::IoError { backtrace, .. }
144132
| Kind::PathPrefixError { backtrace, .. }
145-
| Kind::PoisonError { backtrace, .. }
146133
| Kind::SerdeJsonError { backtrace, .. }
147134
| Kind::SerdeYamlError { backtrace, .. }
148135
| Kind::TokioTaskJoinError { backtrace, .. } => {
Lines changed: 3 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
1-
use crate::{
2-
core::util::get_type_name,
3-
uniffi::{
4-
error::Result,
5-
model::pod::{Pod, PodJob},
6-
},
7-
};
1+
use crate::{core::util::get_type_name, uniffi::error::Result};
82
use heck::ToSnakeCase as _;
93
use indexmap::IndexMap;
10-
use serde::{Deserialize as _, Deserializer, Serialize, Serializer};
4+
use serde::{Serialize, Serializer};
115
use serde_yaml::{self, Value};
126
use std::{
137
collections::{BTreeMap, HashMap},
148
hash::BuildHasher,
159
result,
16-
sync::Arc,
1710
};
1811
/// Converts a model instance into a consistent yaml.
1912
///
@@ -64,48 +57,4 @@ where
6457
sorted.serialize(serializer)
6558
}
6659

67-
#[expect(clippy::expect_used, reason = "Serde requires this signature.")]
68-
pub fn deserialize_pod<'de, D>(deserializer: D) -> result::Result<Arc<Pod>, D::Error>
69-
where
70-
D: Deserializer<'de>,
71-
{
72-
let value = Value::deserialize(deserializer)?;
73-
(value).as_str().map_or_else(
74-
|| {
75-
Ok(serde_yaml::from_value(value.clone())
76-
.expect("Failed to convert from serde value to specific type."))
77-
},
78-
|hash| {
79-
Ok({
80-
Pod {
81-
hash: hash.to_owned(),
82-
..Pod::default()
83-
}
84-
.into()
85-
})
86-
},
87-
)
88-
}
89-
90-
#[expect(clippy::expect_used, reason = "Serde requires this signature.")]
91-
pub fn deserialize_pod_job<'de, D>(deserializer: D) -> result::Result<Arc<PodJob>, D::Error>
92-
where
93-
D: Deserializer<'de>,
94-
{
95-
let value = Value::deserialize(deserializer)?;
96-
(value).as_str().map_or_else(
97-
|| {
98-
Ok(serde_yaml::from_value(value.clone())
99-
.expect("Failed to convert from serde value to specific type."))
100-
},
101-
|hash| {
102-
Ok({
103-
PodJob {
104-
hash: hash.to_owned(),
105-
..PodJob::default()
106-
}
107-
.into()
108-
})
109-
},
110-
)
111-
}
60+
pub mod pod;

src/core/model/pod.rs

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
use crate::uniffi::model::pod::{Pod, PodJob};
2+
use serde::{Deserialize as _, Deserializer};
3+
use serde_yaml::{self, Value};
4+
use std::{result, sync::Arc};
5+
6+
#[expect(clippy::expect_used, reason = "Serde requires this signature.")]
7+
pub fn deserialize_pod<'de, D>(deserializer: D) -> result::Result<Arc<Pod>, D::Error>
8+
where
9+
D: Deserializer<'de>,
10+
{
11+
let value = Value::deserialize(deserializer)?;
12+
(value).as_str().map_or_else(
13+
|| {
14+
Ok(serde_yaml::from_value(value.clone())
15+
.expect("Failed to convert from serde value to specific type."))
16+
},
17+
|hash| {
18+
Ok({
19+
Pod {
20+
hash: hash.to_owned(),
21+
..Pod::default()
22+
}
23+
.into()
24+
})
25+
},
26+
)
27+
}
28+
29+
#[expect(clippy::expect_used, reason = "Serde requires this signature.")]
30+
pub fn deserialize_pod_job<'de, D>(deserializer: D) -> result::Result<Arc<PodJob>, D::Error>
31+
where
32+
D: Deserializer<'de>,
33+
{
34+
let value = Value::deserialize(deserializer)?;
35+
(value).as_str().map_or_else(
36+
|| {
37+
Ok(serde_yaml::from_value(value.clone())
38+
.expect("Failed to convert from serde value to specific type."))
39+
},
40+
|hash| {
41+
Ok({
42+
PodJob {
43+
hash: hash.to_owned(),
44+
..PodJob::default()
45+
}
46+
.into()
47+
})
48+
},
49+
)
50+
}

src/core/operator.rs

Lines changed: 48 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,63 @@
11
use crate::uniffi::{error::Result, model::packet::Packet};
2+
use async_trait;
23
use itertools::Itertools as _;
3-
use std::{
4-
clone::Clone,
5-
collections::HashMap,
6-
iter::IntoIterator,
7-
sync::{Arc, Mutex},
8-
};
4+
use std::{clone::Clone, collections::HashMap, iter::IntoIterator, sync::Arc};
5+
use tokio::sync::Mutex;
96

7+
#[async_trait::async_trait]
108
pub trait Operator {
11-
fn next(&self, packets: Vec<(String, Packet)>) -> Result<Vec<Packet>>;
9+
async fn next(&self, stream_name: String, packet: Packet) -> Result<Vec<Packet>>;
1210
}
1311

1412
pub struct JoinOperator {
1513
parent_count: usize,
16-
received_streams: Arc<Mutex<HashMap<String, Vec<Packet>>>>,
14+
received_packets: Arc<Mutex<HashMap<String, Vec<Packet>>>>,
1715
}
1816

1917
impl JoinOperator {
2018
pub fn new(parent_count: usize) -> Self {
2119
Self {
2220
parent_count,
23-
received_streams: Arc::new(Mutex::new(HashMap::new())),
21+
received_packets: Arc::new(Mutex::new(HashMap::new())),
2422
}
2523
}
2624
}
2725

28-
#[expect(clippy::excessive_nesting, reason = "Nesting manageable.")]
26+
#[async_trait::async_trait]
2927
impl Operator for JoinOperator {
30-
fn next(&self, packets: Vec<(String, Packet)>) -> Result<Vec<Packet>> {
31-
let mut next_packets = vec![];
32-
for (stream, packet) in &packets {
33-
let mut received_streams = self.received_streams.lock()?;
34-
if self.parent_count - usize::from(!received_streams.contains_key(stream))
35-
== received_streams.len()
28+
async fn next(&self, stream_name: String, packet: Packet) -> Result<Vec<Packet>> {
29+
let mut received_packets = self.received_packets.lock().await;
30+
received_packets
31+
.entry(stream_name.clone())
32+
.or_default()
33+
.push(packet.clone());
34+
Ok(
35+
if self.parent_count - usize::from(!received_packets.contains_key(&stream_name))
36+
== received_packets.len()
3637
{
37-
let packets_to_multiplex = received_streams
38+
let packets_to_multiplex = received_packets
3839
.iter()
3940
.filter_map(|(parent_stream, parent_packets)| {
40-
(parent_stream != stream).then_some(parent_packets.clone())
41+
(parent_stream != &stream_name).then_some(parent_packets.clone())
4142
})
42-
.chain(vec![vec![packet.clone()]].into_iter());
43-
let current_packets = packets_to_multiplex.multi_cartesian_product().map(
44-
|packet_combinations_to_merge| {
43+
.chain(vec![vec![packet.clone()]].into_iter())
44+
.collect::<Vec<_>>();
45+
drop(received_packets);
46+
47+
packets_to_multiplex
48+
.into_iter()
49+
.multi_cartesian_product()
50+
.map(|packet_combinations_to_merge| {
4551
packet_combinations_to_merge
4652
.into_iter()
4753
.flat_map(IntoIterator::into_iter)
4854
.collect::<HashMap<_, _>>()
49-
},
50-
);
51-
next_packets.extend(current_packets);
52-
}
53-
received_streams
54-
.entry(stream.clone())
55-
.or_default()
56-
.push(packet.clone());
57-
}
58-
Ok(next_packets)
55+
})
56+
.collect()
57+
} else {
58+
vec![]
59+
},
60+
)
5961
}
6062
}
6163

@@ -69,23 +71,21 @@ impl MapOperator {
6971
}
7072
}
7173

74+
#[async_trait::async_trait]
7275
impl Operator for MapOperator {
73-
fn next(&self, packets: Vec<(String, Packet)>) -> Result<Vec<Packet>> {
74-
Ok(packets
75-
.iter()
76-
.map(|(_, packet)| {
77-
packet
78-
.iter()
79-
.map(|(packet_key, path_set)| {
80-
(
81-
self.map
82-
.get(packet_key)
83-
.map_or_else(|| packet_key.clone(), Clone::clone),
84-
path_set.clone(),
85-
)
86-
})
87-
.collect()
88-
})
89-
.collect())
76+
async fn next(&self, _: String, packet: Packet) -> Result<Vec<Packet>> {
77+
Ok(vec![
78+
packet
79+
.iter()
80+
.map(|(packet_key, path_set)| {
81+
(
82+
self.map
83+
.get(packet_key)
84+
.map_or_else(|| packet_key.clone(), Clone::clone),
85+
path_set.clone(),
86+
)
87+
})
88+
.collect(),
89+
])
9090
}
9191
}

src/core/store/filestore.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use heck::ToSnakeCase as _;
1616
use regex::Regex;
1717
use serde::{Serialize, de::DeserializeOwned};
1818
use serde_yaml;
19-
use snafu::OptionExt as _;
19+
use snafu::{OptionExt as _, ResultExt as _};
2020
use std::{
2121
fmt, fs,
2222
path::{Path, PathBuf},
@@ -189,15 +189,17 @@ impl LocalFileStore {
189189
model_id: &ModelID,
190190
) -> Result<(T, Option<Annotation>, String)> {
191191
match model_id {
192-
ModelID::Hash(hash) => Ok((
193-
serde_yaml::from_str(&fs::read_to_string(self.make_path(
194-
&T::default(),
195-
hash,
196-
Self::SPEC_RELPATH,
197-
))?)?,
198-
None,
199-
hash.to_owned(),
200-
)),
192+
ModelID::Hash(hash) => {
193+
let path = self.make_path(&T::default(), hash, Self::SPEC_RELPATH);
194+
Ok((
195+
serde_yaml::from_str(
196+
&fs::read_to_string(path.clone())
197+
.context(selector::InvalidFilepath { path })?,
198+
)?,
199+
None,
200+
hash.to_owned(),
201+
))
202+
}
201203
ModelID::Annotation(name, version) => {
202204
let hash = self.lookup_hash(&T::default(), name, version)?;
203205
Ok((

src/uniffi/error.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,6 @@ pub(crate) enum Kind {
7878
backtrace: Option<Backtrace>,
7979
},
8080
#[snafu(transparent)]
81-
PoisonError {
82-
source: Box<dyn Error + Send + Sync>,
83-
backtrace: Option<Backtrace>,
84-
},
85-
#[snafu(transparent)]
8681
SerdeJsonError {
8782
source: Box<serde_json::Error>,
8883
backtrace: Option<Backtrace>,

src/uniffi/model/pod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ use crate::{
22
core::{
33
crypto::{hash_blob, hash_buffer},
44
model::{
5-
deserialize_pod, deserialize_pod_job, serialize_hashmap, serialize_hashmap_option,
6-
to_yaml,
5+
pod::{deserialize_pod, deserialize_pod_job},
6+
serialize_hashmap, serialize_hashmap_option, to_yaml,
77
},
88
util::get,
99
validation::validate_packet,

src/uniffi/orchestrator/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use crate::uniffi::{
55
pod::{PodJob, PodResult},
66
},
77
};
8+
use async_trait;
89
use serde::{Deserialize, Serialize};
910
use std::{collections::HashMap, fmt, path::PathBuf, sync::Arc};
1011
use uniffi;

0 commit comments

Comments
 (0)