Module: Brute::FileMutationQueue

Defined in:
lib/brute/file_mutation_queue.rb

Overview

Per-file serialization queue for concurrent tool execution.

When tools run in parallel (via threads or async fibers), multiple tools may target the same file simultaneously. Without serialization, a sequence like [read → patch → write] on the same file would race and lose edits.

This module provides a single public method:

Brute::FileMutationQueue.serialize("/path/to/file") do
  # snapshot + read + modify + write — all atomic for this path
end

Design (mirrors pi-mono’s withFileMutationQueue):

- Operations on the SAME file are serialized (run one at a time)
- Operations on DIFFERENT files run fully in parallel (independent mutexes)
- Symlink-aware: resolves real paths so aliases share one mutex
- Error-safe: mutex is always released in `ensure`, so failures never deadlock
- Self-cleaning: per-file mutexes are removed when no longer in use

Ruby 3.4’s Mutex is fiber-scheduler-aware, so this works correctly with both :thread and :task (Async) concurrency strategies.

Class Method Summary collapse

Class Method Details

.clear!Object

Clear all tracked mutexes. Used in tests and session resets.



51
52
53
54
55
56
# File 'lib/brute/file_mutation_queue.rb', line 51

def clear!
  @guard.synchronize do
    @mutexes.clear
    @waiters.clear
  end
end

.serialize(path) { ... } ⇒ Object

Serialize a block of work for a given file path.

Concurrent calls targeting the same canonical path will execute sequentially in FIFO order. Calls targeting different paths proceed in parallel with zero contention.

Parameters:

  • path (String)

    The file path to serialize on.

Yields:

  • The mutation work to perform (snapshot, read, write, etc.)

Returns:

  • Whatever the block returns.



41
42
43
44
45
46
47
48
# File 'lib/brute/file_mutation_queue.rb', line 41

def serialize(path, &block)
  key = canonical_path(path)
  mutex = acquire_mutex(key)

  mutex.synchronize(&block)
ensure
  release_mutex(key)
end

.sizeObject

Number of file paths currently tracked (for diagnostics).



59
60
61
# File 'lib/brute/file_mutation_queue.rb', line 59

def size
  @guard.synchronize { @mutexes.size }
end