Skip to content

Commit 6e6cc76

Browse files
feat(storage): adding sled, making rocksdb optional
1 parent f9ae01a commit 6e6cc76

File tree

16 files changed

+1262
-121
lines changed

16 files changed

+1262
-121
lines changed

Cargo.lock

Lines changed: 196 additions & 21 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

@@ -82,8 +82,8 @@ url = { version = "2.5" }
8282

8383
# database
8484
redis = "0.24.0"
85-
rocksdb = { version = "0.21.0", features = ["multi-threaded-cf"] }
8685
redb = "2.6.0"
86+
sled = "0.34.7"
8787

8888
# async
8989
async-trait = "0.1.86"
@@ -278,3 +278,8 @@ zero_sized_map_values = "warn"
278278
# https://davidlattimore.github.io/posts/2024/02/04/speeding-up-the-rust-edit-build-run-cycle.html
279279
debug = "line-tables-only"
280280
split-debuginfo = "unpacked"
281+
282+
[profile.bench]
283+
opt-level = 3
284+
debug = false
285+
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,13 +7,17 @@ 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, RedisConnection,
1215
database::StorageBackend,
1316
inmemory::InMemoryDatabase,
1417
redis::RedisConfig,
15-
rocksdb::{RocksDBConfig, RocksDBConnection},
18+
sled::{SledConfig, SledConnection},
1619
};
20+
1721
use prism_telemetry::config::{TelemetryConfig, get_default_telemetry_config};
1822
use serde::{Deserialize, Serialize};
1923
use std::{fs, path::Path, str::FromStr, sync::Arc, time::Duration};
@@ -136,7 +140,7 @@ impl Config {
136140
keystore_path: Some(format!("{}keystore.json", path)),
137141
network: Network::from_str(network_name).unwrap().config(),
138142
da_layer: DALayerOption::default(),
139-
db: StorageBackend::RocksDB(RocksDBConfig::new(&format!("{}data", path))),
143+
db: StorageBackend::Sled(SledConfig::new(&format!("{}data", path))),
140144
telemetry: Some(get_default_telemetry_config()),
141145
max_epochless_gap: DEFAULT_MAX_EPOCHLESS_GAP,
142146
}
@@ -153,20 +157,22 @@ pub enum DALayerOption {
153157
#[derive(Debug, Default, Clone, Eq, PartialEq, Serialize, Deserialize, ValueEnum)]
154158
pub enum DBValues {
155159
#[default]
160+
Sled,
161+
#[cfg(feature = "rocksdb")]
156162
RocksDB,
157163
InMemory,
158164
Redis,
159165
}
160166

161167
#[derive(Args, Deserialize, Clone, Debug)]
162168
pub struct DatabaseArgs {
163-
#[arg(long, value_enum, default_value_t = DBValues::RocksDB)]
164-
/// Storage backend to use. Default: `rocks-db`
169+
#[arg(long, value_enum, default_value_t = DBValues::Sled)]
170+
/// Storage backend to use. Default: `sled`
165171
db_type: DBValues,
166172

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

171177
/// Connection string to Redis, used when `db_type` is `redis`
172178
#[arg(long, required_if_eq("db_type", "redis"))]
@@ -184,7 +190,7 @@ pub fn load_config(args: CommandArgs) -> Result<Config> {
184190
)
185191
.context("Failed to ensure config file exists")?;
186192

187-
if let Some(rocksdb_path) = &args.database.rocksdb_path {
193+
if let Some(rocksdb_path) = &args.database.db_path {
188194
fs::create_dir_all(rocksdb_path).context("Failed to create RocksDB directory")?;
189195
}
190196

@@ -287,9 +293,14 @@ fn apply_command_line_args(config: Config, args: CommandArgs) -> Config {
287293
port: args.webserver.port.unwrap_or(webserver_config.port),
288294
}),
289295
db: match args.database.db_type {
296+
#[cfg(feature = "rocksdb")]
290297
DBValues::RocksDB => StorageBackend::RocksDB(RocksDBConfig {
291298
path: args.database.rocksdb_path.unwrap_or_else(|| format!("{}/data", prism_home)),
292299
}),
300+
DBValues::Sled => StorageBackend::Sled(SledConfig {
301+
path: args.database.db_path.unwrap_or_else(|| format!("{}/data", prism_home)),
302+
..SledConfig::default()
303+
}),
293304
DBValues::Redis => StorageBackend::Redis(RedisConfig {
294305
connection_string: args.database.redis_url.unwrap_or_default(),
295306
}),
@@ -314,13 +325,22 @@ fn apply_command_line_args(config: Config, args: CommandArgs) -> Config {
314325

315326
pub fn initialize_db(cfg: &Config) -> Result<Arc<Box<dyn Database>>> {
316327
match &cfg.db {
328+
#[cfg(feature = "rocksdb")]
317329
StorageBackend::RocksDB(cfg) => {
318330
let db = RocksDBConnection::new(cfg)
319331
.map_err(|e| GeneralError::InitializationError(e.to_string()))
320332
.context("Failed to initialize RocksDB")?;
321333

322334
Ok(Arc::new(Box::new(db) as Box<dyn Database>))
323335
}
336+
StorageBackend::Sled(cfg) => {
337+
let db = SledConnection::new(cfg)
338+
.map_err(|e| GeneralError::InitializationError(e.to_string()))
339+
.context("Failed to initialize Sled")?;
340+
341+
Ok(Arc::new(Box::new(db) as Box<dyn Database>))
342+
}
343+
324344
StorageBackend::InMemory => Ok(Arc::new(
325345
Box::new(InMemoryDatabase::new()) as Box<dyn Database>
326346
)),

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
redis = { workspace = true }
1621
tracing = { workspace = true }
1722
anyhow = { workspace = true }
@@ -21,7 +26,10 @@ prism-da = { workspace = true }
2126
prism-common = { workspace = true }
2227
prism-serde = { workspace = true }
2328
auto_impl = { workspace = true }
24-
rocksdb = { workspace = true }
29+
rocksdb = { version = "0.21.0", features = [
30+
"multi-threaded-cf",
31+
], optional = true }
2532

2633
[dev-dependencies]
34+
paste = { workspace = true }
2735
tempfile.workspace = true

crates/storage/src/database.rs

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

99
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
1010
pub enum StorageBackend {
11+
#[cfg(feature = "rocksdb")]
1112
RocksDB(crate::rocksdb::RocksDBConfig),
1213
InMemory,
1314
Redis(crate::redis::RedisConfig),
15+
Sled(crate::sled::SledConfig),
1416
}
1517

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

crates/storage/src/lib.rs

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

69
#[cfg(test)]

crates/storage/src/rocksdb.rs

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,6 @@ impl TreeWriter for RocksDBConnection {
232232
let encoded_value =
233233
value.as_ref().map(|v| v.encode_to_bytes()).transpose()?.unwrap_or_default();
234234
let version_bytes = version.to_be_bytes();
235-
236235
batch.put(
237236
format!("{}:{}", value_key, version_bytes.to_hex()).as_bytes(),
238237
&encoded_value,
@@ -243,69 +242,3 @@ impl TreeWriter for RocksDBConnection {
243242
Ok(())
244243
}
245244
}
246-
247-
#[cfg(test)]
248-
mod tests {
249-
use super::*;
250-
use jmt::{KeyHash, OwnedValue, Version};
251-
use tempfile::TempDir;
252-
253-
fn setup_db() -> (TempDir, RocksDBConnection) {
254-
let temp_dir = TempDir::new().unwrap();
255-
let cfg = RocksDBConfig::new(temp_dir.path().to_str().unwrap());
256-
let db = RocksDBConnection::new(&cfg).unwrap();
257-
(temp_dir, db)
258-
}
259-
260-
#[test]
261-
fn test_rw_commitment() {
262-
let (_temp_dir, db) = setup_db();
263-
264-
let epoch = 1;
265-
let commitment = Digest([1; 32]);
266-
267-
db.set_commitment(&epoch, &commitment).unwrap();
268-
let read_commitment = db.get_commitment(&epoch).unwrap();
269-
270-
assert_eq!(read_commitment, commitment);
271-
}
272-
273-
#[test]
274-
fn test_write_and_read_value() {
275-
let (_temp_dir, db) = setup_db();
276-
277-
let key_hash = KeyHash([1; 32]);
278-
let value: OwnedValue = vec![4, 5, 6];
279-
let version: Version = 1;
280-
281-
let mut batch = NodeBatch::default();
282-
batch.insert_value(version, key_hash, value.clone());
283-
284-
db.write_node_batch(&batch).unwrap();
285-
286-
let read_value = db.get_value_option(version, key_hash).unwrap();
287-
assert_eq!(read_value, Some(value));
288-
}
289-
290-
#[test]
291-
fn test_get_value_option_with_multiple_versions() {
292-
let (_temp_dir, db) = setup_db();
293-
294-
let key_hash = KeyHash([2; 32]);
295-
let value1: OwnedValue = vec![1, 1, 1];
296-
let value2: OwnedValue = vec![2, 2, 2];
297-
298-
let mut batch = NodeBatch::default();
299-
batch.insert_value(1, key_hash, value1.clone());
300-
batch.insert_value(2, key_hash, value2.clone());
301-
302-
db.write_node_batch(&batch).unwrap();
303-
304-
assert_eq!(db.get_value_option(1, key_hash).unwrap(), Some(value1));
305-
assert_eq!(
306-
db.get_value_option(2, key_hash).unwrap(),
307-
Some(value2.clone())
308-
);
309-
assert_eq!(db.get_value_option(3, key_hash).unwrap(), Some(value2));
310-
}
311-
}

0 commit comments

Comments
 (0)