Skip to content

Retry the database open when Windows briefly denies access - #7

Merged
behrouzbk merged 1 commit into
mainfrom
fix/db-open-retry
Oct 1, 2026
Merged

behrouzbk merged 1 commit into
mainfrom
fix/db-open-retry

Conversation

@behrouzbk

Copy link
Copy Markdown
Owner

What was wrong

Creating a LevelDB database writes a temp file and renames it to CURRENT. On Windows, an antivirus scanning the new file can hold it for a moment, and the rename fails:

IO error: RenameFile …\000002.dbtmp …\CURRENT: Access is denied.

abstract-level hides that error: operations queued behind the open only say Database is not open. On a machine with real-time scanning (Sophos Home + Bitdefender here), npm test often failed one random test this way.

The fix

  • src/state/db.ts: retryTransientOpen retries an open that failed with "Access is denied" or "being used by another process" (25 ms, doubling to 800 ms; about 1.5 s in all). Any other error (corruption, a held LOCK, a bad path) is thrown at once, and after the last retry the real error is thrown. It's hooked into Level's _open, so queued operations just wait.
  • src/node/node.ts: start() waits for the open and names the real cause if the data directory can't be opened.
  • 3 new tests in tests/state/db.test.ts (622 in total). README, docs and site updated to 622. CHANGELOG: Unreleased.

No consensus or network change.

Checked

  • npm run typecheck, npm run build, npm test: 622 passed.
  • Live on Windows: with the CURRENT rename blocked for 120 ms, the open succeeds after a retry. Blocked for good, start() fails with the RenameFile … Access is denied message.
  • Full suite from PowerShell: 8 out of 8 runs passed. Before the fix, it failed about one run in three on the same machine.

Creating a LevelDB database renames a temp file to CURRENT. On Windows an
antivirus scanning the new file can hold it for a moment and the rename
fails with "Access is denied"; queued operations then only report
"Database is not open", so npm test failed one random test on machines
with real-time scanning.

- state/db.ts: retryTransientOpen retries an open that failed with
  "Access is denied" / "being used by another process" (25 ms doubling
  to 800 ms, about 1.5 s in all); any other error is thrown at once, and
  after the last retry the real error is. Hooked into Level's _open, so
  operations queued behind the open simply wait.
- node.ts: start() awaits the open and names the real cause when the
  data directory can't be opened.
- Three tests (622 in total); docs and site say 622.

Live-checked on Windows: a CURRENT rename blocked for 120 ms now opens;
blocked for good, start() reports the RenameFile ... Access is denied
error. The full suite from PowerShell passed 8 runs out of 8.
@behrouzbk
behrouzbk merged commit 9581846 into main Oct 1, 2026
3 checks passed
@behrouzbk
behrouzbk deleted the fix/db-open-retry branch October 1, 2026 16:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant