Concurrency and Locking
Relevant source files
The following files were used as context for generating this wiki page:Concurrency control is a recognized challenge in Cyberpath Sentinel due to its filesystem-based architecture. Unlike traditional database management systems that manage their own memory and I/O, Sentinel relies on the underlying filesystem, which makes handling multi-writer scenarios complex. The project's design prioritizes transparency and auditability over raw throughput, which informs the chosen strategies for managing concurrent access.
The implementation plan addresses this "Concurrency Complexity" with a phased approach, starting with basic file locking and evolving towards more sophisticated mechanisms like Write-Ahead Logging (WAL) and eventually Multi-Version Concurrency Control (MVCC). This ensures durability and data integrity while accommodating the project's unique design goals.
Sources: README.md:43-45, IMPLEMENTATION_PLAN.md:405-418
Architectural Overview
Concurrency management is handled by the "File I/O & Concurrency Control" layer, which sits between the higher-level components (Query Engine, Transaction Manager) and the filesystem abstraction. This layer is responsible for mediating access to document files on disk, preventing data corruption from simultaneous writes.
Sources: README.md:128-136, IMPLEMENTATION_PLAN.md:33-43
The following diagram illustrates the position of the concurrency layer within the Sentinel architecture.
Diagram showing the architectural placement of the Concurrency Control Layer.
Concurrency Control & Locking
The primary mechanism for handling concurrent writes is the FileLockManager. This component is responsible for acquiring and releasing locks on file paths according to a specified strategy. The implementation is planned for Phase 2 of the project development.
Sources: IMPLEMENTATION_PLAN.md:204-206, IMPLEMENTATION_PLAN.md:529-535
FileLockManager
The FileLockManager is designed to manage locks on file paths using a concurrent map. This allows different parts of the system to request locks before performing I/O operations.
pub struct FileLockManager {
locks: DashMap<PathBuf, Arc<RwLock<()>>>,
}
impl FileLockManager {
pub async fn acquire_lock(
&self,
path: &Path,
strategy: LockStrategy,
) -> io::Result<LockGuard>
pub async fn release_lock(&self, guard: LockGuard) -> io::Result<()>
}
Source: IMPLEMENTATION_PLAN.md:208-222
The class diagram below shows the structure of the FileLockManager and its relationship with the LockStrategy enum.
Source: IMPLEMENTATION_PLAN.md:208-219
Lock Strategies
Sentinel plans to support multiple locking strategies to cater to different use cases.
| Strategy | Description | Use Case |
|---|---|---|
Exclusive | Single writer, no readers. | Ensures complete isolation for write operations. |
Shared | Multiple readers, no writers. | Allows concurrent reads when no data is being modified. |
OptimisticMVCC | Multi-Version Concurrency Control. | A long-term goal for high-performance concurrent reads and writes. |
Sources: IMPLEMENTATION_PLAN.md:210-214
Lock Acquisition Flow
The sequence diagram below illustrates the process of a write operation acquiring an exclusive lock on a document.
This diagram shows the flow for acquiring a lock before a file write and releasing it afterward.
Sources: IMPLEMENTATION_PLAN.md:208-222
Phased Implementation Strategy
The challenge of concurrent writes is addressed through a multi-phased approach, balancing implementation complexity with immediate needs.
- Phase 2: File Locking & WAL: The initial solution involves implementing both exclusive/shared file locks and a Write-Ahead Log (WAL). This provides durability and prevents data corruption from concurrent writes.
- Phase 7: MVCC: A more advanced, long-term solution is to implement Multi-Version Concurrency Control. This will allow readers to see a consistent snapshot of the data without being blocked by writers, significantly improving performance for read-heavy workloads.
Sources: IMPLEMENTATION_PLAN.md:405-418, IMPLEMENTATION_PLAN.md:529-535, IMPLEMENTATION_PLAN.md:600-601
The following flowchart depicts the planned evolution of concurrency control in Sentinel.
Source: IMPLEMENTATION_PLAN.md:417
Technology Stack and Tooling
The implementation of concurrency features relies on a set of specific Rust crates and development practices.
| Crate | Purpose |
|---|---|
tokio | Provides the asynchronous runtime for concurrent operations. |
parking_lot | Offers high-performance RwLock and Mutex primitives. |
dashmap | A concurrent hash map used in FileLockManager to store lock states. |
fs2 | Provides cross-platform file locking (fcntl on Unix, LockFile on Windows). |
arc-swap | Used for lock-free atomic swapping of shared data, relevant for caching. |
Sources: IMPLEMENTATION_PLAN.md:118, IMPLEMENTATION_PLAN.md:155, IMPLEMENTATION_PLAN.md:224-225, IMPLEMENTATION_PLAN.md:251, IMPLEMENTATION_PLAN.md:734-758
Furthermore, the project enforces safe concurrency practices through its linting configuration in Cargo.toml. The await_holding_lock lint is set to deny, which prevents compiling code that holds a mutex or other lock across an .await point, a common source of deadlocks.
Sources: Cargo.toml:27
Summary
Sentinel's approach to concurrency and locking is a pragmatic, phased strategy that acknowledges the inherent challenges of its filesystem-based design. It begins with foundational safety mechanisms like file locking and WAL, with a long-term vision for a high-performance MVCC system. This evolution is supported by a carefully selected technology stack and strict compile-time checks to prevent common concurrency bugs, ensuring data integrity remains a top priority.