Skip to main content

eat_rocks/
lib.rs

1//! Restore a [rocks backup](https://github.com/facebook/rocksdb/wiki/How-to-backup-RocksDB)
2//! from object storage
3//!
4//! ```rust,no_run
5//! use eat_rocks::{public_bucket, restore};
6//! # async fn example() -> Result<(), eat_rocks::Error> {
7//! let store = public_bucket("https://constellation.t3.storage.dev")?;
8//! restore(store, "", "/tmp/constellation-db", Default::default()).await?;
9//! # Ok(())
10//! # }
11//! ```
12//!
13//! the `public_bucket` function (`easy` feature, enabled by default) works with
14//! s3-compatible stores (like tigris) which are configured for public read access.
15//!
16//! you can use any [`ObjectStore`](object_store::ObjectStore) to restore from pretty much any backend (S3, GCS, Azure, local filesystem, ...)
17
18pub mod meta;
19pub mod restore;
20
21pub use meta::{BackupFile, BackupMeta};
22pub use restore::{DEFAULT_CONCURRENCY, RestoreOptions, fetch_meta, list_backup_ids, restore};
23
24use std::io;
25use std::path::PathBuf;
26use std::string::FromUtf8Error;
27
28use object_store::path::Path as StorePath;
29
30/// Build an unsigned s3-compatible object store
31///
32/// `endpoint` should include the bucket as a subdomain for virtual-hosted style:
33///
34/// ```text
35/// https://constellation.t3.storage.dev
36/// ```
37///
38/// you can construct your own [`object_store::ObjectStore`] implementation directly for more control.
39#[cfg(feature = "easy")]
40pub fn public_bucket(
41    endpoint: &str,
42) -> Result<std::sync::Arc<dyn object_store::ObjectStore>, Error> {
43    use object_store::aws::AmazonS3Builder;
44    use std::sync::Arc;
45
46    let store = AmazonS3Builder::new()
47        .with_endpoint(endpoint)
48        .with_bucket_name("_")
49        .with_skip_signature(true)
50        .with_allow_http(true)
51        .with_virtual_hosted_style_request(true)
52        .build()
53        .map_err(|e| Error::ObjectStoreBuild {
54            endpoint: endpoint.to_string(),
55            source: e,
56        })?;
57
58    Ok(Arc::new(store))
59}
60
61/// Errors that can occur during backup discovery, metadata parsing, or restore.
62#[derive(Debug, thiserror::Error)]
63pub enum Error {
64    #[cfg(feature = "easy")]
65    #[error("failed to build object store")]
66    ObjectStoreBuild {
67        endpoint: String,
68        #[source]
69        source: object_store::Error,
70    },
71
72    #[error("failed to list objects under {prefix:?}")]
73    List {
74        prefix: StorePath,
75        #[source]
76        source: object_store::Error,
77    },
78
79    #[error("failed to fetch {key:?}")]
80    Fetch {
81        key: StorePath,
82        #[source]
83        source: object_store::Error,
84    },
85
86    #[error("meta file for backup {backup_id} is not valid UTF-8")]
87    MetaEncoding {
88        backup_id: u64,
89        #[source]
90        source: FromUtf8Error,
91    },
92
93    #[error("failed to parse meta file for backup {backup_id}")]
94    MetaParse {
95        backup_id: u64,
96        #[source]
97        source: meta::ParseError,
98    },
99
100    #[error("no backups found")]
101    NoBackups,
102
103    #[error("backup contains {count} excluded file(s) (unsupported)")]
104    ExcludedFiles { count: usize },
105
106    #[error("backup path has unrecognized prefix: {0:?}")]
107    UnrecognizedPathPrefix(String),
108
109    #[error("shared_checksum filename missing underscore: {0:?}")]
110    SharedChecksumNoUnderscore(String),
111
112    #[error("shared_checksum filename missing extension: {0:?}")]
113    SharedChecksumNoExtension(String),
114
115    #[error("private/ path has too few components: {0:?}")]
116    PrivatePathTooShort(String),
117
118    #[error("size mismatch on {path}: expected {expected} bytes, got {actual}")]
119    SizeMismatch {
120        path: String,
121        expected: u64,
122        actual: u64,
123    },
124
125    #[error("crc32c mismatch on {path}: expected {expected:#010x}, got {actual:#010x}")]
126    ChecksumMismatch {
127        path: String,
128        expected: u32,
129        actual: u32,
130    },
131
132    #[error("{}: {source}", path.display())]
133    Io {
134        path: PathBuf,
135        #[source]
136        source: io::Error,
137    },
138}