class << self
Definitions
def serialize(path, &block)
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.
Signature
-
parameter
pathString The file path to serialize on.
-
yields
{block} The mutation work to perform (snapshot, read, write, etc.)
Implementation
def serialize(path, &block)
key = canonical_path(path)
mutex = acquire_mutex(key)
mutex.synchronize(&block)
ensure
release_mutex(key)
end
def clear!
Clear all tracked mutexes. Used in tests and session resets.
Implementation
def clear!
@guard.synchronize do
@mutexes.clear
@waiters.clear
end
end
def size
Number of file paths currently tracked (for diagnostics).
Implementation
def size
@guard.synchronize { @mutexes.size }
end
def canonical_path(path)
Resolve a file path to a canonical key. Uses File.realpath to follow symlinks so that aliases to the same underlying file share one mutex. Falls back to File.expand_path for files that don't exist yet (e.g., new writes).
Implementation
def canonical_path(path)
resolved = File.expand_path(path)
begin
File.realpath(resolved)
rescue Errno::ENOENT
resolved
end
end
def acquire_mutex(key)
Get (or create) a mutex for a file path and increment the waiter count.
Implementation
def acquire_mutex(key)
@guard.synchronize do
@mutexes[key] ||= Mutex.new
@waiters[key] += 1
@mutexes[key]
end
end
def release_mutex(key)
Decrement the waiter count and clean up the mutex if no one else needs it.
Implementation
def release_mutex(key)
@guard.synchronize do
@waiters[key] -= 1
if @waiters[key] <= 0
@mutexes.delete(key)
@waiters.delete(key)
end
end
end