Skip to content

Commit 74e0fb9

Browse files
bkioshnstevenj
andauthoredJan 21, 2025··
feat(rust/cardano-chain-follower): add thread and mmap file stats (#150)
* feat(cardano-chain-follower): add thread and mmap file stats Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): remove log Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): fix mmapfile name Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat call Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread logic Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat call Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): update forever task thread stat Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): linter and format Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat name constants to its own file Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat calling Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): move mmap file to cat-types Signed-off-by: bkioshn <[email protected]> * fix(cardano-blockchain-types): format Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): remove unused dep Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat calling Signed-off-by: bkioshn <[email protected]> * fix: mmapfile Signed-off-by: bkioshn <[email protected]> * fix(cardano-blockchain-types): use RwLock for mmap stat Signed-off-by: bkioshn <[email protected]> * fix(cardano-blockchain-types): add size function Signed-off-by: bkioshn <[email protected]> * fix(catalyst-types): mmap file error and structure Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): stat visibility Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat naming Signed-off-by: bkioshn <[email protected]> * fix(cardano-chain-follower): thread stat worker Signed-off-by: bkioshn <[email protected]> --------- Signed-off-by: bkioshn <[email protected]> Co-authored-by: Steven Johnson <[email protected]>
1 parent 288a5b6 commit 74e0fb9

17 files changed

+634
-53
lines changed
 

‎.config/dictionaries/project.dic

+1
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ maindbname
143143
mapref
144144
mdlint
145145
mdns
146+
MEMMAP
146147
memx
147148
Metadatum
148149
mgrybyk

‎rust/cardano-chain-follower/Cargo.toml

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ mithril-client = { version = "0.10.4", default-features = false, features = [
2020
"num-integer-backend",
2121
] }
2222
cardano-blockchain-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250114-00" }
23-
catalyst-types = { version = "0.0.1", git = "https://github.com/input-output-hk/catalyst-libs.git", tag = "r20250108-00" }
23+
catalyst-types = { version = "0.0.1", path = "../catalyst-types" }
2424

