Crate cycler

Crate cycler 

Source
Expand description

This is a data synchronization system with 1 writer and N readers. All writers and readers can operate on the data at the same time and will access the most up to date version when they switch. This is accomplished by storing N + 2 copies of the data with the writer publishing new versions of the data. The purpose of this is to allow read threads to have an unchanging up to date copy of the main data while the writer can edit it at the same time.

§Requirements

The data type must also implement both ReadAccess and WriteAccess otherwise the access functions won’t be available. These types allow the reader to see a subset of the data, intended for hiding data only the writer needs like a change log for optimization of the copy. If you don’t care about access restrictions you can set ReadAccess::Read and WriteAccess::Write to Self and there will be zero runtime cost as the compiler should optimize that out.

§Optimization

The most optimal thing to do with regard to memory usage is to have a single reader. N + 2 copies of the data must exist because in the worst case scenario all N readers are reading separate copies and the writer is finalizing a write. In this case the N copies of the data that are being read are inaccessible to writes and the last updated index cannot be written to so there must be an additional copy. What this means is that if you only utilize a single writer and distribute that the minimum amount of memory will be used. The trade off is that if you have multiple reading loops that operate at differing rates all the loops will operate at the slowest speed. Adding readers does not increase the amount of data to copy and may only slightly increase the time between copy switches.

This also is based on the clone_from idea to clone values which is not implemented by derive normally (Derivative can auto derive for you). This is a major optimization chance in this case and you can test/track the changes to reduce copy time.

Modules§

atomic_cycler
The AtomicCycler uses a custom atomic read/write lockless lock to keep track of reading and writing to each block without using unsafe code. This implementation is faster than RwLockCycler but it relies on a custom lock that is filled with unsafe code.
rw_lock_cycler
The RwLockCycler uses parking_lot::RwLock to keep track of reading and writing to each block without using unsafe code. This is the first implementation but may not be the fastest as locks are required for each switch. Due to the way the data structure is designed there is always an available slot so all lock obtainment are use the try variant.

Traits§

CyclerReader
This trait is implemented for the read half of a cycler.
CyclerWriter
This trait is implemented for the write half of a cycler.
CyclerWriterDefault
This trait enables the write half of the cycler to be moved to the next chunk by a default copy function. Usually this function is Clone::clone_from but that is not a strict requirement.
CyclerWriterFn
This trait enables the write half of the cycler to move to the next block using a given clone function. This function follows the signature of Clone::clone_from, meaning the arguments are (to, from).
CyclerWriterMutFn
This trait enables the write half of the cycler to move to the next block using a clone function that takes a mutable reference to the previous block. This is not preferable as optimizations where the reader can read the previous block while it’s being cloned are not possible. The function arguments are (from, to)
EnsureSend
Trait that can be implemented to ensure a type is send
EnsureSync
Trait that can be implemented to ensure a type is sync
ReadAccess
This trait should be implemented for any type that can be read from by a cycler. This specifically allows for the separation of read and write data from the cycler readers and writers. If this functionality is not needed then ReadAccess::Read can be set to Self for no runtime cost.
UniversalCyclerReader
This trait is a collection of all the primarily supported reader traits. Other traits may be added to this in the future but none will be taken away without a major version bump. Other traits may also be added that do not fall under this for more specific functionality.
UniversalCyclerWriter
This trait is a collection of all the primarily supported writer traits. Other traits may be added to this in the future but none will be taken away without a major version bump. Other traits may also be added that do not fall under this for more specific functionality (ex: CyclerWriterMutFn).
WriteAccess
This trait should be implemented for any type that can be written to by a cycler. This specifically allows for the separation of read and write data from the cycler readers and writers. If this functionality is not needed then WriteAccess::Write can be set to Self for no runtime cost.

Functions§

build_multiple_reader
Creates a multi reader DefaultCycler, the amount of readers being initial_values.len() - 2.
build_multiple_reader_cloned
Creates a multi reader DefaultCycler with the initial value being cloned.
build_multiple_reader_default
Creates a multi reader DefaultCycler with the initial value being default.
build_single_reader
Creates a single reader DefaultCycler using initial_values as the initial values for the slots.
build_single_reader_cloned
Creates a single reader DefaultCycler cloning initial_value as the initial values for the slots.
build_single_reader_default
Creates a single reader DefaultCycler using default initial values for the slots.

Type Aliases§

DefaultCyclerReader
This is the currently most optimal cycler reader that implements UniversalCyclerReader.
DefaultCyclerWriter
This is the currently most optimal cycler writer that implements UniversalCyclerWriter.