| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
set() writes to a fixed <cacheDir>/.tmp/<uuid> and renames it onto the target for atomicity. When .tmp and the target file are on different filesystems, fs.rename throws EXDEV and the write fails. Add a fallback (on by default) that, on EXDEV, writes a temp file in the target's own directory and renames it there. A same-directory rename stays on one filesystem, so it avoids EXDEV while keeping the atomic replace. - new option `fallback` (default true, set false to keep throwing) - new option `fallbackTmpfileName` (defaults to a random name; a fixed name is only safe without concurrent writes to the same directory) - fallback logic isolated in the private `_renameWithFallback` method - tests for the fallback, custom name, disabled, and fallback-failure paths
|
Warning Review limit reached@gxkl, you've reached your PR review limit, so we couldn't start this review. Next review available in: 54 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR. To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 78a709b8-bb6e-45d7-8bf2-cdf7d3bfd9ea 📥 CommitsReviewing files that changed from the base of the PR and between 153fd19 and dcee3e7. 📒 Files selected for processing (1)
WalkthroughDiskStore adds configurable handling for EXDEV rename failures, including a same-directory temporary-file retry, cleanup behavior, public getters, documentation, and tests for success, custom filenames, failure propagation, and disabled fallback. ChangesEXDEV fallback handling
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant DiskStore.set
participant fs.rename
participant DiskStore._renameWithFallback
participant TargetDirectory
DiskStore.set->>fs.rename: rename primary temp file
fs.rename-->>DiskStore.set: EXDEV error
DiskStore.set->>DiskStore._renameWithFallback: retry fallback
DiskStore._renameWithFallback->>TargetDirectory: write fallback temp file
DiskStore._renameWithFallback->>fs.rename: rename fallback temp file
fs.rename-->>DiskStore._renameWithFallback: success or error
DiskStore._renameWithFallback-->>DiskStore.set: result or propagated error
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. ❤️ ShareComment @coderabbitai help to get the list of available commands. |
Sorry, something went wrong.
There was a problem hiding this comment.
This pull request introduces an EXDEV fallback mechanism to DiskStore to handle cross-device rename failures. When a rename fails with EXDEV, the store can now fallback to writing a temporary file in the target file's own directory before renaming it, ensuring an atomic replacement. This behavior is configurable via the new fallback and fallbackTmpfileName options. The changes also include comprehensive unit tests. The review feedback highlights a critical issue where using a static, shared fallbackTmpfileName for concurrent writes in the same directory can lead to race conditions and data corruption. It is recommended to append a unique identifier, such as a UUID, to the custom fallback file name to prevent these conflicts.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Sorry, something went wrong.
| async _renameWithFallback(dir, filepath, data) { | ||
| const fallbackTmpfile = path.join( | ||
| dir, | ||
| this.fallbackTmpfileName || `.${path.basename(filepath)}.${crypto.randomUUID()}.tmp` |
There was a problem hiding this comment.
Using a static, shared fallbackTmpfileName across different target files in the same directory can lead to severe race conditions and data corruption during concurrent writes. For example, if store.set('dir/fileA') and store.set('dir/fileB') run concurrently, both will attempt to write to and rename the exact same temporary file path (dir/fallbackTmpfileName), causing one to overwrite the other's data or fail with ENOENT.
To prevent this, we should ensure that the temporary file name is always unique per write operation, even when a custom name/prefix is provided. Appending a unique identifier (like a UUID) to the custom name is a robust way to avoid these conflicts.
this.fallbackTmpfileName
? `${this.fallbackTmpfileName}.${crypto.randomUUID()}`
: `.${path.basename(filepath)}.${crypto.randomUUID()}.tmp`
Sorry, something went wrong.
macos-latest is now Apple Silicon (arm64) and Node.js 14 has no macOS arm64 build, so `macos-latest x 14` fails at the setup-node step. Split the matrix so 16/18 keep running on all three OS while 14 runs on Linux and Windows only.
There was a problem hiding this comment.
test/index.test.js (1)🤖 Prompt for all review comments with AI agents142-147: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Consider using assert.rejects for cleaner async error testing.
Both sites use a verbose try/catch block combined with an intentional assert(false) to validate that a promise rejects. Consider using assert.rejects for a more idiomatic and concise approach to testing async errors.
💡 Proposed refactors
- test/index.test.js#L142-L147: Simplify the rejection check for the fallback rename error.
- test/index.test.js#L162-L167: Simplify the rejection check for the EXDEV error.
For test/index.test.js#L142-L147:
- try { - await diskStore.set('exdev-fail/a', 'v'); - assert(false, 'should not run here'); - } catch (err) { - assert(err.message === 'mock fallback rename error'); - } + await assert.rejects( + diskStore.set('exdev-fail/a', 'v'), + err => err.message === 'mock fallback rename error' + );For test/index.test.js#L162-L167:
🤖 Prompt for AI Agents- try { - await store.set('exdev-off', 'v'); - assert(false, 'should not run here'); - } catch (err) { - assert(err.code === 'EXDEV'); - } + await assert.rejects( + store.set('exdev-off', 'v'), + err => err.code === 'EXDEV' + );Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@test/index.test.js` around lines 142 - 147, Replace the try/catch plus intentional assert(false) rejection checks in test/index.test.js at lines 142-147 and 162-167 with assert.rejects assertions. Preserve each test’s existing promise operation and expected error message: “mock fallback rename error” at the anchor site and the EXDEV error at the sibling site.
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. Nitpick comments: In `@test/index.test.js`: - Around line 142-147: Replace the try/catch plus intentional assert(false) rejection checks in test/index.test.js at lines 142-147 and 162-167 with assert.rejects assertions. Preserve each test’s existing promise operation and expected error message: “mock fallback rename error” at the anchor site and the EXDEV error at the sibling site.
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a8806322-f690-4c4d-9d71-b20815839fa1
📥 CommitsReviewing files that changed from the base of the PR and between fb99247 and 153fd19.
📒 Files selected for processing (3)
Sorry, something went wrong.
There was a problem hiding this comment.
LGTM
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Problem
set() writes to a fixed <cacheDir>/.tmp/<uuid> and then fs.renames it onto the target file to get an atomic write. When .tmp and the target file are on different filesystems (e.g. .tmp is a separate mount), fs.rename throws EXDEV: cross-device link not permitted and the write fails outright:
Change
Add a fallback (on by default) that, on EXDEV, writes a temp file in the target's own directory and renames it there. A same-directory rename is always on one filesystem, so it avoids EXDEV while keeping the atomic replace.
Tests
Added cases under EXDEV fallback:
npm test — lint clean, 10 passing.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation