Last active
May 25, 2020 11:35
-
-
Save dlyz/e971d79b37c3450ec9ef7f40f824cdde to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Extensions.FileProviders; | |
using Microsoft.Extensions.FileProviders.Physical; | |
using Microsoft.Extensions.Primitives; | |
using System; | |
using System.Collections.Generic; | |
using System.IO; | |
using System.Linq; | |
using System.Reflection; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace FileWatcherRepro | |
{ | |
class Program | |
{ | |
static async Task Main(string[] args) | |
{ | |
var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); | |
// this triggers System.ArgumentOutOfRangeException | |
{ | |
var triggerDir = Path.Combine(dir, "a"); | |
Directory.CreateDirectory(triggerDir); | |
File.WriteAllText(Path.Combine(triggerDir, "file.txt"), ""); | |
} | |
var cts = new CancellationTokenSource(); | |
var tasks = new List<Task>(); | |
if (args.Contains("--fsloader")) | |
{ | |
tasks.Add(RunFSLoader()); | |
} | |
if (args.Contains("--watcher")) | |
{ | |
tasks.Add(RunFSWatcher()); | |
} | |
if (tasks.Count == 0) | |
{ | |
tasks.Add(RunFSLoader()); | |
tasks.Add(RunFSWatcher()); | |
} | |
var t = Task.WhenAll(tasks); | |
Console.WriteLine("STARTED"); | |
Console.ReadKey(); | |
cts.Cancel(); | |
await t; | |
async Task RunFSLoader() | |
{ | |
Console.WriteLine("Starting FSLoader"); | |
try | |
{ | |
await LoadFileSystem(dir, 2, 1, cts.Token); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("FSLoader failed: {0}", ex); | |
} | |
} | |
async Task RunFSWatcher() | |
{ | |
Console.WriteLine("Starting FSWatcher"); | |
try | |
{ | |
await WatchFile(dir, 1, cts.Token); | |
//await WatchFileProv(dir, cts.Token); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("FSWatcher failed: {0}", ex); | |
} | |
} | |
} | |
static Task LoadFileSystem(string root, int threads, int files, CancellationToken cancellationToken) | |
{ | |
var dir = Path.Combine(root, "inner"); | |
if (Directory.Exists(dir)) | |
{ | |
Directory.Delete(dir, recursive: true); | |
} | |
return Spawn(threads, (i, ct) => Run(Path.Combine(dir, $"pref{i}"), files, ct), cancellationToken); | |
static async Task Run(string dir, int files, CancellationToken cancellationToken) | |
{ | |
Directory.CreateDirectory(dir); | |
var filePath = Path.Combine(dir, "test_file"); | |
for (int i = 0; i < files; i++) | |
{ | |
File.Delete($"{filePath}{i}TMP"); | |
using var writer = File.CreateText($"{filePath}{i}"); | |
for (int j = 0; j < 1024; j++) | |
{ | |
writer.WriteLine(j); | |
} | |
} | |
await Task.Yield(); | |
while (!cancellationToken.IsCancellationRequested) | |
{ | |
for (int i = 0; i < files; i++) | |
{ | |
File.Move($"{filePath}{i}", $"{filePath}{i}TMP"); | |
} | |
for (int i = 0; i < files; i++) | |
{ | |
File.Move($"{filePath}{i}TMP", $"{filePath}{i}"); | |
} | |
await Task.Delay(100); | |
} | |
} | |
} | |
static Task WatchFile(string root, int watchers, CancellationToken cancellationToken) | |
{ | |
if (!root.EndsWith(Path.DirectorySeparatorChar)) | |
{ | |
root += Path.DirectorySeparatorChar; | |
} | |
return Spawn(watchers, (i, ct) => Run(root, i+1, ct), cancellationToken); | |
static async Task Run(string root, int id, CancellationToken cancellationToken) | |
{ | |
using var watcher = new PhysicalFilesWatcher( | |
root, | |
new FileSystemWatcher(root), | |
pollForChanges: false, | |
ExclusionFilters.Sensitive | |
); | |
var tcs = new TaskCompletionSource<object>(TaskCreationOptions.RunContinuationsAsynchronously); | |
int num = 1; | |
using var registration = ChangeToken.OnChange( | |
() => watcher.CreateFileChangeToken($"appsettings.{id}.json"), | |
() => | |
{ | |
Console.Write($"{id}:{num++} "); | |
} | |
); | |
using var reg = cancellationToken.Register(() => tcs.TrySetResult(null)); | |
await tcs.Task; | |
} | |
} | |
static async Task Spawn(int count, Func<int, CancellationToken, Task> factory, CancellationToken cancellationToken) | |
{ | |
using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, default); | |
var tasks = new List<Task>(); | |
for (int i = 0; i < count; i++) | |
{ | |
tasks.Add(factory(i, cts.Token)); | |
} | |
await Task.WhenAny(tasks); | |
if (!cancellationToken.IsCancellationRequested) | |
{ | |
cts.Cancel(); | |
} | |
await Task.WhenAll(tasks); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment