summaryrefslogtreecommitdiff
path: root/src/collection.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/collection.rs')
-rw-r--r--src/collection.rs78
1 files changed, 74 insertions, 4 deletions
diff --git a/src/collection.rs b/src/collection.rs
index a84c1ce..c51e3cf 100644
--- a/src/collection.rs
+++ b/src/collection.rs
@@ -1,6 +1,6 @@
use std::marker::PhantomData;
-use crate::{key::Keyable, lockable::Lock};
+use crate::{key::Keyable, lockable::RawLock};
mod boxed;
mod guard;
@@ -8,25 +8,95 @@ mod owned;
mod r#ref;
mod retry;
+/// Locks a collection of locks, which cannot be shared immutably.
+///
+/// This could be a tuple of [`Lockable`] types, an array, or a `Vec`. But it
+/// can be safely locked without causing a deadlock.
+///
+/// The data in this collection is guaranteed to not contain duplicates because
+/// `L` must always implement [`OwnedLockable`]. The underlying data may not be
+/// immutably referenced and locked. Because of this, there is no need for
+/// sorting the locks in the collection, or checking for duplicates, because it
+/// can be guaranteed that until the underlying collection is mutated (which
+/// requires releasing all acquired locks in the collection to do), then the
+/// locks will stay in the same order and be locked in that order, preventing
+/// cyclic wait.
+///
+/// [`Lockable`]: `crate::lockable::Lockable`
+/// [`OwnedLockable`]: `crate::lockable::OwnedLockable`
#[derive(Debug)]
pub struct OwnedLockCollection<L> {
data: L,
}
-/// A type which can be locked.
+/// Locks a reference to a collection of locks, by sorting them by memory
+/// address.
///
/// This could be a tuple of [`Lockable`] types, an array, or a `Vec`. But it
/// can be safely locked without causing a deadlock.
+///
+/// Upon construction, it must be confirmed that the collection contains no
+/// duplicate locks. This can be done by either using [`OwnedLockable`] or by
+/// checking. Regardless of how this is done, the locks will be sorted by their
+/// memory address before locking them. The sorted order of the locks is stored
+/// within this collection.
+///
+/// Unlike [`BoxedLockCollection`], this type does not allocate memory for the
+/// data, although it does allocate memory for the sorted list of lock
+/// references. This makes it slightly faster, but lifetimes must be handled.
+///
+/// [`Lockable`]: `crate::lockable::Lockable`
+/// [`OwnedLockable`]: `crate::lockable::OwnedLockable`
pub struct RefLockCollection<'a, L> {
data: &'a L,
- locks: Vec<&'a dyn Lock>,
+ locks: Vec<&'a dyn RawLock>,
}
+/// Locks a collection of locks, stored in the heap, by sorting them by memory
+/// address.
+///
+/// This could be a tuple of [`Lockable`] types, an array, or a `Vec`. But it
+/// can be safely locked without causing a deadlock.
+///
+/// Upon construction, it must be confirmed that the collection contains no
+/// duplicate locks. This can be done by either using [`OwnedLockable`] or by
+/// checking. Regardless of how this is done, the locks will be sorted by their
+/// memory address before locking them. The sorted order of the locks is stored
+/// within this collection.
+///
+/// Unlike [`RefLockCollection`], this is a self-referential type which boxes
+/// the data that is given to it. This means no lifetimes are necessary on the
+/// type itself, but it is slightly slower because of the memory allocation.
+///
+/// [`Lockable`]: `crate::lockable::Lockable`
+/// [`OwnedLockable`]: `crate::lockable::OwnedLockable`
pub struct BoxedLockCollection<L> {
data: Box<L>,
- locks: Vec<&'static dyn Lock>,
+ locks: Vec<&'static dyn RawLock>,
}
+/// Locks a collection of locks using a retrying algorithm.
+///
+/// This could be a tuple of [`Lockable`] types, an array, or a `Vec`. But it
+/// can be safely locked without causing a deadlock.
+///
+/// The data in this collection is guaranteed to not contain duplicates, but it
+/// also not be sorted. In some cases the lack of sorting can increase
+/// performance. However, in most cases, this collection will be slower. Cyclic
+/// wait is not guaranteed here, so the locking algorithm must release all its
+/// locks if one of the lock attempts blocks. This results in wasted time and
+/// potential [livelocking].
+///
+/// However, one case where this might be faster than [`RefLockCollection`] is
+/// when the first lock in the collection is always the first in any
+/// collection, and the other locks in the collection are always locked after
+/// that first lock is acquired. This means that as soon as it is locked, there
+/// will be no need to unlock it later on subsequent lock attempts, because
+/// they will always succeed.
+///
+/// [`Lockable`]: `crate::lockable::Lockable`
+/// [`OwnedLockable`]: `crate::lockable::OwnedLockable`
+/// [livelocking]: https://en.wikipedia.org/wiki/Deadlock#Livelock
#[derive(Debug)]
pub struct RetryingLockCollection<L> {
data: L,