Skip to content

Commit 8efec0c

Browse files
committed
feat(directory,bindingtester): implement move and move_to
1 parent 25c986c commit 8efec0c

File tree

7 files changed

+221
-28
lines changed

7 files changed

+221
-28
lines changed

foundationdb-bindingtester/src/main.rs

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
#[macro_use]
22
extern crate log;
33

4-
// TODO: Fix 1330929912
5-
64
use foundationdb as fdb;
75
use foundationdb_sys as fdb_sys;
86

@@ -1899,13 +1897,83 @@ impl StackMachine {
18991897
//
19001898
// Pop 2 tuples off the stack as [old_path, new_path]. Call move with the
19011899
// specified old_path and new_path. Append the result onto the directory list.
1902-
DirectoryMove => unimplemented!(),
1900+
DirectoryMove => {
1901+
debug!("Move stack: {:?}", self.stack);
1902+
1903+
let paths = self.pop_tuple(2).await;
1904+
1905+
let directory = self
1906+
.get_current_directory()
1907+
.expect("could not find a directory");
1908+
1909+
let txn = match trx {
1910+
TransactionState::Transaction(ref t) => t,
1911+
_ => {
1912+
panic!("could not find an active transaction");
1913+
}
1914+
};
1915+
1916+
match directory
1917+
.move_to(
1918+
txn,
1919+
(*paths.get(0).unwrap().to_vec()).to_owned(),
1920+
(*paths.get(1).unwrap().to_vec()).to_owned(),
1921+
)
1922+
.await
1923+
{
1924+
Ok(s) => {
1925+
debug!(
1926+
"pushing moved directory {:?} at index {}",
1927+
&s,
1928+
self.directory_stack.len()
1929+
);
1930+
self.directory_stack
1931+
.push(DirectoryStackItem::DirectorySubspace(s));
1932+
}
1933+
Err(e) => {
1934+
self.push_directory_err(&instr.code, number, e);
1935+
}
1936+
};
1937+
}
19031938

19041939
// Use the current directory for this operation.
19051940
//
19061941
// Pop 1 tuple off the stack as [new_absolute_path]. Call moveTo with the
19071942
// specified new_absolute_path. Append the result onto the directory list.
1908-
DirectoryMoveTo => unimplemented!(),
1943+
DirectoryMoveTo => {
1944+
debug!("MoveTo stack: {:?}", self.stack);
1945+
1946+
let paths = self.pop_tuple(1).await;
1947+
1948+
let directory = self
1949+
.get_current_directory()
1950+
.expect("could not find a directory");
1951+
1952+
let txn = match trx {
1953+
TransactionState::Transaction(ref t) => t,
1954+
_ => {
1955+
panic!("could not find an active transaction");
1956+
}
1957+
};
1958+
1959+
match directory
1960+
.move_directory(txn, (*paths.get(0).unwrap().to_vec()).to_owned())
1961+
.await
1962+
{
1963+
Ok(s) => {
1964+
debug!(
1965+
"pushing moved directory {:?} at index {}",
1966+
&s,
1967+
self.directory_stack.len()
1968+
);
1969+
self.directory_stack
1970+
.push(DirectoryStackItem::DirectorySubspace(s));
1971+
}
1972+
Err(e) => {
1973+
self.push_directory_err(&instr.code, number, e);
1974+
}
1975+
};
1976+
}
19091977

19101978
// Use the current directory for this operation.
19111979
//

foundationdb/src/directory/directory_layer.rs

Lines changed: 71 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ use crate::tuple::hca::HighContentionAllocator;
55
use crate::tuple::{Subspace, TuplePack, TupleUnpack};
66
use crate::{FdbResult, Transaction};
77

8-
use crate::directory::Directory;
98
use crate::directory::DirectorySubspace;
9+
use crate::directory::{compare_slice_string, Directory};
1010
use async_trait::async_trait;
1111
use byteorder::{LittleEndian, WriteBytesExt};
12+
use std::cmp::Ordering;
13+
1214

1315
// TODO: useful?
1416
const _LAYER_VERSION: (u8, u8, u8) = (1, 0, 0);
@@ -17,7 +19,7 @@ const MINOR_VERSION: u32 = 0;
1719
const PATCH_VERSION: u32 = 0;
1820
const DEFAULT_NODE_PREFIX: &[u8] = b"\xFE";
1921
const DEFAULT_HCA_PREFIX: &[u8] = b"hca";
20-
const DEFAULT_SUB_DIRS: i64 = 0;
22+
pub(crate) const DEFAULT_SUB_DIRS: i64 = 0;
2123

2224
/// An implementation of FoundationDB's directory that is compatible with other bindings.
2325
///
@@ -144,7 +146,7 @@ impl Directory for DirectoryLayer {
144146
/// `exists` returns true if the directory at path (relative to the default root directory) exists, and false otherwise.
145147
async fn exists(&self, trx: &Transaction, path: Vec<String>) -> Result<bool, DirectoryError> {
146148
match dbg!(
147-
self.find_or_create_node(trx, path.to_owned(), false, None, None)
149+
self.find_or_create_node(trx, path.to_owned(), false, None)
148150
.await
149151
) {
150152
Ok(_node) => Ok(true),
@@ -155,25 +157,81 @@ impl Directory for DirectoryLayer {
155157
}
156158
}
157159

160+
async fn move_directory(
161+
&self,
162+
_trx: &Transaction,
163+
_new_path: Vec<String>,
164+
) -> Result<DirectorySubspace, DirectoryError> {
165+
Err(DirectoryError::CannotMoveRootDirectory)
166+
}
167+
158168
/// `move_to` the directory from old_path to new_path(both relative to this
159169
/// Directory), and returns the directory (at its new location) and its
160170
/// contents as a Subspace. Move will return an error if a directory
161171
/// does not exist at oldPath, a directory already exists at newPath, or the
162172
/// parent directory of newPath does not exist.
163173
async fn move_to(
164174
&self,
165-
_trx: &Transaction,
166-
_old_path: Vec<String>,
167-
_new_path: Vec<String>,
168-
) -> Result<Subspace, DirectoryError> {
169-
unimplemented!()
175+
trx: &Transaction,
176+
old_path: Vec<String>,
177+
new_path: Vec<String>,
178+
) -> Result<DirectorySubspace, DirectoryError> {
179+
self.check_version(trx, false).await?;
180+
181+
let mut slice_end = old_path.len();
182+
if slice_end > new_path.len() {
183+
slice_end = new_path.len();
184+
}
185+
186+
if compare_slice_string(&old_path[..], &new_path[..slice_end]) == Ordering::Equal
187+
|| old_path.is_empty()
188+
|| new_path.is_empty()
189+
{
190+
return Err(DirectoryError::CannotMoveBetweenSubdirectory);
191+
}
192+
193+
let old_node = self
194+
.find_or_create_node(&trx, old_path.to_owned(), false, None)
195+
.await?;
196+
197+
if self.exists(&trx, new_path.to_owned()).await? {
198+
return Err(DirectoryError::DirAlreadyExists);
199+
}
200+
201+
let new_node_parent = self
202+
.find_or_create_node(
203+
&trx,
204+
Vec::from(&new_path.to_owned()[..new_path.len() - 1]),
205+
true,
206+
None,
207+
)
208+
.await?;
209+
210+
let content_subspace = old_node.content_subspace.clone().unwrap();
211+
212+
let prefix = self.node_subspace.unpack(content_subspace.bytes())?;
213+
214+
if new_node_parent.is_new_node {
215+
return Err(DirectoryError::CannotMoveMissingParent);
216+
}
217+
218+
// create new node
219+
self.find_or_create_node(&trx, new_path.to_owned(), true, Some(prefix))
220+
.await?;
221+
222+
let child_name = old_path.last().unwrap().to_owned();
223+
new_node_parent.remove_child(&trx, child_name).await;
224+
225+
return self
226+
.contents_of_node(old_node.content_subspace, new_path, old_node.layer)
227+
.await;
170228
}
171229

172230
/// `remove` the subdirectory of this Directory located at `path` and all of its subdirectories,
173231
/// as well as all of their contents.
174232
async fn remove(&self, trx: &Transaction, path: Vec<String>) -> Result<bool, DirectoryError> {
175233
let node = self
176-
.find_or_create_node(trx, path.to_owned(), false, None, None)
234+
.find_or_create_node(trx, path.to_owned(), false, None)
177235
.await?;
178236
node.remove_all(trx).await?;
179237
Ok(true)
@@ -187,7 +245,7 @@ impl Directory for DirectoryLayer {
187245
path: Vec<String>,
188246
) -> Result<Vec<String>, DirectoryError> {
189247
let node = self
190-
.find_or_create_node(trx, path.to_owned(), false, None, None)
248+
.find_or_create_node(trx, path.to_owned(), false, None)
191249
.await?;
192250
node.list(&trx).await
193251
}
@@ -220,13 +278,7 @@ impl DirectoryLayer {
220278
}
221279

222280
match self
223-
.find_or_create_node(
224-
&trx,
225-
path.to_owned(),
226-
allow_create,
227-
prefix.to_owned(),
228-
layer.to_owned(),
229-
)
281+
.find_or_create_node(&trx, path.to_owned(), allow_create, prefix.to_owned())
230282
.await
231283
{
232284
Ok(node) => {
@@ -358,6 +410,7 @@ impl DirectoryLayer {
358410
node_subspace: self.get_root_node_subspace(),
359411
content_subspace: None,
360412
parent_node_reference: self.get_root_node_subspace(),
413+
is_new_node: false,
361414
};
362415
let mut node_path = vec![];
363416

@@ -407,6 +460,7 @@ impl DirectoryLayer {
407460
node_subspace: self.node_subspace.subspace(&prefix.as_slice()),
408461
content_subspace: Some(Subspace::from_bytes(&prefix.as_slice())),
409462
parent_node_reference: key.to_owned(),
463+
is_new_node: new_node,
410464
};
411465

412466
node.retrieve_layer(&trx).await?;

foundationdb/src/directory/directory_subspace.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
use crate::directory::directory_layer::DirectoryLayer;
22
use crate::directory::error::DirectoryError;
3-
use crate::directory::Directory;
3+
use crate::directory::{compare_slice_string, Directory};
44
use crate::tuple::{PackResult, Subspace, TuplePack, TupleUnpack};
55
use crate::Transaction;
66
use async_trait::async_trait;
77

8+
use std::cmp::Ordering;
9+
810
/// `DirectorySubspace` is a directory that can act as a subspace
911
#[derive(Clone, Debug)]
1012
pub struct DirectorySubspace {
@@ -95,12 +97,39 @@ impl Directory for DirectorySubspace {
9597
.await
9698
}
9799

100+
async fn move_directory(
101+
&self,
102+
trx: &Transaction,
103+
new_path: Vec<String>,
104+
) -> Result<DirectorySubspace, DirectoryError> {
105+
// equivalent of moveTo in Go
106+
// return moveTo(t, d.dl, d.path, newAbsolutePath)
107+
let partition_length = self.path.len();
108+
109+
if new_path.is_empty() {
110+
return Err(DirectoryError::CannotMoveBetweenPartition);
111+
}
112+
113+
dbg!(&new_path, &self.path);
114+
115+
if compare_slice_string(&new_path[..partition_length], &self.path) != Ordering::Equal {
116+
Err(DirectoryError::CannotMoveBetweenPartition)
117+
} else {
118+
self.move_to(
119+
trx,
120+
Vec::from(&self.path[partition_length..]),
121+
Vec::from(&new_path[partition_length..]),
122+
)
123+
.await
124+
}
125+
}
126+
98127
async fn move_to(
99128
&self,
100129
trx: &Transaction,
101130
old_path: Vec<String>,
102131
new_path: Vec<String>,
103-
) -> Result<Subspace, DirectoryError> {
132+
) -> Result<DirectorySubspace, DirectoryError> {
104133
self.move_to(
105134
trx,
106135
self.directory

foundationdb/src/directory/error.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,13 @@ pub enum DirectoryError {
3636
PrefixNotAllowed,
3737
/// cannot specify a prefix in a partition.
3838
CannotPrefixInPartition,
39+
/// the root directory cannot be moved
40+
CannotMoveRootDirectory,
41+
CannotMoveBetweenPartition,
42+
/// the destination directory cannot be a subdirectory of the source directory
43+
CannotMoveBetweenSubdirectory,
44+
/// the parent of the destination directory does not exist. Create it first
45+
CannotMoveMissingParent,
3946
IoError(io::Error),
4047
FdbError(error::FdbError),
4148
HcaError(HcaError),

foundationdb/src/directory/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,12 @@ mod node;
1919
use crate::directory::error::DirectoryError;
2020

2121

22-
23-
use crate::tuple::{PackResult, Subspace, TuplePack, TupleUnpack};
24-
use crate::{Transaction};
22+
use crate::Transaction;
2523

2624
use crate::directory::directory_subspace::DirectorySubspace;
2725
use async_trait::async_trait;
28-
26+
use core::cmp;
27+
use std::cmp::Ordering;
2928

3029
#[async_trait]
3130
pub trait Directory {
@@ -50,16 +49,33 @@ pub trait Directory {
5049
layer: Option<Vec<u8>>,
5150
) -> Result<DirectorySubspace, DirectoryError>;
5251
async fn exists(&self, trx: &Transaction, path: Vec<String>) -> Result<bool, DirectoryError>;
52+
async fn move_directory(
53+
&self,
54+
trx: &Transaction,
55+
new_path: Vec<String>,
56+
) -> Result<DirectorySubspace, DirectoryError>;
5357
async fn move_to(
5458
&self,
5559
trx: &Transaction,
5660
old_path: Vec<String>,
5761
new_path: Vec<String>,
58-
) -> Result<Subspace, DirectoryError>;
62+
) -> Result<DirectorySubspace, DirectoryError>;
5963
async fn remove(&self, trx: &Transaction, path: Vec<String>) -> Result<bool, DirectoryError>;
6064
async fn list(
6165
&self,
6266
trx: &Transaction,
6367
path: Vec<String>,
6468
) -> Result<Vec<String>, DirectoryError>;
6569
}
70+
71+
pub fn compare_slice_string(a: &[String], b: &[String]) -> cmp::Ordering {
72+
for (ai, bi) in a.iter().zip(b.iter()) {
73+
match ai.cmp(&bi) {
74+
Ordering::Equal => continue,
75+
ord => return ord,
76+
}
77+
}
78+
79+
/* if every single element was equal, compare length */
80+
a.len().cmp(&b.len())
81+
}

0 commit comments

Comments
 (0)