Skip to content

Commit 9281bd3

Browse files
committed
fix(foundationdb): layer verification
1 parent 3c596fe commit 9281bd3

File tree

5 files changed

+193
-31
lines changed

5 files changed

+193
-31
lines changed

foundationdb/src/directory/directory_layer.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::tuple::{Subspace, TuplePack};
66
use crate::{FdbResult, Transaction};
77

88
use crate::directory::DirectorySubspace;
9-
use crate::directory::{compare_slice_string, Directory};
9+
use crate::directory::{compare_slice, Directory};
1010
use async_trait::async_trait;
1111
use byteorder::{LittleEndian, WriteBytesExt};
1212
use std::cmp::Ordering;
@@ -120,7 +120,7 @@ impl Directory for DirectoryLayer {
120120
}
121121

122122
match self
123-
.find_or_create_node(trx, path.to_owned(), false, None)
123+
.find_or_create_node(trx, path.to_owned(), false, None, None)
124124
.await
125125
{
126126
Ok(_node) => Ok(true),
@@ -157,15 +157,15 @@ impl Directory for DirectoryLayer {
157157
slice_end = new_path.len();
158158
}
159159

160-
if compare_slice_string(&old_path[..], &new_path[..slice_end]) == Ordering::Equal
160+
if compare_slice(&old_path[..], &new_path[..slice_end]) == Ordering::Equal
161161
|| old_path.is_empty()
162162
|| new_path.is_empty()
163163
{
164164
return Err(DirectoryError::CannotMoveBetweenSubdirectory);
165165
}
166166

167167
let old_node = self
168-
.find_or_create_node(&trx, old_path.to_owned(), false, None)
168+
.find_or_create_node(&trx, old_path.to_owned(), false, None, None)
169169
.await?;
170170

171171
if self.exists(&trx, new_path.to_owned()).await? {
@@ -178,6 +178,7 @@ impl Directory for DirectoryLayer {
178178
Vec::from(&new_path.to_owned()[..new_path.len() - 1]),
179179
true,
180180
None,
181+
None,
181182
)
182183
.await?;
183184

@@ -190,7 +191,7 @@ impl Directory for DirectoryLayer {
190191
}
191192

192193
// create new node
193-
self.find_or_create_node(&trx, new_path.to_owned(), true, Some(prefix))
194+
self.find_or_create_node(&trx, new_path.to_owned(), true, Some(prefix), None)
194195
.await?;
195196

196197
let child_name = old_path.last().unwrap().to_owned();
@@ -205,7 +206,7 @@ impl Directory for DirectoryLayer {
205206
/// as well as all of their contents.
206207
async fn remove(&self, trx: &Transaction, path: Vec<String>) -> Result<bool, DirectoryError> {
207208
let node = self
208-
.find_or_create_node(trx, path.to_owned(), false, None)
209+
.find_or_create_node(trx, path.to_owned(), false, None, None)
209210
.await?;
210211
node.remove_all(trx).await?;
211212
Ok(true)
@@ -219,7 +220,7 @@ impl Directory for DirectoryLayer {
219220
path: Vec<String>,
220221
) -> Result<Vec<String>, DirectoryError> {
221222
let node = self
222-
.find_or_create_node(trx, path.to_owned(), false, None)
223+
.find_or_create_node(trx, path.to_owned(), false, None, None)
223224
.await?;
224225
node.list(&trx).await
225226
}
@@ -259,7 +260,13 @@ impl DirectoryLayer {
259260
}
260261

261262
match self
262-
.find_or_create_node(&trx, path.to_owned(), allow_create, prefix.to_owned())
263+
.find_or_create_node(
264+
&trx,
265+
path.to_owned(),
266+
allow_create,
267+
prefix.to_owned(),
268+
layer.to_owned(),
269+
)
263270
.await
264271
{
265272
Ok(node) => {
@@ -384,6 +391,7 @@ impl DirectoryLayer {
384391
path: Vec<String>,
385392
allow_creation: bool,
386393
prefix: Option<Vec<u8>>,
394+
layer: Option<Vec<u8>>,
387395
) -> Result<Node, DirectoryError> {
388396
let mut node = Node {
389397
layer: None,
@@ -449,6 +457,10 @@ impl DirectoryLayer {
449457
if new_node {
450458
trx.set(key.bytes(), prefix.as_slice());
451459
}
460+
461+
if i == last_path_index && layer.is_some() && new_node {
462+
node.store_layer(&trx, layer.to_owned().unwrap().to_owned())?;
463+
}
452464
}
453465

454466
Ok(node)

foundationdb/src/directory/directory_subspace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::directory::directory_layer::DirectoryLayer;
22
use crate::directory::error::DirectoryError;
3-
use crate::directory::{compare_slice_string, Directory};
3+
use crate::directory::{compare_slice, Directory};
44
use crate::tuple::{PackResult, Subspace, TuplePack, TupleUnpack};
55
use crate::Transaction;
66
use async_trait::async_trait;
@@ -112,7 +112,7 @@ impl Directory for DirectorySubspace {
112112
return Err(DirectoryError::CannotMoveBetweenPartition);
113113
}
114114

115-
if compare_slice_string(&new_path[..partition_length], &self.path) != Ordering::Equal {
115+
if compare_slice(&new_path[..partition_length], &self.path) != Ordering::Equal {
116116
Err(DirectoryError::CannotMoveBetweenPartition)
117117
} else {
118118
self.move_to(

foundationdb/src/directory/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ pub trait Directory {
7070
fn get_layer(&self) -> Vec<u8>;
7171
}
7272

73-
pub fn compare_slice_string(a: &[String], b: &[String]) -> cmp::Ordering {
73+
pub fn compare_slice<T: Ord>(a: &[T], b: &[T]) -> cmp::Ordering {
7474
for (ai, bi) in a.iter().zip(b.iter()) {
7575
match ai.cmp(&bi) {
7676
Ordering::Equal => continue,

foundationdb/src/directory/node.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@
77
// copied, modified, or distributed except according to those terms.
88

99
use crate::directory::directory_layer::DEFAULT_SUB_DIRS;
10-
use crate::directory::DirectoryError;
10+
use crate::directory::{compare_slice, DirectoryError};
1111
use crate::tuple::{Subspace, TuplePack};
1212
use crate::{FdbError, RangeOption, Transaction};
1313

14+
use std::cmp::Ordering;
15+
1416
/// Node are used to represent the paths generated by a Directory.
1517
/// They are stored in the `Directory.node_subspace``.
1618
#[derive(Debug)]
@@ -47,15 +49,25 @@ impl Node {
4749
unimplemented!("partition is not yet supported")
4850
}
4951

50-
if layer_bytes.len() != layer.len() {
51-
Err(DirectoryError::IncompatibleLayer)
52-
} else {
53-
Ok(())
52+
match compare_slice(&layer_bytes[..], &layer[..]) {
53+
Ordering::Less | Ordering::Greater => Err(DirectoryError::IncompatibleLayer),
54+
Ordering::Equal => Ok(()),
5455
}
5556
}
5657
}
5758
}
5859

60+
pub(crate) fn store_layer(
61+
&mut self,
62+
trx: &Transaction,
63+
layer: Vec<u8>,
64+
) -> Result<(), FdbError> {
65+
let key = self.node_subspace.subspace(&b"layer".to_vec());
66+
trx.set(key.bytes(), layer.as_slice());
67+
self.layer = Some(layer);
68+
Ok(())
69+
}
70+
5971
/// retrieve the layer used for this node
6072
pub(crate) async fn retrieve_layer(&mut self, trx: &Transaction) -> Result<(), FdbError> {
6173
if self.layer == None {

foundationdb/tests/directory.rs

Lines changed: 153 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ fn test_create_or_open_directory() {
2929
futures::executor::block_on(test_create_or_open_async_then_delete(
3030
&db,
3131
&directory,
32-
vec![String::from("application")],
32+
vec![String::from("a")],
3333
))
3434
.expect("failed to run");
3535

@@ -43,15 +43,117 @@ fn test_create_or_open_directory() {
4343
futures::executor::block_on(test_list(&db, &directory, vec![String::from("a")], 10))
4444
.expect("failed to run");
4545

46-
// TODO: fix prefix
47-
// futures::executor::block_on(test_prefix(
48-
// &db,
49-
// vec![String::from("prefix")],
50-
// vec![0x01, 0x02],
51-
// ))
52-
// .expect("failed to run");
46+
futures::executor::block_on(test_children_content_subspace(
47+
&db,
48+
&directory,
49+
vec![String::from("c")],
50+
))
51+
.expect("failed to run");
52+
53+
futures::executor::block_on(test_bad_layer(&db)).expect("failed to run");
54+
55+
eprintln!("clearing all keys");
56+
let trx = db.create_trx().expect("cannot create txn");
57+
trx.clear_range(b"", b"\xff");
58+
futures::executor::block_on(trx.commit()).expect("could not clear keys");
59+
60+
// test deletions, first we need to create it
61+
futures::executor::block_on(test_create_or_open_async_then_delete(
62+
&db,
63+
&directory,
64+
vec![String::from("deletion")],
65+
))
66+
.expect("failed to run");
67+
68+
futures::executor::block_on(test_create_then_delete(
69+
&db,
70+
&directory,
71+
vec![String::from("n0")],
72+
1,
73+
))
74+
.expect("failed to run");
75+
76+
futures::executor::block_on(test_prefix(
77+
&db,
78+
vec![String::from("prefix")],
79+
vec![0xFC, 0xFC],
80+
))
81+
.expect("failed to run");
82+
futures::executor::block_on(test_not_allowed_prefix(&db, vec![0xFC, 0xFC]))
83+
.expect_err("should have failed");
84+
85+
// moves
86+
eprintln!("clearing all keys");
87+
let trx = db.create_trx().expect("cannot create txn");
88+
trx.clear_range(b"", b"\xff");
89+
futures::executor::block_on(trx.commit()).expect("could not clear keys");
90+
91+
futures::executor::block_on(test_create_then_move_to(
92+
&db,
93+
&directory,
94+
vec![String::from("d"), String::from("e")],
95+
vec![String::from("a")],
96+
))
97+
.expect("failed to run");
98+
99+
// trying to move on empty path
100+
match futures::executor::block_on(test_move_to(
101+
&db,
102+
&directory,
103+
vec![String::from("dsa")],
104+
vec![],
105+
)) {
106+
Err(DirectoryError::NoPathProvided) => {}
107+
_ => panic!("should have failed"),
108+
}
109+
110+
// trying to move on empty path
111+
match futures::executor::block_on(test_move_to(
112+
&db,
113+
&directory,
114+
vec![],
115+
vec![String::from("dsa")],
116+
)) {
117+
Err(DirectoryError::NoPathProvided) => {}
118+
Err(err) => panic!("should have NoPathProvided, got {:?}", err),
119+
Ok(()) => panic!("should not be fine"),
120+
}
121+
122+
// source path does not exists
123+
match futures::executor::block_on(test_move_to(
124+
&db,
125+
&directory,
126+
vec![String::from("e")],
127+
vec![String::from("f")],
128+
)) {
129+
Err(DirectoryError::PathDoesNotExists) => {}
130+
Err(err) => panic!("should have NoPathProvided, got {:?}", err),
131+
Ok(()) => panic!("should not be fine"),
132+
}
53133

54-
futures::executor::block_on(test_bad_layer(&db)).expect_err("should have failed");
134+
// destination's parent does not exists
135+
match futures::executor::block_on(test_create_then_move_to(
136+
&db,
137+
&directory,
138+
vec![String::from("a"), String::from("g")],
139+
vec![String::from("i-do-not-exists-yet"), String::from("z")],
140+
)) {
141+
Err(DirectoryError::ParentDirDoesNotExists) => {}
142+
Err(err) => panic!("should have ParentDirDoesNotExists, got {:?}", err),
143+
Ok(()) => panic!("should not be fine"),
144+
}
145+
146+
// destination not empty
147+
match futures::executor::block_on(test_create_then_move_to(
148+
&db,
149+
&directory,
150+
vec![String::from("a"), String::from("g")],
151+
vec![String::from("a"), String::from("g")],
152+
)) {
153+
Err(DirectoryError::BadDestinationDirectory) => {}
154+
Err(err) => panic!("should have BadDestinationDirectory, got {:?}", err),
155+
Ok(()) => panic!("should not be fine"),
156+
}
55157
}
56158

57159
async fn test_prefix(
@@ -89,7 +191,7 @@ async fn test_not_allowed_prefix(db: &Database, prefix: Vec<u8>) -> Result<(), D
89191
directory
90192
.create_or_open(
91193
&trx,
92-
vec![String::from("bad_layer")],
194+
vec![String::from("prefix_not_allowed")],
93195
Some(prefix.to_owned()),
94196
None,
95197
)
@@ -288,23 +390,27 @@ async fn test_create_or_open_async_then_delete(
288390
}
289391

290392
/// testing that we throwing Err(DirectoryError::IncompatibleLayer)
291-
async fn test_bad_layer(db: &Database) -> Result<DirectorySubspace, DirectoryError> {
393+
async fn test_bad_layer(db: &Database) -> Result<(), DirectoryError> {
292394
let directory = DirectoryLayer {
293395
..Default::default()
294396
};
295397
let trx = db.create_trx()?;
296398

399+
eprintln!("creating directory with one layer");
297400
directory
298401
.create_or_open(&trx, vec![String::from("bad_layer")], None, Some(vec![0u8]))
299402
.await?;
300403

301-
let directory = DirectoryLayer {
302-
..Default::default()
303-
};
404+
trx.commit().await.expect("cannot commit");
405+
let trx = db.create_trx()?;
304406

305-
return directory
407+
eprintln!("opening directory with another");
408+
let result = directory
306409
.create_or_open(&trx, vec![String::from("bad_layer")], None, Some(vec![1u8]))
307410
.await;
411+
412+
assert!(result.is_err(), "expected an error, got {:?}", result);
413+
Ok(())
308414
}
309415

310416
/// testing list functionality. Will open paths and create n sub-folders.
@@ -352,3 +458,35 @@ async fn test_list(
352458

353459
Ok(())
354460
}
461+
462+
/// checks that the content_subspace of the children is inside the parent
463+
async fn test_children_content_subspace(
464+
db: &Database,
465+
directory: &DirectoryLayer,
466+
paths: Vec<String>,
467+
) -> Result<(), DirectoryError> {
468+
let trx = db.create_trx()?;
469+
470+
eprintln!("parent = {:?}", paths.to_owned());
471+
472+
let _root_subspace = directory
473+
.create_or_open(&trx, paths.to_owned(), None, None)
474+
.await?;
475+
476+
let mut children_path = paths.clone();
477+
children_path.push(String::from("nested"));
478+
eprintln!("children = {:?}", children_path.to_owned());
479+
480+
let children_subspace = directory
481+
.create_or_open(&trx, children_path.to_owned(), None, None)
482+
.await?;
483+
484+
trx.commit().await.expect("could not commit");
485+
let trx = db.create_trx()?;
486+
487+
let open_children_subspace = directory.open(&trx, children_path.to_owned(), None).await?;
488+
489+
assert_eq!(children_subspace.bytes(), open_children_subspace.bytes());
490+
491+
Ok(())
492+
}

0 commit comments

Comments
 (0)