Crates.io | trailing_cell |
lib.rs | trailing_cell |
version | 0.3.0 |
source | src |
created_at | 2018-01-10 20:36:12.225393 |
updated_at | 2018-01-17 14:43:29.285147 |
description | Provides wrappers for sharing a data structure where read speed is important and strict consistency is not (data can be stale). |
homepage | |
repository | https://github.com/sirkibsirkib/trailing_cell |
max_upload_size | |
id | 46279 |
size | 16,277 |
This little project is inspired by works such as magnetic
and evmap
, which concentrate on lock-freedom. Here I introduce some wrapper representing a sort of Cell
that implements 'trailing state' semantics. This structure is useful in the situation you have a performance-critical data structure for which reads must be fast, but writes can be slow (perhaps they are very rare). The key here is that the state is provided by the user, and under the user's control.
For instance, I intend to use this for a game to store a bidir-map
between client ID's of which there is a fixed amount) and player ID's (which are tied to players, like usernames).
A set of connected TcWriter<M>
s have any number (initially 0) of reading
TcReader<T,M>
objects for any types T
(typically the same type T).
This is particularly useful when:
T
data has the set of writers W and readers R, where W != R.It also has with it the nice properties of:
TcWriter::clone
).TcWriter::add_reader
).T
state.The implementation allows readers to be initialized with not only different
local states, but even initial states of different types, (so long as they
all implement TakesMessage<M>
for the same M
as the writer(s)). It's not
clear to me how this option might be useful, but it costs nothing to
support, so why not.
For the writers and readers to communicate, they rely on some concept of 'message'. As such, before one can do anything, one needs to implement trait TakesMessage
for the objects that are going to represent 'state'. This involves implementing only one function, which defines how your state object is updated when faced with a particular message.
All that remains then is to create a first writer object. All readers connected to it descend from this writer, either directly or from other writers that descend from it. These readers can then be thrown around on threads as desired, each calling whichever functions necessary, all ultimately boiling down to:
TcWriter
and TcReader
are implemented as wrappers over a bus::Bus
, where writers act as M
producers, and readers act as M
consumers. However, a message from any writer arrives at all readers. Readers consume buffered messages when they call their TcReader::update
function, and serially apply these messages to their local state (as defined by the trait).
See tests.rs
for more annotated examples.