Skip to content

Commit 1739e4c

Browse files
feat(storage): adding sled, making rocksdb optional
1 parent 2fc3018 commit 1739e4c

17 files changed

Lines changed: 1281 additions & 124 deletions

File tree

Cargo.lock

Lines changed: 195 additions & 23 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ authors = [
88
]
99
edition = "2024"
1010
description = "prism is the first trust-minimized key-transparency solution, allowing for automatic verification of service providers via light clients. Powered by Celestia."
11-
homepage = "https://prism.deltadevs.xyz"
11+
homepage = "https://prism.rs"
1212
repository = "https://github.com/deltadevsde/prism"
13-
license = "MIT"
13+
license = "AGPL-3.0"
1414
keywords = ["crypto", "key-transparency"]
1515
readme = "README.md"
1616

@@ -81,8 +81,8 @@ reqwest = { version = "0.12", features = ["json"] }
8181
url = { version = "2.5" }
8282

8383
# database
84-
rocksdb = { version = "0.21.0", features = ["multi-threaded-cf"] }
8584
redb = "2.6.0"
85+
sled = "0.34.7"
8686

8787
# async
8888
async-trait = "0.1.86"
@@ -277,3 +277,8 @@ zero_sized_map_values = "warn"
277277
# https://davidlattimore.github.io/posts/2024/02/04/speeding-up-the-rust-edit-build-run-cycle.html
278278
debug = "line-tables-only"
279279
split-debuginfo = "unpacked"
280+
281+
[profile.bench]
282+
opt-level = 3
283+
debug = false
284+
lto = true

crates/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ path = "src/main.rs"
1212

1313
[features]
1414
default = []
15+
rocksdb = ["prism-storage/rocksdb"]
1516
test_utils = []
1617

1718

crates/cli/src/cfg.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,16 @@ use prism_errors::{DataAvailabilityError, GeneralError};
77
use prism_keys::VerifyingKey;
88
use prism_prover::{prover::DEFAULT_MAX_EPOCHLESS_GAP, webserver::WebServerConfig};
99
use prism_serde::base64::FromBase64;
10+
11+
#[cfg(feature = "rocksdb")]
12+
use prism_storage::rocksdb::{RocksDBConfig, RocksDBConnection};
1013
use prism_storage::{
1114
Database,
1215
database::StorageBackend,
1316
inmemory::InMemoryDatabase,
14-
rocksdb::{RocksDBConfig, RocksDBConnection},
17+
sled::{SledConfig, SledConnection},
1518
};
19+
1620
use prism_telemetry::config::{TelemetryConfig, get_default_telemetry_config};
1721
use serde::{Deserialize, Serialize};
1822
use std::{fs, path::Path, str::FromStr, sync::Arc, time::Duration};
@@ -135,7 +139,7 @@ impl Config {
135139
keystore_path: Some(format!("{}keystore.json", path)),
136140
network: Network::from_str(network_name).unwrap().config(),
137141
da_layer: DALayerOption::default(),
138-
db: StorageBackend::RocksDB(RocksDBConfig::new(&format!("{}data", path))),
142+
db: StorageBackend::Sled(SledConfig::new(&format!("{}data", path))),
139143
telemetry: Some(get_default_telemetry_config()),
140144
max_epochless_gap: DEFAULT_MAX_EPOCHLESS_GAP,
141145
}
@@ -152,19 +156,21 @@ pub enum DALayerOption {
152156
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize, ValueEnum)]
153157
pub enum DBValues {
154158
#[default]
159+
Sled,
160+
#[cfg(feature = "rocksdb")]
155161
RocksDB,
156162
InMemory,
157163
}
158164

159165
#[derive(Args, Deserialize, Clone, Debug)]
160166
pub struct DatabaseArgs {
161-
#[arg(long, value_enum, default_value_t = DBValues::RocksDB)]
162-
/// Storage backend to use. Default: `rocks-db`
167+
#[arg(long, value_enum, default_value_t = DBValues::Sled)]
168+
/// Storage backend to use. Default: `sled`
163169
db_type: DBValues,
164170

165-
/// Path to the RocksDB database, used when `db_type` is `rocks-db`
171+
/// Path to the database, used when `db_type` is `rocks-db` or `sled`
166172
#[arg(long)]
167-
rocksdb_path: Option<String>,
173+
db_path: Option<String>,
168174
}
169175

