Skip to content

fix(server): return SQLite write versions atomically - #4408

Merged
johntmyers merged 2 commits into
NVIDIA:mainfrom
ericcurtin:fix/4401-sqlite-write-returning/ericcurtin
Oct 12, 2026
Merged

johntmyers merged 2 commits into
NVIDIA:mainfrom
ericcurtin:fix/4401-sqlite-write-returning/ericcurtin

Conversation

@ericcurtin

Copy link
Copy Markdown
Contributor

Summary

SQLite put_if returned the version of a later writer. Use RETURNING, as Postgres does.

Related Issue

Closes #4401

Changes

  • RETURNING for version-checked updates and unconditional upserts.
  • Shared write_result_from_row helper.
  • Concurrent writer test.

Testing

  • Checks appropriate to the affected code and behavior pass
  • Unit tests added/updated (if applicable)
  • E2E tests added/updated (if applicable)

cargo fmt, cargo clippy --all-targets and cargo test --lib for openshell-server. The new test fails (duplicate versions) without the change.

Checklist

  • Follows Conventional Commits
  • Commits are signed off (DCO)
  • Architecture docs updated (if applicable)

Use RETURNING instead of a follow-up read.

Signed-off-by: Eric Curtin <eric.curtin@docker.com>
@copy-pr-bot

copy-pr-bot Bot commented Oct 11, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@ericcurtin

Copy link
Copy Markdown
Contributor Author

@johntmyers @elezar PTAL when you get a chance, and /ok to test b7b318366d882887c088b8a9b66de5632a13b7a2 if it looks good. Thank you!

Signed-off-by: Eric Curtin <eric.curtin@docker.com>
@johntmyers johntmyers added the test:e2e Requires end-to-end coverage label Oct 12, 2026
@johntmyers

Copy link
Copy Markdown
Collaborator

/ok to test 73eddf6

@github-actions

Copy link
Copy Markdown

Label test:e2e applied, but pull-request/4408 does not exist yet. A maintainer needs to comment /ok to test 73eddf6ca34af086b7326616e351420699dda2b4 to mirror this PR. Once the mirror exists, re-apply the label or re-run Branch E2E Checks from the Actions tab.

@johntmyers johntmyers left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

gator-agent

PR Review Status

@ericcurtin, I reviewed the latest head in response to your review and testing request. Both SQLite write paths now return their own version and timestamps atomically, and the concurrent-writer regression test covers both paths. No blocking findings remain.

I applied test:e2e and authorized the current-head test mirror. Branch Checks, Helm Lint, and E2E are running; Trivy Changes is queued after workflow approval. Gator will inspect the results next cycle.

Blocking findings: None.
Carried findings: None.
Non-blocking suggestions: None.

Gator metadata
  • Validation: Focused persistence correctness fix for the reproducible race in #4401; no duplicate implementation found.
  • Docs: Not needed; restores existing write-result semantics without adding a direct UX or configuration change.
  • Checks: DCO passed; Branch Checks and Helm Lint running; Trivy Changes queued on current head.
  • E2E: test:e2e applied; current-head Branch E2E Checks running with build jobs active.
  • Head SHA: 73eddf6ca34af086b7326616e351420699dda2b4
  • Base SHA: eeba0e7954c0fb4d8e9e2e29d1bfa68e290eb8b3
  • Merge base SHA: eeba0e7954c0fb4d8e9e2e29d1bfa68e290eb8b3
  • Patch ID: 144e9bdf8cbee1027a37d30c4aaac120db127e31
  • Gator payload: 12
  • Review mode: initial
  • Previous reviewed SHA: none
  • Review budget exhausted: no
  • Maintainer decision required: no
  • Next state: gator:watch-pipeline

@johntmyers johntmyers added gator:watch-pipeline Gator is monitoring PR CI/CD status gator:approval-needed Gator completed review; maintainer approval needed and removed gator:watch-pipeline Gator is monitoring PR CI/CD status labels Oct 12, 2026
@johntmyers
johntmyers added this pull request to the merge queue Oct 12, 2026
Merged via the queue into NVIDIA:main with commit 473b5f9 Oct 12, 2026
118 of 120 checks passed
@johntmyers

Copy link
Copy Markdown
Collaborator

gator-agent

Monitoring Complete

Monitoring is complete because this PR has merged.

Final status: Gator found no blocking review findings. Branch Checks, Helm Lint, Trivy Changes, and E2E passed, and a maintainer approval was submitted before merge.

I removed the active gator:* label because there is nothing left for gator to monitor on this PR.

Gator metadata
  • Head SHA: 73eddf6ca34af086b7326616e351420699dda2b4
  • Gator payload: 12

