fix(fuse): keep a rename made as its create lands (B152); wake an op once the name it waits for is free (B153)

Adoption asks again under the tree lock whether a rename is queued, and
writes the node row through the lock's outbox, so a rename made while
the create landed is no longer undone in the tree and the row.

An op that finds its name held fails as NameHeld: it backs off by the
minimum without doubling, and wakes the waiters for its name again once
its failure is recorded, so a trash that landed in between is not missed.
This commit is contained in:
nvrl committed 2026-10-04 06:04:20 +02:00
1 parent 6d75a56b00
commit 7269cb5118
5 files changed
+117 -10

No files matched your search

+40
View File
@@ -12,6 +12,46 @@ Conventions:
---
## B153 — An op waiting for a name sat out its backoff after the name was free
**Status:** Fixed (unverified).
**Found:** 2026-10-04, by the simulation's LAN profile (`one_client_on_a_good_link`, seed 4,
about one run in five, also before the B151 change). `d` was renamed over `c.bin` while the
create of the old `c.bin` was on the wire. The queues did not drain within 4 s: the rename still
owed `c.bin is still held by a node whose trash or rename is queued`.
**Where:** the failure path of `Core::run_pending_drain` in `crates/pdfs-fuse/src/drain.rs`.
**Cause.** The rename found the name held by the queued trash of the old `c.bin` and failed. The
trash landed a millisecond later and woke the ops waiting for the name
(`Db::wake_ops_waiting_for`), before the rename had recorded its failure, so there was nothing to
wake. The failure then set the doubled backoff of a network error, 4 s on the first attempt and
more after it.
**Fix.** A held name fails as `NameHeld`, which backs off by the minimum (2 s) without doubling,
and the op wakes the waiters for its name again once its failure is recorded. Unit test
`a_held_name_is_a_wait_and_other_failures_are_not`; the seed is the regression check.
## B152 — A rename made as its create landed was undone in the tree
**Status:** Fixed (unverified).
**Found:** 2026-10-04, by the simulation's LAN profile (`one_client_on_a_good_link`, seed 4,
about one run in ten). `a.txt` was renamed to `b.txt` 3 ms before its create finished landing.
The next rename, `b.txt` to `e.md`, answered `ENOENT`, and the node row kept `a.txt` although
Drive had `b.txt`.
**Where:** `Core::adopt_real_uid` in `crates/pdfs-fuse/src/drain.rs`.
**Cause.** Adoption puts the node Drive made into the tree, but keeps the tree's name and folder
while a rename is queued. It asked whether one was queued before it wrote the remote uid into the
queue and took the tree lock. A rename between the two was overwritten with the name the create
was sent with, in the tree and in the node row, which was written after the lock.
**Fix.** Adoption asks again under the tree lock. `Core::queue_rename` queues its op before it
renames the entry under that lock, so a renamed entry always has its op. The node row is written
through the lock's outbox, in order with the rename's own write. No test: the window is inside
one call and no fake hook reaches it; the seed is the regression check.
## B151 — A file deleted after its create lost its answer stays on Drive
**Status:** Fixed (unverified).
+4
View File
@@ -33,6 +33,10 @@ folder by local id too.
for this release.
### Fixed
- **A file renamed just as its upload finished keeps its new name.** The mount no longer showed
the old name, and a second rename no longer failed with "No such file or directory" (B152).
- **A change that waits for a name to be freed no longer waits seconds after it is.** A rename or
upload over a file being deleted goes out as soon as the delete lands (B153).
- **A file deleted right after it was made no longer stays on Drive when the link lost Drive's
answer.** The node Drive made is trashed (B151).
- **A new file no longer lands twice when the link loses Drive's answer to its upload.** The
+4 -1
View File
@@ -9,7 +9,7 @@ Tracks `docs/MILESTONE-3.0.0.md`. Update it with every commit that moves a phase
- **Phase 2**: local ids, inode = local id, one tree for every mount (2.10.0).
- **Phase 3, first part**: mkdir, create, rename, unlink and rmdir on the mount are recorded
locally and sent from the queue; `"local_first": false` brings back the old path (5e0f30c).
- Fixes from the simulation and account runs since then: B127 and B141 to B151.
- Fixes from the simulation and account runs since then: B127 and B141 to B153.
- **Sync issues, first cut** (§6.2): refusals sorted into issues, shown at once in the app,
tray and CLI; Export button and `pdfs sync export`; `pdfs sync issues`.
@@ -49,6 +49,9 @@ Tracks `docs/MILESTONE-3.0.0.md`. Update it with every commit that moves a phase
- [ ] Simulation passes on the Wi-Fi profile: `one_client_on_a_slow_link` failed in CI on
seeds 2 and 3. Two bugs (B127, B151) and a harness gap: a settle did not read the log, so
it could not explain a known bug's damage. All three fixed; not yet confirmed in CI.
Replays then found two races on the LAN profile too (B152, B153), both fixed. One
slow-link run of seed 2 failed once with a rename answering `ENOENT` as a folder move
landed. Not reproduced in 8 runs since; it may be B152.
- [ ] Known-bug list in `sim/run.rs` is empty: B125 and B130 open; B127, B129 and B132 fixed
but unconfirmed.
- [ ] A clean account run. The one on a6f36d5 (2026-10-04, LAN: 427 passed, 12 failed)