diff --git a/foundationdb/src/directory/mod.rs b/foundationdb/src/directory/mod.rs index f728bea7..7cc782fb 100644 --- a/foundationdb/src/directory/mod.rs +++ b/foundationdb/src/directory/mod.rs @@ -153,10 +153,9 @@ impl DirectoryLayer { paths: Vec, ) -> Result { let nodes = self.find_nodes(trx, paths.to_owned()).await?; - match nodes.last() { - None => Err(DirectoryError::DirNotExists), - Some(_) => Ok(true), + None => Ok(false), + Some(node) => Ok(node.content_subspace.is_some()), } } @@ -220,20 +219,35 @@ impl DirectoryLayer { .await?; last_node_from_old_path - .delete_content_subspace(&trx) + .delete_content_from_node_subspace(&trx) .await?; Ok(true) } - /// Exists returns true if the directory at path (relative to this Directory) - /// exists, and false otherwise. + /// `Remove` the subdirectory of this Directory located at `path` and all of its subdirectories, + /// as well as all of their contents. pub async fn remove( &self, - _trx: &Transaction, - _path: Vec, + trx: &Transaction, + path: Vec, ) -> Result { - unimplemented!("move is not supported yet") + self.check_version(trx, false).await?; + if path.is_empty() { + return Err(DirectoryError::NoPathProvided); + } + + let nodes = self.find_nodes(&trx, path.to_owned()).await?; + + match nodes.last() { + None => Ok(false), + Some(node) => { + println!("found a node to delete: {:?}", node); + node.delete_content_from_node_subspace(&trx).await?; + node.delete_content_from_content_subspace(&trx).await?; + Ok(true) + } + } } /// List returns the names of the immediate subdirectories of the default root directory as a slice of strings. @@ -409,6 +423,7 @@ impl DirectoryLayer { node.retrieve_layer(&trx).await?; if let Some(fdb_slice) = trx.get(node.node_subspace.bytes(), false).await? { + println!("found something in {:?}", node.node_subspace.to_owned()); node.content_subspace = Some(Subspace::from_bytes(&*fdb_slice)); } diff --git a/foundationdb/src/directory/node.rs b/foundationdb/src/directory/node.rs index 2f480cb0..e574f1b5 100644 --- a/foundationdb/src/directory/node.rs +++ b/foundationdb/src/directory/node.rs @@ -63,15 +63,36 @@ impl Node { } /// delete subspace from the node_subspace - pub(crate) async fn delete_content_subspace( - &mut self, + pub(crate) async fn delete_content_from_node_subspace( + &self, trx: &Transaction, ) -> Result<(), DirectoryError> { - let key = self.node_subspace.to_owned(); - trx.clear(key.bytes()); + println!( + "deleting node_subspace {:?}", + &self.node_subspace.to_owned() + ); + trx.clear(&self.node_subspace.bytes()); + //trx.clear_subspace_range(&self.node_subspace.to_owned()); Ok(()) } + pub(crate) async fn delete_content_from_content_subspace( + &self, + trx: &Transaction, + ) -> Result<(), DirectoryError> { + match self.content_subspace.to_owned() { + None => Ok(()), + Some(subspace) => { + println!( + "deleting content_subspace {:?}", + &self.content_subspace.to_owned() + ); + trx.clear_subspace_range(&subspace); + Ok(()) + } + } + } + /// retrieve the layer used for this node pub(crate) async fn retrieve_layer(&mut self, trx: &Transaction) -> Result<(), FdbError> { if self.layer == None { diff --git a/foundationdb/tests/directory.rs b/foundationdb/tests/directory.rs index 46ca8dba..304896ae 100644 --- a/foundationdb/tests/directory.rs +++ b/foundationdb/tests/directory.rs @@ -12,7 +12,7 @@ use foundationdb::*; mod common; #[test] -fn test_directory() { +fn test_create_or_open_directory() { let _guard = unsafe { foundationdb::boot() }; let db = futures::executor::block_on(common::database()).expect("cannot open fdb"); @@ -49,12 +49,63 @@ fn test_directory() { .expect("failed to run"); futures::executor::block_on(test_bad_layer(&db)).expect("failed to run"); +} + +#[test] +fn test_delete() { + let _guard = unsafe { foundationdb::boot() }; + let db = futures::executor::block_on(common::database()).expect("cannot open fdb"); + + eprintln!("clearing all keys"); + let trx = db.create_trx().expect("cannot create txn"); + trx.clear_range(b"", b"\xff"); + futures::executor::block_on(trx.commit()).expect("could not clear keys"); + + eprintln!("creating directories"); + let directory = DirectoryLayer::default(); + + // test deletions, first we need to create it + futures::executor::block_on(test_create_or_open_async( + &db, + &directory, + vec![String::from("deletion")], + )) + .expect("failed to run"); + // then delete it + futures::executor::block_on(test_delete_async( + &db, + &directory, + vec![String::from("deletion")], + )) + .expect("failed to run"); + + futures::executor::block_on(test_create_then_delete( + &db, + &directory, + vec![String::from("n0")], + 1, + )) + .expect("failed to run"); +} + +#[test] +fn test_move() { + let _guard = unsafe { foundationdb::boot() }; + let db = futures::executor::block_on(common::database()).expect("cannot open fdb"); + + eprintln!("clearing all keys"); + let trx = db.create_trx().expect("cannot create txn"); + trx.clear_range(b"", b"\xff"); + futures::executor::block_on(trx.commit()).expect("could not clear keys"); + + eprintln!("creating directories"); + let directory = DirectoryLayer::default(); futures::executor::block_on(test_create_then_move_to( &db, &directory, vec![String::from("d"), String::from("e")], - vec![String::from("a"), String::from("g")], + vec![String::from("a")], )) .expect("failed to run"); @@ -130,6 +181,68 @@ fn test_directory() { } } +async fn test_create_then_delete( + db: &Database, + directory: &DirectoryLayer, + paths: Vec, + sub_path_to_create: usize, +) -> Result<(), DirectoryError> { + // creating directory + let trx = db.create_trx()?; + directory.create_or_open(&trx, paths.to_owned()).await?; + + trx.commit().await.expect("could not commit"); + + let trx = db.create_trx()?; + let children = directory.list(&trx, paths.to_owned()).await?; + assert!(children.is_empty()); + trx.commit().await.expect("could not commit"); + + for i in 0..sub_path_to_create { + let trx = db.create_trx()?; + let mut sub_path = paths.clone(); + let path_name = format!("{}", i); + sub_path.push(path_name.to_owned()); + + // creating subfolders + eprintln!("creating {:?}", sub_path.to_owned()); + directory.create(&trx, sub_path.to_owned()).await; + trx.commit().await.expect("could not commit"); + + // checking it does exists + let trx = db.create_trx()?; + eprintln!("trying to get {:?}", sub_path.to_owned()); + let exists = directory.exists(&trx, sub_path.to_owned()).await?; + assert!(exists, "path {:?} should exists", sub_path.to_owned()); + trx.commit().await.expect("could not commit"); + + let trx = db.create_trx()?; + let children = directory.list(&trx, paths.to_owned()).await?; + assert!(children.contains(&path_name.to_owned())); + trx.commit().await.expect("could not commit"); + + // trying to delete it + let trx = db.create_trx()?; + eprintln!("deleting {:?}", sub_path.to_owned()); + let delete_result = directory.remove(&trx, sub_path.to_owned()).await?; + assert!(delete_result); + trx.commit().await.expect("could not commit"); + + // checking it does not exists + let trx = db.create_trx()?; + eprintln!("trying to get {:?}", sub_path.to_owned()); + let exists = directory.exists(&trx, sub_path.to_owned()).await?; + assert!(!exists, "path {:?} should not exists", sub_path.to_owned()); + trx.commit().await.expect("could not commit"); + } + let trx = db.create_trx()?; + let children = directory.list(&trx, paths.to_owned()).await?; + assert!(children.is_empty(), "children is not empty: {:?}", children); + trx.commit().await.expect("could not commit"); + + Ok(()) +} + async fn test_create_then_move_to( db: &Database, directory: &DirectoryLayer, @@ -231,6 +344,30 @@ async fn test_create_or_open_async( Ok(()) } +async fn test_delete_async( + db: &Database, + directory: &DirectoryLayer, + paths: Vec, +) -> FdbResult<()> { + let trx = db.create_trx()?; + let _ = directory + .create_or_open(&trx, paths.to_owned()) + .await + .expect("cannot create"); + eprintln!("removing {:?}", paths.to_owned()); + let delete_output = directory.remove(&trx, paths.to_owned()).await; + assert!(delete_output.is_ok()); + trx.commit().await.expect("could not commit"); + + // checking it does not exists + let trx = db.create_trx()?; + let exists = directory.exists(&trx, paths.to_owned()).await.expect("bla"); + assert!(!exists, "path {:?} should not exists", paths.to_owned()); + trx.commit().await.expect("could not commit"); + + Ok(()) +} + /// testing that we throwing Err(DirectoryError::IncompatibleLayer) async fn test_bad_layer(db: &Database) -> Result<(), DirectoryError> { let directory = DirectoryLayer {