mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-02 22:41:47 -06:00
M2: cancel obsolete in-flight requests (#702)
* render: cancel obsolete in-flight requests * #623: recheck cancellation after busy publication * #623: record rendering session in roadmap * M2: a request cancelled during the parse doesn't leave its worker unable to render The abort was cached as the worker's parse result, so every later request on that worker failed as unparsable. Also drops ROADMAP edits that described other PRs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Brandon Thomas <echelon@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
Brandon Thomas
parent
7fafadc3a2
commit
742c42ab63
@@ -27,14 +27,20 @@ impl From<RenderRequest> for Key {
|
||||
}
|
||||
}
|
||||
|
||||
impl Key {
|
||||
fn request(self) -> RenderRequest {
|
||||
RenderRequest { page: self.page, kind: self.kind, tile: self.tile, scale: f32::from_bits(self.scale), tag: self.tag }
|
||||
}
|
||||
}
|
||||
|
||||
struct Completed {
|
||||
page: RenderedPage,
|
||||
bytes: usize,
|
||||
valid: Option<Arc<AtomicBool>>,
|
||||
valid: Vec<Arc<AtomicBool>>,
|
||||
}
|
||||
|
||||
fn valid(token: &Option<Arc<AtomicBool>>) -> bool {
|
||||
token.as_ref().is_none_or(|v| v.load(Ordering::Acquire))
|
||||
fn valid(tokens: &[Arc<AtomicBool>]) -> bool {
|
||||
tokens.iter().all(|token| token.load(Ordering::Acquire))
|
||||
}
|
||||
|
||||
#[cfg(any(test, not(target_arch = "wasm32")))]
|
||||
@@ -124,21 +130,23 @@ impl Default for WorkQueue {
|
||||
}
|
||||
|
||||
impl WorkQueue {
|
||||
pub(super) fn replace(&self, requests: Vec<RenderRequest>) {
|
||||
pub(super) fn replace(&self, requests: Vec<RenderRequest>) -> Vec<RenderRequest> {
|
||||
let mut state = lock(&self.state);
|
||||
if state.closed {
|
||||
return;
|
||||
return Vec::new();
|
||||
}
|
||||
let mut desired = HashSet::with_capacity(requests.len());
|
||||
let requests: Vec<_> = requests.into_iter().filter(|r| desired.insert(Key::from(*r))).collect();
|
||||
state.results.retain(|r| desired.contains(&Key::from(r.page.request)) && valid(&r.valid));
|
||||
state.bytes = state.results.iter().fold(0usize, |n, r| n.saturating_add(r.bytes));
|
||||
let completed: HashSet<_> = state.results.iter().map(|r| Key::from(r.page.request)).collect();
|
||||
let obsolete = state.active.iter().filter(|key| !desired.contains(key)).copied().map(Key::request).collect();
|
||||
state.desired = requests.iter().enumerate().map(|(priority, req)| (Key::from(*req), priority)).collect();
|
||||
state.pending =
|
||||
requests.into_iter().rev().filter(|r| !state.active.contains(&Key::from(*r)) && !completed.contains(&Key::from(*r))).collect();
|
||||
drop(state);
|
||||
self.changed.notify_all();
|
||||
obsolete
|
||||
}
|
||||
|
||||
pub(super) fn pop(&self) -> Option<RenderRequest> {
|
||||
@@ -179,6 +187,11 @@ impl WorkQueue {
|
||||
/// using the pool's fallback parser, including when failure occurs after enqueueing.
|
||||
#[cfg(any(test, not(target_arch = "wasm32")))]
|
||||
pub(super) fn send_valid(&self, page: RenderedPage, token: Option<Arc<AtomicBool>>) -> Result<(), ()> {
|
||||
self.send_valid_with_tokens(page, token.into_iter().collect())
|
||||
}
|
||||
|
||||
#[cfg(any(test, not(target_arch = "wasm32")))]
|
||||
pub(super) fn send_valid_with_tokens(&self, page: RenderedPage, tokens: Vec<Arc<AtomicBool>>) -> Result<(), ()> {
|
||||
let key = Key::from(page.request);
|
||||
let bytes = result_bytes(&page);
|
||||
let mut state = lock(&self.state);
|
||||
@@ -191,7 +204,7 @@ impl WorkQueue {
|
||||
state.active.remove(&key);
|
||||
return Ok(());
|
||||
}
|
||||
if !valid(&token) {
|
||||
if !valid(&tokens) {
|
||||
state.retry(page.request);
|
||||
self.changed.notify_all();
|
||||
return Ok(());
|
||||
@@ -199,7 +212,7 @@ impl WorkQueue {
|
||||
if state.results.len() < self.max_count && (state.results.is_empty() || state.bytes.saturating_add(bytes) <= self.max_bytes) {
|
||||
state.active.remove(&key);
|
||||
state.bytes = state.bytes.saturating_add(bytes);
|
||||
state.results.push_back(Completed { page, bytes, valid: token });
|
||||
state.results.push_back(Completed { page, bytes, valid: tokens });
|
||||
drop(state);
|
||||
self.changed.notify_all();
|
||||
return Ok(());
|
||||
@@ -236,7 +249,7 @@ impl WorkQueue {
|
||||
}
|
||||
}
|
||||
state.bytes = state.bytes.saturating_add(bytes);
|
||||
state.results.push_front(Completed { page, bytes, valid: None });
|
||||
state.results.push_front(Completed { page, bytes, valid: Vec::new() });
|
||||
drop(state);
|
||||
self.changed.notify_all();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user