Skip to content

Commit 5d18008

Browse files
committed
feat(foundationdb): initial commit for Directory.Move
1 parent 17129a6 commit 5d18008

File tree

4 files changed

+106
-12
lines changed

4 files changed

+106
-12
lines changed

foundationdb/src/directory/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub enum DirectoryError {
2222
DirAlreadyExists,
2323
/// missing path.
2424
DirNotExists,
25+
/// Parent does not exists
26+
ParentDirDoesNotExists,
2527
/// the layer is incompatible.
2628
IncompatibleLayer,
2729
Message(String),

foundationdb/src/directory/mod.rs

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,47 @@ impl DirectoryLayer {
167167
/// parent directory of newPath does not exist.
168168
pub async fn move_to(
169169
&self,
170-
_trx: &Transaction,
171-
_old_path: Vec<String>,
172-
_new_path: Vec<String>,
170+
trx: &Transaction,
171+
old_path: Vec<String>,
172+
new_path: Vec<String>,
173173
) -> Result<bool, DirectoryError> {
174-
unimplemented!("move is not supported yet")
174+
self.check_version(trx, false).await?;
175+
176+
let mut old_nodes = self.find_nodes(&trx, old_path.to_owned()).await?;
177+
let last_node_from_old_path = match old_nodes.last_mut() {
178+
None => return Err(DirectoryError::Message(String::from("empty path"))),
179+
Some(node) => node,
180+
};
181+
let content_subspace = last_node_from_old_path
182+
.content_subspace
183+
.as_ref()
184+
.ok_or(DirectoryError::DirNotExists)?;
185+
186+
let mut new_nodes = self.find_nodes(&trx, new_path.to_owned()).await?;
187+
// assert that parent of the new node exists
188+
if new_nodes.get(new_nodes.len() - 2).is_none() {
189+
return Err(DirectoryError::ParentDirDoesNotExists);
190+
}
191+
192+
let last_node_from_new_path = match new_nodes.last_mut() {
193+
None => return Err(DirectoryError::Message(String::from("empty path"))),
194+
Some(node) => {
195+
if node.content_subspace.is_some() {
196+
return Err(DirectoryError::DirNotExists);
197+
}
198+
node
199+
}
200+
};
201+
202+
last_node_from_new_path
203+
.persist_content_subspace(&trx, content_subspace.to_owned())
204+
.await?;
205+
206+
last_node_from_old_path
207+
.delete_content_subspace(&trx)
208+
.await?;
209+
210+
Ok(true)
175211
}
176212

177213
/// Exists returns true if the directory at path (relative to this Directory)
@@ -258,7 +294,7 @@ impl DirectoryLayer {
258294
// creating subspace
259295
let allocator = self.allocator.allocate(trx).await?;
260296
parent_subspace = node
261-
.create_subspace(&trx, allocator, &parent_subspace)
297+
.create_and_write_content_subspace(&trx, allocator, &parent_subspace)
262298
.await?;
263299
}
264300
Some(subspace) => parent_subspace = subspace.clone(),

foundationdb/src/directory/node.rs

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,38 @@ impl Node {
3838

3939
/// This will use the generated id and:
4040
///
41-
/// * persist the node in the directory subspace dedicated to nodes
41+
/// * persist the node in the directory subspace
4242
/// * create the content_subspace and returns it
43-
pub(crate) async fn create_subspace(
43+
pub(crate) async fn create_and_write_content_subspace(
4444
&mut self,
4545
trx: &Transaction,
4646
generated_id: i64,
4747
parent_subspace: &Subspace,
4848
) -> Result<Subspace, DirectoryError> {
49-
let new_subspace = parent_subspace.subspace(&generated_id);
49+
let subspace = parent_subspace.subspace(&generated_id);
50+
self.persist_content_subspace(&trx, subspace).await
51+
}
5052

53+
/// `persist_content_subspace` will save the provided subspace as the `content_subspace`
54+
pub(crate) async fn persist_content_subspace(
55+
&mut self,
56+
trx: &Transaction,
57+
subspace: Subspace,
58+
) -> Result<Subspace, DirectoryError> {
5159
let key = self.node_subspace.to_owned();
52-
trx.set(key.bytes(), new_subspace.bytes());
53-
54-
self.content_subspace = Some(new_subspace.to_owned());
60+
trx.set(key.bytes(), subspace.bytes());
61+
self.content_subspace = Some(subspace.to_owned());
62+
Ok(subspace)
63+
}
5564

56-
Ok(new_subspace)
65+
/// delete subspace from the node_subspace
66+
pub(crate) async fn delete_content_subspace(
67+
&mut self,
68+
trx: &Transaction,
69+
) -> Result<(), DirectoryError> {
70+
let key = self.node_subspace.to_owned();
71+
trx.clear(key.bytes());
72+
Ok(())
5773
}
5874

5975
/// retrieve the layer used for this node

foundationdb/tests/directory.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,46 @@ fn test_directory() {
4949
.expect("failed to run");
5050

5151
futures::executor::block_on(test_bad_layer(&db)).expect("failed to run");
52+
53+
futures::executor::block_on(test_move_to(
54+
&db,
55+
&directory,
56+
vec![String::from("d"), String::from("e")],
57+
vec![String::from("a"), String::from("g")],
58+
))
59+
.expect("failed to run");
60+
}
61+
62+
async fn test_move_to(
63+
db: &Database,
64+
directory: &DirectoryLayer,
65+
old_paths: Vec<String>,
66+
new_paths: Vec<String>,
67+
) -> Result<(), DirectoryError> {
68+
let trx = db.create_trx()?;
69+
let create_output = directory.create_or_open(&trx, old_paths.to_owned()).await?;
70+
71+
trx.commit().await.expect("could not commit");
72+
let trx = db.create_trx()?;
73+
74+
let move_output = directory
75+
.move_to(&trx, old_paths.to_owned(), new_paths.to_owned())
76+
.await?;
77+
assert!(move_output);
78+
79+
trx.commit().await.expect("could not commit");
80+
let trx = db.create_trx()?;
81+
82+
let open_output = directory.open(&trx, new_paths).await?;
83+
assert_eq!(create_output.bytes(), open_output.bytes());
84+
85+
trx.commit().await.expect("could not commit");
86+
let trx = db.create_trx()?;
87+
88+
let open_old_path = directory.open(&trx, old_paths).await;
89+
assert!(open_old_path.is_err());
90+
91+
Ok(())
5292
}
5393

5494
async fn test_create_then_open_async(

0 commit comments

Comments
 (0)