diff --git a/Cargo.lock b/Cargo.lock index 6b40737c3..d48a1eaeb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -161,6 +161,17 @@ name = "itoa" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "kv" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "lmdb-rkv 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -171,6 +182,27 @@ name = "libc" version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "lmdb-rkv" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "lmdb-rkv-sys 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lmdb-rkv-sys" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-integer" version = "0.1.41" @@ -188,6 +220,11 @@ dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "pkg-config" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "ppv-lite86" version = "0.2.6" @@ -474,6 +511,7 @@ dependencies = [ "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "kv 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)", @@ -511,6 +549,14 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "toml" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicode-width" version = "0.1.7" @@ -589,10 +635,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum kv 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "db74e838988c38867eac475ff9793b34ee520618c73cad9dc5a450caa4f5a5e6" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" +"checksum lmdb-rkv 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "605061e5465304475be2041f19967a900175ea1b6d8f47fbab84a84fb8c48452" +"checksum lmdb-rkv-sys 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7982ba0460e939e26a52ee12c8075deab0ebd44ed21881f656841b70e021b7c8" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" "checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" @@ -628,6 +678,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum toml 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "01d1404644c8b12b16bfcffa4322403a91a451584daaaa7c28d3152e6cbc98cf" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9fde2f6a4bea1d6e007c4ad38c6839fa71cbb63b6dbf5b595aa38dc9b1093c11" diff --git a/Cargo.toml b/Cargo.toml index f61df728c..c65c7e6fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ serde_json = "1.0" chrono = { version = "0.4.10", features = ["serde"] } failure = {version = "0.1.5", features = ["derive"] } clap = "~2.33.0" +kv = "0.9.3" [dev-dependencies] proptest = "0.9.4" diff --git a/TODO.txt b/TODO.txt index 0d8c7da95..045580c49 100644 --- a/TODO.txt +++ b/TODO.txt @@ -13,3 +13,4 @@ * design expiration - need to be sure that create / delete operations don't get reversed * cli tools +* move test-only tools somewhere else (helpers in tests/?) diff --git a/src/bin/task.rs b/src/bin/task.rs index e777fd317..d9ce502e2 100644 --- a/src/bin/task.rs +++ b/src/bin/task.rs @@ -27,7 +27,7 @@ fn main() { .unwrap(); } ("list", _) => { - for task in replica.all_tasks() { + for task in replica.all_tasks().unwrap() { println!("{:?}", task); } } diff --git a/src/replica.rs b/src/replica.rs index 0d7a49ff0..dc07b3290 100644 --- a/src/replica.rs +++ b/src/replica.rs @@ -47,17 +47,17 @@ impl Replica { } /// Get all tasks as an iterator of (&Uuid, &HashMap) - pub fn all_tasks<'a>(&'a self) -> impl Iterator + 'a { + pub fn all_tasks<'a>(&'a self) -> Fallible + 'a> { self.taskdb.all_tasks() } /// Get the UUIDs of all tasks - pub fn all_task_uuids<'a>(&'a self) -> impl Iterator + 'a { + pub fn all_task_uuids<'a>(&'a self) -> Fallible + 'a> { self.taskdb.all_task_uuids() } /// Get an existing task by its UUID - pub fn get_task(&self, uuid: &Uuid) -> Option { + pub fn get_task(&self, uuid: &Uuid) -> Fallible> { self.taskdb.get_task(&uuid) } } @@ -74,7 +74,7 @@ mod tests { let uuid = Uuid::new_v4(); rep.create_task(uuid.clone()).unwrap(); - assert_eq!(rep.get_task(&uuid), Some(TaskMap::new())); + assert_eq!(rep.get_task(&uuid).unwrap(), Some(TaskMap::new())); } #[test] @@ -84,7 +84,7 @@ mod tests { rep.create_task(uuid.clone()).unwrap(); rep.delete_task(uuid.clone()).unwrap(); - assert_eq!(rep.get_task(&uuid), None); + assert_eq!(rep.get_task(&uuid).unwrap(), None); } #[test] @@ -97,13 +97,13 @@ mod tests { .unwrap(); let mut task = TaskMap::new(); task.insert("title".into(), "snarsblat".into()); - assert_eq!(rep.get_task(&uuid), Some(task)); + assert_eq!(rep.get_task(&uuid).unwrap(), Some(task)); } #[test] fn get_does_not_exist() { let rep = Replica::new(DB::new_inmemory().into()); let uuid = Uuid::new_v4(); - assert_eq!(rep.get_task(&uuid), None); + assert_eq!(rep.get_task(&uuid).unwrap(), None); } } diff --git a/src/taskdb.rs b/src/taskdb.rs index be5dc8388..ba448dafc 100644 --- a/src/taskdb.rs +++ b/src/taskdb.rs @@ -34,10 +34,11 @@ impl DB { /// to modify the DB. In cases where an operation does not make sense, this function will do /// nothing and return an error (but leave the DB in a consistent state). pub fn apply(&mut self, op: Operation) -> Fallible<()> { + // TODO: differentiate error types here? if let err @ Err(_) = self.apply_op(&op) { return err; } - self.storage.add_operation(op); + self.storage.add_operation(op)?; Ok(()) } @@ -45,12 +46,12 @@ impl DB { match op { &Operation::Create { uuid } => { // insert if the task does not already exist - if !self.storage.create_task(uuid, HashMap::new()) { + if !self.storage.create_task(uuid, HashMap::new())? { return Err(Error::DBError(format!("Task {} already exists", uuid)).into()); } } &Operation::Delete { ref uuid } => { - if !self.storage.delete_task(uuid) { + if !self.storage.delete_task(uuid)? { return Err(Error::DBError(format!("Task {} does not exist", uuid)).into()); } } @@ -61,13 +62,13 @@ impl DB { timestamp: _, } => { // update if this task exists, otherwise ignore - if let Some(task) = self.storage.get_task(uuid) { + if let Some(task) = self.storage.get_task(uuid)? { let mut task = task.clone(); match value { Some(ref val) => task.insert(property.to_string(), val.clone()), None => task.remove(property), }; - self.storage.set_task(uuid.clone(), task); + self.storage.set_task(uuid.clone(), task)?; } else { return Err(Error::DBError(format!("Task {} does not exist", uuid)).into()); } @@ -78,38 +79,41 @@ impl DB { } /// Get all tasks. This is not a terribly efficient operation. - pub fn all_tasks<'a>(&'a self) -> impl Iterator + 'a { - self.all_task_uuids() - .map(move |u| (u, self.get_task(&u).unwrap())) + pub fn all_tasks<'a>(&'a self) -> Fallible + 'a> { + Ok(self + .all_task_uuids()? + // TODO: don't unwrap result (just option) + .map(move |u| (u, self.get_task(&u).unwrap().unwrap()))) } /// Get the UUIDs of all tasks - pub fn all_task_uuids<'a>(&'a self) -> impl Iterator + 'a { + pub fn all_task_uuids<'a>(&'a self) -> Fallible + 'a> { self.storage.get_task_uuids() } /// Get a single task, by uuid. - pub fn get_task(&self, uuid: &Uuid) -> Option { + pub fn get_task(&self, uuid: &Uuid) -> Fallible> { self.storage.get_task(uuid) } /// Sync to the given server, pulling remote changes and pushing local changes. - pub fn sync(&mut self, username: &str, server: &mut Server) { + pub fn sync(&mut self, username: &str, server: &mut Server) -> Fallible<()> { // retry synchronizing until the server accepts our version (this allows for races between // replicas trying to sync to the same server) loop { // first pull changes and "rebase" on top of them - let new_versions = server.get_versions(username, self.storage.base_version()); + let new_versions = server.get_versions(username, self.storage.base_version()?); for version_blob in new_versions { let version_str = str::from_utf8(&version_blob).unwrap(); let version: Version = serde_json::from_str(version_str).unwrap(); - assert_eq!(version.version, self.storage.base_version() + 1); + assert_eq!(version.version, self.storage.base_version()? + 1); println!("applying version {:?} from server", version.version); - self.apply_version(version); + self.apply_version(version)?; } - let operations: Vec = self.storage.operations().map(|o| o.clone()).collect(); + let operations: Vec = + self.storage.operations()?.map(|o| o.clone()).collect(); if operations.len() == 0 { // nothing to sync back to the server.. break; @@ -117,7 +121,7 @@ impl DB { // now make a version of our local changes and push those let new_version = Version { - version: self.storage.base_version() + 1, + version: self.storage.base_version()? + 1, operations: operations, }; let new_version_str = serde_json::to_string(&new_version).unwrap(); @@ -125,13 +129,15 @@ impl DB { if let VersionAdd::Ok = server.add_version(username, new_version.version, new_version_str.into()) { - self.storage.local_operations_synced(new_version.version); + self.storage.local_operations_synced(new_version.version)?; break; } } + + Ok(()) } - fn apply_version(&mut self, mut version: Version) { + fn apply_version(&mut self, mut version: Version) -> Fallible<()> { // The situation here is that the server has already applied all server operations, and we // have already applied all local operations, so states have diverged by several // operations. We need to figure out what operations to apply locally and on the server in @@ -158,7 +164,7 @@ impl DB { // indicating no operation is required. If this happens for a local op, we can just omit // it. If it happens for server op, then we must copy the remaining local ops. let mut local_operations: Vec = - self.storage.operations().map(|o| o.clone()).collect(); + self.storage.operations()?.map(|o| o.clone()).collect(); for server_op in version.operations.drain(..) { let mut new_local_ops = Vec::with_capacity(local_operations.len()); let mut svr_op = Some(server_op); @@ -181,7 +187,8 @@ impl DB { local_operations = new_local_ops; } self.storage - .update_version(version.version, local_operations); + .update_version(version.version, local_operations)?; + Ok(()) } // functions for supporting tests @@ -189,6 +196,7 @@ impl DB { pub fn sorted_tasks(&self) -> Vec<(Uuid, Vec<(String, String)>)> { let mut res: Vec<(Uuid, Vec<(String, String)>)> = self .all_tasks() + .unwrap() .map(|(u, t)| { let mut t = t .iter() @@ -203,7 +211,11 @@ impl DB { } pub fn operations(&self) -> Vec { - self.storage.operations().map(|o| o.clone()).collect() + self.storage + .operations() + .unwrap() + .map(|o| o.clone()) + .collect() } } diff --git a/src/taskstorage/inmemory.rs b/src/taskstorage/inmemory.rs index 798be6053..790cd341d 100644 --- a/src/taskstorage/inmemory.rs +++ b/src/taskstorage/inmemory.rs @@ -1,5 +1,6 @@ use crate::operation::Operation; use crate::taskstorage::{TaskMap, TaskStorage}; +use failure::Fallible; use std::collections::hash_map::Entry; use std::collections::HashMap; use uuid::Uuid; @@ -30,72 +31,76 @@ impl InMemoryStorage { impl TaskStorage for InMemoryStorage { /// Get an (immutable) task, if it is in the storage - fn get_task(&self, uuid: &Uuid) -> Option { + fn get_task(&self, uuid: &Uuid) -> Fallible> { match self.tasks.get(uuid) { - None => None, - Some(t) => Some(t.clone()), + None => Ok(None), + Some(t) => Ok(Some(t.clone())), } } /// Create a 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, task: TaskMap) -> bool { + fn create_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible { if let ent @ Entry::Vacant(_) = self.tasks.entry(uuid) { ent.or_insert(task); - true + Ok(true) } else { - false + Ok(false) } } /// Set a task, overwriting any existing task. - fn set_task(&mut self, uuid: Uuid, task: TaskMap) { + fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible<()> { self.tasks.insert(uuid, task); + Ok(()) } /// Delete a task, if it exists. Returns true if the task was deleted (already existed) - fn delete_task(&mut self, uuid: &Uuid) -> bool { + fn delete_task(&mut self, uuid: &Uuid) -> Fallible { if let Some(_) = self.tasks.remove(uuid) { - true + Ok(true) } else { - false + Ok(false) } } - fn get_task_uuids<'a>(&'a self) -> Box + 'a> { - Box::new(self.tasks.keys().map(|u| u.clone())) + fn get_task_uuids<'a>(&'a self) -> Fallible + 'a>> { + Ok(Box::new(self.tasks.keys().map(|u| u.clone()))) } /// Add an operation to 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) { + fn add_operation(&mut self, op: Operation) -> Fallible<()> { self.operations.push(op); + Ok(()) } /// Get the current base_version for this storage -- the last version synced from the server. - fn base_version(&self) -> u64 { - return self.base_version; + fn base_version(&self) -> Fallible { + Ok(self.base_version) } /// Get the current set of outstanding operations (operations that have not been sync'd to the /// server yet) - fn operations<'a>(&'a self) -> Box + 'a> { - Box::new(self.operations.iter()) + fn operations<'a>(&'a self) -> Fallible + 'a>> { + Ok(Box::new(self.operations.iter())) } /// Apply the next version from the server. This replaces the existing base_version and /// operations. It's up to the caller (TaskDB) to ensure this is done consistently. - fn update_version(&mut self, version: u64, new_operations: Vec) { + fn update_version(&mut self, version: u64, new_operations: Vec) -> Fallible<()> { // ensure that we are applying the versions in order.. assert_eq!(version, self.base_version + 1); self.base_version = version; self.operations = new_operations; + Ok(()) } /// Record the outstanding operations as synced to the server in the given version. - fn local_operations_synced(&mut self, version: u64) { + fn local_operations_synced(&mut self, version: u64) -> Fallible<()> { assert_eq!(version, self.base_version + 1); self.base_version = version; self.operations = vec![]; + Ok(()) } } diff --git a/src/taskstorage/lmdb.rs b/src/taskstorage/lmdb.rs new file mode 100644 index 000000000..1a7d75c7f --- /dev/null +++ b/src/taskstorage/lmdb.rs @@ -0,0 +1,95 @@ +use crate::operation::Operation; +use crate::taskstorage::{TaskMap, TaskStorage}; +use kv::{Config, Error, Manager, ValueRef}; +use uuid::Uuid; + +pub struct KVStorage { + // TODO: make the manager global with lazy-static + manager: Manager, + config: Config, +} + +impl KVStorage { + pub fn new(directory: &str) -> KVStorage { + let mut config = Config::default(directory); + config.bucket("base_version", None); + config.bucket("operations", None); + config.bucket("tasks", None); + KVStorage { + manager: Manager::new(), + config, + } + } +} + +impl TaskStorage for KVStorage { + /// Get an (immutable) task, if it is in the storage + fn get_task(&self, uuid: &Uuid) -> Option { + match self.tasks.get(uuid) { + None => None, + Some(t) => Some(t.clone()), + } + } + + /// Create a 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, task: TaskMap) -> bool { + if let ent @ Entry::Vacant(_) = self.tasks.entry(uuid) { + ent.or_insert(task); + true + } else { + false + } + } + + /// Set a task, overwriting any existing task. + fn set_task(&mut self, uuid: Uuid, task: TaskMap) { + self.tasks.insert(uuid, task); + } + + /// Delete a task, if it exists. Returns true if the task was deleted (already existed) + fn delete_task(&mut self, uuid: &Uuid) -> bool { + if let Some(_) = self.tasks.remove(uuid) { + true + } else { + false + } + } + + fn get_task_uuids<'a>(&'a self) -> Box + 'a> { + Box::new(self.tasks.keys().map(|u| u.clone())) + } + + /// Add an operation to 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) { + self.operations.push(op); + } + + /// Get the current base_version for this storage -- the last version synced from the server. + fn base_version(&self) -> u64 { + return self.base_version; + } + + /// Get the current set of outstanding operations (operations that have not been sync'd to the + /// server yet) + fn operations<'a>(&'a self) -> Box + 'a> { + Box::new(self.operations.iter()) + } + + /// Apply the next version from the server. This replaces the existing base_version and + /// operations. It's up to the caller (TaskDB) to ensure this is done consistently. + fn update_version(&mut self, version: u64, new_operations: Vec) { + // ensure that we are applying the versions in order.. + assert_eq!(version, self.base_version + 1); + self.base_version = version; + self.operations = new_operations; + } + + /// Record the outstanding operations as synced to the server in the given version. + fn local_operations_synced(&mut self, version: u64) { + assert_eq!(version, self.base_version + 1); + self.base_version = version; + self.operations = vec![]; + } +} diff --git a/src/taskstorage/mod.rs b/src/taskstorage/mod.rs index dd8e233de..3f339ac29 100644 --- a/src/taskstorage/mod.rs +++ b/src/taskstorage/mod.rs @@ -1,4 +1,5 @@ use crate::Operation; +use failure::Fallible; use std::collections::HashMap; use std::fmt; use uuid::Uuid; @@ -15,36 +16,36 @@ pub type TaskMap = HashMap; /// implementation, which is the sole consumer of this trait. pub trait TaskStorage: fmt::Debug { /// Get an (immutable) task, if it is in the storage - fn get_task(&self, uuid: &Uuid) -> Option; + fn get_task(&self, uuid: &Uuid) -> Fallible>; /// Create a 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, task: TaskMap) -> bool; + fn create_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible; /// Set a task, overwriting any existing task. - fn set_task(&mut self, uuid: Uuid, task: TaskMap); + 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) -> bool; + fn delete_task(&mut self, uuid: &Uuid) -> Fallible; /// Get the uuids of all tasks in the storage, in undefined order. - fn get_task_uuids<'a>(&'a self) -> Box + 'a>; + fn get_task_uuids<'a>(&'a self) -> Fallible + 'a>>; /// Add an operation to 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); + fn add_operation(&mut self, op: Operation) -> Fallible<()>; /// Get the current base_version for this storage -- the last version synced from the server. - fn base_version(&self) -> u64; + fn base_version(&self) -> Fallible; /// Get the current set of outstanding operations (operations that have not been sync'd to the /// server yet) - fn operations<'a>(&'a self) -> Box + 'a>; + fn operations<'a>(&'a self) -> Fallible + 'a>>; /// Apply the next version from the server. This replaces the existing base_version and /// operations. It's up to the caller (TaskDB) to ensure this is done consistently. - fn update_version(&mut self, version: u64, new_operations: Vec); + fn update_version(&mut self, version: u64, new_operations: Vec) -> Fallible<()>; /// Record the outstanding operations as synced to the server in the given version. - fn local_operations_synced(&mut self, version: u64); + fn local_operations_synced(&mut self, version: u64) -> Fallible<()>; } diff --git a/tests/sync.rs b/tests/sync.rs index 8c684b4f9..b3f73f6de 100644 --- a/tests/sync.rs +++ b/tests/sync.rs @@ -11,10 +11,10 @@ fn test_sync() { let mut server = Server::new(); let mut db1 = newdb(); - db1.sync("me", &mut server); + db1.sync("me", &mut server).unwrap(); let mut db2 = newdb(); - db2.sync("me", &mut server); + db2.sync("me", &mut server).unwrap(); // make some changes in parallel to db1 and db2.. let uuid1 = Uuid::new_v4(); @@ -38,9 +38,9 @@ fn test_sync() { .unwrap(); // and synchronize those around - db1.sync("me", &mut server); - db2.sync("me", &mut server); - db1.sync("me", &mut server); + db1.sync("me", &mut server).unwrap(); + db2.sync("me", &mut server).unwrap(); + db1.sync("me", &mut server).unwrap(); assert_eq!(db1.sorted_tasks(), db2.sorted_tasks()); // now make updates to the same task on both sides @@ -60,9 +60,9 @@ fn test_sync() { .unwrap(); // and synchronize those around - db1.sync("me", &mut server); - db2.sync("me", &mut server); - db1.sync("me", &mut server); + db1.sync("me", &mut server).unwrap(); + db2.sync("me", &mut server).unwrap(); + db1.sync("me", &mut server).unwrap(); assert_eq!(db1.sorted_tasks(), db2.sorted_tasks()); } @@ -71,10 +71,10 @@ fn test_sync_create_delete() { let mut server = Server::new(); let mut db1 = newdb(); - db1.sync("me", &mut server); + db1.sync("me", &mut server).unwrap(); let mut db2 = newdb(); - db2.sync("me", &mut server); + db2.sync("me", &mut server).unwrap(); // create and update a task.. let uuid = Uuid::new_v4(); @@ -88,9 +88,9 @@ fn test_sync_create_delete() { .unwrap(); // and synchronize those around - db1.sync("me", &mut server); - db2.sync("me", &mut server); - db1.sync("me", &mut server); + db1.sync("me", &mut server).unwrap(); + db2.sync("me", &mut server).unwrap(); + db1.sync("me", &mut server).unwrap(); assert_eq!(db1.sorted_tasks(), db2.sorted_tasks()); // delete and re-create the task on db1 @@ -113,8 +113,8 @@ fn test_sync_create_delete() { }) .unwrap(); - db1.sync("me", &mut server); - db2.sync("me", &mut server); - db1.sync("me", &mut server); + db1.sync("me", &mut server).unwrap(); + db2.sync("me", &mut server).unwrap(); + db1.sync("me", &mut server).unwrap(); assert_eq!(db1.sorted_tasks(), db2.sorted_tasks()); } diff --git a/tests/sync_action_sequences.rs b/tests/sync_action_sequences.rs index 4f18976e2..58ed9ba77 100644 --- a/tests/sync_action_sequences.rs +++ b/tests/sync_action_sequences.rs @@ -59,7 +59,7 @@ proptest! { println!(" {:?} (ignored)", e); } }, - Action::Sync => db.sync("me", &mut server), + Action::Sync => db.sync("me", &mut server).unwrap(), } }