foundationdb/directory/
directory_subspace.rs

1// Copyright 2018 foundationdb-rs developers, https://github.com/Clikengo/foundationdb-rs/graphs/contributors
2// Copyright 2013-2018 Apple, Inc and the FoundationDB project authors.
3//
4// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
5// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
6// http://opensource.org/licenses/MIT>, at your option. This file may not be
7// copied, modified, or distributed except according to those terms.
8
9//! The resulting Subspace generated with a Directory
10
11use crate::directory::directory_layer::DirectoryLayer;
12use crate::directory::error::DirectoryError;
13use crate::directory::{Directory, DirectoryOutput};
14use crate::tuple::{PackResult, Subspace, TuplePack, TupleUnpack};
15use crate::Transaction;
16use async_trait::async_trait;
17
18/// A `DirectorySubspace` represents the contents of a directory, but it also remembers
19/// the path with which it was opened and offers convenience methods to operate on the directory at that path.
20/// An instance of `DirectorySubspace` can be used for all the usual subspace operations.
21/// It can also be used to operate on the directory with which it was opened.
22#[derive(Debug, Clone)]
23pub struct DirectorySubspace {
24    pub(crate) directory_layer: DirectoryLayer,
25    subspace: Subspace,
26    path: Vec<String>,
27    layer: Vec<u8>,
28}
29
30impl DirectorySubspace {
31    pub fn new(
32        path: &[String],
33        prefix: Vec<u8>,
34        directory_layer: &DirectoryLayer,
35        layer: Vec<u8>,
36    ) -> Self {
37        DirectorySubspace {
38            directory_layer: directory_layer.clone(),
39            subspace: Subspace::from_bytes(prefix),
40            path: Vec::from(path),
41            layer,
42        }
43    }
44
45    // https://github.com/apple/foundationdb/blob/master/bindings/flow/DirectorySubspace.cpp#L105
46    fn get_partition_subpath(
47        &self,
48        path: &[String],
49        directory_layer: Option<DirectoryLayer>,
50    ) -> Result<Vec<String>, DirectoryError> {
51        let directory = match directory_layer {
52            None => self.directory_layer.clone(),
53            Some(d) => d,
54        };
55
56        if directory.path.len() > self.path.len() {
57            return Err(DirectoryError::CannotCreateSubpath);
58        }
59
60        let mut new_path = vec![];
61
62        new_path.extend_from_slice(&self.path[directory.path.len()..]);
63        new_path.extend_from_slice(path);
64
65        Ok(new_path)
66    }
67}
68
69impl DirectorySubspace {
70    pub fn subspace<T: TuplePack>(&self, t: &T) -> Subspace {
71        self.subspace.subspace(t)
72    }
73
74    pub fn bytes(&self) -> &[u8] {
75        self.subspace.bytes()
76    }
77
78    pub fn pack<T: TuplePack>(&self, t: &T) -> Vec<u8> {
79        self.subspace.pack(t)
80    }
81
82    pub fn unpack<'de, T: TupleUnpack<'de>>(&self, key: &'de [u8]) -> PackResult<T> {
83        self.subspace.unpack(key)
84    }
85
86    pub fn range(&self) -> (Vec<u8>, Vec<u8>) {
87        self.subspace.range()
88    }
89
90    pub fn get_path(&self) -> &[String] {
91        self.path.as_slice()
92    }
93
94    pub fn set_path(&mut self, path: Vec<String>) {
95        self.path = path;
96    }
97
98    pub fn get_layer(&self) -> &[u8] {
99        self.layer.as_slice()
100    }
101
102    pub fn is_start_of(&self, key: &[u8]) -> bool {
103        self.subspace.is_start_of(key)
104    }
105
106    fn get_directory_layer_for_path(&self, _: &[String]) -> DirectoryLayer {
107        self.directory_layer.clone()
108    }
109}
110
111#[async_trait]
112impl Directory for DirectorySubspace {
113    async fn create_or_open(
114        &self,
115        txn: &Transaction,
116        path: &[String],
117        prefix: Option<&[u8]>,
118        layer: Option<&[u8]>,
119    ) -> Result<DirectoryOutput, DirectoryError> {
120        self.directory_layer
121            .create_or_open(txn, &self.get_partition_subpath(path, None)?, prefix, layer)
122            .await
123    }
124
125    async fn create(
126        &self,
127        txn: &Transaction,
128        path: &[String],
129        prefix: Option<&[u8]>,
130        layer: Option<&[u8]>,
131    ) -> Result<DirectoryOutput, DirectoryError> {
132        self.directory_layer
133            .create(txn, &self.get_partition_subpath(path, None)?, prefix, layer)
134            .await
135    }
136
137    async fn open(
138        &self,
139        txn: &Transaction,
140        path: &[String],
141        layer: Option<&[u8]>,
142    ) -> Result<DirectoryOutput, DirectoryError> {
143        self.directory_layer
144            .open(txn, &self.get_partition_subpath(path, None)?, layer)
145            .await
146    }
147
148    async fn exists(&self, trx: &Transaction, path: &[String]) -> Result<bool, DirectoryError> {
149        let directory_layer = self.get_directory_layer_for_path(path);
150
151        directory_layer
152            .exists(
153                trx,
154                &self.get_partition_subpath(path, Some(directory_layer.clone()))?,
155            )
156            .await
157    }
158
159    async fn move_directory(
160        &self,
161        trx: &Transaction,
162        new_path: &[String],
163    ) -> Result<DirectoryOutput, DirectoryError> {
164        let directory_layer = self.get_directory_layer_for_path(&[]);
165        let directory_layer_path = &directory_layer.path;
166
167        if directory_layer_path.len() > new_path.len() {
168            return Err(DirectoryError::CannotMoveBetweenPartition);
169        }
170
171        for (i, path) in directory_layer_path.iter().enumerate() {
172            match new_path.get(i) {
173                None => return Err(DirectoryError::CannotMoveBetweenPartition),
174                Some(new_path_item) => {
175                    if !new_path_item.eq(path) {
176                        return Err(DirectoryError::CannotMoveBetweenPartition);
177                    }
178                }
179            }
180        }
181
182        let mut new_relative_path = vec![];
183        new_relative_path.extend_from_slice(&new_path[directory_layer_path.len()..]);
184
185        directory_layer
186            .move_to(
187                trx,
188                &self.get_partition_subpath(&[], Some(directory_layer.clone()))?,
189                &new_relative_path,
190            )
191            .await
192    }
193
194    async fn move_to(
195        &self,
196        trx: &Transaction,
197        old_path: &[String],
198        new_path: &[String],
199    ) -> Result<DirectoryOutput, DirectoryError> {
200        self.directory_layer
201            .move_to(
202                trx,
203                &self.get_partition_subpath(old_path, None)?,
204                &self.get_partition_subpath(new_path, None)?,
205            )
206            .await
207    }
208
209    async fn remove(&self, trx: &Transaction, path: &[String]) -> Result<bool, DirectoryError> {
210        let directory_layer = self.get_directory_layer_for_path(path);
211        directory_layer
212            .remove(
213                trx,
214                &self.get_partition_subpath(path, Some(directory_layer.clone()))?,
215            )
216            .await
217    }
218
219    async fn remove_if_exists(
220        &self,
221        trx: &Transaction,
222        path: &[String],
223    ) -> Result<bool, DirectoryError> {
224        let directory_layer = self.get_directory_layer_for_path(path);
225        directory_layer
226            .remove_if_exists(
227                trx,
228                &self.get_partition_subpath(path, Some(directory_layer.clone()))?,
229            )
230            .await
231    }
232
233    async fn list(
234        &self,
235        trx: &Transaction,
236        path: &[String],
237    ) -> Result<Vec<String>, DirectoryError> {
238        self.directory_layer
239            .list(trx, &self.get_partition_subpath(path, None)?)
240            .await
241    }
242}