2525
thiserror = "1.0.69"
2626
tokio = { version = "1.42.0", features = [
@@ -31,7 +31,7 @@ tokio = { version = "1.42.0", features = [
3131
] }
3232
tracing = "0.1.41"
3333
tracing-log = "0.2.0"
34-
dashmap = "6.1.0"
34+
dashmap = { version = "6.1.0", features = ["serde"] }
3535
url = "2.5.4"
3636
anyhow = "1.0.95"
3737
chrono = "0.4.39"
@@ -48,14 +48,14 @@ serde = "1.0.217"
4848
serde_json = "1.0.134"
4949
mimalloc = { version = "0.1.43", optional = true }
5050
memx = "0.1.32"
51-
fmmap = { version = "0.3.3", features = ["sync", "tokio-async"] }
5251
zstd = "0.13.2"
5352
logcall = "0.1.11"
5453
tar = "0.4.43"
5554
ureq = { version = "2.12.1", features = ["native-certs"] }
5655
http = "1.2.0"
5756
hickory-resolver = { version = "0.24.2", features = ["dns-over-rustls"] }
5857
moka = { version = "0.12.9", features = ["sync"] }
58+
cpu-time = "1.0.0"
5959

6060
[dev-dependencies]
6161
tracing-subscriber = { version = "0.3.19", features = ["env-filter"] }

‎rust/cardano-chain-follower/src/chain_sync.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,13 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver<MithrilU
528528

529529
// Start the Live chain backfill task.
530530
let _backfill_join_handle = spawn(async move {
531+
stats::start_thread(
532+
cfg.chain,
533+
stats::thread::name::LIVE_SYNC_BACKFILL_AND_PURGE,
534+
true,
535+
);
531536
live_sync_backfill_and_purge(backfill_cfg.clone(), rx, sync_waiter).await;
537+
stats::stop_thread(cfg.chain, stats::thread::name::LIVE_SYNC_BACKFILL_AND_PURGE);
532538
});
533539

534540
// Live Fill data starts at fork 1.
@@ -539,7 +545,6 @@ pub(crate) async fn chain_sync(cfg: ChainSyncConfig, rx: mpsc::Receiver<MithrilU
539545
loop {
540546
// We never have a connection if we end up around the loop, so make a new one.
541547
let mut peer = persistent_reconnect(&cfg.relay_address, cfg.chain).await;
542-
543548
match resync_live_tip(&mut peer, cfg.chain).await {
544549
Ok(tip) => debug!("Tip Resynchronized to {tip}"),
545550
Err(error) => {

‎rust/cardano-chain-follower/src/chain_sync_config.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,13 @@ impl ChainSyncConfig {
150150
// Start the Mithril Snapshot Follower
151151
let rx = self.mithril_cfg.run().await?;
152152

153+
let config = self.clone();
153154
// Start Chain Sync
154-
*locked_handle = Some(tokio::spawn(chain_sync(self.clone(), rx)));
155+
*locked_handle = Some(tokio::spawn(async move {
156+
stats::start_thread(config.chain, stats::thread::name::CHAIN_SYNC, true);
157+
chain_sync(config.clone(), rx).await;
158+
stats::stop_thread(config.chain, stats::thread::name::CHAIN_SYNC);
159+
}));
155160

156161
// sync_map.insert(chain, handle);
157162
debug!("Chain Sync for {} : Started", self.chain);

‎rust/cardano-chain-follower/src/chain_sync_ready.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use tokio::{
1212
};
1313
use tracing::error;
1414

15-
use crate::chain_update;
15+
use crate::{chain_update, stats};
1616

1717
/// Data we hold related to sync being ready or not.
1818
struct SyncReady {
@@ -88,6 +88,7 @@ pub(crate) fn wait_for_sync_ready(chain: Network) -> SyncReadyWaiter {
8888
let (tx, rx) = oneshot::channel::<()>();
8989

9090
tokio::spawn(async move {
91+
stats::start_thread(chain, stats::thread::name::WAIT_FOR_SYNC_READY, true);
9192
// We are safe to use `expect` here because the SYNC_READY list is exhaustively
9293
// initialized. Its a Serious BUG if that not True, so panic is OK.
9394
#[allow(clippy::expect_used)]
@@ -101,7 +102,7 @@ pub(crate) fn wait_for_sync_ready(chain: Network) -> SyncReadyWaiter {
101102
if let Ok(()) = rx.await {
102103
status.ready = true;
103104
}
104-
105+
stats::stop_thread(chain, stats::thread::name::WAIT_FOR_SYNC_READY);
105106
// If the channel closes early, we can NEVER use the Blockchain data.
106107
});
107108

‎rust/cardano-chain-follower/src/mithril_query.rs

+12-5
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,32 @@
22
33
use std::path::Path;
44

5-
use cardano_blockchain_types::Point;
5+
use cardano_blockchain_types::{Network, Point};
66
use pallas_hardano::storage::immutable::FallibleBlock;
77
use tokio::task;
88

9-
use crate::error::{Error, Result};
9+
use crate::{
10+
error::{Error, Result},
11+
stats,
12+
};
1013

1114
/// Synchronous Immutable block iterator.
1215
pub(crate) type ImmutableBlockIterator = Box<dyn Iterator<Item = FallibleBlock> + Send + Sync>;
1316

1417
/// Get a mithril snapshot iterator.
1518
pub(crate) async fn make_mithril_iterator(
16-
path: &Path, start: &Point,
19+
path: &Path, start: &Point, chain: Network,
1720
) -> Result<ImmutableBlockIterator> {
1821
let path = path.to_path_buf();
1922
let start = start.clone();
2023
// Initial input
2124
let res = task::spawn_blocking(move || {
22-
pallas_hardano::storage::immutable::read_blocks_from_point(&path, start.clone().into())
23-
.map_err(|error| Error::MithrilSnapshot(Some(error)))
25+
stats::start_thread(chain, stats::thread::name::MITHRIL_ITERATOR, false);
26+
let result =
27+
pallas_hardano::storage::immutable::read_blocks_from_point(&path, start.clone().into())
28+
.map_err(|error| Error::MithrilSnapshot(Some(error)));
29+
stats::stop_thread(chain, stats::thread::name::MITHRIL_ITERATOR);
30+
result
2431
})
2532
.await;
2633

‎rust/cardano-chain-follower/src/mithril_snapshot_config.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ use crate::{
2424
mithril_snapshot_data::{latest_mithril_snapshot_id, SnapshotData},
2525
mithril_snapshot_sync::background_mithril_update,
2626
snapshot_id::SnapshotId,
27+
stats,
2728
turbo_downloader::DlConfig,
2829
};
2930

@@ -413,7 +414,16 @@ impl MithrilSnapshotConfig {
413414
let (tx, rx) = mpsc::channel::<MithrilUpdateMessage>(2);
414415

415416
// let handle = tokio::spawn(background_mithril_update(chain, self.clone(), tx));
416-
*locked_handle = Some(tokio::spawn(background_mithril_update(self.clone(), tx)));
417+
let config = self.clone();
418+
*locked_handle = Some(tokio::spawn(async move {
419+
stats::start_thread(
420+
config.chain,
421+
stats::thread::name::MITHRIL_SNAPSHOT_UPDATER,
422+
true,
423+
);
424+
background_mithril_update(config.clone(), tx).await;
425+
stats::stop_thread(config.chain, stats::thread::name::MITHRIL_SNAPSHOT_UPDATER);
426+
}));
417427

418428
// sync_map.insert(chain, handle);
419429
debug!(

‎rust/cardano-chain-follower/src/mithril_snapshot_iterator.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl MithrilSnapshotIterator {
7373
chain: Network, path: &Path, from: &Point, search_interval: u64,
7474
) -> Option<MithrilSnapshotIterator> {
7575
let point = probe_point(from, search_interval);
76-
let Ok(mut iterator) = make_mithril_iterator(path, &point).await else {
76+
let Ok(mut iterator) = make_mithril_iterator(path, &point, chain).await else {
7777
return None;
7878
};
7979

@@ -116,7 +116,7 @@ impl MithrilSnapshotIterator {
116116
let this = this?;
117117

118118
// Remake the iterator, based on the new known point.
119-
let Ok(iterator) = make_mithril_iterator(path, &this).await else {
119+
let Ok(iterator) = make_mithril_iterator(path, &this, chain).await else {
120120
return None;
121121
};
122122

@@ -176,7 +176,7 @@ impl MithrilSnapshotIterator {
176176

177177
debug!("Actual Mithril Iterator Start: {}", from);
178178

179-
let iterator = make_mithril_iterator(path, from).await?;
179+
let iterator = make_mithril_iterator(path, from, chain).await?;
180180

181181
Ok(MithrilSnapshotIterator {
182182
inner: Arc::new(Mutex::new(MithrilSnapshotIteratorInner {

‎rust/cardano-chain-follower/src/mithril_snapshot_sync.rs

+7-2
Original file line numberDiff line numberDiff line change
@@ -300,9 +300,12 @@ async fn validate_mithril_snapshot(
300300
match tokio::spawn(async move {
301301
// This can be long running and CPU Intensive.
302302
// So we spawn it off to a background task.
303-
MessageBuilder::new()
303+
stats::start_thread(chain, stats::thread::name::COMPUTE_SNAPSHOT_MSG, true);
304+
let result = MessageBuilder::new()
304305
.compute_snapshot_message(&cert, &mithril_path)
305-
.await
306+
.await;
307+
stats::stop_thread(chain, stats::thread::name::COMPUTE_SNAPSHOT_MSG);
308+
result
306309
})
307310
.await
308311
{
@@ -517,6 +520,7 @@ fn background_validate_mithril_snapshot(
517520
chain: Network, certificate: MithrilCertificate, tmp_path: PathBuf,
518521
) -> tokio::task::JoinHandle<bool> {
519522
tokio::spawn(async move {
523+
stats::start_thread(chain, stats::thread::name::VALIDATE_MITHRIL_SNAPSHOT, true);
520524
debug!(
521525
"Mithril Snapshot background updater for: {} : Check Certificate.",
522526
chain
@@ -540,6 +544,7 @@ fn background_validate_mithril_snapshot(
540544
chain
541545
);
542546

547+
stats::stop_thread(chain, stats::thread::name::VALIDATE_MITHRIL_SNAPSHOT);
543548
true
544549
})
545550
}

‎rust/cardano-chain-follower/src/mithril_turbo_downloader.rs

+29-24
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,8 @@ use std::{
1414

1515
use anyhow::{anyhow, bail};
1616
use async_trait::async_trait;
17-
use catalyst_types::conversion::from_saturating;
17+
use catalyst_types::{conversion::from_saturating, mmap_file::MemoryMapFile};
1818
use dashmap::DashSet;
19-
use fmmap::MmapFileExt;
2019
use memx::memcmp;
2120
use mithril_client::{
2221
common::CompressionAlgorithm, snapshot_downloader::SnapshotDownloader, MithrilResult,
@@ -134,8 +133,7 @@ impl Inner {
134133
self.ext_size.fetch_add(entry_size, Ordering::SeqCst);
135134

136135
// Try and deduplicate the file if we can, otherwise just extract it.
137-
if let Ok((prev_mmap, _)) =
138-
Self::can_deduplicate(&rel_file, entry_size, prev_file.as_ref())
136+
if let Ok(prev_mmap) = Self::can_deduplicate(&rel_file, entry_size, prev_file.as_ref())
139137
{
140138
let expected_file_size = from_saturating(entry_size);
141139
let mut buf: Vec<u8> = Vec::with_capacity(expected_file_size);
@@ -225,7 +223,7 @@ impl Inner {
225223
/// Check if a given path from the archive is able to be deduplicated.
226224
fn can_deduplicate(
227225
rel_file: &Path, file_size: u64, prev_file: Option<&PathBuf>,
228-
) -> MithrilResult<(fmmap::MmapFile, u64)> {
226+
) -> MithrilResult<MemoryMapFile> {
229227
// Can't dedup if the current file is not de-dupable (must be immutable)
230228
if rel_file.starts_with("immutable") {
231229
// Can't dedup if we don't have a previous file to dedup against.
@@ -234,8 +232,8 @@ impl Inner {
234232
// If the current file is not exactly the same as the previous file size, we
235233
// can't dedup.
236234
if file_size == current_size {
237-
if let Ok(pref_file_loaded) = mmap_open_sync(prev_file) {
238-
if pref_file_loaded.1 == file_size {
235+
if let Ok(pref_file_loaded) = Self::mmap_open_sync(prev_file) {
236+
if pref_file_loaded.size() == file_size {
239237
return Ok(pref_file_loaded);
240238
}
241239
}
@@ -245,6 +243,17 @@ impl Inner {
245243
}
246244
bail!("Can not deduplicate.");
247245
}
246+
247+
/// Open a file using mmap for performance.
248+
fn mmap_open_sync(path: &Path) -> MithrilResult<MemoryMapFile> {
249+
match MemoryMapFile::try_from(path) {
250+
Ok(mmap_file) => Ok(mmap_file),
251+
Err(error) => {
252+
error!(error=%error, file=%path.to_string_lossy(), "Failed to open file");
253+
Err(error.into())
254+
},
255+
}
256+
}
248257
}
249258

250259
/// A snapshot downloader that accelerates Download using `aria2`.
@@ -302,7 +311,17 @@ impl MithrilTurboDownloader {
302311
let target_dir = target_dir.to_owned();
303312

304313
// This is fully synchronous IO, so do it on a sync thread.
305-
let result = spawn_blocking(move || inner.dl_and_dedup(&location, &target_dir)).await;
314+
let result = spawn_blocking(move || {
315+
stats::start_thread(
316+
inner.cfg.chain,
317+
stats::thread::name::MITHRIL_DL_DEDUP,
318+
false,
319+
);
320+
let result = inner.dl_and_dedup(&location, &target_dir);
321+
stats::stop_thread(inner.cfg.chain, stats::thread::name::MITHRIL_DL_DEDUP);
322+
result
323+
})
324+
.await;
306325

307326
if let Ok(result) = result {
308327
return result;
@@ -321,20 +340,6 @@ fn get_file_size_sync(file: &Path) -> Option<u64> {
321340
Some(metadata.len())
322341
}
323342

324-
/// Open a file using mmap for performance.
325-
fn mmap_open_sync(path: &Path) -> MithrilResult<(fmmap::MmapFile, u64)> {
326-
match fmmap::MmapFile::open_with_options(path, fmmap::Options::new().read(true).populate()) {
327-
Ok(file) => {
328-
let len = file.len() as u64;
329-
Ok((file, len))
330-
},
331-
Err(error) => {
332-
error!(error=%error, file=%path.to_string_lossy(), "Failed to open file");
333-
Err(error.into())
334-
},
335-
}
336-
}
337-
338343
#[async_trait]
339344
impl SnapshotDownloader for MithrilTurboDownloader {
340345
async fn download_unpack(
@@ -366,9 +371,9 @@ impl SnapshotDownloader for MithrilTurboDownloader {
366371

367372
async fn probe(&self, location: &str) -> MithrilResult<()> {
368373
debug!("Probe Snapshot location='{location}'.");
369-
370374
let dl_config = self.inner.cfg.dl_config.clone().unwrap_or_default();
371-
let dl_processor = ParallelDownloadProcessor::new(location, dl_config).await?;
375+
let dl_processor =
376+
ParallelDownloadProcessor::new(location, dl_config, self.inner.cfg.chain).await?;
372377

373378
// Decompress and extract and de-dupe each file in the archive.
374379
stats::mithril_extract_started(self.inner.cfg.chain);

0 commit comments

Comments
 (0)
Please sign in to comment.