1use crate::{Result, internal_error};
3use ckb_db_schema::Col;
4use ckb_logger::info;
5use rocksdb::ops::{GetColumnFamilys, GetPinned, GetPinnedCF, OpenCF};
6use rocksdb::{DBPinnableSlice, Options, ReadOnlyDB as RawReadOnlyDB};
7use std::path::Path;
8use std::sync::Arc;
9
10pub struct ReadOnlyDB {
12 pub(crate) inner: Arc<RawReadOnlyDB>,
13}
14
15impl ReadOnlyDB {
16 pub fn open_cf<P, I, N>(path: P, cf_names: I) -> Result<Option<Self>>
22 where
23 P: AsRef<Path>,
24 I: IntoIterator<Item = N>,
25 N: AsRef<str>,
26 {
27 let opts = Options::default();
28 RawReadOnlyDB::open_cf(&opts, path, cf_names).map_or_else(
29 |err| {
30 let err_str = err.as_ref();
31 if err_str.starts_with("IO error: No such file or directory") {
33 Ok(None)
34 } else if err_str.starts_with("Corruption:") {
35 info!("DB corrupted: {err_str}.");
36 Err(internal_error("DB corrupted"))
37 } else {
38 Err(internal_error(format!(
39 "failed to open the database: {err}"
40 )))
41 }
42 },
43 |db| {
44 Ok(Some(ReadOnlyDB {
45 inner: Arc::new(db),
46 }))
47 },
48 )
49 }
50
51 pub fn get_pinned_default(&self, key: &[u8]) -> Result<Option<DBPinnableSlice>> {
54 self.inner.get_pinned(key).map_err(internal_error)
55 }
56
57 pub fn get_pinned(&self, col: Col, key: &[u8]) -> Result<Option<DBPinnableSlice>> {
60 let cf = self
61 .inner
62 .cf_handle(col)
63 .ok_or_else(|| internal_error(format!("column {col} not found")))?;
64 self.inner.get_pinned_cf(cf, key).map_err(internal_error)
65 }
66}