diff --git a/Cargo.lock b/Cargo.lock index 5f61f97c..9040664b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -662,6 +662,7 @@ dependencies = [ "dashmap", "js-sys", "multihash", + "redb", "rexie", "sled", "thiserror", @@ -1016,9 +1017,9 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -2818,10 +2819,10 @@ dependencies = [ "libp2p", "lumina-node", "mime_guess", + "redb", "rust-embed", "serde", "serde_repr", - "sled", "tokio", "tracing", "tracing-appender", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index eb1e93a3..a1bf99c2 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -35,14 +35,11 @@ clap = { version = "4.4.4", features = ["derive"] } directories = "5.0.1" dotenvy = "0.15.7" mime_guess = "2.0" +redb = "2" rust-embed = { version = "8.0.0", features = ["interpolate-folder-path"] } serde = "1.0.189" serde_repr = "0.1" -# Upgrading this dependency invalidates existing persistent dbs. -# Those can be restored by migrating between versions: -# https://docs.rs/sled/latest/sled/struct.Db.html#examples-1 -sled = "0.34.7" -tokio = { version = "1.29.0", features = ["fs", "macros", "rt-multi-thread"] } +tokio = { version = "1.29.0", features = ["macros", "rt-multi-thread"] } tracing = "0.1.37" tracing-appender = "0.2.2" tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } diff --git a/cli/src/native.rs b/cli/src/native.rs index aa417dd9..d270f1e5 100644 --- a/cli/src/native.rs +++ b/cli/src/native.rs @@ -1,5 +1,6 @@ use std::env; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; +use std::sync::Arc; use std::time::Duration; use anyhow::{bail, Context, Result}; @@ -8,12 +9,10 @@ use celestia_rpc::Client; use clap::Parser; use directories::ProjectDirs; use libp2p::{identity, multiaddr::Protocol, Multiaddr}; -use lumina_node::blockstore::SledBlockstore; +use lumina_node::blockstore::RedbBlockstore; use lumina_node::network::{canonical_network_bootnodes, network_genesis, network_id, Network}; use lumina_node::node::{Node, NodeConfig}; -use lumina_node::store::{SledStore, Store}; -use sled::Db; -use tokio::fs; +use lumina_node::store::{RedbStore, Store}; use tokio::task::spawn_blocking; use tokio::time::sleep; use tracing::info; @@ -60,8 +59,8 @@ pub(crate) async fn run(args: Params) -> Result<()> { info!("Initializing store"); let db = open_db(args.store, &network_id).await?; - let store = SledStore::new(db.clone()).await?; - let blockstore = SledBlockstore::new(db).await?; + let store = RedbStore::new(db.clone()).await?; + let blockstore = RedbBlockstore::new(db); match store.head_height().await { Ok(height) => info!("Initialised store with head height: {height}"), @@ -88,35 +87,53 @@ pub(crate) async fn run(args: Params) -> Result<()> { } } -async fn open_db(path: Option, network_id: &str) -> Result { - if let Some(path) = path { - let db = spawn_blocking(|| sled::open(path)).await??; - return Ok(db); - } +async fn open_db(path: Option, network_id: &str) -> Result> { + let network_id = network_id.to_owned(); + + spawn_blocking(move || { + use std::fs; - let cache_dir = - ProjectDirs::from("co", "eiger", "lumina").context("Couldn't find lumina's cache dir")?; - let mut cache_dir = cache_dir.cache_dir().to_owned(); - - // TODO: remove it in 2 months or after a few releases - // If we find an old ('celestia') cache dir, move it to the new one. - if let Some(old_cache_dir) = ProjectDirs::from("co", "eiger", "celestia") { - let old_cache_dir = old_cache_dir.cache_dir(); - if old_cache_dir.exists() && !cache_dir.exists() { - warn!( - "Migrating old cache dir to a new location: {} -> {}", - old_cache_dir.display(), - cache_dir.display() - ); - fs::rename(old_cache_dir, &cache_dir).await?; + if let Some(path) = path { + let db = redb::Database::create(path)?; + return Ok(Arc::new(db)); } - } - cache_dir.push(network_id); - // TODO: should we create there also a subdirectory for the 'db' - // in case we want to put there some other stuff too? - let db = spawn_blocking(|| sled::open(cache_dir)).await??; - Ok(db) + let cache_dir = ProjectDirs::from("co", "eiger", "lumina") + .context("failed to construct project path")? + .cache_dir() + .join(&network_id) + .to_owned(); + + let old_cache_dir = ProjectDirs::from("co", "eiger", "celestia") + .context("failed to construct project path")? + .cache_dir() + .join(&network_id) + .to_owned(); + + if is_sled_db(&old_cache_dir) { + warn!("Removing deprecated store {}", old_cache_dir.display()); + fs::remove_dir_all(&old_cache_dir)?; + } + + if is_sled_db(&cache_dir) { + warn!("Removing deprecated store {}", cache_dir.display()); + fs::remove_dir_all(&cache_dir)?; + } + + // Directories need to pre-exist + fs::create_dir_all(&cache_dir)?; + + let path = cache_dir.join("db"); + let db = redb::Database::create(path)?; + + Ok(Arc::new(db)) + }) + .await? +} + +fn is_sled_db(path: impl AsRef) -> bool { + let path = path.as_ref(); + path.join("blobs").is_dir() && path.join("conf").is_file() && path.join("db").is_file() } /// Get the address of the local bridge node diff --git a/node/Cargo.toml b/node/Cargo.toml index 4ddd11e2..2efe0f58 100644 --- a/node/Cargo.toml +++ b/node/Cargo.toml @@ -50,7 +50,7 @@ tracing = "0.1.37" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] backoff = { version = "0.4.0", features = ["tokio"] } -blockstore = { workspace = true, features = ["sled"] } +blockstore = { workspace = true, features = ["sled", "redb"] } # Upgrading this dependency invalidates existing persistent dbs. # Those can be restored by migrating between versions: # https://docs.rs/sled/latest/sled/struct.Db.html#examples-1 diff --git a/node/src/blockstore.rs b/node/src/blockstore.rs index 6409cd2e..fd80e978 100644 --- a/node/src/blockstore.rs +++ b/node/src/blockstore.rs @@ -13,6 +13,12 @@ pub type InMemoryBlockstore = blockstore::InMemoryBlockstore; /// [`SledBlockstore`]: blockstore::SledBlockstore pub type SledBlockstore = blockstore::SledBlockstore; +#[cfg(not(target_arch = "wasm32"))] +/// A [`RedbBlockstore`]. +/// +/// [`RedbBlockstore`]: blockstore::RedbBlockstore +pub type RedbBlockstore = blockstore::RedbBlockstore; + #[cfg(target_arch = "wasm32")] /// An [`IndexedDbBlockstore`]. ///