Repository navigation
api: move the create path's sandboxes writes into sandbox-store - #1329
Merged
Merged
Conversation
|
Thanks for opening this pull request! A SPACE maintainer will take a look. CONTRIBUTING.md explains how we review outside contributions. |
ac-pplx
force-pushed
the
ac/lifecycle-move-create
branch
from
November 2, 2026 20:58
ce4ec19 to
3e6c98e
Compare
This was referenced Nov 2, 2026
Merged
ac-pplx
force-pushed
the
ac/lifecycle-move-create
branch
from
November 2, 2026 23:25
3e6c98e to
c0d143f
Compare
This was referenced Nov 3, 2026
Merged
ac-pplx
marked this pull request as ready for review
November 3, 2026 03:50
ac-pplx
marked this pull request as draft
November 3, 2026 03:52
ac-pplx
force-pushed
the
ac/lifecycle-move-create
branch
from
November 3, 2026 06:00
c0d143f to
e26649a
Compare
ac-pplx
marked this pull request as ready for review
November 3, 2026 06:29
kumarpallav-pplx
requested review from
kumarpallav-pplx and
nikhilbirmiwal-pplx
November 3, 2026 06:30
nikhilbirmiwal-pplx
approved these changes
Nov 3, 2026
The create path finalized its row and removed the row of a failed create with inline SQL in the api controller. Move those six statements into pplx-space-sandbox-store's create module, byte-for-byte except for binds: - finalize_created: the creating/restoring -> reported-state CAS (operation step) - record_created_placement: the post-create active_node_id write (observed projection) - delete_failed_create: the failed or rolled-back create's row delete, shared by the four call sites (operation step) Callers keep their transactions, error handling and logging. The store functions take any executor, and every bind encodes the same Postgres type as before; the api keeps finalize_created_sandbox as a thin wrapper that converts OperationId. The sql! locators of the two UPDATEs now name the store module. The DELETE keeps its unlocated text. Three Postgres-backed store tests characterize behaviour no existing test pinned: delete_failed_create removes the row and its cascading dependents in every lifecycle, record_created_placement writes the node and placement_changed_at whatever the lifecycle, and finalize_created records command_ready_pending as the inverse of command readiness on a creating row. The sandbox_writes ratchet drops queries.rs and lowers updates.rs from 4 to 2; queries.rs's file_size cap drops to 2527.
ac-pplx
force-pushed
the
ac/lifecycle-move-create
branch
from
November 3, 2026 21:23
e26649a to
4a6d0e9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The api controller finalized a created
sandboxesrow, and deleted a failed create's row, with inline SQL. This moves those six statements into the store'screatemodule (nowpub mod). SQL is byte-for-byte except for binds. Callers keep transactions, error handling and logging. The store functions take any executor, and every bind encodes the same Postgres type as before. The api keepsfinalize_created_sandboxas a wrapper that convertsOperationId.Moved (old → new):
api::controllers::sandbox::queries::finalize_created_sandbox'sUPDATE→sandbox_store::create::finalize_created(operation step; theWHERECAS is the guard).queries::create_with_sandbox_id_inner'sUPDATE … SET active_node_id→create::record_created_placement(observed projection; id only).DELETE FROM sandboxes WHERE id = $1increate_with_sandbox_id_innerand 2× inupdates::rollback_created_sandbox→create::delete_failed_create(operation step; no lifecycle predicate).sql!locators change: the twoUPDATEs now carry/*pplx_space_sandbox_store::create:<line>*/(seen inpg_stat_activityand query monitoring). TheDELETEstill has none.Baseline:
sandbox_writesdropsqueries.rs(4 → gone) and lowersupdates.rs(4 → 2).queries.rs'sfile_sizecap drops from 2571 to 2527;updates.rsstays at 1008 (already over on main, advisory).Validation
At
ce4ec1989:cargo nextest run -p pplx-space-sandbox-store -p pplx-space-api --all-features: 2168 passed, 1 config skip, 0 dependency skips.AND restore_lease_token = $6failscreate_postgres_tests::create_finalization_accepts_operation_leased_restoring_state.cargo clippy --workspace --all-features -D warnings: clean.scripts/tests/smoke-kind-typed.sh all52m07s: ECW 85 passed, 0 failed, 3 inconclusive; native 35 passed. The cold and warm-pool create scenarios passed rerun withSPACE_SMOKE_KIND_COLD_RECEIPTS;local.restarted_btrfs_send_is_rejected_and_retriedneeds otel mode (unrelated).At
3e6c98eb(final), which differs only in store doc comments and new store tests; compiled statements are identical apart fromsql!locator line numbers:cargo nextest run -p pplx-space-sandbox-store --all-features: 22 passed, 0 skipped (Postgres ran), incl. the newtests/create_finish_tests.rs:delete_failed_create_removes_the_row_whatever_its_lifecycle,record_created_placement_records_the_node_on_any_lifecycle,finalize_created_records_command_readiness_on_a_creating_row.AND lifecycle <> 'deleting'failsdelete_failed_create_…; M2 droppingplacement_changed_at = NOW()failsrecord_created_placement_…; M3.bind(command_ready)failsfinalize_created_records_….--all-targets --all-features -D warnings), store rustdoc (-D warnings),cargo fmt --check,cargo check -p pplx-space-api --all-features: clean.cargo archvs. main's baseline: 0 required. No existing test changed.Severity and risk
Severity: n/a (refactor). Risk: low; statements, binds and caller handling are unchanged. Revert to roll back.
Rollout
Old and new pods issue the same statements bar locator comments. No migration.
Not covered
delete_failed_createthrough a failed create, and the Kind runs were not checked for one. The new store tests pin the statement itself; its four call sites differ from main only in the call.record_created_placementruns in the Direct create tests, but only the new store test asserts its effect, becausefinalize_createdrewritesactive_node_idafterwards.Open PRs that will need to rebase
finalize_created_sandboxUPDATE→create::finalize_created. It takes any executor, so it can run on [space] fence every placement writer against the provider-terminate path #559's fence transaction (&mut *tx).UPDATE→create::record_created_placement, which can run on that transaction too.DELETEand the tworollback_created_sandboxDELETEs →create::delete_failed_create. [space] fence every placement writer against the provider-terminate path #559 replaces them with guarded deletes (lifecycle <> 'deleting',lifecycle = 'deleting', and acreating/restoringdelete that checks for an active execution), whichdelete_failed_createdoes not express. Those need store functions too, or a reviewed baseline entry: after this PR,queries.rshas nosandbox_writesentry andupdates.rsis capped at 2.insert_unplacedinsandbox/store/src/create.rs. That function wasn't moved, so this is a file-level overlap only.sandbox/store/src/tests.rs'suse super::{…}next to the newmodline; file-level only.AI assistance: Claude Code (an AI agent) wrote the code change and this description.
After the wave-2 restack
This PR is one layer of a 10-PR stack, restacked onto main
c5fdf0c7(which includes #826) and then rebased mechanically onto42a99002, which changed only baseline context lines, in order #1329 → #1336 → #1338 → #1339 → #1342 → #1347 → #1333 → #1335 → #1328 → #1332. The validation earlier in this description ran at pre-restack heads; this layer's head is4a6d0e9e.git range-diffshows=). For every file [cluster-controller] re-place an evacuated stopped sandbox as stopped on another node, materialized by the shim without a VM #826 and this stack share, each SQL line [cluster-controller] re-place an evacuated stopped sandbox as stopped on another node, materialized by the shim without a VM #826 added was checked to be present verbatim at the top head, in place or in the store module it moved to.cargo fmt --all -- --check,cargo check --workspace --all-targets --all-featuresandcargo arch(0 required findings, with main's layers and table-owner rules), and the ratchet and caps this layer changes are recounted exactly.e90aa284before that rebase; nextest passed 4370 tests again at77fbae1e):cargo clippy --workspace --locked --all-targets --all-features -- -D warningsis clean, andSPACE_CI_REQUIRE_TEST_DEPS=1 cargo nextest run --all-featurespassed 4355 tests across the store, api, internal-api server, cluster-controller server, metrics, db-test-fixtures, common-core, common-svc and portability crates, [cluster-controller] re-place an evacuated stopped sandbox as stopped on another node, materialized by the shim without a VM #826's suites included.scripts/tests/smoke-kind-typed.sh allgave ECW 91/91 and native 42/42, including [cluster-controller] re-place an evacuated stopped sandbox as stopped on another node, materialized by the shim without a VM #826'snative.forced_drain_re_places_stopped_sandboxand its re-drain and restarted variants. The Direct substrate lane'sallgave ECW 51/51 and native 27/27. No flakes and no reruns.+/-lines and its SQL string literals match its reviewed head (range-diff plus a literal multiset compare).