SOW-0174: Overlapping registry watches and exact unwatch
KT
2d ago+1026+1026+0123456789012345678901234567890123456789-236-236-012345678901234567890123456789
Summary
Registry::unwatch_directoryforgets every registered file under the directory (path-component prefix) unless another watch still covers it. Before, it removed files only when the watch string exactly matched the internal directory key, so a trailing slash or a directly watched machine-id directory left stale entries. Files on disk are never touched.- Overlapping watches (a root plus one of its machine-id directories) now work in either order. Only outermost watched directories hold a notify watch; nested ones are covered by the recursive watch above them, so notify never sees overlapping watches.
- Watch changes remove before adding, roll back on failure, and rescan directories whose watch changed hands (events in the gap are lost). A failed watch or unwatch leaves the registry unchanged; no directory can get stuck as watched.
- notify 8.2 (inotify) keeps a stale entry when a directory under a recursive watch is deleted, after which unwatching any ancestor fails with
EINVAL. This happened before this change too, without overlap.Monitornow keeps its event sender and rebuilds its watcher in that case, keeping the caller's receiver. - Create and rename events for paths outside every watched directory are ignored, so events queued before an unwatch do not re-register its files.
Stacked on #24 (SOW-0173).
Validation
- New
journal-registry/tests/overlapping_watches.rs(10 tests, real notify watcher). 9 of 10 fail against the previous code; the remaining one is a guard. cargo test --workspace: 695 passed, 0 failed.cargo clippy -p systemd-journal-sdk-registry --all-targets: no warnings in changed lines..agents/sow/audit.sh: clean.
Summary by cubic
Fixes Registry::unwatch_directory so it forgets exactly the files no remaining watch covers, whatever form the watch string had, and makes overlapping watches (a root plus one of its machine-id directories) work in either order.
- Unwatch previously removed files only when the watch string exactly matched the internal directory key, leaving stale entries for trailing slashes and directly watched machine-id directories; files on disk are never touched.
- Only outermost watched directories hold a notify watch, so nested directories are covered by the recursive watch above them.
- Watch changes remove before adding and roll back on failure, so a failed watch or unwatch leaves the registry unchanged and no directory gets stuck as watched.
Monitornow keeps its event sender and rebuilds its watcher when notify 8.2 leaves a stale entry after a deleted subdirectory, which previously broke unwatching any ancestor withEINVAL; the rebuild arms every directory it can, returns the first error, and rescans skip already-registered files so indexed time ranges survive.- Create and rename events for paths outside every watched directory are ignored, so events queued before an unwatch do not re-register its files.
- Covered by 11 new tests in
journal-registry/tests/overlapping_watches.rs; the guard passes against the previous code, the rest fail.