1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
use failure::Fallible; use std::collections::HashMap; use uuid::Uuid; #[cfg(test)] mod inmemory; mod kv; mod operation; pub use self::kv::KVStorage; #[cfg(test)] pub use inmemory::InMemoryStorage; pub use operation::Operation; /// An in-memory representation of a task as a simple hashmap pub type TaskMap = HashMap<String, String>; #[cfg(test)] fn taskmap_with(mut properties: Vec<(String, String)>) -> TaskMap { let mut rv = TaskMap::new(); for (p, v) in properties.drain(..) { rv.insert(p, v); } rv } /// The type of VersionIds pub use crate::server::VersionId; /// The default for base_version. pub(crate) const DEFAULT_BASE_VERSION: Uuid = crate::server::NO_VERSION_ID; /// A TaskStorage transaction, in which storage operations are performed. /// /// # Concurrency /// /// Serializable consistency must be maintained. Concurrent access is unusual /// and some implementations may simply apply a mutex to limit access to /// one transaction at a time. /// /// # Commiting and Aborting /// /// A transaction is not visible to other readers until it is committed with /// [`crate::taskstorage::TaskStorageTxn::commit`]. Transactions are aborted if they are dropped. /// It is safe and performant to drop transactions that did not modify any data without committing. pub trait TaskStorageTxn { /// Get an (immutable) task, if it is in the storage fn get_task(&mut self, uuid: &Uuid) -> Fallible<Option<TaskMap>>; /// Create an (empty) task, only if it does not already exist. Returns true if /// the task was created (did not already exist). fn create_task(&mut self, uuid: Uuid) -> Fallible<bool>; /// Set a task, overwriting any existing task. If the task does not exist, this implicitly /// creates it (use `get_task` to check first, if necessary). fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible<()>; /// Delete a task, if it exists. Returns true if the task was deleted (already existed) fn delete_task(&mut self, uuid: &Uuid) -> Fallible<bool>; /// Get the uuids and bodies of all tasks in the storage, in undefined order. fn all_tasks(&mut self) -> Fallible<Vec<(Uuid, TaskMap)>>; /// Get the uuids of all tasks in the storage, in undefined order. fn all_task_uuids(&mut self) -> Fallible<Vec<Uuid>>; /// Get the current base_version for this storage -- the last version synced from the server. fn base_version(&mut self) -> Fallible<VersionId>; /// Set the current base_version for this storage. fn set_base_version(&mut self, version: VersionId) -> Fallible<()>; /// Get the current set of outstanding operations (operations that have not been sync'd to the /// server yet) fn operations(&mut self) -> Fallible<Vec<Operation>>; /// Add an operation to the end of the list of operations in the storage. Note that this /// merely *stores* the operation; it is up to the TaskDB to apply it. fn add_operation(&mut self, op: Operation) -> Fallible<()>; /// Replace the current list of operations with a new list. fn set_operations(&mut self, ops: Vec<Operation>) -> Fallible<()>; /// Get the entire working set, with each task UUID at its appropriate (1-based) index. /// Element 0 is always None. fn get_working_set(&mut self) -> Fallible<Vec<Option<Uuid>>>; /// Add a task to the working set and return its (one-based) index. This index will be one greater /// than the highest used index. fn add_to_working_set(&mut self, uuid: &Uuid) -> Fallible<usize>; /// Clear all tasks from the working set in preparation for a garbage-collection operation. /// Note that this is the only way items are removed from the set. fn clear_working_set(&mut self) -> Fallible<()>; /// Commit any changes made in the transaction. It is an error to call this more than /// once. fn commit(&mut self) -> Fallible<()>; } /// A trait for objects able to act as task storage. Most of the interesting behavior is in the /// [`crate::taskstorage::TaskStorageTxn`] trait. pub trait TaskStorage { /// Begin a transaction fn txn<'a>(&'a mut self) -> Fallible<Box<dyn TaskStorageTxn + 'a>>; }