170176
pub fn load_config(args: CommandArgs) -> Result<Config> {
@@ -178,7 +184,7 @@ pub fn load_config(args: CommandArgs) -> Result<Config> {
178184
)
179185
.context("Failed to ensure config file exists")?;
180186

181-
if let Some(rocksdb_path) = &args.database.rocksdb_path {
187+
if let Some(rocksdb_path) = &args.database.db_path {
182188
fs::create_dir_all(rocksdb_path).context("Failed to create RocksDB directory")?;
183189
}
184190

@@ -278,9 +284,14 @@ fn apply_command_line_args(config: Config, args: CommandArgs) -> Config {
278284
port: args.webserver.port.unwrap_or(webserver_config.port),
279285
}),
280286
db: match args.database.db_type {
287+
#[cfg(feature = "rocksdb")]
281288
DBValues::RocksDB => StorageBackend::RocksDB(RocksDBConfig {
282289
path: args.database.rocksdb_path.unwrap_or_else(|| format!("{}/data", prism_home)),
283290
}),
291+
DBValues::Sled => StorageBackend::Sled(SledConfig {
292+
path: args.database.db_path.unwrap_or_else(|| format!("{}/data", prism_home)),
293+
..SledConfig::default()
294+
}),
284295
DBValues::InMemory => StorageBackend::InMemory,
285296
},
286297
network: NetworkConfig {
@@ -302,13 +313,22 @@ fn apply_command_line_args(config: Config, args: CommandArgs) -> Config {
302313

303314
pub fn initialize_db(cfg: &Config) -> Result<Arc<Box<dyn Database>>> {
304315
match &cfg.db {
316+
#[cfg(feature = "rocksdb")]
305317
StorageBackend::RocksDB(cfg) => {
306318
let db = RocksDBConnection::new(cfg)
307319
.map_err(|e| GeneralError::InitializationError(e.to_string()))
308320
.context("Failed to initialize RocksDB")?;
309321

310322
Ok(Arc::new(Box::new(db) as Box<dyn Database>))
311323
}
324+
StorageBackend::Sled(cfg) => {
325+
let db = SledConnection::new(cfg)
326+
.map_err(|e| GeneralError::InitializationError(e.to_string()))
327+
.context("Failed to initialize Sled")?;
328+
329+
Ok(Arc::new(Box::new(db) as Box<dyn Database>))
330+
}
331+
312332
StorageBackend::InMemory => Ok(Arc::new(
313333
Box::new(InMemoryDatabase::new()) as Box<dyn Database>
314334
)),

crates/storage/Cargo.toml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,13 @@ license.workspace = true
1010
keywords.workspace = true
1111
readme.workspace = true
1212

13+
[features]
14+
default = []
15+
rocksdb = ["dep:rocksdb"]
16+
1317
[dependencies]
1418
serde = { workspace = true }
19+
sled = { workspace = true }
1520
tracing = { workspace = true }
1621
anyhow = { workspace = true }
1722
jmt = { workspace = true }
@@ -20,7 +25,10 @@ prism-da = { workspace = true }
2025
prism-common = { workspace = true }
2126
prism-serde = { workspace = true }
2227
auto_impl = { workspace = true }
23-
rocksdb = { workspace = true }
28+
rocksdb = { version = "0.21.0", features = [
29+
"multi-threaded-cf",
30+
], optional = true }
2431

2532
[dev-dependencies]
33+
paste = { workspace = true }
2634
tempfile.workspace = true

crates/storage/src/database.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,10 @@ use serde::{Deserialize, Serialize};
77

88
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
99
pub enum StorageBackend {
10+
#[cfg(feature = "rocksdb")]
1011
RocksDB(crate::rocksdb::RocksDBConfig),
1112
InMemory,
13+
Sled(crate::sled::SledConfig),
1214
}
1315

1416
#[auto_impl(&, Box, Arc)]

crates/storage/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
pub mod database;
22
pub mod inmemory;
3+
pub mod sled;
4+
5+
#[cfg(feature = "rocksdb")]
36
pub mod rocksdb;
47

58
#[cfg(test)]

crates/storage/src/rocksdb.rs

Lines changed: 0 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -265,69 +265,3 @@ impl TreeWriter for RocksDBConnection {
265265
Ok(())
266266
}
267267
}
268-
269-
#[cfg(test)]
270-
mod tests {
271-
use super::*;
272-
use jmt::{KeyHash, OwnedValue, Version};
273-
use tempfile::TempDir;
274-
275-
fn setup_db() -> (TempDir, RocksDBConnection) {
276-
let temp_dir = TempDir::new().unwrap();
277-
let cfg = RocksDBConfig::new(temp_dir.path().to_str().unwrap());
278-
let db = RocksDBConnection::new(&cfg).unwrap();
279-
(temp_dir, db)
280-
}
281-
282-
#[test]
283-
fn test_rw_commitment() {
284-
let (_temp_dir, db) = setup_db();
285-
286-
let epoch = 1;
287-
let commitment = Digest([1; 32]);
288-
289-
db.set_commitment(&epoch, &commitment).unwrap();
290-
let read_commitment = db.get_commitment(&epoch).unwrap();
291-
292-
assert_eq!(read_commitment, commitment);
293-
}
294-
295-
#[test]
296-
fn test_write_and_read_value() {
297-
let (_temp_dir, db) = setup_db();
298-
299-
let key_hash = KeyHash([1; 32]);
300-
let value: OwnedValue = vec![4, 5, 6];
301-
let version: Version = 1;
302-
303-
let mut batch = NodeBatch::default();
304-
batch.insert_value(version, key_hash, value.clone());
305-
306-
db.write_node_batch(&batch).unwrap();
307-
308-
let read_value = db.get_value_option(version, key_hash).unwrap();
309-
assert_eq!(read_value, Some(value));
310-
}
311-
312-
#[test]
313-
fn test_get_value_option_with_multiple_versions() {
314-
let (_temp_dir, db) = setup_db();
315-
316-
let key_hash = KeyHash([2; 32]);
317-
let value1: OwnedValue = vec![1, 1, 1];
318-
let value2: OwnedValue = vec![2, 2, 2];
319-
320-
let mut batch = NodeBatch::default();
321-
batch.insert_value(1, key_hash, value1.clone());
322-
batch.insert_value(2, key_hash, value2.clone());
323-
324-
db.write_node_batch(&batch).unwrap();
325-
326-
assert_eq!(db.get_value_option(1, key_hash).unwrap(), Some(value1));
327-
assert_eq!(
328-
db.get_value_option(2, key_hash).unwrap(),
329-
Some(value2.clone())
330-
);
331-
assert_eq!(db.get_value_option(3, key_hash).unwrap(), Some(value2));
332-
}
333-
}

0 commit comments

Comments
 (0)