Skip to content

Commit d91b2fb

Browse files
wan9chiclaude
andcommitted
refactor(fspy): rename CollectedAccesses and drop its async wrapper
Nothing is collected anymore — frames are borrowed in place — and the async wrapper descended from the file-lock era, when acquiring the trace could block until every sender exited. Closing is now bounded by the number of reported records and runs inline, so the type becomes ChannelAccesses with a TryFrom<Receiver> conversion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent a5c8ec3 commit d91b2fb

3 files changed

Lines changed: 23 additions & 22 deletions

File tree

crates/fspy/src/ipc.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,33 @@ use fspy_shared::ipc::{
44
PathAccess,
55
channel::{Frames, Receiver},
66
};
7-
use tokio::task::spawn_blocking;
87

98
// Shared memory size for storing path accesses.
109
// 4 GiB is large enough to store path accesses in almost any realistic scenario.
1110
// This doesn't allocate physical memory until it's actually used.
1211
pub const SHM_CAPACITY: usize = 4 * 1024 * 1024 * 1024;
1312

14-
/// The validated path accesses collected from a closed IPC channel.
15-
pub struct CollectedAccesses {
13+
/// The path accesses a run reported through the IPC channel.
14+
pub struct ChannelAccesses {
1615
frames: Frames,
1716
}
1817

19-
impl CollectedAccesses {
20-
/// Closes the channel and validates the collected trace.
18+
impl TryFrom<Receiver> for ChannelAccesses {
19+
type Error = io::Error;
20+
21+
/// Closes the channel and rejects traces that cannot back the run's
22+
/// file accesses.
2123
///
22-
/// Never waits for tracked processes: closing rejects new records and
24+
/// Never waits for tracked processes closing rejects new records and
2325
/// atomically ignores unfinished ones (see
24-
/// [`fspy_shared::ipc::channel::Receiver::close`]).
26+
/// [`fspy_shared::ipc::channel::Receiver::close`]) — and its work is
27+
/// bounded by the number of reported records, so it runs inline.
2528
///
26-
/// Fails when the trace cannot back the run's file accesses: a record
27-
/// was lost before close, or the shared-memory metadata was corrupted.
28-
/// Failing here — instead of returning a silently short trace — keeps
29-
/// the tracking result trustworthy for caching.
30-
pub fn collect(receiver: Receiver) -> io::Result<Self> {
29+
/// Fails when a record was lost before close or the shared-memory
30+
/// metadata was corrupted. Failing here — instead of returning a
31+
/// silently short trace — keeps the tracking result trustworthy for
32+
/// caching.
33+
fn try_from(receiver: Receiver) -> io::Result<Self> {
3134
let frames = receiver.close()?;
3235
if !frames.is_complete() {
3336
return Err(io::Error::new(
@@ -37,11 +40,9 @@ impl CollectedAccesses {
3740
}
3841
Ok(Self { frames })
3942
}
43+
}
4044

41-
pub async fn collect_async(receiver: Receiver) -> io::Result<Self> {
42-
spawn_blocking(move || Self::collect(receiver)).await.expect("collect task panicked")
43-
}
44-
45+
impl ChannelAccesses {
4546
pub fn iter_path_accesses(&self) -> impl Iterator<Item = PathAccess<'_>> {
4647
self.frames.iter().map(|frame| {
4748
wincode::deserialize_exact(frame)

crates/fspy/src/unix/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use tokio::task::spawn_blocking;
2525
use tokio_util::sync::CancellationToken;
2626

2727
#[cfg(not(target_env = "musl"))]
28-
use crate::ipc::{CollectedAccesses, SHM_CAPACITY};
28+
use crate::ipc::{ChannelAccesses, SHM_CAPACITY};
2929
use crate::{ChildTermination, Command, TrackedChild, arena::PathAccessArena, error::SpawnError};
3030

3131
#[derive(Debug)]
@@ -162,7 +162,7 @@ impl SpyImpl {
162162
// Close the ipc channel after the child has exited.
163163
// We are not interested in path accesses from descendants after the main child has exited.
164164
#[cfg(not(target_env = "musl"))]
165-
let ipc_accesses = CollectedAccesses::collect_async(ipc_receiver).await?;
165+
let ipc_accesses = ChannelAccesses::try_from(ipc_receiver)?;
166166
let path_accesses = PathAccessIterable {
167167
arenas,
168168
#[cfg(not(target_env = "musl"))]
@@ -180,7 +180,7 @@ impl SpyImpl {
180180
pub struct PathAccessIterable {
181181
arenas: Vec<PathAccessArena>,
182182
#[cfg(not(target_env = "musl"))]
183-
ipc_accesses: CollectedAccesses,
183+
ipc_accesses: ChannelAccesses,
184184
}
185185

186186
impl PathAccessIterable {

crates/fspy/src/windows/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ use crate::{
2424
ChildTermination, TrackedChild,
2525
command::Command,
2626
error::SpawnError,
27-
ipc::{CollectedAccesses, SHM_CAPACITY},
27+
ipc::{ChannelAccesses, SHM_CAPACITY},
2828
};
2929

3030
const INTERPOSE_CDYLIB: Artifact =
3131
artifact!("fspy_preload", "CARGO_CDYLIB_FILE_FSPY_PRELOAD_WINDOWS");
3232

3333
pub struct PathAccessIterable {
34-
ipc_accesses: CollectedAccesses,
34+
ipc_accesses: ChannelAccesses,
3535
}
3636

3737
impl PathAccessIterable {
@@ -169,7 +169,7 @@ impl SpyImpl {
169169
};
170170
// Close the ipc channel after the child has exited.
171171
// We are not interested in path accesses from descendants after the main child has exited.
172-
let ipc_accesses = CollectedAccesses::collect_async(receiver).await?;
172+
let ipc_accesses = ChannelAccesses::try_from(receiver)?;
173173
let path_accesses = PathAccessIterable { ipc_accesses };
174174

175175
io::Result::Ok(ChildTermination { status, path_accesses })

0 commit comments

Comments
 (0)