A library for high concurrency reads.
This library is named after the 2 (identical) tables that are held internally:
- Active - this is the table that all Readers view. This table will never be write locked, so readers never face contention.
- Standby - this is the table that writers mutate. A writer should face minimal
contention retrieving this table since Readers move to the Active table
whenever calling
.read().
There are 2 ways to use this crate:
- Direct interaction with
AsLock/AsLockHandle. This is more flexible since users can pass in any struct they want and mutate it however they choose. All updates though, will need to be done by passing a function instead of via mutable methods (UpdateTablestrait). - Using collections which are built out of the primitives but which provide an
API similar to
RwLock<T>; writers can directly call to methods without having to provide a mutator function.
There are 2 flavors/modules:
- Lockless - this variant trades off increased performance against changing the
API to be less like a
RwLock. This centers around theAsLockHandle, which is conceptually similar toArc<RwLock>(requires a separateAsLockHandleper thread/task). - Sync - this centers around using an
AsLock, which is meant to feel like aRwLock. The main difference is that you still cannot gain direct write access to the underlying table due to the need to keep them identical.
The cost of minimizing contention is:
- Memory - Internally there are 2 copies of the underlying type the user created. This is needed to allow there to always be a table that Readers can access out without contention.
- CPU - The writer must apply all updates twice, once to each table. Lock contention for the writer should be less than with a plain RwLock due to Readers using the active_table, so it's possible that write times themselves will drop.
Example
Example of the 3 usage patters: build your own wrapper, use prebuilt collections, and use the primitives. Each of these can be done with both sync and lockless.
use sleep;
use Duration;
use Arc;
// Create wrapper class so that users can interact with the active_standby
// struct via a RwLock-like interface. See the implementation of the
// collections for more examples.
// Use a premade collection which wraps `AsLock<Vec<T>>`, to provide an
// interface akin to `RwLock<Vec<T>>`.
// Use the raw AsLock interface to update the underlying data.
Testing
There are a number of tests that come with active_standby (see tests/tests_script.sh for examples):