Skip to content

Fix FSEvents routing for differently cased watch paths - #64191

Draft
Jake Bailey (jakebailey) wants to merge 3 commits into
microsoft:mainfrom
jakebailey:fix-64089
Draft

Fix FSEvents routing for differently cased watch paths#64191
Jake Bailey (jakebailey) wants to merge 3 commits into
microsoft:mainfrom
jakebailey:fix-64089

Conversation

@jakebailey

Copy link
Copy Markdown
Member

Fixes #64089

Use the watched volume's case sensitivity when routing FSEvents and
filtering file watches. Preserve caller-visible root casing, including
shared callbacks, overflow matching, and root deletion handling.
Skip shared path prefixes eight bytes at a time and handle ASCII case
folding without component splitting. Retain the Unicode fallback for
case-equivalent paths with different UTF-8 lengths.

Reuse the parent directory's comparer for WatchFile instead of querying
filesystem case sensitivity twice. Add routing benchmarks and expand
boundary and Unicode alignment coverage.

Compare against the initial casing fix on Apple M1. Allocations are
unchanged: zero for exact matches and rejections, and one for rebasing
a differently cased event path.

goos: darwin
goarch: arm64
pkg: github.com/microsoft/TypeScript/tsc/internal/fswatch
cpu: Apple M1
                                           │    before     │                after                │
                                           │    sec/op     │    sec/op     vs base               │
FSEventsDisplayPath/exact-match-8             9.031n ± ∞ ¹   8.958n ± ∞ ¹        ~ (p=0.548 n=5)
FSEventsDisplayPath/case-mismatch-8          130.50n ± ∞ ¹   80.89n ± ∞ ¹  -38.02% (p=0.008 n=5)
FSEventsDisplayPath/sibling-miss-8           103.20n ± ∞ ¹   14.26n ± ∞ ¹  -86.18% (p=0.008 n=5)
FSEventsDisplayPath/unrelated-miss-8         26.120n ± ∞ ¹   6.676n ± ∞ ¹  -74.44% (p=0.008 n=5)
FSEventsDisplayPath/unicode-match-8          115.30n ± ∞ ¹   74.29n ± ∞ ¹  -35.57% (p=0.008 n=5)
FSEventsDisplayPath/unicode-length-match-8    98.83n ± ∞ ¹   52.34n ± ∞ ¹  -47.04% (p=0.008 n=5)
FSEventsRoutingFanout/100-8                  10.799µ ± ∞ ¹   1.634µ ± ∞ ¹  -84.87% (p=0.008 n=5)
FSEventsRoutingFanout/1000-8                 109.21µ ± ∞ ¹   15.10µ ± ∞ ¹  -86.18% (p=0.008 n=5)
geomean                                       284.3n         94.97n        -66.60%
¹ need >= 6 samples for confidence interval at level 0.95
Use CoreFoundation case folding and NFC normalization for non-ASCII
comparisons on case-insensitive Darwin watches. Recognize expanding
aliases such as sharp s and SS without merging distinct dotted-I,
dotless-I, circled-letter, or fullwidth spellings.

Preserve the ASCII fast path, prepare watch-root comparison forms, and
share lazy event folding across routing and callback filtering. Rebase
using original path boundaries rather than folded byte lengths.

Cover file and directory watches, shared callbacks, symlinks, overflow,
and root termination with filesystem regressions and routing benchmarks.
Keep fswatch isolated and leave Windows and case-sensitive behavior
unchanged.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Darwin-specific filesystem semantics, Unicode folding, and assembly-backed CoreFoundation integration warrant final human validation.

Pull request overview

Fixes FSEvents event routing when requested path casing differs from disk casing.

Changes:

  • Adds volume-aware, Unicode-capable path comparison.
  • Applies case-aware routing to directory, file, overflow, and deletion events.
  • Adds macOS integration tests, unit tests, benchmarks, and documentation.
File summaries
File Description
tsc/internal/fswatch/watcher.go Integrates comparers into watch sharing and callback routing.
tsc/internal/fswatch/watcher_test.go Updates file callback tests.
tsc/internal/fswatch/README.md Documents FSEvents casing behavior.
tsc/internal/fswatch/pathcompare.go Implements path comparison, folding, and rebasing.
tsc/internal/fswatch/pathcompare_test.go Tests comparison and file filtering.
tsc/internal/fswatch/fsevents_darwin.go Adds case-aware FSEvents routing.
tsc/internal/fswatch/fsevents_darwin_fold_test.go Tests Unicode folding and aliases.
tsc/internal/fswatch/fsevents_darwin_ffi.s Adds the CoreFoundation folding trampoline.
tsc/internal/fswatch/fsevents_darwin_ffi.go Implements native CoreFoundation path folding.
tsc/internal/fswatch/fsevents_darwin_case_test.go Tests casing differences on macOS filesystems.
tsc/internal/fswatch/fsevents_darwin_bench_test.go Benchmarks routing and folding fan-out.
tsc/internal/fswatch/CHANGES.md Records the behavior change.
tsc/internal/fswatch/canonicalize_other.go Provides non-Darwin comparer behavior.
tsc/internal/fswatch/canonicalize_darwin.go Detects per-volume case sensitivity.
Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Author: Team For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FSEvents watcher drops events when requested casing differs from disk casing

3 participants