TxMap
A concurrent transactional hash map for Rust with fine-grained user-defined locking, internal mutability for easy sharing, and composable transactions.
Features
- Proven performance One of the fastest concurrent map implementations available
- Customizable Choose the number of shards, shard locking policy (Mutex, RwLock or bring your own) and capacity
- Immediate Transactions Immediately execute an atomic, composable batch of modifications
- Parameterized Transactions Create re-usable transactions for faster parameterized execution
- Guards/conditions Declarative preconditions that must hold before a transaction runs
- Fluent API Chain operations to build or execute transactions with a fluent interface
- Optional serde support Use the
serdefeature to enable it - Rapidhash hasher by default The
rapidhashfeature (enabled by default) uses the rapidhash hasher for improved performance. Disable default features and opt out withdefault-features = falsein yourCargo.tomlto fall back to the standard library'sRandomState(SipHash).
License
Licensed under the MIT License.
Usage
Add txmap to your Cargo.toml:
[]
= "3.0.2"
Creating a TxMap
use *;
let map = new;
This creates a map using the default options. To customise these options you can use a map builder which allows configuring them.
| Option | Default |
|---|---|
| Shard count | 32 |
| Lock policy | MutexPolicy |
| Hasher | rapidhash::fast::RandomState |
| Initial capacity | 0 |
Two shard locking policies are provided: MutexPolicy (default) and RwLockPolicy. You can also use your own policy by implementing LockPolicy.
// Creating a TxMap via a builder
let map = default
.with_shards
.
.with_capacity
.build;
Key type requirements
The key type K must implement Clone, Hash and Eq.
The value type V has no required trait bounds.
Immediate Transactions
You may need to run a one-off transaction, for these cases use map.immediate_tx().
use *;
// Create a state struct for the transaction, it must implement Default
let db: = new;
db.insert;
db.insert;
// Use the state struct as the generic type
// The transaction will create an instance to use as the mutable state and return it wrapped in a TxResult
let result = db.
// Transfer 50 from alice to bob in one atomic transaction
.modify
.modify
.execute;
assert!;
Parameterized transactions
Some transaction might need to be run many times, or with different parameters. For these cases create a prepared transaction with map.prepared_tx().
Prepared transactions need a transaction schema, created via the macro tx_schema.
use *;
// The example below will create 4 types to use in the transaction
// 1. Transfer: Contains constants for SCHEMA and all key handles used in the transaction, (from and to)
// 2. TransferKeys: Used to pass in the actual keys for each execution
// 3. TransferParams: Used to pass in the real parameters for each execution
// 4. TransferState: Used by the transaction to store state and is returned as part of the final result
tx_schema!
let db: = new;
db.insert;
db.insert;
let transfer_tx = db
.prepared_tx // pass in the SCHEMA constant
// prepared transactions also pass in your parameters to all closures
.modify
.modify
.into_transaction;
// Execute with different parameters
// Use the ...Keys and ...Params structs created by the `tx_schema` macro
let result1 = transfer_tx.execute;
assert_eq!;
let result2 = transfer_tx.execute;
assert_eq!;
Transaction with guards (preconditions)
Perhaps Alice doesn't have enough funds to make a transfer and you need to prevent a transfer if it would cause a negative balance.
Guards can be used to veto a transaction if they fail, in which case TxResult::RequirementNotMet is returned.
use *;
let db: = new;
db.insert;
db.insert;
let result = db
.
// Add all your requirements up front
// Requirements cannot be added after modifications
.require
.require
.modify
.modify
.execute;
match result
Transaction operations
Transactions are built with a fluent interface, many operations can be chained together atomically into a single transaction. Available transaction operations are as follows
| Transaction operation | Description |
|---|---|
get |
Reads a value, allows updating state without making any changes. |
insert_with |
Insert a value generated from the key. |
insert_with_if_absent |
Insert a value generated from the key, only if the key is absent. |
modify |
Mutate an existing value in-place. Does nothing if key absent. |
move_value |
Remove a value from one key and insert it with another key. |
remove |
Remove the given key. |
remove_if |
Remove the given key if it also satisfies a condition. |
swap_value |
Swap the values of two keys. |
update |
Update a single entry. Return Some(v) to insert/replace, None to remove. |
TxMap operations
All transaction operations (or variations of them) are also available on TxMap. There are also some additional operations which require map level locking and therefore are only available on TxMap. These are as follows
| TxMap operation | Description |
|---|---|
clear |
Removes all entries |
len |
Returns how many entries the map contains |
is_empty |
Returns if the map is empty |
fold |
Performs a fold on all the entries |
iter |
Creates an iterator over all the entries |
retain |
Retains any entry which satisfies a condition |