diff --git a/docs/src/running-sync-server.md b/docs/src/running-sync-server.md index 2cc3b7454..e8b8c56ce 100644 --- a/docs/src/running-sync-server.md +++ b/docs/src/running-sync-server.md @@ -6,3 +6,6 @@ Run `taskchampion-sync-server` to start the sync server. Use `--port` to specify the port it should listen on, and `--data-dir` to specify the directory which it should store its data. It only serves HTTP; the expectation is that a frontend proxy will be used for HTTPS support. + +The server has optional parameters `--snapshot-days` and `--snapshot-version`, giving the target number of days and versions, respectively, between snapshots of the client state. +The default values for these parameters are generally adequate. diff --git a/replica-server-tests/tests/cross-sync.rs b/replica-server-tests/tests/cross-sync.rs index ea2aa5fd9..8ade694da 100644 --- a/replica-server-tests/tests/cross-sync.rs +++ b/replica-server-tests/tests/cross-sync.rs @@ -5,7 +5,7 @@ use taskchampion_sync_server::{storage::InMemoryStorage, Server}; #[actix_rt::test] async fn cross_sync() -> anyhow::Result<()> { - let server = Server::new(Box::new(InMemoryStorage::new())); + let server = Server::new(Default::default(), Box::new(InMemoryStorage::new())); let httpserver = HttpServer::new(move || App::new().configure(|sc| server.config(sc))).bind("0.0.0.0:0")?; diff --git a/sync-server/src/api/add_snapshot.rs b/sync-server/src/api/add_snapshot.rs index e04fc0872..5c47b6c38 100644 --- a/sync-server/src/api/add_snapshot.rs +++ b/sync-server/src/api/add_snapshot.rs @@ -2,6 +2,7 @@ use crate::api::{client_key_header, failure_to_ise, ServerState, SNAPSHOT_CONTEN use crate::server::{add_snapshot, VersionId, NIL_VERSION_ID}; use actix_web::{error, post, web, HttpMessage, HttpRequest, HttpResponse, Result}; use futures::StreamExt; +use std::sync::Arc; /// Max snapshot size: 100MB const MAX_SIZE: usize = 100 * 1024 * 1024; @@ -17,7 +18,7 @@ const MAX_SIZE: usize = 100 * 1024 * 1024; #[post("/v1/client/add-snapshot/{version_id}")] pub(crate) async fn service( req: HttpRequest, - server_state: web::Data, + server_state: web::Data>, web::Path((version_id,)): web::Path<(VersionId,)>, mut payload: web::Payload, ) -> Result { @@ -46,7 +47,7 @@ pub(crate) async fn service( // note that we do not open the transaction until the body has been read // completely, to avoid blocking other storage access while that data is // in transit. - let mut txn = server_state.txn().map_err(failure_to_ise)?; + let mut txn = server_state.storage.txn().map_err(failure_to_ise)?; // get, or create, the client let client = match txn.get_client(client_key).map_err(failure_to_ise)? { @@ -58,7 +59,15 @@ pub(crate) async fn service( } }; - add_snapshot(txn, client_key, client, version_id, body.to_vec()).map_err(failure_to_ise)?; + add_snapshot( + txn, + &server_state.config, + client_key, + client, + version_id, + body.to_vec(), + ) + .map_err(failure_to_ise)?; Ok(HttpResponse::Ok().body("")) } @@ -84,7 +93,7 @@ mod test { txn.add_version(client_key, version_id, NIL_VERSION_ID, vec![])?; } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -126,7 +135,7 @@ mod test { txn.new_client(client_key, NIL_VERSION_ID).unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -156,7 +165,7 @@ mod test { let client_key = Uuid::new_v4(); let version_id = Uuid::new_v4(); let storage: Box = Box::new(InMemoryStorage::new()); - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -176,7 +185,7 @@ mod test { let client_key = Uuid::new_v4(); let version_id = Uuid::new_v4(); let storage: Box = Box::new(InMemoryStorage::new()); - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; diff --git a/sync-server/src/api/add_version.rs b/sync-server/src/api/add_version.rs index 8c46f1458..ecf8a18dc 100644 --- a/sync-server/src/api/add_version.rs +++ b/sync-server/src/api/add_version.rs @@ -5,6 +5,7 @@ use crate::api::{ use crate::server::{add_version, AddVersionResult, SnapshotUrgency, VersionId, NIL_VERSION_ID}; use actix_web::{error, post, web, HttpMessage, HttpRequest, HttpResponse, Result}; use futures::StreamExt; +use std::sync::Arc; /// Max history segment size: 100MB const MAX_SIZE: usize = 100 * 1024 * 1024; @@ -25,7 +26,7 @@ const MAX_SIZE: usize = 100 * 1024 * 1024; #[post("/v1/client/add-version/{parent_version_id}")] pub(crate) async fn service( req: HttpRequest, - server_state: web::Data, + server_state: web::Data>, web::Path((parent_version_id,)): web::Path<(VersionId,)>, mut payload: web::Payload, ) -> Result { @@ -54,7 +55,7 @@ pub(crate) async fn service( // note that we do not open the transaction until the body has been read // completely, to avoid blocking other storage access while that data is // in transit. - let mut txn = server_state.txn().map_err(failure_to_ise)?; + let mut txn = server_state.storage.txn().map_err(failure_to_ise)?; // get, or create, the client let client = match txn.get_client(client_key).map_err(failure_to_ise)? { @@ -66,9 +67,15 @@ pub(crate) async fn service( } }; - let (result, snap_urgency) = - add_version(txn, client_key, client, parent_version_id, body.to_vec()) - .map_err(failure_to_ise)?; + let (result, snap_urgency) = add_version( + txn, + &server_state.config, + client_key, + client, + parent_version_id, + body.to_vec(), + ) + .map_err(failure_to_ise)?; Ok(match result { AddVersionResult::Ok(version_id) => { @@ -114,7 +121,7 @@ mod test { txn.new_client(client_key, Uuid::nil()).unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -156,7 +163,7 @@ mod test { txn.new_client(client_key, version_id).unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -184,7 +191,7 @@ mod test { let client_key = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let storage: Box = Box::new(InMemoryStorage::new()); - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -204,7 +211,7 @@ mod test { let client_key = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let storage: Box = Box::new(InMemoryStorage::new()); - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; diff --git a/sync-server/src/api/get_child_version.rs b/sync-server/src/api/get_child_version.rs index d146a2024..2c2f6651e 100644 --- a/sync-server/src/api/get_child_version.rs +++ b/sync-server/src/api/get_child_version.rs @@ -4,6 +4,7 @@ use crate::api::{ }; use crate::server::{get_child_version, GetVersionResult, VersionId}; use actix_web::{error, get, web, HttpRequest, HttpResponse, Result}; +use std::sync::Arc; /// Get a child version. /// @@ -16,10 +17,10 @@ use actix_web::{error, get, web, HttpRequest, HttpResponse, Result}; #[get("/v1/client/get-child-version/{parent_version_id}")] pub(crate) async fn service( req: HttpRequest, - server_state: web::Data, + server_state: web::Data>, web::Path((parent_version_id,)): web::Path<(VersionId,)>, ) -> Result { - let mut txn = server_state.txn().map_err(failure_to_ise)?; + let mut txn = server_state.storage.txn().map_err(failure_to_ise)?; let client_key = client_key_header(&req)?; @@ -28,8 +29,14 @@ pub(crate) async fn service( .map_err(failure_to_ise)? .ok_or_else(|| error::ErrorNotFound("no such client"))?; - return match get_child_version(txn, client_key, client, parent_version_id) - .map_err(failure_to_ise)? + return match get_child_version( + txn, + &server_state.config, + client_key, + client, + parent_version_id, + ) + .map_err(failure_to_ise)? { GetVersionResult::Success { version_id, @@ -69,7 +76,7 @@ mod test { .unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -103,7 +110,7 @@ mod test { let client_key = Uuid::new_v4(); let parent_version_id = Uuid::new_v4(); let storage: Box = Box::new(InMemoryStorage::new()); - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -129,7 +136,7 @@ mod test { let mut txn = storage.txn().unwrap(); txn.new_client(client_key, Uuid::new_v4()).unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; diff --git a/sync-server/src/api/get_snapshot.rs b/sync-server/src/api/get_snapshot.rs index 5d1086610..cf76655c8 100644 --- a/sync-server/src/api/get_snapshot.rs +++ b/sync-server/src/api/get_snapshot.rs @@ -3,6 +3,7 @@ use crate::api::{ }; use crate::server::get_snapshot; use actix_web::{error, get, web, HttpRequest, HttpResponse, Result}; +use std::sync::Arc; /// Get a snapshot. /// @@ -15,9 +16,9 @@ use actix_web::{error, get, web, HttpRequest, HttpResponse, Result}; #[get("/v1/client/snapshot")] pub(crate) async fn service( req: HttpRequest, - server_state: web::Data, + server_state: web::Data>, ) -> Result { - let mut txn = server_state.txn().map_err(failure_to_ise)?; + let mut txn = server_state.storage.txn().map_err(failure_to_ise)?; let client_key = client_key_header(&req)?; @@ -27,7 +28,7 @@ pub(crate) async fn service( .ok_or_else(|| error::ErrorNotFound("no such client"))?; if let Some((version_id, data)) = - get_snapshot(txn, client_key, client).map_err(failure_to_ise)? + get_snapshot(txn, &server_state.config, client_key, client).map_err(failure_to_ise)? { Ok(HttpResponse::Ok() .content_type(SNAPSHOT_CONTENT_TYPE) @@ -58,7 +59,7 @@ mod test { txn.new_client(client_key, Uuid::new_v4()).unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; @@ -94,7 +95,7 @@ mod test { .unwrap(); } - let server = Server::new(storage); + let server = Server::new(Default::default(), storage); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; diff --git a/sync-server/src/api/mod.rs b/sync-server/src/api/mod.rs index b3157438a..1a12b2826 100644 --- a/sync-server/src/api/mod.rs +++ b/sync-server/src/api/mod.rs @@ -1,7 +1,7 @@ use crate::server::ClientKey; use crate::storage::Storage; +use crate::ServerConfig; use actix_web::{error, http::StatusCode, web, HttpRequest, Result, Scope}; -use std::sync::Arc; mod add_snapshot; mod add_version; @@ -27,8 +27,11 @@ pub(crate) const PARENT_VERSION_ID_HEADER: &str = "X-Parent-Version-Id"; /// The header name for parent version ID pub(crate) const SNAPSHOT_REQUEST_HEADER: &str = "X-Snapshot-Request"; -/// The type containing a reference to the Storage object in the Actix state. -pub(crate) type ServerState = Arc; +/// The type containing a reference to the persistent state for the server +pub(crate) struct ServerState { + pub(crate) storage: Box, + pub(crate) config: ServerConfig, +} pub(crate) fn api_scope() -> Scope { web::scope("") diff --git a/sync-server/src/bin/taskchampion-sync-server.rs b/sync-server/src/bin/taskchampion-sync-server.rs index d0ca6c9af..80ca56d68 100644 --- a/sync-server/src/bin/taskchampion-sync-server.rs +++ b/sync-server/src/bin/taskchampion-sync-server.rs @@ -3,7 +3,7 @@ use actix_web::{middleware::Logger, App, HttpServer}; use clap::Arg; use taskchampion_sync_server::storage::SqliteStorage; -use taskchampion_sync_server::Server; +use taskchampion_sync_server::{Server, ServerConfig}; #[actix_web::main] async fn main() -> anyhow::Result<()> { @@ -31,12 +31,33 @@ async fn main() -> anyhow::Result<()> { .takes_value(true) .required(true), ) + .arg( + Arg::with_name("snapshot-versions") + .long("snapshot-versions") + .value_name("NUM") + .help("Target number of versions between snapshots") + .default_value("100") + .takes_value(true) + .required(false), + ) + .arg( + Arg::with_name("snapshot-days") + .long("snapshot-days") + .value_name("NUM") + .help("Target number of days between snapshots") + .default_value("14") + .takes_value(true) + .required(false), + ) .get_matches(); let data_dir = matches.value_of("data-dir").unwrap(); let port = matches.value_of("port").unwrap(); + let snapshot_versions = matches.value_of("snapshot-versions").unwrap(); + let snapshot_days = matches.value_of("snapshot-versions").unwrap(); - let server = Server::new(Box::new(SqliteStorage::new(data_dir)?)); + let config = ServerConfig::from_args(snapshot_days, snapshot_versions)?; + let server = Server::new(config, Box::new(SqliteStorage::new(data_dir)?)); log::warn!("Serving on port {}", port); HttpServer::new(move || { @@ -58,7 +79,7 @@ mod test { #[actix_rt::test] async fn test_index_get() { - let server = Server::new(Box::new(InMemoryStorage::new())); + let server = Server::new(Default::default(), Box::new(InMemoryStorage::new())); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; diff --git a/sync-server/src/lib.rs b/sync-server/src/lib.rs index 535f5b39b..012f0c43f 100644 --- a/sync-server/src/lib.rs +++ b/sync-server/src/lib.rs @@ -6,7 +6,9 @@ pub mod storage; use crate::storage::Storage; use actix_web::{get, middleware, web, Responder}; +use anyhow::Context; use api::{api_scope, ServerState}; +use std::sync::Arc; #[get("/")] async fn index() -> impl Responder { @@ -16,14 +18,44 @@ async fn index() -> impl Responder { /// A Server represents a sync server. #[derive(Clone)] pub struct Server { - storage: ServerState, + server_state: Arc, +} + +/// ServerConfig contains configuration parameters for the server. +pub struct ServerConfig { + /// Target number of days between snapshots. + pub snapshot_days: i64, + + /// Target number of versions between snapshots. + pub snapshot_versions: u32, +} + +impl Default for ServerConfig { + fn default() -> Self { + ServerConfig { + snapshot_days: 14, + snapshot_versions: 100, + } + } +} +impl ServerConfig { + pub fn from_args(snapshot_days: &str, snapshot_versions: &str) -> anyhow::Result { + Ok(ServerConfig { + snapshot_days: snapshot_days + .parse() + .context("--snapshot-days must be a number")?, + snapshot_versions: snapshot_versions + .parse() + .context("--snapshot-days must be a number")?, + }) + } } impl Server { /// Create a new sync server with the given storage implementation. - pub fn new(storage: Box) -> Self { + pub fn new(config: ServerConfig, storage: Box) -> Self { Self { - storage: storage.into(), + server_state: Arc::new(ServerState { config, storage }), } } @@ -31,7 +63,7 @@ impl Server { pub fn config(&self, cfg: &mut web::ServiceConfig) { cfg.service( web::scope("") - .data(self.storage.clone()) + .data(self.server_state.clone()) .wrap( middleware::DefaultHeaders::new() .header("Cache-Control", "no-store, max-age=0"), @@ -55,7 +87,7 @@ mod test { #[actix_rt::test] async fn test_cache_control() { - let server = Server::new(Box::new(InMemoryStorage::new())); + let server = Server::new(Default::default(), Box::new(InMemoryStorage::new())); let app = App::new().configure(|sc| server.config(sc)); let mut app = test::init_service(app).await; diff --git a/sync-server/src/server.rs b/sync-server/src/server.rs index 78399b5a1..c1947e0ca 100644 --- a/sync-server/src/server.rs +++ b/sync-server/src/server.rs @@ -2,6 +2,7 @@ //! invariants, and so on. This does not implement the HTTP-specific portions; those //! are in [`crate::api`]. See the protocol documentation for details. use crate::storage::{Client, Snapshot, StorageTxn}; +use crate::ServerConfig; // TODO: move here use chrono::Utc; use uuid::Uuid; @@ -13,12 +14,6 @@ pub const NIL_VERSION_ID: VersionId = Uuid::nil(); /// than this will be rejected. const SNAPSHOT_SEARCH_LEN: i32 = 5; -/// Maximum number of days between snapshots -const SNAPSHOT_DAYS: i64 = 14; - -/// Maximum number of versions between snapshots -const SNAPSHOT_VERSIONS: u32 = 30; - pub(crate) type HistorySegment = Vec; pub(crate) type ClientKey = Uuid; pub(crate) type VersionId = Uuid; @@ -38,6 +33,7 @@ pub(crate) enum GetVersionResult { /// Implementation of the GetChildVersion protocol transaction pub(crate) fn get_child_version<'a>( mut txn: Box, + _config: &ServerConfig, client_key: ClientKey, client: Client, parent_version_id: VersionId, @@ -96,10 +92,10 @@ pub(crate) enum SnapshotUrgency { impl SnapshotUrgency { /// Calculate the urgency for a snapshot based on its age in days - fn for_days(days: i64) -> Self { - if days >= SNAPSHOT_DAYS * 3 / 2 { + fn for_days(config: &ServerConfig, days: i64) -> Self { + if days >= config.snapshot_days * 3 / 2 { SnapshotUrgency::High - } else if days >= SNAPSHOT_DAYS { + } else if days >= config.snapshot_days { SnapshotUrgency::Low } else { SnapshotUrgency::None @@ -107,10 +103,10 @@ impl SnapshotUrgency { } /// Calculate the urgency for a snapshot based on its age in versions - fn for_versions_since(versions_since: u32) -> Self { - if versions_since >= SNAPSHOT_VERSIONS * 3 / 2 { + fn for_versions_since(config: &ServerConfig, versions_since: u32) -> Self { + if versions_since >= config.snapshot_versions * 3 / 2 { SnapshotUrgency::High - } else if versions_since >= SNAPSHOT_VERSIONS { + } else if versions_since >= config.snapshot_versions { SnapshotUrgency::Low } else { SnapshotUrgency::None @@ -121,6 +117,7 @@ impl SnapshotUrgency { /// Implementation of the AddVersion protocol transaction pub(crate) fn add_version<'a>( mut txn: Box, + config: &ServerConfig, client_key: ClientKey, client: Client, parent_version_id: VersionId, @@ -156,7 +153,7 @@ pub(crate) fn add_version<'a>( let time_urgency = match client.snapshot { None => SnapshotUrgency::High, Some(Snapshot { timestamp, .. }) => { - SnapshotUrgency::for_days((Utc::now() - timestamp).num_days()) + SnapshotUrgency::for_days(config, (Utc::now() - timestamp).num_days()) } }; @@ -164,7 +161,7 @@ pub(crate) fn add_version<'a>( let version_urgency = match client.snapshot { None => SnapshotUrgency::High, Some(Snapshot { versions_since, .. }) => { - SnapshotUrgency::for_versions_since(versions_since) + SnapshotUrgency::for_versions_since(config, versions_since) } }; @@ -177,6 +174,7 @@ pub(crate) fn add_version<'a>( /// Implementation of the AddSnapshot protocol transaction pub(crate) fn add_snapshot<'a>( mut txn: Box, + _config: &ServerConfig, client_key: ClientKey, client: Client, version_id: VersionId, @@ -261,6 +259,7 @@ pub(crate) fn add_snapshot<'a>( /// Implementation of the GetSnapshot protocol transaction pub(crate) fn get_snapshot<'a>( mut txn: Box, + _config: &ServerConfig, client_key: ClientKey, client: Client, ) -> anyhow::Result)>> { @@ -297,18 +296,29 @@ mod test { #[test] fn snapshot_urgency_for_days() { use SnapshotUrgency::*; - assert_eq!(SnapshotUrgency::for_days(0), None); - assert_eq!(SnapshotUrgency::for_days(SNAPSHOT_DAYS), Low); - assert_eq!(SnapshotUrgency::for_days(SNAPSHOT_DAYS * 2), High); + let config = ServerConfig::default(); + assert_eq!(SnapshotUrgency::for_days(&config, 0), None); + assert_eq!( + SnapshotUrgency::for_days(&config, config.snapshot_days), + Low + ); + assert_eq!( + SnapshotUrgency::for_days(&config, config.snapshot_days * 2), + High + ); } #[test] fn snapshot_urgency_for_versions_since() { use SnapshotUrgency::*; - assert_eq!(SnapshotUrgency::for_versions_since(0), None); - assert_eq!(SnapshotUrgency::for_versions_since(SNAPSHOT_VERSIONS), Low); + let config = ServerConfig::default(); + assert_eq!(SnapshotUrgency::for_versions_since(&config, 0), None); assert_eq!( - SnapshotUrgency::for_versions_since(SNAPSHOT_VERSIONS * 2), + SnapshotUrgency::for_versions_since(&config, config.snapshot_versions), + Low + ); + assert_eq!( + SnapshotUrgency::for_versions_since(&config, config.snapshot_versions * 2), High ); } @@ -325,7 +335,13 @@ mod test { // when no snapshot exists, the first version is NotFound let client = txn.get_client(client_key)?.unwrap(); assert_eq!( - get_child_version(txn, client_key, client, NIL_VERSION_ID)?, + get_child_version( + txn, + &ServerConfig::default(), + client_key, + client, + NIL_VERSION_ID + )?, GetVersionResult::NotFound ); Ok(()) @@ -353,7 +369,13 @@ mod test { // when a snapshot exists, the first version is GONE let client = txn.get_client(client_key)?.unwrap(); assert_eq!( - get_child_version(txn, client_key, client, NIL_VERSION_ID)?, + get_child_version( + txn, + &ServerConfig::default(), + client_key, + client, + NIL_VERSION_ID + )?, GetVersionResult::Gone ); Ok(()) @@ -374,7 +396,13 @@ mod test { let client = txn.get_client(client_key)?.unwrap(); assert_eq!( - get_child_version(txn, client_key, client, parent_version_id)?, + get_child_version( + txn, + &ServerConfig::default(), + client_key, + client, + parent_version_id + )?, GetVersionResult::NotFound ); Ok(()) @@ -395,7 +423,13 @@ mod test { let client = txn.get_client(client_key)?.unwrap(); assert_eq!( - get_child_version(txn, client_key, client, parent_version_id)?, + get_child_version( + txn, + &ServerConfig::default(), + client_key, + client, + parent_version_id + )?, GetVersionResult::Gone ); Ok(()) @@ -422,7 +456,13 @@ mod test { let client = txn.get_client(client_key)?.unwrap(); assert_eq!( - get_child_version(txn, client_key, client, parent_version_id)?, + get_child_version( + txn, + &ServerConfig::default(), + client_key, + client, + parent_version_id + )?, GetVersionResult::Success { version_id, parent_version_id, @@ -516,7 +556,15 @@ mod test { // try to add a child of a version other than the latest assert_eq!( - add_version(txn, client_key, client, versions[1], vec![3, 6, 9])?.0, + add_version( + txn, + &ServerConfig::default(), + client_key, + client, + versions[1], + vec![3, 6, 9] + )? + .0, AddVersionResult::ExpectedParentVersion(versions[2]) ); @@ -539,7 +587,14 @@ mod test { let mut txn = storage.txn()?; let client = txn.get_client(client_key)?.unwrap(); - let result = add_version(txn, client_key, client, versions[0], vec![3, 6, 9])?; + let result = add_version( + txn, + &ServerConfig::default(), + client_key, + client, + versions[0], + vec![3, 6, 9], + )?; av_success_check( &storage, @@ -563,7 +618,14 @@ mod test { let client = txn.get_client(client_key)?.unwrap(); let parent_version_id = Uuid::nil(); - let result = add_version(txn, client_key, client, parent_version_id, vec![3, 6, 9])?; + let result = add_version( + txn, + &ServerConfig::default(), + client_key, + client, + parent_version_id, + vec![3, 6, 9], + )?; av_success_check( &storage, @@ -586,7 +648,14 @@ mod test { let mut txn = storage.txn()?; let client = txn.get_client(client_key)?.unwrap(); - let result = add_version(txn, client_key, client, versions[0], vec![1, 2, 3])?; + let result = add_version( + txn, + &ServerConfig::default(), + client_key, + client, + versions[0], + vec![1, 2, 3], + )?; av_success_check( &storage, @@ -610,7 +679,14 @@ mod test { let mut txn = storage.txn()?; let client = txn.get_client(client_key)?.unwrap(); - let result = add_version(txn, client_key, client, versions[0], vec![1, 2, 3])?; + let result = add_version( + txn, + &ServerConfig::default(), + client_key, + client, + versions[0], + vec![1, 2, 3], + )?; av_success_check( &storage, @@ -634,7 +710,17 @@ mod test { let mut txn = storage.txn()?; let client = txn.get_client(client_key)?.unwrap(); - let result = add_version(txn, client_key, client, versions[49], vec![1, 2, 3])?; + let result = add_version( + txn, + &ServerConfig { + snapshot_versions: 30, + ..ServerConfig::default() + }, + client_key, + client, + versions[49], + vec![1, 2, 3], + )?; av_success_check( &storage, @@ -664,7 +750,14 @@ mod test { // add a snapshot for that version let client = txn.get_client(client_key)?.unwrap(); - add_snapshot(txn, client_key, client, version_id, vec![1, 2, 3])?; + add_snapshot( + txn, + &ServerConfig::default(), + client_key, + client, + version_id, + vec![1, 2, 3], + )?; // verify the snapshot let mut txn = storage.txn()?; @@ -697,7 +790,14 @@ mod test { // add a snapshot for version 1 let client = txn.get_client(client_key)?.unwrap(); - add_snapshot(txn, client_key, client, version_id_1, vec![1, 2, 3])?; + add_snapshot( + txn, + &ServerConfig::default(), + client_key, + client, + version_id_1, + vec![1, 2, 3], + )?; // verify the snapshot let mut txn = storage.txn()?; @@ -731,7 +831,14 @@ mod test { // add a snapshot for unknown version let client = txn.get_client(client_key)?.unwrap(); let version_id_unk = Uuid::new_v4(); - add_snapshot(txn, client_key, client, version_id_unk, vec![1, 2, 3])?; + add_snapshot( + txn, + &ServerConfig::default(), + client_key, + client, + version_id_unk, + vec![1, 2, 3], + )?; // verify the snapshot does not exist let mut txn = storage.txn()?; @@ -763,7 +870,14 @@ mod test { // add a snapshot for the earliest of those let client = txn.get_client(client_key)?.unwrap(); - add_snapshot(txn, client_key, client, version_ids[0], vec![1, 2, 3])?; + add_snapshot( + txn, + &ServerConfig::default(), + client_key, + client, + version_ids[0], + vec![1, 2, 3], + )?; // verify the snapshot does not exist let mut txn = storage.txn()?; @@ -805,7 +919,14 @@ mod test { // add a snapshot for the earliest of those let client = txn.get_client(client_key)?.unwrap(); - add_snapshot(txn, client_key, client, version_ids[0], vec![9, 9, 9])?; + add_snapshot( + txn, + &ServerConfig::default(), + client_key, + client, + version_ids[0], + vec![9, 9, 9], + )?; // verify the snapshot was not replaced let mut txn = storage.txn()?; @@ -834,7 +955,14 @@ mod test { // add a snapshot for the nil version let client = txn.get_client(client_key)?.unwrap(); - add_snapshot(txn, client_key, client, NIL_VERSION_ID, vec![9, 9, 9])?; + add_snapshot( + txn, + &ServerConfig::default(), + client_key, + client, + NIL_VERSION_ID, + vec![9, 9, 9], + )?; // verify the snapshot does not exist let mut txn = storage.txn()?; @@ -867,7 +995,7 @@ mod test { let client = txn.get_client(client_key)?.unwrap(); assert_eq!( - get_snapshot(txn, client_key, client)?, + get_snapshot(txn, &ServerConfig::default(), client_key, client)?, Some((snapshot_version_id, data.clone())) ); @@ -885,7 +1013,10 @@ mod test { txn.new_client(client_key, NIL_VERSION_ID)?; let client = txn.get_client(client_key)?.unwrap(); - assert_eq!(get_snapshot(txn, client_key, client)?, None); + assert_eq!( + get_snapshot(txn, &ServerConfig::default(), client_key, client)?, + None + ); Ok(()) } diff --git a/taskchampion/src/server/local.rs b/taskchampion/src/server/local.rs index 966b93bd6..ccd2c8d3c 100644 --- a/taskchampion/src/server/local.rs +++ b/taskchampion/src/server/local.rs @@ -1,5 +1,5 @@ use crate::server::{ - AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NO_VERSION_ID, + AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NIL_VERSION_ID, }; use crate::storage::sqlite::StoredUuid; use anyhow::Context; @@ -53,7 +53,7 @@ impl LocalServer { |r| r.get(0), ) .optional()?; - Ok(result.map(|x| x.0).unwrap_or(NO_VERSION_ID)) + Ok(result.map(|x| x.0).unwrap_or(NIL_VERSION_ID)) } fn set_latest_version_id(&mut self, version_id: VersionId) -> anyhow::Result<()> { @@ -122,7 +122,7 @@ impl Server for LocalServer { // check the parent_version_id for linearity let latest_version_id = self.get_latest_version_id()?; - if latest_version_id != NO_VERSION_ID && parent_version_id != latest_version_id { + if latest_version_id != NIL_VERSION_ID && parent_version_id != latest_version_id { return Ok(AddVersionResult::ExpectedParentVersion(latest_version_id)); } @@ -166,7 +166,7 @@ mod test { fn test_empty() -> anyhow::Result<()> { let tmp_dir = TempDir::new()?; let mut server = LocalServer::new(&tmp_dir.path())?; - let child_version = server.get_child_version(NO_VERSION_ID)?; + let child_version = server.get_child_version(NIL_VERSION_ID)?; assert_eq!(child_version, GetVersionResult::NoSuchVersion); Ok(()) } @@ -176,17 +176,17 @@ mod test { let tmp_dir = TempDir::new()?; let mut server = LocalServer::new(&tmp_dir.path())?; let history = b"1234".to_vec(); - match server.add_version(NO_VERSION_ID, history.clone())? { + match server.add_version(NIL_VERSION_ID, history.clone())? { AddVersionResult::ExpectedParentVersion(_) => { panic!("should have accepted the version") } AddVersionResult::Ok(version_id) => { - let new_version = server.get_child_version(NO_VERSION_ID)?; + let new_version = server.get_child_version(NIL_VERSION_ID)?; assert_eq!( new_version, GetVersionResult::Version { version_id, - parent_version_id: NO_VERSION_ID, + parent_version_id: NIL_VERSION_ID, history_segment: history, } ); diff --git a/taskchampion/src/server/test.rs b/taskchampion/src/server/test.rs index 798a54c1e..18a7e62bd 100644 --- a/taskchampion/src/server/test.rs +++ b/taskchampion/src/server/test.rs @@ -1,5 +1,5 @@ use crate::server::{ - AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NO_VERSION_ID, + AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NIL_VERSION_ID, }; use std::collections::HashMap; use uuid::Uuid; @@ -20,7 +20,7 @@ impl TestServer { /// A test server has no notion of clients, signatures, encryption, etc. pub fn new() -> TestServer { TestServer { - latest_version_id: NO_VERSION_ID, + latest_version_id: NIL_VERSION_ID, versions: HashMap::new(), } } @@ -38,7 +38,7 @@ impl Server for TestServer { // no signature validation // check the parent_version_id for linearity - if self.latest_version_id != NO_VERSION_ID { + if self.latest_version_id != NIL_VERSION_ID { if parent_version_id != self.latest_version_id { return Ok(AddVersionResult::ExpectedParentVersion( self.latest_version_id, diff --git a/taskchampion/src/server/types.rs b/taskchampion/src/server/types.rs index 466e286a5..5995dfed5 100644 --- a/taskchampion/src/server/types.rs +++ b/taskchampion/src/server/types.rs @@ -4,7 +4,7 @@ use uuid::Uuid; pub type VersionId = Uuid; /// The distinguished value for "no version" -pub const NO_VERSION_ID: VersionId = Uuid::nil(); +pub const NIL_VERSION_ID: VersionId = Uuid::nil(); /// A segment in the history of this task database, in the form of a sequence of operations. This /// data is pre-encoded, and from the protocol level appears as a sequence of bytes. diff --git a/taskchampion/src/storage/mod.rs b/taskchampion/src/storage/mod.rs index 18e64a9bb..0b3e3da32 100644 --- a/taskchampion/src/storage/mod.rs +++ b/taskchampion/src/storage/mod.rs @@ -36,7 +36,7 @@ fn taskmap_with(mut properties: Vec<(String, String)>) -> TaskMap { pub use crate::server::VersionId; /// The default for base_version. -pub(crate) const DEFAULT_BASE_VERSION: Uuid = crate::server::NO_VERSION_ID; +pub(crate) const DEFAULT_BASE_VERSION: Uuid = crate::server::NIL_VERSION_ID; /// A Storage transaction, in which storage operations are performed. ///