VOOZH about

URL: https://deepwiki.com/hypervel/filesystem/4.2-file-locking

⇱ File Locking | hypervel/filesystem | DeepWiki


Loading...
Menu

File Locking

Purpose and Scope

This document covers the file locking functionality provided by the LockableFile class, which enables safe concurrent access to local files through shared and exclusive locks. File locking is essential when multiple processes or coroutines need to read from or write to the same file without data corruption or race conditions.

This functionality is specifically for local filesystem operations and is independent of the main filesystem driver system. For general file operations through filesystem disks, see Filesystem Drivers. For cloud storage URL generation, see URL Generation.

Sources: src/LockableFile.php1-191


Overview

The LockableFile class provides a wrapper around PHP's file locking mechanism (flock()) with additional features:

  • Shared locks (LOCK_SH): Multiple readers can hold shared locks simultaneously
  • Exclusive locks (LOCK_EX): Only one writer can hold an exclusive lock at a time
  • Blocking and non-blocking modes: Control whether lock acquisition waits or fails immediately
  • Coroutine safety: Automatic handling of Hyperf coroutines to prevent deadlocks
  • Automatic cleanup: Locks are released when the file is closed
  • Exception-based error handling: Lock failures throw LockTimeoutException

Sources: src/LockableFile.php13-41


Class Structure

The LockableFile class manages file resources with locking capabilities:


Key Properties

PropertyTypeDescription
handleresourceThe underlying file resource from fopen()
pathstringThe absolute path to the file
isLockedboolTracks whether a lock is currently held

Sources: src/LockableFile.php15-30 src/Exceptions/LockTimeoutException.php1-11


Lock Types

Shared Locks (LOCK_SH)

Shared locks allow multiple readers to access the file simultaneously. Use shared locks when:

  • Reading file contents
  • Multiple processes need concurrent read access
  • No writes will occur during the lock period

The getSharedLock() method acquires a shared lock using LOCK_SH:


Sources: src/LockableFile.php116-127

Exclusive Locks (LOCK_EX)

Exclusive locks ensure only one process can access the file. Use exclusive locks when:

  • Writing to the file
  • Modifying file contents
  • Ensuring no other process reads or writes during the operation

The getExclusiveLock() method acquires an exclusive lock using LOCK_EX:


Sources: src/LockableFile.php136-147


Blocking vs Non-Blocking Modes

Both getSharedLock() and getExclusiveLock() accept a $block parameter that controls acquisition behavior:

Mode$block ValueBehavior
Non-blockingfalse (default)Returns immediately; throws LockTimeoutException if lock unavailable
BlockingtrueWaits indefinitely until the lock becomes available

Non-Blocking Mode Flow


Implementation uses LOCK_NB flag when $block is false:


Sources: src/LockableFile.php116-147

Blocking Mode Flow


When blocking, flock() waits until the file lock becomes available (no LOCK_NB flag).

Sources: src/LockableFile.php119-139


Coroutine Safety

The LockableFile class provides automatic coroutine safety for Hyperf applications. When running inside a coroutine, file locking operations are wrapped with Hyperf\Coroutine\Locker to prevent deadlocks between coroutines.

Atomic Operation Flow


Implementation Details

The atomic() method src/LockableFile.php175-190 wraps critical sections:


This two-level locking approach ensures:

  1. Coroutine-level coordination: Locker::lock() prevents multiple coroutines in the same process from calling flock() simultaneously
  2. Process-level coordination: flock() prevents multiple processes from accessing the file simultaneously

Sources: src/LockableFile.php175-190


File Operations

Reading Files

The read() method reads file contents, optionally limited to a specific length:


  • If $length is null, reads the entire file (or at least 1 byte if empty)
  • Calls clearstatcache() before reading to ensure fresh file size information
  • Returns the file contents as a string

Sources: src/LockableFile.php66-71

Writing Files

The write() method appends content to the file:


  • Uses fwrite() to write contents to the file
  • Calls fflush() to ensure data is written to disk
  • Returns $this for method chaining

Sources: src/LockableFile.php86-93

Truncating Files

The truncate() method clears the file contents:


  • Rewinds the file pointer to the beginning
  • Truncates the file to zero bytes using ftruncate()
  • Returns $this for method chaining

Sources: src/LockableFile.php100-107


Usage Patterns

Pattern 1: Read with Shared Lock


Pattern 2: Write with Exclusive Lock


Pattern 3: Update with Read-Modify-Write


Sources: src/LockableFile.php35-173


File Modes

The LockableFile constructor accepts standard PHP file mode strings:

ModeDescriptionReadWriteCreateTruncate
rRead-only
r+Read/write
wWrite-only
w+Read/write
aAppend
a+Read/append
cWrite-only
c+Read/write

The constructor automatically creates parent directories if they don't exist src/LockableFile.php46-51

Sources: src/LockableFile.php35-61


Error Handling

LockTimeoutException

The LockTimeoutException is thrown when a non-blocking lock acquisition fails:


Exception message format:

Unable to acquire file lock at path [{path}].

Sources: src/Exceptions/LockTimeoutException.php1-11 src/LockableFile.php119-141


Lock Lifecycle


Automatic Lock Release

The close() method automatically releases any held locks before closing the file resource:


This ensures locks are never left dangling, even if the developer forgets to call releaseLock() explicitly.

Sources: src/LockableFile.php154-173


Integration with Filesystem Drivers

The LockableFile class is independent of the main filesystem driver system (FilesystemAdapter, FilesystemManager, etc.). It operates directly on local file system paths and cannot be used with cloud storage drivers like S3 or GCS.

For filesystem operations through configured disks, use the standard Filesystem API. The LockableFile class is a specialized utility for scenarios requiring fine-grained control over file locking, such as:

  • Cache file management
  • Log file rotation
  • Configuration file updates
  • Database file locking (SQLite, etc.)

Sources: src/LockableFile.php1-191


Performance Considerations

Lock Granularity

File locks are advisory in PHP, meaning cooperating processes must explicitly acquire locks. Non-cooperating processes can still access the file.

Blocking Behavior

  • Blocking locks (block: true) can cause coroutines to wait indefinitely if a lock is never released
  • Non-blocking locks (block: false) allow immediate failure handling but require retry logic

Coroutine Overhead

The coroutine safety mechanism adds a small performance overhead:

  • Spin-lock loop with 1ms sleep intervals when waiting for Locker::lock()
  • Additional lock/unlock operations beyond the file system lock

For non-coroutine contexts, this overhead is zero as the atomic wrapper becomes a no-op.

Sources: src/LockableFile.php175-190