Repository navigation
perf(pm): rayon-only best snapshot (repro, do not merge) #2881
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
66d9fff
33a10c1
e17dbc8
0d52d56
a89a59e
0f56496
19ce70e
b4e77c8
c41407a
84baf04
036f479
896e172
0914e12
f5006bb
1286998
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||
|---|---|---|---|---|---|---|---|---|
|
|
@@ -13,6 +13,35 @@ use super::fetch::{ | |||||||
| use super::http::get_client; | ||||||||
| use crate::model::manifest::{CoreVersionManifest, FullManifest}; | ||||||||
|
|
||||||||
| /// Parse JSON bytes on rayon's CPU thread pool (native) or inline | ||||||||
| /// (wasm32). Keeps the tokio runtime free of `simd_json` CPU work so | ||||||||
| /// other in-flight manifest fetches can keep driving network IO while | ||||||||
| /// this one is parsing. Rayon's global pool work-steals across | ||||||||
| /// `num_cpus` threads, so concurrent manifest parses parallelise. | ||||||||
| async fn parse_json_off_runtime<T>(bytes: Vec<u8>) -> Result<T, anyhow::Error> | ||||||||
| where | ||||||||
| T: serde::de::DeserializeOwned + Send + 'static, | ||||||||
| { | ||||||||
| #[cfg(not(target_arch = "wasm32"))] | ||||||||
| { | ||||||||
| let (tx, rx) = tokio::sync::oneshot::channel(); | ||||||||
| rayon::spawn(move || { | ||||||||
| let mut buf = bytes; | ||||||||
| let result = simd_json::serde::from_slice::<T>(&mut buf) | ||||||||
| .map_err(|e| anyhow!("JSON parse error: {e}")); | ||||||||
| // Receiver dropped means the awaiting future was cancelled. | ||||||||
| let _ = tx.send(result); | ||||||||
| }); | ||||||||
| rx.await | ||||||||
| .map_err(|e| anyhow!("rayon parse channel closed: {e}"))? | ||||||||
|
Comment on lines
+35
to
+36
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a panic occurs within the
Suggested change
References
|
||||||||
| } | ||||||||
| #[cfg(target_arch = "wasm32")] | ||||||||
| { | ||||||||
| let mut buf = bytes; | ||||||||
| simd_json::serde::from_slice::<T>(&mut buf).map_err(|e| anyhow!("JSON parse error: {e}")) | ||||||||
| } | ||||||||
| } | ||||||||
|
|
||||||||
| /// Result of a full manifest fetch with ETag support. | ||||||||
| /// Transient return value, immediately destructured — Box not needed. | ||||||||
| #[allow(clippy::large_enum_variant)] | ||||||||
|
|
@@ -91,11 +120,13 @@ pub async fn fetch_full_manifest(opts: FetchManifestOptions<'_>) -> Result<Fetch | |||||||
| .await | ||||||||
| .map_err(|e| FetchError::Permanent(anyhow!("Response read error: {e}")))? | ||||||||
| .to_vec(); | ||||||||
| // Save raw bytes before simd_json mutates the parse buffer. | ||||||||
| let mut parse_buf = raw_bytes.clone(); | ||||||||
| let mut manifest: FullManifest = | ||||||||
| simd_json::serde::from_slice(&mut parse_buf) | ||||||||
| .map_err(|e| FetchError::Permanent(anyhow!("JSON parse error: {e}")))?; | ||||||||
| // simd_json mutates the parse buffer; clone so the raw | ||||||||
| // bytes survive for `manifest.raw`. Parse runs off-runtime | ||||||||
| // on rayon (native) so it cannot block sibling fetches. | ||||||||
| let parse_buf = raw_bytes.clone(); | ||||||||
| let mut manifest: FullManifest = parse_json_off_runtime(parse_buf) | ||||||||
| .await | ||||||||
| .map_err(FetchError::Permanent)?; | ||||||||
| manifest.raw = std::sync::Arc::from(raw_bytes); | ||||||||
|
|
||||||||
| Ok(FetchManifestResult::Ok(manifest, new_etag)) | ||||||||
|
|
@@ -182,13 +213,14 @@ pub async fn fetch_version_manifest( | |||||||
| .map_err(classify_reqwest_error)?; | ||||||||
|
|
||||||||
| if response.status().is_success() { | ||||||||
| let mut bytes = response | ||||||||
| let bytes = response | ||||||||
| .bytes() | ||||||||
| .await | ||||||||
| .map_err(|e| FetchError::Permanent(anyhow!("Response read error: {e}")))? | ||||||||
| .to_vec(); | ||||||||
| simd_json::serde::from_slice(&mut bytes) | ||||||||
| .map_err(|e| FetchError::Permanent(anyhow!("JSON parse error: {e}"))) | ||||||||
| parse_json_off_runtime::<CoreVersionManifest>(bytes) | ||||||||
| .await | ||||||||
| .map_err(FetchError::Permanent) | ||||||||
| } else { | ||||||||
| Err(classify_status(response.status(), &url)) | ||||||||
| } | ||||||||
|
|
||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current implementation with
.ok().flatten()silently swallows panics that might occur within therayon::spawntask (e.g., infull.get_core_version). This can lead to confusing behavior, as a panic during parsing would manifest as a "version not found" error downstream, which is misleading.According to the repository's general rules, panics should be treated as unrecoverable bugs and not be silently recovered from. To adhere to this, you should propagate the panic to the calling
tokiotask.You can achieve this by replacing
.ok().flatten()with.expect(...)to ensure that a panic in the spawned task will cause the awaiting task to panic as well.References