FileSystemWatcher on macOS raises no Error when FSEvents drops events: the flags arrive on the watched folder's own path, which is skipped first
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 76/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- csharp, macos
調査の方向性
src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.OSX.csを読み、特にルートパスのスキップとShouldRescanOccurの呼び出し付近にあるProcessEventsを確認してください。macOSで、提供されている大量削除用コンソールアプリを使って再現し、取りこぼされたFSEventsによってwatcherのErrorイベントが発生するか確認してください。ルートパスのイベントに取りこぼしを示すフラグが含まれている場合にエラーとして報告され、その処理順序を対象とする回帰テストがあることを完了条件とします。
索引モデルが issue の本文から書いたものです。
説明
Description
On macOS, when more changes arrive at once than FSEvents queues, FSEvents drops events and says so with one event flagged kFSEventStreamEventFlagMustScanSubDirs | kFSEventStreamEventFlagUserDropped (0x3). That event's path is the watched folder itself.
ProcessEvents in FileSystemWatcher.OSX.cs skips every event on the watched folder's own path ("Match Windows and don't notify us about changes to the Root folder") before it calls ShouldRescanOccur. So the dropped-events flags never reach the Error event. The watcher loses changes silently, and its consumer can't tell it should rescan.
Reproduction Steps
A net10.0/net11.0 console app:
using System.Collections.Concurrent;
int count = args.Length > 0 ? int.Parse(args[0]) : 1000;
string folder = Directory.CreateTempSubdirectory("fsw-burst-").FullName;
for (int i = 0; i < count; i++)
{
File.WriteAllText(Path.Combine(folder, $"F{i}.txt"), "x");
}
Thread.Sleep(1000);
ConcurrentDictionary<string, bool> deleted = new();
int errors = 0;
using FileSystemWatcher watcher = new(folder);
watcher.Deleted += (_, e) => deleted[e.FullPath] = true;
watcher.Error += (_, e) => { Interlocked.Increment(ref errors); Console.WriteLine($"Error: {e.GetException().Message}"); };
watcher.EnableRaisingEvents = true;
Thread.Sleep(1000);
Parallel.For(0, count, i => File.Delete(Path.Combine(folder, $"F{i}.txt")));
Thread.Sleep(5000);
Console.WriteLine($"{Environment.Version}: {count} files deleted, {deleted.Count} Deleted events, {errors} Error events");
Directory.Delete(folder, true);
Output on macOS 27.0.1, Apple Silicon, three runs on each runtime:
10.0.14: 1000 files deleted, 467 Deleted events, 0 Error events
10.0.14: 1000 files deleted, 544 Deleted events, 0 Error events
10.0.14: 1000 files deleted, 488 Deleted events, 0 Error events
11.0.0: 1000 files deleted, 466 Deleted events, 0 Error events
11.0.0: 1000 files deleted, 722 Deleted events, 0 Error events
11.0.0: 1000 files deleted, 1000 Deleted events, 0 Error events
A raw FSEvents stream, created with the flags the watcher uses (FileEvents, NoDefer, WatchRoot; latency 0) and watching the same burst, got 460 events: 459 file removals and one event on the watched folder's own path with flags 0x3. The same happens with IncludeSubdirectories = true and the files in a subfolder: the flagged event is still on the watched folder's path.
Expected behavior
Either a Deleted event for every file, or an Error event saying events were lost.
Actual behavior
About half the deletions are reported, with no Error event.
Regression?
Not known.
Known Workarounds
Treat a burst of changes as possibly lossy, and list again the folders it touched.
Configuration
macOS 27.0.1 (Apple Silicon), .NET 10.0.14 and 11.0.0-rc.3.26522.148.
Other information
Calling ShouldRescanOccur before the root-path skip would fix it. #130637 changes the exception this path raises to InternalBufferOverflowException. Its test reaches the path through a mount in a subfolder, so it doesn't hit this ordering.
- 主要言語
- C#
- スター
- 18.4k
- フォーク
- 5.8k
- 平均マージ
- 2日 16時間
- マージ済み PR(30日)
- 631
環境構築
このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
dotnet/runtime のほかの issue
-
area-System.ComponentModel untriaged
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
dotnet/runtime#136608 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
area-System.IO bug untriaged
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
dotnet/runtime#136599 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[mono] Native memory leak on the first invoke of every open-instance delegate to a virtual methodオープンarea-VM-meta-mono untriaged
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
dotnet/runtime#136284 · リアクション 6 件 ·
メンテナーはふだん 1 日以内に返信
-
Several MemoryExtensions.LastIndexOfAnyExcept overloads incorrectly document "first occurrence"対応中かも @ehsan-raoufi が 6 日前に担当しました。 オープンarea-System.Memory untriaged
難易度 1/5 1時間未満 初心者へのやさしさ 83/100
dotnet/runtime#136282 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
MemoryExtensions.LastIndexOf ignores a custom comparer for bitwise-equatable element types対応中かも @aw0lid が 7 日前に担当しました。 オープンarea-System.Runtime untriaged
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
dotnet/runtime#136281 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
possible bug
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
-
Include host.wslc.internal in the HTTPS development certificate対応中かも @afscrome が今日担当しました。 オープンarea-commandlinetools
難易度 2/5 1〜3時間 初心者へのやさしさ 70/100
dotnet/aspnetcore#70122 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
:1st_place_medal: good first issue :cowboy_hat_face: refactor :roller_coaster: enhancement
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
ApplETS/Backend-Hello#78 ·
-
難易度 2/5 1〜3時間 初心者へのやさしさ 74/100
メンテナーはふだん 2 日以内に返信
-
status/triage
難易度 2/5 1〜3時間 初心者へのやさしさ 85/100
Altinn/altinn-studio#21642 ·
メンテナーはふだん 1 日以内に返信