Skip to content

paths: drop the reported-path ancestor search - #986

Open
daandemeyer wants to merge 1 commit into
notify-rs:mainfrom
daandemeyer:push-xsnkltwoqtxu
Open

daandemeyer wants to merge 1 commit into
notify-rs:mainfrom
daandemeyer:push-xsnkltwoqtxu

Conversation

@daandemeyer

@daandemeyer daandemeyer commented Aug 17, 2026 •

Copy link
Copy Markdown
Contributor

Every watch knows what to call its path in events: watch "logs" and you
get "logs/app.txt", not the absolute path. When we walk a recursive
watch the walker already knows the right name for each entry and passes
it in. WatchMetadata::new ignored that and went looking through every
watch we have to work the same name out again.

On kqueue that happens for every entry in the walk, which gets slow
quickly. Metadata for one root plus N entries, release build:

10k     65 ms   ->  5 ms
50k     2.5 s   ->  15 ms
100k    10.5 s  ->  30 ms

The search was doing one useful thing though. Watch "logs", then watch
"/repo" around it, and the outer walk would rename logs/access to
"/repo/logs/access". That name sticks even after "/repo" is unwatched.
So the walk now handles that itself: WalkRoots notices when it walks
into an existing recursive user watch and names everything below after
that one. Same rule as before, just a small stack instead of a scan per
entry.

Two small things change. inotify gives brand new directories under a
nested watch the right name straight away, and entries found at runtime
keep the name their parent gave them, where the search could flip them
to the outer spelling later on.

Tests: the nested case (unwatch included) on inotify and kqueue, a late
create event for a directory the user has since watched by name, and
unit tests for WalkRoots in paths.rs that run everywhere.

Signed-off-by: Daan De Meyer daan@amutable.com

@JohnTitor

Copy link
Copy Markdown
Member

I intentionally added this, I might misundertstand something, let me dive deep.

@daandemeyer

Copy link
Copy Markdown
Contributor Author

Extended the commit message a bit and added two tests to encode the current behavior

@daandemeyer

Copy link
Copy Markdown
Contributor Author

@JohnTitor Any chance you could take another look at this?

@daandemeyer

Copy link
Copy Markdown
Contributor Author

Ping

@JohnTitor

Copy link
Copy Markdown
Member

So, the problem is that it remains even after unwatching, like:

  1. Recursively watch logs.
  2. Recursively watch /repo.
  3. Stop watching /repo.

Now only the relative logs watch remains. Creating logs/access/app.txt should report logs/access/app.txt, but this PR makes it report /repo/logs/access/app.txt instead.
IMHO I'd keep that guarantee to avoid potential confusion.

Every watch knows what to call its path in events: watch "logs" and you
get "logs/app.txt", not the absolute path. When we walk a recursive
watch the walker already knows the right name for each entry and passes
it in. WatchMetadata::new ignored that and went looking through every
watch we have to work the same name out again.

On kqueue that happens for every entry in the walk, which gets slow
quickly. Metadata for one root plus N entries, release build:

    10k     65 ms   ->  5 ms
    50k     2.5 s   ->  15 ms
    100k    10.5 s  ->  30 ms

The search was doing one useful thing though. Watch "logs", then watch
"/repo" around it, and the outer walk would rename logs/access to
"/repo/logs/access". That name sticks even after "/repo" is unwatched.
So the walk now handles that itself: WalkRoots notices when it walks
into an existing recursive user watch and names everything below after
that one. Same rule as before, just a small stack instead of a scan per
entry.

Two small things change. inotify gives brand new directories under a
nested watch the right name straight away, and entries found at runtime
keep the name their parent gave them, where the search could flip them
to the outer spelling later on.

Tests: the nested case (unwatch included) on inotify and kqueue, a late
create event for a directory the user has since watched by name, and
unit tests for WalkRoots in paths.rs that run everywhere.

Signed-off-by: Daan De Meyer <daan@amutable.com>
@daandemeyer

Copy link
Copy Markdown
Contributor Author

So, the problem is that it remains even after unwatching, like:

1. Recursively watch `logs`.

2. Recursively watch `/repo`.

3. Stop watching `/repo`.

Now only the relative logs watch remains. Creating logs/access/app.txt should report logs/access/app.txt, but this PR makes it report /repo/logs/access/app.txt instead. IMHO I'd keep that guarantee to avoid potential confusion.

OK, makes sense, reworked it like that. Though that complicated the PR slightly. Rather than reducing complexity it now increases performance, see the updated PR description. I added a bunch of tests to make sure the current behavior is encoded.

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.

2 participants