Skip to content

Commit feb73da

Browse files
committed
feat(client-cli): allow unexpected download verifier to work from db root
And take in account the fact that directories (root or immutable) could not exist before download.
1 parent 1023860 commit feb73da

File tree

1 file changed

+86
-32
lines changed

1 file changed

+86
-32
lines changed

mithril-client/src/utils/unexpected_downloaded_file_verifier.rs

Lines changed: 86 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,34 +14,34 @@ use std::path::{Path, PathBuf};
1414

1515
use anyhow::Context;
1616

17-
use mithril_common::digesters::immutable_trio_names;
17+
use mithril_common::digesters::{immutable_trio_names, IMMUTABLE_DIR};
1818
use mithril_common::entities::ImmutableFileNumber;
1919
use mithril_common::StdResult;
2020

2121
const BASE_ERROR: &str = "Unexpected downloaded file check failed";
2222

2323
/// Tool to check and remove unexpected files when downloading and unpacking Mithril archives
2424
pub struct UnexpectedDownloadedFileVerifier {
25-
dir_to_check: PathBuf,
25+
target_cardano_db_dir: PathBuf,
2626
immutable_files_range_to_expect: RangeInclusive<ImmutableFileNumber>,
2727
}
2828

2929
/// List of expected files after downloading and unpacking, yielded by `UnexpectedDownloadedFileVerifier::compute_expected_state_after_download`
3030
pub struct ExpectedFilesAfterDownload {
31-
dir_to_check: PathBuf,
31+
target_immutable_files_dir: PathBuf,
3232
expected_files: HashSet<PathBuf>,
3333
}
3434

