Skip to content

Commit bb84eeb

Browse files
Alenardlachaume
andcommitted
refactor(aggregator): add snapshot_ancillary to snapshotter
moving the responsability to identify the files to include in the archive from the ancillary artifact builder to the snapshotter. Co-authored-by: Damien Lachaume <[email protected]>
1 parent a56a259 commit bb84eeb

File tree

5 files changed

+143
-82
lines changed

5 files changed

+143
-82
lines changed

mithril-aggregator/src/artifact_builder/cardano_database_artifacts/ancillary.rs

Lines changed: 4 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -146,17 +146,14 @@ impl AncillaryArtifactBuilder {
146146
beacon.immutable_file_number
147147
);
148148

149-
let paths_to_include =
150-
Self::get_files_and_directories_to_snapshot(beacon.immutable_file_number);
151-
152149
let archive_name = format!(
153150
"{}-e{}-i{}.ancillary",
154151
self.cardano_network, *beacon.epoch, beacon.immutable_file_number,
155152
);
156153

157154
let snapshot = self
158155
.snapshotter
159-
.snapshot_subset(&archive_name, paths_to_include)
156+
.snapshot_ancillary(beacon.immutable_file_number, &archive_name)
160157
.with_context(|| {
161158
format!(
162159
"Failed to create ancillary archive for immutable file number: {}",
@@ -236,19 +233,13 @@ impl AncillaryArtifactBuilder {
236233

237234
#[cfg(test)]
238235
mod tests {
239-
use std::fs::File;
240-
241-
use flate2::read::GzDecoder;
242-
use tar::Archive;
243-
244236
use mithril_common::{
245-
digesters::{DummyCardanoDbBuilder, IMMUTABLE_DIR, LEDGER_DIR, VOLATILE_DIR},
237+
digesters::DummyCardanoDbBuilder,
246238
test_utils::{assert_equivalent, TempDir},
247239
};
248240

249-
use crate::services::{CompressedArchiveSnapshotter, DumbSnapshotter, MockSnapshotter};
241+
use crate::services::{DumbSnapshotter, MockSnapshotter};
250242
use crate::test_tools::TestLogger;
251-
use crate::tools::file_archiver::FileArchiver;
252243

253244
use super::*;
254245

@@ -511,79 +502,11 @@ mod tests {
511502
assert!(!archive_path.exists());
512503
}
513504

514-
#[tokio::test]
515-
async fn create_archive_should_embed_ledger_volatile_directories_and_last_immutables() {
516-
let test_dir = "create_archive/cardano_database";
517-
let cardano_db = DummyCardanoDbBuilder::new(test_dir)
518-
.with_immutables(&[1, 2, 3])
519-
.with_ledger_files(&["437", "537", "637", "737"])
520-
.with_volatile_files(&["blocks-0.dat", "blocks-1.dat", "blocks-2.dat"])
521-
.build();
522-
std::fs::create_dir(cardano_db.get_dir().join("whatever")).unwrap();
523-
524-
let db_directory = cardano_db.get_dir().to_path_buf();
525-
let snapshotter = CompressedArchiveSnapshotter::new(
526-
db_directory.clone(),
527-
db_directory.parent().unwrap().join("snapshot_dest"),
528-
CompressionAlgorithm::Gzip,
529-
Arc::new(FileArchiver::new_for_test(
530-
cardano_db.get_dir().join("verification"),
531-
)),
532-
TestLogger::stdout(),
533-
)
534-
.unwrap();
535-
536-
let builder = AncillaryArtifactBuilder::new(
537-
vec![Arc::new(MockAncillaryFileUploader::new())],
538-
Arc::new(snapshotter),
539-
CardanoNetwork::DevNet(123),
540-
TestLogger::stdout(),
541-
)
542-
.unwrap();
543-
544-
let snapshot = builder
545-
.create_ancillary_archive(&CardanoDbBeacon::new(99, 2))
546-
.unwrap();
547-
548-
let mut archive = {
549-
let file_tar_gz = File::open(snapshot.get_file_path()).unwrap();
550-
let file_tar_gz_decoder = GzDecoder::new(file_tar_gz);
551-
Archive::new(file_tar_gz_decoder)
552-
};
553-
554-
let dst = cardano_db.get_dir().join("unpack_dir");
555-
archive.unpack(dst.clone()).unwrap();
556-
557-
let expected_immutable_path = dst.join(IMMUTABLE_DIR);
558-
assert!(expected_immutable_path.join("00003.chunk").exists());
559-
assert!(expected_immutable_path.join("00003.primary").exists());
560-
assert!(expected_immutable_path.join("00003.secondary").exists());
561-
let immutables_nb = std::fs::read_dir(expected_immutable_path).unwrap().count();
562-
assert_eq!(3, immutables_nb);
563-
564-
let expected_ledger_path = dst.join(LEDGER_DIR);
565-
assert!(expected_ledger_path.join("437").exists());
566-
assert!(expected_ledger_path.join("537").exists());
567-
assert!(expected_ledger_path.join("637").exists());
568-
assert!(expected_ledger_path.join("737").exists());
569-
let volatile_nb = std::fs::read_dir(expected_ledger_path).unwrap().count();
570-
assert_eq!(4, volatile_nb);
571-
572-
let expected_volatile_path = dst.join(VOLATILE_DIR);
573-
assert!(expected_volatile_path.join("blocks-0.dat").exists());
574-
assert!(expected_volatile_path.join("blocks-1.dat").exists());
575-
assert!(expected_volatile_path.join("blocks-2.dat").exists());
576-
let ledger_nb = std::fs::read_dir(expected_volatile_path).unwrap().count();
577-
assert_eq!(3, ledger_nb);
578-
579-
assert!(!dst.join("whatever").exists());
580-
}
581-
582505
#[tokio::test]
583506
async fn upload_should_return_error_and_not_upload_when_archive_creation_fails() {
584507
let mut snapshotter = MockSnapshotter::new();
585508
snapshotter
586-
.expect_snapshot_subset()
509+
.expect_snapshot_ancillary()
587510
.returning(|_, _| Err(anyhow!("Failed to create archive")));
588511

589512
let mut uploader = MockAncillaryFileUploader::new();

mithril-aggregator/src/services/snapshotter/compressed_archive_snapshotter.rs

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fs;
44
use std::path::PathBuf;
55
use std::sync::Arc;
66

7-
use mithril_common::digesters::{immutable_trio_names, IMMUTABLE_DIR};
7+
use mithril_common::digesters::{immutable_trio_names, LedgerFile, IMMUTABLE_DIR, LEDGER_DIR};
88
use mithril_common::entities::{CompressionAlgorithm, ImmutableFileNumber};
99
use mithril_common::logging::LoggerExtensions;
1010
use mithril_common::StdResult;
@@ -51,6 +51,22 @@ impl Snapshotter for CompressedArchiveSnapshotter {
5151
self.snapshot(archive_name_without_extension, appender)
5252
}
5353

54+
fn snapshot_ancillary(
55+
&self,
56+
immutable_file_number: ImmutableFileNumber,
57+
archive_name_without_extension: &str,
58+
) -> StdResult<FileArchive> {
59+
debug!(
60+
self.logger,
61+
"Snapshotting ancillary archive: '{archive_name_without_extension}'"
62+
);
63+
64+
let paths_to_include =
65+
self.get_files_and_directories_for_ancillary_snapshot(immutable_file_number)?;
66+
let appender = AppenderEntries::new(paths_to_include, self.db_directory.clone())?;
67+
self.snapshot(archive_name_without_extension, appender)
68+
}
69+
5470
fn snapshot_immutable_trio(
5571
&self,
5672
immutable_file_number: ImmutableFileNumber,
@@ -126,6 +142,36 @@ impl CompressedArchiveSnapshotter {
126142
appender,
127143
)
128144
}
145+
146+
/// Returns the list of files and directories to include in ancillary snapshot.
147+
///
148+
/// The immutable file included in the ancillary archive corresponds to the last one (and not finalized yet)
149+
/// when the immutable file number given to the function corresponds to the penultimate.
150+
fn get_files_and_directories_for_ancillary_snapshot(
151+
&self,
152+
immutable_file_number: u64,
153+
) -> StdResult<Vec<PathBuf>> {
154+
let mut files_to_snapshot = Vec::with_capacity(4);
155+
156+
let next_immutable_file_number = immutable_file_number + 1;
157+
files_to_snapshot.extend_from_slice(
158+
immutable_trio_names(next_immutable_file_number)
159+
.iter()
160+
.map(|filename| PathBuf::from(IMMUTABLE_DIR).join(filename))
161+
.collect::<Vec<_>>()
162+
.as_slice(),
163+
);
164+
165+
let db_ledger_dir = self.db_directory.join(LEDGER_DIR);
166+
let ledger_files = LedgerFile::list_all_in_dir(&db_ledger_dir)?;
167+
let last_ledger = ledger_files.last().ok_or(anyhow!(
168+
"No ledger file found in directory: `{}`",
169+
db_ledger_dir.display()
170+
))?;
171+
files_to_snapshot.push(PathBuf::from(LEDGER_DIR).join(&last_ledger.filename));
172+
173+
Ok(files_to_snapshot)
174+
}
129175
}
130176

131177
#[cfg(test)]
@@ -282,4 +328,49 @@ mod tests {
282328
);
283329
}
284330
}
331+
332+
mod snapshot_ancillary {
333+
use mithril_common::digesters::VOLATILE_DIR;
334+
335+
use super::*;
336+
337+
#[tokio::test]
338+
async fn create_archive_should_embed_only_last_ledger_and_last_immutables() {
339+
let test_dir = get_test_directory(
340+
"create_archive_should_embed_only_last_ledger_and_last_immutables",
341+
);
342+
let cardano_db = DummyCardanoDbBuilder::new(
343+
"create_archive_should_embed_only_last_ledger_and_last_immutables",
344+
)
345+
.with_immutables(&[1, 2, 3])
346+
.with_ledger_files(&["437", "537", "637", "737", "9not_included"])
347+
.with_volatile_files(&["blocks-0.dat", "blocks-1.dat", "blocks-2.dat"])
348+
.build();
349+
fs::create_dir(cardano_db.get_dir().join("whatever")).unwrap();
350+
351+
let db_directory = cardano_db.get_dir();
352+
let snapshotter =
353+
snapshotter_for_test(&test_dir, db_directory, CompressionAlgorithm::Gzip);
354+
355+
let snapshot = snapshotter.snapshot_ancillary(2, "ancillary").unwrap();
356+
357+
let unpack_dir = unpack_gz_decoder(test_dir, snapshot);
358+
359+
let expected_immutable_path = unpack_dir.join(IMMUTABLE_DIR);
360+
assert!(expected_immutable_path.join("00003.chunk").exists());
361+
assert!(expected_immutable_path.join("00003.primary").exists());
362+
assert!(expected_immutable_path.join("00003.secondary").exists());
363+
assert_eq!(3, list_files(&expected_immutable_path).len());
364+
365+
// Only the last ledger file should be included
366+
let expected_ledger_path = unpack_dir.join(LEDGER_DIR);
367+
assert!(expected_ledger_path.join("737").exists());
368+
assert_eq!(1, list_files(&expected_ledger_path).len());
369+
370+
let expected_volatile_path = unpack_dir.join(VOLATILE_DIR);
371+
assert!(!expected_volatile_path.exists());
372+
373+
assert!(!unpack_dir.join("whatever").exists());
374+
}
375+
}
285376
}

mithril-aggregator/src/services/snapshotter/interface.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ pub trait Snapshotter: Sync + Send {
1818
files: Vec<PathBuf>,
1919
) -> StdResult<FileArchive>;
2020

21+
/// Create a new snapshot of ancillary files.
22+
///
23+
/// Ancillary files include the last, uncompleted, immutable trio and the last ledger file.
24+
fn snapshot_ancillary(
25+
&self,
26+
immutable_file_number: ImmutableFileNumber,
27+
archive_name_without_extension: &str,
28+
) -> StdResult<FileArchive>;
29+
2130
/// Create a new snapshot of an immutable trio.
2231
fn snapshot_immutable_trio(
2332
&self,

mithril-aggregator/src/services/snapshotter/test_doubles.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,14 @@ impl Snapshotter for DumbSnapshotter {
6767
self.snapshot_all(archive_name_without_extension)
6868
}
6969

70+
fn snapshot_ancillary(
71+
&self,
72+
_immutable_file_number: ImmutableFileNumber,
73+
archive_name_without_extension: &str,
74+
) -> StdResult<FileArchive> {
75+
self.snapshot_all(archive_name_without_extension)
76+
}
77+
7078
fn snapshot_immutable_trio(
7179
&self,
7280
_immutable_file_number: ImmutableFileNumber,
@@ -131,6 +139,14 @@ impl Snapshotter for FakeSnapshotter {
131139
self.snapshot_all(archive_name_without_extension)
132140
}
133141

142+
fn snapshot_ancillary(
143+
&self,
144+
_immutable_file_number: ImmutableFileNumber,
145+
archive_name_without_extension: &str,
146+
) -> StdResult<FileArchive> {
147+
self.snapshot_all(archive_name_without_extension)
148+
}
149+
134150
fn snapshot_immutable_trio(
135151
&self,
136152
_immutable_file_number: ImmutableFileNumber,
@@ -199,6 +215,17 @@ mod tests {
199215
)
200216
);
201217
}
218+
{
219+
let ancillary_snapshot = snapshotter
220+
.snapshot_ancillary(3, "whatever")
221+
.expect("Dumb snapshotter::snapshot_ancillary should not fail.");
222+
assert_eq!(
223+
Some(ancillary_snapshot),
224+
snapshotter.get_last_snapshot().expect(
225+
"Dumb snapshotter::get_last_snapshot should not fail when some last snapshot."
226+
)
227+
);
228+
}
202229
{
203230
let immutable_snapshot = snapshotter
204231
.snapshot_immutable_trio(4, "whatever")
@@ -257,6 +284,16 @@ mod tests {
257284
);
258285
assert!(full_snapshot.get_file_path().is_file());
259286
}
287+
{
288+
let ancillary_snapshot =
289+
fake_snapshotter.snapshot_ancillary(3, filename).unwrap();
290+
291+
assert_eq!(
292+
ancillary_snapshot.get_file_path(),
293+
&test_dir.join(filename).with_extension("tar.gz")
294+
);
295+
assert!(ancillary_snapshot.get_file_path().is_file());
296+
}
260297
{
261298
let immutable_snapshot = fake_snapshotter
262299
.snapshot_immutable_trio(5, filename)

mithril-aggregator/src/tools/file_archiver/entities.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ impl ArchiveParameters {
2929
#[derive(Debug, Clone, PartialEq, Eq)]
3030
pub struct FileArchive {
3131
pub(super) filepath: PathBuf,
32+
// Todo: rename to `archive_size` and add `uncompressed_size` field.
3233
pub(super) filesize: u64,
3334
pub(super) compression_algorithm: CompressionAlgorithm,
3435
}

0 commit comments

Comments
 (0)