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 (UpdateTables
trait). - 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 separateAsLockHandle
per 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):