@johntmyers johntmyers removed the gator:approval-needed Gator completed review; maintainer approval needed label Oct 12, 2026
krishicks added a commit that referenced this pull request Oct 23, 2026
sqlite_concurrent_writes_return_their_own_resource_version (#4408) runs
8 writers that each make 25 unconditional and 25 version-checked writes
against one row of an on-disk WAL database with synchronous=FULL.
Writers serialize on the SQLite write lock and wait out sqlx's default
5s busy_timeout. Prior to this change, the per-commit fsync cost on the
Windows runners was high enough that a waiting writer starved past that
timeout and failed with "database is locked" after about 7s.

Now, each writer makes 5 writes on Windows and 25 elsewhere. The test
still races every writer on the same row, which is what it checks.

Signed-off-by: Kris Hicks <khicks@nvidia.com>
purp pushed a commit to purp/OpenShell that referenced this pull request Oct 23, 2026
* fix(isolation): validate Unix socket paths the same way on every host

Prior to this change, SandboxTransport::validate checked Unix socket
paths with Path::is_absolute(). On Windows that requires a drive or UNC
prefix, so a POSIX path such as /run/backend.sock was rejected as
"invalid boundary control transport endpoint". The isolation backend
registration work in NVIDIA#3898 added tests that register Unix endpoints
in the core registration types, gateway config, gateway config
preflight, and supervisor backend setup; all of them failed on the
Windows MSVC runners. The Windows test job only runs on PRs labeled
test:windows, so the break went unnoticed on main.

Unix transport is refused at runtime on non-Unix hosts, so these paths
are always POSIX paths regardless of where they are validated. Now, both
the core registration validator and the sandbox backend protocol
validator use a new openshell_core::paths::is_posix_absolute helper,
which applies the POSIX rule (the path starts with '/') on every host.
On Unix this matches is_absolute() exactly.

Signed-off-by: Kris Hicks <khicks@nvidia.com>

* test(supervisor): run baseline write-back cases only on Unix hosts

The startup policy write-refusal tests from NVIDIA#3785 rely on
enrich_proto_baseline_paths adding the proxy baseline paths (/usr,
/tmp, /dev/null, ...) to a policy, which triggers a write-back that the
fake gateway then refuses. Enrichment only adds paths that exist on the
host. Prior to this change, the tests assumed those paths exist, so on
Windows enrichment added nothing, the precondition assertions failed,
and the baseline case of permanent_codes_still_exit never saw a write
to refuse.

Now, the four baseline write-back tests are gated to Unix, and
permanent_codes_still_exit checks the image policy upload case on every
host and the baseline write-back case only on Unix.

Signed-off-by: Kris Hicks <khicks@nvidia.com>

* test(server): scale the SQLite concurrent-write test for Windows fsync

sqlite_concurrent_writes_return_their_own_resource_version (NVIDIA#4408) runs
8 writers that each make 25 unconditional and 25 version-checked writes
against one row of an on-disk WAL database with synchronous=FULL.
Writers serialize on the SQLite write lock and wait out sqlx's default
5s busy_timeout. Prior to this change, the per-commit fsync cost on the
Windows runners was high enough that a waiting writer starved past that
timeout and failed with "database is locked" after about 7s.

Now, each writer makes 5 writes on Windows and 25 elsewhere. The test
still races every writer on the same row, which is what it checks.

Signed-off-by: Kris Hicks <khicks@nvidia.com>

* test(server): hold scope-mix locks for wall-clock time, not timer ticks

random_scope_mix_never_deadlocks (NVIDIA#4147) runs 64 tasks of 50 random
lock operations and holds each operation's locks for 0-2 ms, failing if
the mix does not finish within 20s. Prior to this change, the hold was a
tokio::time::sleep. Windows timers round a 1 ms sleep up to about 16 ms,
and a quarter of the operations take the exclusive global lock, so the
serialized holds alone took several seconds and the full mix exceeded
the 20s deadline on the Windows runners.

Now, occupy yields until a std::time::Instant deadline, so holds last
0-2 ms of wall-clock time on every platform and the deadline means the
same thing everywhere.

Signed-off-by: Kris Hicks <khicks@nvidia.com>

* test(supervisor): run sandbox instance host tests only on Unix hosts

The sandbox_instance_host tests added with per-instance supervisor
state (NVIDIA#4701) admit hosted instances through SandboxInstanceHost::new,
which prepares a private directory per instance. Hosted sandbox
instances are Unix-only: on other hosts prepare_private_dir returns
"hosted sandbox instances require a Unix host". Prior to this change,
the test module still compiled and ran on Windows, so all three tests
failed while creating their host.

Now, the test module is gated to Unix, and the Unix-only permission
check inside one test no longer needs its own cfg attribute.

Signed-off-by: Kris Hicks <khicks@nvidia.com>

---------

Signed-off-by: Kris Hicks <khicks@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

test:e2e Requires end-to-end coverage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: SQLite writes can return the wrong resource version

2 participants