Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit 33bca7b

Browse files
authored
bottomless-cli: add verify command (#744)
* bottomless-cli: fix too eager create_dir_all() call The way create_dir_all() is called on a path to the database, it also creates the final file name as a directory. As a result, restoration later fails, because `data.tmp` cannot be moved to `data`, with `data` being already mistakenly created as a directory. * bottomless-cli: add `verify` command The command works similarly to `restore`, except it restores to a temporary directory and runs a `pragma integrity_check` query. On success it should return: ``` bottomless-cli -e http://localhost:9000 -n ns-:default -d e4e57664-01ad-76cc-9f19-a96700d5b2e4 verify Snapshot size: 13512704 Verification: ok ```
1 parent af93298 commit 33bca7b

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

bottomless-cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ tokio = { version = "1.23.0", features = ["macros", "rt", "rt-multi-thread"] }
2121
tracing = "0.1.37"
2222
tracing-subscriber = "0.3.16"
2323
uuid = "1.4.1"
24+
rusqlite = { workspace = true }

bottomless-cli/src/main.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,22 @@ enum Commands {
7171
)]
7272
utc_time: Option<NaiveDateTime>,
7373
},
74+
#[clap(about = "Verify integrity of the database")]
75+
Verify {
76+
#[clap(
77+
long,
78+
short,
79+
long_help = "Generation to verify.\nSkip this parameter to verify the newest generation."
80+
)]
81+
generation: Option<uuid::Uuid>,
82+
#[clap(
83+
long,
84+
short,
85+
conflicts_with = "generation",
86+
long_help = "UTC timestamp which is an upper bound for the transactions to be verified."
87+
)]
88+
utc_time: Option<NaiveDateTime>,
89+
},
7490
#[clap(about = "Remove given generation from remote storage")]
7591
Rm {
7692
#[clap(long, short)]
@@ -125,7 +141,8 @@ async fn run() -> Result<()> {
125141
}
126142
}
127143
};
128-
let database = database + "/dbs/" + namespace.strip_prefix("ns-").unwrap() + "/data";
144+
let database_dir = database + "/dbs/" + namespace.strip_prefix("ns-").unwrap();
145+
let database = database_dir.clone() + "/data";
129146
tracing::info!("Database: '{}' (namespace: {})", database, namespace);
130147

131148
let mut client = Replicator::new(database.clone()).await?;
@@ -149,9 +166,29 @@ async fn run() -> Result<()> {
149166
generation,
150167
utc_time,
151168
} => {
152-
tokio::fs::create_dir_all(&database).await?;
169+
tokio::fs::create_dir_all(&database_dir).await?;
153170
client.restore(generation, utc_time).await?;
154171
}
172+
Commands::Verify {
173+
generation,
174+
utc_time,
175+
} => {
176+
let temp = std::env::temp_dir().join("bottomless-verification-do-not-touch");
177+
let mut client = Replicator::new(temp.display().to_string()).await?;
178+
let _ = tokio::fs::remove_file(&temp).await;
179+
client.restore(generation, utc_time).await?;
180+
let size = tokio::fs::metadata(&temp).await?.len();
181+
println!("Snapshot size: {size}");
182+
let conn = rusqlite::Connection::open(&temp)?;
183+
let mut stmt = conn.prepare("PRAGMA integrity_check")?;
184+
let mut rows = stmt.query(())?;
185+
let result: String = rows.next()?.unwrap().get(0)?;
186+
println!("Verification: {result}");
187+
let _ = tokio::fs::remove_file(&temp).await;
188+
if result != "ok" {
189+
std::process::exit(1)
190+
}
191+
}
155192
Commands::Rm {
156193
generation,
157194
older_than,

0 commit comments

Comments
 (0)