Vixen
02b45cc4
csharp
public sealed class FileChangeCoalescer

Turns the stream of events a filesystem actually produces into the changes a program meant to hear about.

No guide page documents this yet — the page shows what the code says about itself.

Remarks

Raw filesystem events are not a description of what the user did. Saving one file in a text editor produces, depending on the editor, one write, or a truncate and three writes, or a new temporary file followed by a rename over the original — and a hot-reload pipeline that reacts to each of those separately compiles the same shader four times, twice from a half-written file. This is where that becomes "one file changed".

Four things are handled, and each of them is a real editor's real behaviour:

Debouncing. Nothing is reported until it has been quiet for the debounce window, so a truncate-then-write is one change and not two, and a file still being written is not reported at all. Atomic save. A rename onto a path whose source was created inside the same window is the write-elsewhere-then-rename pattern; it is reported as a change to the destination, and the temporary file is not reported at all. Cancelling pairs. Created-then-deleted is nothing. Deleted-then-created is a change. A consumer that reloads on both reads the same file either way, but one that drops a cache on delete would drop it for a file that never went away. Our own writes. A path passed to Suppress is ignored for the suppression window. Without it, the asset pipeline writing an artefact wakes the watcher, which reimports, which writes an artefact.

Time is a parameter rather than a clock. Every method takes the current timestamp, which means the debounce window can be tested exactly instead of approximately — a test for a hundred-millisecond window that sleeps for a hundred milliseconds is a test that fails on a loaded machine.

Not thread-safe. FileWatcher owns one and holds a lock over it, because the events arrive on whichever thread the platform felt like using.

Fields and properties (4)

  • public TimeSpan Debounce

    How long a path must be quiet before its change is reported.

  • public TimeSpan SuppressionWindow

    How long a suppressed path stays suppressed.

  • public long DroppedCount

    How many raw events were dropped because the buffer was full.

  • public int PendingCount

    How many paths are waiting for the debounce window to close.

Methods (5)

  • public FileChangeCoalescer(int capacity = 4096)

    Creates a coalescer.

  • public void Suppress(VirtualPath path, long timestamp)

    Ignores events for a path for the next SuppressionWindow.

  • public void Record(FileChange change, long timestamp)

    Feeds in one raw event.

  • public int Drain(long timestamp, ICollection<FileChange> into)

    Takes every change whose debounce window has closed.

  • public void Clear()

    Forgets everything pending. For a consumer that has just rescanned instead.

Used by (2)

  • FileChangeCoalescerTestsVixen.Core.IO.Tests
  • FileWatcherVixen.Core.IO