Repository navigation
fix(core): serialize file tool operations and make writes atomic (#29078) - #29499
DavidAPierce merged 12 commits into
Conversation
…gle-gemini#29078) Parallel tool executions (such as concurrent sub-agents) scheduling file modifications on the same path can interleave read-modify-write operations, resulting in lost updates, inaccurate diff calculations, and corrupted shadow Git snapshots. - Introduce an in-process per-path async mutex (withPathLock) supporting immediate cancellation while queued - Normalize lock keys to real paths with parent directory resolution fallback - Serialize read-modify-write critical sections in EditTool and WriteFileTool per resolved path - Atomically write files via sibling temp files with permission preservation and Windows EBUSY/EPERM/EACCES retries - Serialize shadow Git repository snapshot creation per resolved project root to prevent .git/index.lock collisions - Add comprehensive regression and unit tests for concurrent edits, atomic writes, and snapshot serialization
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses critical race conditions in file system operations and Git snapshotting within the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
|
📊 PR Size: size/L
|
There was a problem hiding this comment.
Code Review
This pull request introduces an in-process, per-path mutex utility (withPathLock) to serialize concurrent file system operations, preventing race conditions and data loss when multiple tools or agents attempt to write to or edit the same file concurrently. It updates StandardFileSystemService to write files atomically using sibling temporary files and rename operations (with retry logic for Windows lock errors), and integrates the path lock mechanism into GitService (for snapshot creation), EditTool, and WriteFileTool. Comprehensive unit and integration tests have been added to verify atomicity, concurrency, and abort handling. I have no additional feedback to provide as the implementation is robust and well-tested.
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces an in-process, per-path mutex (withPathLock) to serialize read-modify-write operations on the same file, preventing concurrent edits or writes from interleaving and causing data loss. This lock is integrated into the file system service, git snapshotting, edit tool, and write-file tool. Feedback on the changes highlights two potential sources of test flakiness in CI environments: one in fileSystemService.atomic.test.ts where a temporary ENOENT during file replacement could cause assertion failures, and another in pathMutex.test.ts where real-time timing assertions (Date.now()) should be replaced with robust event-order checks.
- Exclude ENOENT (-1) sizes during transient file replacement in StandardFileSystemService atomicity test - Replace real-time elapsed measurement in pathMutex test with deterministic event sequence assertion
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces an in-process, per-path mutex (withPathLock) to serialize concurrent file operations and prevent race conditions or lost updates. This locking mechanism is integrated into EditToolInvocation, WriteFileToolInvocation, and GitService.createFileSnapshot. Additionally, StandardFileSystemService.writeTextFile has been updated to perform atomic writes by writing to a temporary sibling file and renaming it into place, while preserving file permissions and retrying on transient Windows lock errors. Comprehensive unit and atomic tests have been added to verify these changes. As there are no review comments, I have no additional feedback to provide.
|
/run-test |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces an in-process, per-path mutex utility (withPathLock) to serialize concurrent file system operations (edits, writes, and git snapshots) against the same file path, preventing race conditions and lost updates. It also refactors StandardFileSystemService.writeTextFile to write atomically by writing to a sibling temporary file and renaming it into place, while preserving permissions and retrying on transient Windows lock errors. Comprehensive unit and integration tests have been added to verify these concurrency and atomicity improvements. There are no review comments provided, so I have no feedback to provide on the review itself.
|
✅ 70 tests passed successfully on gemini-3-flash-preview. 🧠 Model Steering GuidanceThis PR modifies files that affect the model's behavior (prompts, tools, or instructions).
This is an automated guidance message triggered by steering logic signatures. |
Normalize target file paths with path.resolve and dynamic regex escaping in fileSystemService.test.ts, and skip disk-level POSIX permission preservation on Windows in fileSystemService.atomic.test.ts.
Head branch was pushed to by a user without write access
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces an in-process, per-path mutex utility (withPathLock) to serialize concurrent file operations and prevent race conditions. It updates StandardFileSystemService to write files atomically using sibling temporary files and rename operations, preserving permissions and handling Windows-specific lock errors. Additionally, it integrates the path lock into GitService snapshot creation, EditToolInvocation, and WriteFileToolInvocation to safely serialize concurrent reads and writes targeting the same files. Comprehensive unit and integration tests have been added to verify these concurrency controls. I have no further feedback to provide as no review comments were submitted.
Summary
Fixes concurrent file operations race conditions across tool executions (notably parallel sub-agents) in
packages/core. When multiple tool invocations execute simultaneously against the same file path, uncoordinated read-modify-write sequences cause silent lost updates, inaccurate diff calculations, and shadow Git snapshot collisions (.git/index.lock).This PR:
withPathLock) supporting immediate cancellation while queued.EditToolandWriteFileToolby resolved path.StandardFileSystemService.writeTextFileusing sibling temporary files with permission preservation and WindowsEBUSY/EPERM/EACCESrename retries..git/index.lockcollisions.Details
withPathLock): Coordinates file tool actions inside the Node.js process using normalized absolute path keys withresolveToRealPathand parent directory resolution fallback. Waiters in the lock queue observeAbortSignaland reject immediately if aborted, while handing off the lock chain safely to downstream waiters.EditTool&WriteFileToolSerialization: WrapscalculateEditwriteTextFileand file existence verification inwithPathLock. Prevents two parallel operations from reading an identical base version and clobbering each other's edits.StandardFileSystemService: Writes content to a unique sibling.tmpfile (${realPath}.${randomUUID()}.tmp) and atomically renames (fs.rename) it to the target path. Preserves existing file permissions (0600), handles symlink target resolution, cleans up temp files on error, and retries on Windows transient lock/sharing violation errors (EBUSY,EPERM,EACCES).createFileSnapshotinwithPathLock('git-snapshot:' + realProjectRoot)to prevent concurrent staging (git add .) and commit operations from conflicting or locking.git/index.lock.eslint-disablerules.Related Issues
Closes #29078
How to Validate
1. Automated Vitest Tests
Run the dedicated concurrency and core test suites:
Expected: All 6 test files pass (162 tests passed).
2. Manual Verification
withPathLock. Both operations persisted cleanly with zero lost updates.GitService.createFileSnapshotin the same shadow repository executed concurrently without.git/index.lockcollisions or corrupted snapshot history.test.txtpreserved both lines on disk with no lost updates.Pre-Merge Checklist