Skip to content

fix(drive,daemon,gmail,docs): move the lease ledger lock to flock - #1712

Merged
newhoggy merged 2 commits into
mainfrom
issue-1687-lease-ledger-lock
Sep 17, 2026
Merged

newhoggy merged 2 commits into
mainfrom
issue-1687-lease-ledger-lock

Conversation

@newhoggy

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • cargo build
  • cargo test --lib drive::lease::ledger (27 passed)
  • cargo clippy --all-targets -- -D warnings
  • Reviewed via /code-review high; fixed the findings (missing #[cfg(unix)] on a new Windows-breaking test, a tracing::info! notice silently dropped by the CLI's default warn filter, and doc/CHANGELOG claims about Drop never unlinking that didn't carve out the non-Unix fallback)

The lock guarding the Drive lease ledger and gmail insert's ledger was a
create_new marker released by Drop unlinking it by path. That made it
ledger-global and non-waiting (an unrelated concurrent leased write hard
failed instead of queuing), left a permanent lock behind a SIGKILLed
holder with no stale-lock detection, and its own "remove the lock file and
retry" advice let a second acquirer's marker be deleted by the first
holder's Drop with no identity check, reopening a lease-token
double-spend. drive lease prune also deleted a row's backup before
securing the lock that would record its removal, so a lock collision
could strand a row pointing at an already-deleted backup and abort the
rest of the batch.

Move to flock(2) on a persistent sibling <path>.lock file, kernel-released
on process death, so Drop never unlinks anything and a crashed holder
never leaves a stale lock. Every leased write now waits for a busy lock
instead of failing outright; prune now takes its lock before touching a
row's backup, so a collision leaves both untouched instead of stranding
one. gmail insert's identical lock gets the same fix but stays
non-waiting, since it is held for a whole multi-message run. The new
FileLock primitive lives in src/daemon/paths.rs, shared by both ledgers.

Fixes #1687.
…lter for issue #1687

The new flock regression test used nix's Unix-only flock symbols with no
#[cfg(unix)], breaking the Windows build. The "waiting for lock" notice was
emitted via tracing::info!, which the CLI's default `warn` filter silently
drops, contradicting the documented "prints a one-line notice" behavior —
switched to tracing::warn! to match the module's existing convention.
Doc comments and the CHANGELOG entry claimed "Drop never unlinks the lock
file" unconditionally; non-Unix falls back to the old marker-plus-unlink
scheme, so that guarantee is Unix-only — callouts added.
@github-actions

Copy link
Copy Markdown

Coverage

Total: 97.27% ⚪ -0.01 pp vs main

Comparing c666c00..83b0b16 (merge-base → PR head)

File Before After Δ
src/daemon/paths.rs 99.49% 92.8% 🔴 -6.69 pp
src/drive/lease/prune.rs 100% 99.33% 🔴 -0.67 pp
src/drive/lease/ledger.rs 100% 99.75% 🔴 -0.25 pp
src/drive/lease/check.rs 99.79% 99.61% 🔴 -0.18 pp
🔇 5 ignored region(s), 0 tolerated region(s)

ignore removes the lines from both reports; tolerate keeps them in the reported percentage but scores them against the baseline, so a cross-run flip cannot move a delta. Regions are read from each revision's own source.

File Kind Lines Rev Reason
src/cli/drive/lease.rs ignore 408-412 both a sheet restore's fresh backup is always a DriveCopy — restore.rs's own recheck refuses unless the target is still a spreadsheet, and acquire() only ever takes a Bytes backup of a non-native target; this arm exists solely for exhaustiveness over the shared LeaseBackup enum
src/cli/drive/lease.rs ignore 882-885 both guards this test helper against misuse; every call site below passes an acquire subcommand
src/cli/drive/lease.rs ignore 896-899 both guards this test helper against misuse; every call site below passes a prune subcommand
src/drive/lease/ledger.rs ignore 743-747 both mutate_locked refuses before ever calling the closure, so its body never runs — a hit here is a regression, not a coverage gap
src/drive/lease/restore.rs ignore 977-981 both every test using this double refuses before authenticating; a hit here is a regression, not a coverage gap

Patch coverage

Patch: 89.55% (197/220 new lines covered)

File Patch Uncovered new lines
src/cli/gmail/insert/ledger.rs 100% (18/18)
src/daemon/paths.rs 62.79% (27/43) 199-200, 202, 204-205, 301-305, 323, 326-330
src/drive/lease/check.rs 100% (50/50)
src/drive/lease/ledger.rs 98.97% (96/97) 430
src/drive/lease/prune.rs 45.45% (5/11) 288-289, 295-298
src/drive/lease/restore.rs 100% (1/1)
Uncovered new lines (23)
  • src/daemon/paths.rs:199
  • src/daemon/paths.rs:200
  • src/daemon/paths.rs:202
  • src/daemon/paths.rs:204
  • src/daemon/paths.rs:205
  • src/daemon/paths.rs:301
  • src/daemon/paths.rs:302
  • src/daemon/paths.rs:303
  • src/daemon/paths.rs:304
  • src/daemon/paths.rs:305
  • src/daemon/paths.rs:323
  • src/daemon/paths.rs:326
  • src/daemon/paths.rs:327
  • src/daemon/paths.rs:328
  • src/daemon/paths.rs:329
  • src/daemon/paths.rs:330
  • src/drive/lease/ledger.rs:430
  • src/drive/lease/prune.rs:288
  • src/drive/lease/prune.rs:289
  • src/drive/lease/prune.rs:295
  • src/drive/lease/prune.rs:296
  • src/drive/lease/prune.rs:297
  • src/drive/lease/prune.rs:298

Indirect coverage changes

🔴 1 lines lost coverage, 🟢 0 lines gained coverage on unchanged code.

Indirect changes
  • src/drive/lease/check.rs:331 🔴 covered → uncovered

📦 Full per-file coverage summary · run summary

@newhoggy
newhoggy merged commit e78ba2f into main Sep 17, 2026
17 checks passed
@newhoggy
newhoggy deleted the issue-1687-lease-ledger-lock branch September 17, 2026 16:28
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.

refactor(drive): lease ledger lock is ledger-global, non-waiting, Drop-unlinks-by-path; prune deletes backup before locking

1 participant