Skip to content

Commit

Permalink
Merge failure batches without sorting
Browse files Browse the repository at this point in the history
I don't think we should actually use this code, but I couldn't resist
writing it.
  • Loading branch information
Stebalien committed Jan 16, 2024
1 parent 5c9a4e4 commit 53e10d4
Showing 1 changed file with 35 additions and 33 deletions.
68 changes: 35 additions & 33 deletions runtime/src/util/batch_return.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use fvm_ipld_encoding::tuple::*;
use fvm_shared::error::ExitCode;
use std::fmt;

#[derive(Serialize_tuple, Deserialize_tuple, Clone, Debug, PartialEq, Eq)]
#[derive(Serialize_tuple, Deserialize_tuple, Copy, Clone, Debug, PartialEq, Eq)]
pub struct FailCode {
pub idx: u32,
pub code: ExitCode,
Expand Down Expand Up @@ -101,39 +101,41 @@ impl fmt::Display for BatchReturn {
/// indexed against only those successful items.
/// E.g. stack([OK, E1, OK, E2], [OK, E3], [E4]) => [E4, E1, E3, E2]
pub fn stack(batch_returns: &[BatchReturn]) -> BatchReturn {
if batch_returns.is_empty() {
let Some((base, rest)) = batch_returns.split_first() else {
return BatchReturn::empty();
}
let mut base = batch_returns[0].clone();
for nxt in &batch_returns[1..] {
assert_eq!(
base.success_count as usize,
nxt.size(),
"can't stack batch of {} on batch with {} successes",
nxt.size(),
base.success_count
);
let mut nxt_fail = nxt.fail_codes.iter().peekable();
let mut base_fail = base.fail_codes.iter().peekable();
let mut offset = 0;
let mut new_fail_codes = vec![];
while nxt_fail.peek().is_some() {
let nxt_fail = nxt_fail.next().unwrap();
while base_fail.peek().is_some()
&& base_fail.peek().unwrap().idx <= nxt_fail.idx + offset
{
base_fail.next();
offset += 1;
}
new_fail_codes.push(FailCode { idx: nxt_fail.idx + offset, code: nxt_fail.code })
}
base.fail_codes.extend(new_fail_codes);
base.fail_codes.sort_by(|a, b| a.idx.cmp(&b.idx));
base.success_count = nxt.success_count;
}
assert_eq!(base.size(), batch_returns[0].size());
assert_eq!(base.success_count, batch_returns[batch_returns.len() - 1].success_count);
base
};
// Recursively fold each batch into the previous batch, starting at the base.
let base_iter = Box::new(base.fail_codes.iter().copied()) as Box<dyn Iterator<Item = FailCode>>;
let (success_count, fail_codes) = rest.iter().fold(
(base.success_count, base_iter.peekable()),
|(success_count, mut base_iter), next| {
assert_eq!(
success_count as usize,
next.size(),
"can't stack batch of {} on batch with {} successes",
next.size(),
success_count
);
let mut offset = 0;
let mut next_iter = next.fail_codes.iter().copied().peekable();
let res = Box::new(std::iter::from_fn(move || {
let take_base = (base_iter.peek(), next_iter.peek()) {
(Some(b), Some(n)) => b.idx <= n.idx + offset,
(Some(_), None) => true,
(None, Some(_)) => false,
(None, None) => return None,
};
if take_base {
offset += 1;
base_iter.next()
} else {
next_iter.next().map(|n| FailCode { idx: n.idx + offset, code: n.code })
}
})) as Box<dyn Iterator<Item = FailCode>>;
(next.success_count, res.peekable())
},
);
BatchReturn { success_count, fail_codes: fail_codes.collect() }
}

pub struct BatchReturnGen {
Expand Down

0 comments on commit 53e10d4

Please sign in to comment.