Repository navigation
refactor(git-index): make transaction store async, drop actor - #4140
Conversation
|
| fn close(&self) -> bool { | ||
| self.gc_task.abort(); | ||
| self.shared | ||
| .database | ||
| .lock() | ||
| .unwrap_or_else(PoisonError::into_inner) | ||
| .take() | ||
| .is_some() |
There was a problem hiding this comment.
🔴 Store shutdown leaves cleanup writes running
When preview-input GC is writing, shutdown returns before its aborted task and accepted SQL work finish. Project retirement can then find the session database still leased and fail to remove its shard.
Learn more
A store's background GC task borrows a database lease while purging expired preview inputs. StoreInner::close only requests abort and immediately reports that it closed the store. A purge already admitted to the SQL runtime can outlive that abort; the database retirement reservation requires all clients to finish before removing the shard. remove_remote_deleted_project attempts that reservation after Git store retirement. The previous actor shutdown joined its worker before returning.
Example: A purge starts writing at the same time a project deletion retires its Git store. Shutdown reports success while the write still holds its database client; the destructive reservation refuses deletion, although Git retirement succeeded.
Recommended fix: Make store shutdown asynchronous and await GC termination and any accepted purge settlement before reporting closure. Keep the database lease until that join completes, and propagate failures to the retirement caller.
Was this helpful? React with 👍 or 👎 to provide feedback.
Summary
Step 5 of the storage redesign (
docs/plans/storage/README.md), third slice. This deletes the first of the three storage actor threads the design removes.GitIndexTransactionStorewas a synchronous trait. The daemon implemented it with a dedicatedtracedecay-git-index-storethread: callers sent aStoreCommand(10 variants, capacity 64), and the thread settled each one against the async global-db store withnative_runtime::block_on. The trait is now async, andDaemonGitIndexTransactionStoreawaits the global-db store directly. The thread, its command protocol and itsblock_onpath are deleted.NativeTaskstarted with the store, on the same schedule. Open reads the next expiry, a save with an earlier expiry wakes the task, the task purges in batches of 256 and retries after 5 s on failure. A failed purge no longer fails the next unrelated command. Expired inputs still never read as available, because the read query checks expiry itself.GitIndexTransactionPortandGitIndexTransactionService(contracts) and the daemon's git handlers are async. Preview and apply still do synchronous Git work and call the configuration authority, which still usesblock_on. So they run throughnative_runtime::on_blocking_pool, which polls a future on one blocking-pool thread wherever its caller runs. The removed code usedspawn_blockingfor the same reason.DaemonGitIndexShutdownReceiptV1.store_actors_joinedkeeps its name for its reader in daemon shutdown. It now counts closed stores.Test plan
store_awaited_on_a_native_worker_never_parks_it: open, save and read on a native worker complete, and neither native wait counter moves. Putting back theblock_onsettle inread_preview_inputfails it.failed_gc_retries_after_its_delay_without_failing_commands,restart_reconstructs_expired_cleanup_deadline,same_repository_mutations_never_enter_the_native_section_togetherand the shutdown test each fail under a targeted mutation: no retry, no deadline reload, four concurrent mutations, and a lease kept past shutdown.on_blocking_pool_never_polls_on_a_tokio_caller_thread//crates/tracedecay-code-index-runtime:unit_test(639 passed; the git_transactions filter passes 10 of 10 runs),//crates/tracedecay-daemon-service:unit_test, the global-db, store and contracts targets,//crates/tracedecay:unit_test --test_arg=git_, andruntime_acceptance_suite --test_arg=git_preview_and_apply_have_real_cli_mcp_runtime_paritybazel build --config=clippyon each touched crate, andrustfmt_check_2024//crates/tracedecay:daemon_suite,:mcp_suite,:session_suitein CIRefs #4052