pub mod database;
pub mod disk_index;
pub mod disk_segment;
pub mod export;
pub mod file_io;
pub mod import;
pub mod index;
pub mod memory_age;
pub mod memory_run;
pub mod meta;
pub mod spend_session;
pub mod table;
pub mod types;
pub use database::UtxoDatabase;
pub use export::{
CKPT_TREE_A, CKPT_TREE_B, CheckpointExportTimings, IBD_UTXOS_TREE, Phase3Finish,
ckpt_inactive_slot, ckpt_tree_for_slot, is_ibd_utxo_tree_name, phase3_path,
run_checkpoint_export_replace, run_watermark_export, sync_tree_after_persist,
};
pub use import::{bootstrap_ckpt_from_legacy_standalone, seed_from_ibd_utxos};
pub use index::take_last_query_split_ms;
pub use memory_run::{advance_gc_fence_to, set_gc_fence};
pub use meta::{
clear_engine_dirty_flag, contiguous_length_sidecar, engine_dirty_flag_path,
read_contiguous_length_sidecar, remove_contiguous_length_sidecar,
write_contiguous_length_sidecar,
};
pub use spend_session::{
PartialSpendSession, SpendSession, hotpath_timer_sample, session_fill_utxo_set,
session_to_utxo_set,
};
#[cfg(feature = "production")]
pub use spend_session::{
SpendSessionLookup, session_lookup_matches_fill, spend_session_lookup_enabled,
};
pub use types::{
IdCodec, OUTPUT_ID_DELETED, OutputDetail, OutputHeader, OutputId, OutputKV, OutputKey,
outpoint_to_output_key, output_key_to_outpoint, to_output_key,
};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Instant;
static TIP_DISK_SEGS_HINT: AtomicU64 = AtomicU64::new(0);
static TIP_DISK_MS_HINT: AtomicU64 = AtomicU64::new(0);
pub fn note_tip_disk_hints(segs: u64, disk_ms: u64) {
TIP_DISK_SEGS_HINT.store(segs, Ordering::Relaxed);
TIP_DISK_MS_HINT.store(disk_ms, Ordering::Relaxed);
}
pub fn tip_disk_segs_hint() -> u64 {
TIP_DISK_SEGS_HINT.load(Ordering::Relaxed)
}
pub fn tip_disk_ms_hint() -> u64 {
TIP_DISK_MS_HINT.load(Ordering::Relaxed)
}
static LOCK_SEG_WAIT_NS: AtomicU64 = AtomicU64::new(0);
static LOCK_AGE_WAIT_NS: AtomicU64 = AtomicU64::new(0);
static LOCK_TIMER_SAMPLES: AtomicU64 = AtomicU64::new(0);
fn lock_timers_enabled() -> bool {
matches!(
std::env::var("BLVM_IBD_LOCK_TIMERS")
.ok()
.as_deref()
.map(str::trim),
Some("1") | Some("true") | Some("yes") | Some("on")
)
}
#[inline]
pub(crate) fn timed_segments_read<'a, T>(
lock: &'a parking_lot::RwLock<T>,
) -> parking_lot::RwLockReadGuard<'a, T> {
if !lock_timers_enabled() {
return lock.read();
}
let t0 = Instant::now();
let g = lock.read();
LOCK_SEG_WAIT_NS.fetch_add(t0.elapsed().as_nanos() as u64, Ordering::Relaxed);
maybe_log_lock_timers();
g
}
#[inline]
pub(crate) fn timed_age_runs_read<'a, T>(
lock: &'a parking_lot::RwLock<T>,
) -> parking_lot::RwLockReadGuard<'a, T> {
if !lock_timers_enabled() {
return lock.read();
}
let t0 = Instant::now();
let g = lock.read();
LOCK_AGE_WAIT_NS.fetch_add(t0.elapsed().as_nanos() as u64, Ordering::Relaxed);
maybe_log_lock_timers();
g
}
fn maybe_log_lock_timers() {
let n = LOCK_TIMER_SAMPLES.fetch_add(1, Ordering::Relaxed) + 1;
if n % 4096 != 0 {
return;
}
let seg = LOCK_SEG_WAIT_NS.swap(0, Ordering::Relaxed);
let age = LOCK_AGE_WAIT_NS.swap(0, Ordering::Relaxed);
tracing::info!(
"[IBD_LOCK_TIMERS] samples={} seg_wait_ms={:.3} age_wait_ms={:.3}",
n,
seg as f64 / 1_000_000.0,
age as f64 / 1_000_000.0
);
}
pub fn engine_segment_max_height(table_path: &std::path::Path) -> i32 {
let mut p = table_path.as_os_str().to_owned();
p.push(".segs");
disk_index::DiskIndex::peek_segment_dir_max_height(&std::path::PathBuf::from(p))
}