3535
impl UnexpectedDownloadedFileVerifier {
3636
/// `UnexpectedDownloadedFileVerifier` factory
3737
pub fn new<P: AsRef<Path>>(
38-
dir_to_check: P,
38+
target_cardano_db_dir: P,
3939
network_kind: &str,
4040
include_ancillary: bool,
4141
last_downloaded_immutable_file_number: ImmutableFileNumber,
4242
) -> Self {
4343
Self {
44-
dir_to_check: dir_to_check.as_ref().to_path_buf(),
44+
target_cardano_db_dir: target_cardano_db_dir.as_ref().to_path_buf(),
4545
immutable_files_range_to_expect: compute_immutable_files_range_to_expect(
4646
network_kind,
4747
include_ancillary,
@@ -50,32 +50,42 @@ impl UnexpectedDownloadedFileVerifier {
5050
}
5151
}
5252

53+
fn target_immutable_files_dir(&self) -> PathBuf {
54+
self.target_cardano_db_dir.join(IMMUTABLE_DIR)
55+
}
56+
5357
/// Compute the expected state of the folder after download finish
5458
pub async fn compute_expected_state_after_download(
5559
&self,
5660
) -> StdResult<ExpectedFilesAfterDownload> {
57-
let dir_to_check = self.dir_to_check.to_path_buf();
61+
let immutable_files_dir = self.target_immutable_files_dir();
5862
let immutable_files_range_to_expect = self.immutable_files_range_to_expect.clone();
5963
// target databases can be quite large, avoid blocking the main thread
6064
let expected_files = tokio::task::spawn_blocking(move || -> StdResult<HashSet<PathBuf>> {
61-
let mut files: HashSet<PathBuf> = std::fs::read_dir(&dir_to_check)
62-
.with_context(|| format!("Failed to read directory {}", dir_to_check.display()))?
63-
.flat_map(|e| e.map(|e| e.path()))
64-
.collect();
65+
let mut files: HashSet<PathBuf> = if immutable_files_dir.exists() {
66+
std::fs::read_dir(&immutable_files_dir)
67+
.with_context(|| {
68+
format!("Failed to read directory {}", immutable_files_dir.display())
69+
})?
70+
.flat_map(|e| e.map(|e| e.path()))
71+
.collect()
72+
} else {
73+
HashSet::new()
74+
};
6575

6676
// Complete the list with all rightfully downloaded immutable files
6777
for immutable_file_name in
6878
immutable_files_range_to_expect.flat_map(immutable_trio_names)
6979
{
70-
files.insert(dir_to_check.join(immutable_file_name));
80+
files.insert(immutable_files_dir.join(immutable_file_name));
7181
}
7282
Ok(files)
7383
})
7484
.await?
7585
.with_context(|| BASE_ERROR)?;
7686

7787
Ok(ExpectedFilesAfterDownload {
78-
dir_to_check: self.dir_to_check.clone(),
88+
target_immutable_files_dir: self.target_immutable_files_dir(),
7989
expected_files,
8090
})
8191
}
@@ -105,7 +115,7 @@ impl ExpectedFilesAfterDownload {
105115
/// *Note: removed directories names are suffixed with a "/"*
106116
pub async fn remove_unexpected_files(self) -> StdResult<Vec<String>> {
107117
tokio::task::spawn_blocking(move || {
108-
let unexpected_entries: Vec<_> = std::fs::read_dir(&self.dir_to_check)
118+
let unexpected_entries: Vec<_> = std::fs::read_dir(&self.target_immutable_files_dir)
109119
.with_context(|| BASE_ERROR)?
110120
.flatten()
111121
.filter(|f| !self.expected_files.contains(&f.path().to_path_buf()))
@@ -159,6 +169,12 @@ mod tests {
159169

160170
use super::*;
161171

172+
fn create_immutable_files_dir(parent_dir: &Path) -> PathBuf {
173+
let immutable_files_dir = parent_dir.join(IMMUTABLE_DIR);
174+
create_dir(&immutable_files_dir).unwrap();
175+
immutable_files_dir
176+
}
177+
162178
fn create_immutable_trio(dir: &Path, immutable_file_number: ImmutableFileNumber) {
163179
for immutable_file_name in immutable_trio_names(immutable_file_number) {
164180
File::create(dir.join(immutable_file_name)).unwrap();
@@ -201,8 +217,10 @@ mod tests {
201217
use super::*;
202218

203219
#[tokio::test]
204-
async fn when_dir_empty_return_empty_if_immutable_files_range_is_empty() {
220+
async fn when_dir_empty_return_empty_if_immutable_files_dir_does_not_exist_and_range_is_empty(
221+
) {
205222
let temp_dir = temp_dir_create!();
223+
create_immutable_files_dir(&temp_dir);
206224
let existing_files =
207225
UnexpectedDownloadedFileVerifier::new(&temp_dir, "network", false, 0)
208226
.compute_expected_state_after_download()
@@ -213,7 +231,20 @@ mod tests {
213231
}
214232

215233
#[tokio::test]
216-
async fn when_dir_empty_return_immutables_trios_if_immutable_files_range_is_not_empty() {
234+
async fn when_dir_empty_return_empty_if_immutable_files_dir_exist_and_range_is_empty() {
235+
let temp_dir = temp_dir_create!();
236+
let existing_files =
237+
UnexpectedDownloadedFileVerifier::new(&temp_dir, "network", false, 0)
238+
.compute_expected_state_after_download()
239+
.await
240+
.unwrap();
241+
242+
assert_eq!(existing_files.expected_files, HashSet::<PathBuf>::new());
243+
}
244+
245+
#[tokio::test]
246+
async fn when_immutable_files_dir_does_not_exist_return_immutables_trios_if_immutable_files_range_is_not_empty(
247+
) {
217248
let temp_dir = temp_dir_create!();
218249
let existing_files =
219250
UnexpectedDownloadedFileVerifier::new(&temp_dir, "network", false, 1)
@@ -224,21 +255,43 @@ mod tests {
224255
assert_eq!(
225256
existing_files.expected_files,
226257
HashSet::from([
227-
temp_dir.join("00001.chunk"),
228-
temp_dir.join("00001.primary"),
229-
temp_dir.join("00001.secondary"),
258+
temp_dir.join(IMMUTABLE_DIR).join("00001.chunk"),
259+
temp_dir.join(IMMUTABLE_DIR).join("00001.primary"),
260+
temp_dir.join(IMMUTABLE_DIR).join("00001.secondary"),
230261
])
231262
);
232263
}
233264

234265
#[tokio::test]
235-
async fn add_existing_files_and_dirs() {
266+
async fn when_immutable_files_dir_empty_return_immutables_trios_if_immutable_files_range_is_not_empty(
267+
) {
236268
let temp_dir = temp_dir_create!();
237-
create_dir(temp_dir.join("dir_1")).unwrap();
238-
create_dir(temp_dir.join("dir_2")).unwrap();
239-
File::create(temp_dir.join("file_1.txt")).unwrap();
240-
File::create(temp_dir.join("file_2.txt")).unwrap();
241-
File::create(temp_dir.join("dir_2").join("file_3.txt")).unwrap();
269+
let immutable_files_dir = create_immutable_files_dir(&temp_dir);
270+
let existing_files =
271+
UnexpectedDownloadedFileVerifier::new(&temp_dir, "network", false, 1)
272+
.compute_expected_state_after_download()
273+
.await
274+
.unwrap();
275+
276+
assert_eq!(
277+
existing_files.expected_files,
278+
HashSet::from([
279+
immutable_files_dir.join("00001.chunk"),
280+
immutable_files_dir.join("00001.primary"),
281+
immutable_files_dir.join("00001.secondary"),
282+
])
283+
);
284+
}
285+
286+
#[tokio::test]
287+
async fn add_existing_files_and_dirs_from_immutable_files_dir_to_expected_files() {
288+
let temp_dir = temp_dir_create!();
289+
let immutable_files_dir = create_immutable_files_dir(&temp_dir);
290+
create_dir(immutable_files_dir.join("dir_1")).unwrap();
291+
create_dir(immutable_files_dir.join("dir_2")).unwrap();
292+
File::create(immutable_files_dir.join("file_1.txt")).unwrap();
293+
File::create(immutable_files_dir.join("file_2.txt")).unwrap();
294+
File::create(immutable_files_dir.join("dir_2").join("file_3.txt")).unwrap();
242295

243296
let existing_files =
244297
UnexpectedDownloadedFileVerifier::new(&temp_dir, "network", false, 0)
@@ -249,10 +302,10 @@ mod tests {
249302
assert_eq!(
250303
existing_files.expected_files,
251304
HashSet::from([
252-
temp_dir.join("dir_1"),
253-
temp_dir.join("dir_2"),
254-
temp_dir.join("file_1.txt"),
255-
temp_dir.join("file_2.txt"),
305+
immutable_files_dir.join("dir_1"),
306+
immutable_files_dir.join("dir_2"),
307+
immutable_files_dir.join("file_1.txt"),
308+
immutable_files_dir.join("file_2.txt"),
256309
])
257310
);
258311
}
@@ -267,7 +320,7 @@ mod tests {
267320
async fn when_dir_empty_do_nothing_and_return_none() {
268321
let temp_dir = temp_dir_create!();
269322
let existing_before = ExpectedFilesAfterDownload {
270-
dir_to_check: temp_dir.clone(),
323+
target_immutable_files_dir: temp_dir.clone(),
271324
expected_files: HashSet::new(),
272325
};
273326

@@ -282,7 +335,7 @@ mod tests {
282335
create_dir(temp_dir.join("dir_1")).unwrap();
283336
File::create(temp_dir.join("file_1.txt")).unwrap();
284337
let existing_before = ExpectedFilesAfterDownload {
285-
dir_to_check: temp_dir.clone(),
338+
target_immutable_files_dir: temp_dir.clone(),
286339
expected_files: HashSet::from([
287340
temp_dir.join("file_1.txt"),
288341
temp_dir.join("dir_1"),
@@ -299,7 +352,7 @@ mod tests {
299352
) {
300353
let temp_dir = temp_dir_create!();
301354
let existing_before = ExpectedFilesAfterDownload {
302-
dir_to_check: temp_dir.clone(),
355+
target_immutable_files_dir: temp_dir.clone(),
303356
expected_files: HashSet::new(),
304357
};
305358

@@ -331,8 +384,9 @@ mod tests {
331384
let temp_dir = temp_dir_create!();
332385
let verifier = UnexpectedDownloadedFileVerifier::new(&temp_dir, "network", false, 19999);
333386

387+
let immutable_files_dir = create_immutable_files_dir(&temp_dir);
334388
for immutable_file_number in 0..=30000 {
335-
create_immutable_trio(&temp_dir, immutable_file_number);
389+
create_immutable_trio(&immutable_files_dir, immutable_file_number);
336390
}
337391

338392
let now = Instant::now();

0 commit comments

Comments
 (0)