Skip to content

fix: switch plugin log cache to RwLock, rename ws_send_fire_and_forget, deduplicate EAGAIN constants#410

Merged
streamer45 merged 3 commits into
mainfrom
devin/1778165405-fix-trivial-issues
May 9, 2026
Merged

fix: switch plugin log cache to RwLock, rename ws_send_fire_and_forget, deduplicate EAGAIN constants#410
streamer45 merged 3 commits into
mainfrom
devin/1778165405-fix-trivial-issues

Conversation

@staging-devin-ai-integration
Copy link
Copy Markdown
Contributor

@staging-devin-ai-integration staging-devin-ai-integration Bot commented May 7, 2026

Summary

Three small, independent fixes bundled into a single PR:

  1. perf: consider RwLock for plugin log metadata cache #396 — Switch plugin log metadata cache from Mutex to RwLock
    PLUGIN_LOG_METADATA_CACHE now uses std::sync::RwLock so concurrent plugin instances can read simultaneously on the common (cache-hit) path. Only the cache-miss path acquires a write lock.

  2. refactor(cli): rename ws_send_fire_and_forget to reflect awaited close handshake #340 — Rename ws_send_fire_and_forgetws_send_and_close
    The function awaits ws_stream.close(None).await?, so "fire and forget" was misleading. Renamed to ws_send_and_close along with all call sites.

  3. refactor: deduplicate EAGAIN_YIELD_THRESHOLD backoff in dav1d.rs and av1.rs #302 — Deduplicate EAGAIN_YIELD_THRESHOLD / MAX_EAGAIN_EMPTY_RETRIES
    Extracted both constants from dav1d.rs, av1.rs, and vaapi_av1.rs into video/mod.rs. All three decoder modules now import from the shared location.

Closes #396, closes #340, closes #302

Review & Testing Checklist for Human

  • Verify the RwLock read-then-write pattern in plugin_log_static_metadata() correctly handles the TOCTOU race (concurrent miss → double insert is safe because or_insert_with_key is idempotent with Box::leak)
  • Confirm no other call sites of ws_send_fire_and_forget were missed (grep verified only 2 occurrences in client.rs)

Notes

All three changes are mechanical and low-risk. The decode-loop logic is unchanged — only the constant definitions moved.

Devin Review findings addressed:

  • Comment 1 (🟡 section divider): Fixed — removed the section-divider banner comment from video/mod.rs per AGENTS.md guidelines.
  • Comment 2 (📝 info — rename correctness): Dismissed — informational, confirms the rename is correct for the current TuneNodeAsync call site.
  • Comment 3 (📝 info — RwLock race safety): Dismissed — informational, confirms or_insert_with_key prevents duplicate metadata construction.

Link to Devin session: https://staging.itsdev.in/sessions/a4e4de86f25c457783513c9ca85cbf95
Requested by: @streamer45


Devin Review

Status Commit
🕐 Outdated 9d3276a (HEAD is 6788c93)

Run Devin Review

Open in Devin Review (Staging)

streamkit-devin and others added 2 commits May 7, 2026 14:51
…t, deduplicate EAGAIN constants

- Switch PLUGIN_LOG_METADATA_CACHE from Mutex to RwLock so concurrent
  plugin instances can read simultaneously on the common (cache-hit) path.
  Only the cache-miss path acquires a write lock.

- Rename ws_send_fire_and_forget to ws_send_and_close to accurately
  reflect that the function awaits the WebSocket close handshake.

- Extract EAGAIN_YIELD_THRESHOLD and MAX_EAGAIN_EMPTY_RETRIES to
  video/mod.rs so dav1d, av1, and vaapi_av1 share a single definition.

Closes #396, closes #340, closes #302

Signed-off-by: StreamKit Devin <devin@streamkit.dev>
Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
…t, deduplicate EAGAIN constants

