stratus/eth/storage/permanent/rocks/
rocks_db.rs1use std::collections::BTreeMap;
2use std::path::Path;
3use std::sync::Arc;
4use std::time::Instant;
5
6use anyhow::Context;
7use rocksdb::DB;
8use rocksdb::Options;
9
10use super::rocks_config::CacheSetting;
11use super::rocks_config::DbConfig;
12#[cfg(feature = "metrics")]
13use crate::infra::metrics;
14
15#[tracing::instrument(skip_all, fields(path = ?path.as_ref()))]
21pub fn create_or_open_db(path: impl AsRef<Path>, cf_configs: &BTreeMap<&'static str, Options>) -> anyhow::Result<(&'static Arc<DB>, Options)> {
22 let path = path.as_ref();
23
24 tracing::debug!("creating settings for each column family");
25 let cf_config_iter = cf_configs.iter().map(|(name, opts)| (*name, opts.clone()));
26
27 tracing::debug!("generating options for column families");
28 let db_opts = DbConfig::Default.to_options(CacheSetting::Disabled);
29
30 if !path.exists() {
31 tracing::warn!(?path, "RocksDB at path doesn't exist, creating a new one there instead");
32 }
33
34 let open_db = || DB::open_cf_with_opts(&db_opts, path, cf_config_iter.clone());
35
36 tracing::debug!("attempting to open RocksDB");
37 let instant = Instant::now();
38 let db = match open_db() {
39 Ok(db) => db,
40 Err(e) => {
41 tracing::error!(reason = ?e, "failed to open RocksDB, trying to repair it to open again...");
42 DB::repair(&db_opts, path).context("attempting to repair RocksDB cause it failed to open")?;
43 open_db().context("trying to open RocksDB a second time, after repairing")?
44 }
45 };
46
47 let waited_for = instant.elapsed();
48 tracing::info!(?waited_for, db_path = ?path, "successfully opened RocksDB");
49
50 #[cfg(feature = "metrics")]
51 {
52 let db_name = path.file_name().with_context(|| format!("invalid db path without name '{path:?}'"))?.to_str();
53 metrics::set_rocks_last_startup_delay_millis(waited_for.as_millis() as u64, db_name);
54 }
55
56 Ok((Box::leak(Box::new(Arc::new(db))), db_opts))
59}