From b1ceaaf636cd21098ad77bc1d75ae88684252373 Mon Sep 17 00:00:00 2001 From: Draklaw Date: Sun, 5 Sep 2021 01:09:59 +0200 Subject: [PATCH] Implement RefStore for SimpleCas. --- cas-core/src/lib.rs | 2 +- cas-simple/src/cas.rs | 75 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/cas-core/src/lib.rs b/cas-core/src/lib.rs index 9d8bacd..5db84a5 100644 --- a/cas-core/src/lib.rs +++ b/cas-core/src/lib.rs @@ -39,6 +39,6 @@ pub use crate::{ object_type::{ObjectType}, object_metadata::{ObjectMetadata}, pipeline::{Pipeline, DefaultPipeline, Reader, Writer, ReadWrapper, WriteWrapper}, - cas::{Cas}, + cas::{Cas, RefStore}, }; diff --git a/cas-simple/src/cas.rs b/cas-simple/src/cas.rs index 9d3714d..52e5360 100644 --- a/cas-simple/src/cas.rs +++ b/cas-simple/src/cas.rs @@ -21,7 +21,7 @@ use digest::DynDigest; use toml::Value; use cas_core::{ Cas, DefaultPipeline, Error, ObjectId, ObjectMetadata, ObjectType, - Pipeline, Reader, ReadWrapper, Result, Writer, + Pipeline, Reader, ReadWrapper, RefStore, Result, Writer, }; use crate::utils::{ @@ -162,6 +162,57 @@ impl Cas for SimpleCas { } } +impl RefStore for SimpleCas { + fn get_ref>(&self, key: P) -> Result { + let path = ref_dir(&self.db_path).join(key.as_ref()); + if !path.exists() { + Error::err(format!("reference {} does not exists", key.as_ref().to_string_lossy())) + } + else if !path.is_file() { + Error::err(format!("reference {} is not a file", key.as_ref().to_string_lossy())) + } + else { + let file = std::fs::read(path).or_else(|err| + Error::err(format!("failed to read reference file for {}: {}", key.as_ref().to_string_lossy(), err)) + )?; + Ok( + ObjectId::from_str( + std::str::from_utf8(&file).or_else(|err| + Error::err(format!("invalid reference file at {}: {}", key.as_ref().to_string_lossy(), err)) + )? + )? + ) + } + } + + fn set_ref>(&mut self, key: P, value: &ObjectId) -> Result<()> { + let path = ref_dir(&self.db_path).join(key.as_ref()); + std::fs::create_dir_all(path.parent().ok_or_else(|| + Error::error(format!("reference file {} has no parent dir?", key.as_ref().to_string_lossy())) + )?).or_else(|err| + Error::err(format!("failed to create reference dir for {}: {}", key.as_ref().to_string_lossy(), err)) + )?; + std::fs::write(path, value.to_string()).or_else(|err| + Error::err(format!("failed to write reference {}: {}", key.as_ref().to_string_lossy(), err)) + ) + } + + fn remove_ref>(&mut self, key: P) -> Result<()> { + let path = ref_dir(&self.db_path).join(key.as_ref()); + if !path.exists() { + Error::err(format!("reference {} does not exists", key.as_ref().to_string_lossy())) + } + else if !path.is_file() { + Error::err(format!("reference {} is not a file", key.as_ref().to_string_lossy())) + } + else { + std::fs::remove_file(path).or_else(|err| + Error::err(format!("failed to remove reference file {}: {}", key.as_ref().to_string_lossy(), err)) + ) + } + } +} + pub struct ObjectIdIterator { root_dirs: Vec, @@ -560,4 +611,26 @@ mod tests { .collect::>>().unwrap(); assert_eq!(objects, oids); } + + #[test] + fn test_reference() { + let dir = tempfile::tempdir().expect("failed to create temp test dir"); + let cas_path = get_cas_path(dir.path()); + let config = get_config(); + + let mut cas = SimpleCas::create(cas_path.clone(), config) + .expect("failed to create SimpleCas object"); + + let oid_0 = ObjectId::from_str("f731f6bc6a6a73bad170e56452473ef6930b7a0ab33cc54be44221a89b49d786").unwrap(); + + assert!(cas.get_ref("foo/bar").is_err()); + assert!(cas.remove_ref("foo/bar").is_err()); + + cas.set_ref("foo/bar", &oid_0).unwrap(); + assert_eq!(cas.get_ref("foo/bar").unwrap(), oid_0); + + cas.remove_ref("foo/bar").unwrap(); + + assert!(cas.get_ref("foo/bar").is_err()); + } }