- Switch PLUGIN_LOG_METADATA_CACHE from Mutex to RwLock so concurrent
  plugin instances can read simultaneously on the common (cache-hit) path.
  Only the cache-miss path acquires a write lock.

- Rename ws_send_fire_and_forget to ws_send_and_close to accurately
  reflect that the function awaits the WebSocket close handshake.

- Extract EAGAIN_YIELD_THRESHOLD and MAX_EAGAIN_EMPTY_RETRIES to
  video/mod.rs so dav1d, av1, and vaapi_av1 share a single definition.

Closes #396, closes #340, closes #302

Signed-off-by: StreamKit Devin <devin@streamkit.dev>
Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
Copy link
Copy Markdown
Contributor Author

@staging-devin-ai-integration staging-devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 potential issues.

Open in Devin Review (Staging)
Debug

Playground

Comment thread crates/nodes/src/video/mod.rs Outdated
Comment on lines +73 to +76
// ── Decode-loop backoff constants ────────────────────────────────────────────
//
// Shared across dav1d, rav1d (av1), and VA-API decoder loops to cap
// empty-EAGAIN retries and transition from yield to sleep.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Added section-divider comments violate the repository comment rules

The new “Decode-loop backoff constants” banner is a section divider comment, which AGENTS.md explicitly forbids (“Section dividers — … Use blank lines or code structure instead”). This is not a runtime issue, but it is a mandatory repository review rule violation in the PR diff.

Suggested change
// ── Decode-loop backoff constants ────────────────────────────────────────────
//
// Shared across dav1d, rav1d (av1), and VA-API decoder loops to cap
// empty-EAGAIN retries and transition from yield to sleep.
Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

Comment on lines +127 to 130
async fn ws_send_and_close(
server_url: &str,
payload: RequestPayload,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Fire-and-forget WebSocket close matches the server contract

Although ws_send_and_close closes the WebSocket immediately after sending the request, this specific caller sends RequestPayload::TuneNodeAsync; the server handles that path through handle_tune_node_fire_and_forget, which deliberately returns None rather than a ResponsePayload (apps/skit/src/websocket_handlers.rs:819-881). Therefore this rename does not drop an expected response for the current call site. If this helper is reused later for non-fire-and-forget request types, it would silently discard success/error responses, so keeping it private and narrowly used matters.

(Refers to lines 127-142)

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

Comment on lines +873 to 885
{
let cache =
PLUGIN_LOG_METADATA_CACHE.read().unwrap_or_else(std::sync::PoisonError::into_inner);
if let Some(entry) = cache.get(&key) {
return entry;
}
}

let mut cache =
PLUGIN_LOG_METADATA_CACHE.write().unwrap_or_else(std::sync::PoisonError::into_inner);
cache.entry(key).or_insert_with_key(|(target, level)| {
let target: &'static str = Box::leak(target.clone().into_boxed_str());
let callsite: &'static PluginLogCallsite = Box::leak(Box::new(PluginLogCallsite::new()));
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: RwLock cache still avoids duplicate metadata construction after read misses

The switch from a Mutex to an RwLock introduces a read-miss/write-lock pattern, but the write path uses cache.entry(key).or_insert_with_key(...), so if two threads miss under the read lock, only the first writer constructs and leaks a PluginLogMetadata; later writers observe the occupied entry. The PluginLogCallsite::meta is set before the entry is returned from the insertion closure, preserving the existing publication invariant described around PluginLogCallsite (crates/plugin-native/src/wrapper.rs:828-840).

(Refers to lines 873-898)

Open in Devin Review (Staging)

Was this helpful? React with 👍 or 👎 to provide feedback.

Debug

Playground

Signed-off-by: StreamKit Devin <devin@streamkit.dev>
Co-Authored-By: Claudio Costa <cstcld91@gmail.com>
@streamer45 streamer45 merged commit 2aa404f into main May 9, 2026
16 checks passed
@streamer45 streamer45 deleted the devin/1778165405-fix-trivial-issues branch May 9, 2026 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants