fix: correct schema upgrade logic (and refactor)

Schema upgrades were buggy from 4->5 (the v5 would be skipped).  This
change also refactors the logic slightly so that future additions can
be clearer (no need to have if and else-if combinations).
This commit is contained in:
Greg Heartsfield 2022-10-09 08:24:01 -05:00
parent 2739e49362
commit 2af5f9fbe8
3 changed files with 192 additions and 142 deletions

27
Cargo.lock generated
View File

@ -286,6 +286,26 @@ dependencies = [
"tracing-subscriber 0.3.15",
]
[[package]]
name = "const_format"
version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79f926bc2341a80e6bb5a16e18057c8c90ca3edbdeb9fa497bd0f82b1f4df4e6"
dependencies = [
"const_format_proc_macros",
]
[[package]]
name = "const_format_proc_macros"
version = "0.2.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef196d5d972878a48da7decb7686eded338b4858fbabeed513d63a7c98b2b82d"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "core-foundation"
version = "0.9.3"
@ -1008,6 +1028,7 @@ dependencies = [
"bitcoin_hashes",
"config",
"console-subscriber",
"const_format",
"futures",
"futures-util",
"governor",
@ -2216,6 +2237,12 @@ dependencies = [
"tinyvec",
]
[[package]]
name = "unicode-xid"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
[[package]]
name = "url"
version = "2.3.1"

View File

@ -31,6 +31,7 @@ hyper-tls = "0.5"
http = { version = "0.2" }
parse_duration = "2"
rand = "0.8"
const_format = "0.2.28"
[dev-dependencies]
anyhow = "1"

View File

@ -3,9 +3,11 @@ use crate::db::PooledConnection;
use crate::error::Result;
use crate::event::{single_char_tagname, Event};
use crate::utils::is_lower_hex;
use const_format::formatcp;
use rusqlite::limits::Limit;
use rusqlite::params;
use rusqlite::Connection;
use std::cmp::Ordering;
use std::time::Instant;
use tracing::{debug, error, info};
@ -17,15 +19,19 @@ PRAGMA journal_size_limit=32768;
pragma mmap_size = 536870912; -- 512MB of mmap
"##;
/// Latest database version
pub const DB_VERSION: usize = 6;
/// Schema definition
const INIT_SQL: &str = r##"
const INIT_SQL: &str = formatcp!(
r##"
-- Database settings
PRAGMA encoding = "UTF-8";
PRAGMA journal_mode=WAL;
PRAGMA main.synchronous=NORMAL;
PRAGMA foreign_keys = ON;
PRAGMA application_id = 1654008667;
PRAGMA user_version = 6;
PRAGMA user_version = {};
-- Event Table
CREATE TABLE IF NOT EXISTS event (
@ -72,7 +78,9 @@ FOREIGN KEY(metadata_event) REFERENCES event(id) ON UPDATE CASCADE ON DELETE CAS
);
CREATE INDEX IF NOT EXISTS user_verification_name_index ON user_verification(name);
CREATE INDEX IF NOT EXISTS user_verification_event_index ON user_verification(metadata_event);
"##;
"##,
DB_VERSION
);
/// Determine the current application database schema version.
pub fn db_version(conn: &mut Connection) -> Result<usize> {
@ -100,6 +108,9 @@ pub fn upgrade_db(conn: &mut PooledConnection) -> Result<()> {
(conn.limit(Limit::SQLITE_LIMIT_SQL_LENGTH) as f64 / (1024 * 1024) as f64).floor()
);
match curr_version.cmp(&DB_VERSION) {
// Database is new or not current
Ordering::Less => {
// initialize from scratch
if curr_version == 0 {
match conn.execute_batch(INIT_SQL) {
@ -112,6 +123,7 @@ pub fn upgrade_db(conn: &mut PooledConnection) -> Result<()> {
}
}
}
if curr_version == 1 {
// only change is adding a hidden column to events.
let upgrade_sql = r##"
@ -130,6 +142,7 @@ PRAGMA user_version = 2;
}
}
}
if curr_version == 2 {
// this version lacks the tag column
info!("database schema needs update from 2->3");
@ -177,6 +190,7 @@ PRAGMA user_version = 3;
tx.commit()?;
info!("Upgrade complete");
}
if curr_version == 3 {
info!("database schema needs update from 3->4");
let upgrade_sql = r##"
@ -224,7 +238,9 @@ PRAGMA user_version=5;
panic!("database could not be upgraded");
}
}
} else if curr_version == 5 {
}
if curr_version == 5 {
info!("database schema needs update from 5->6");
// We need to rebuild the tags table. iterate through the
// event table. build event from json, insert tags into a
@ -275,14 +291,20 @@ PRAGMA user_version=5;
let start = Instant::now();
conn.execute("VACUUM;", [])?;
info!("vacuumed DB after tags rebuild in {:?}", start.elapsed());
} else if curr_version == 6 {
debug!("Database version was already current (v6)");
} else if curr_version > 6 {
}
}
// Database is current, all is good
Ordering::Equal => {
debug!("Database version was already current (v{})", DB_VERSION);
}
// Database is newer than what this code understands, abort
Ordering::Greater => {
panic!(
"Database version is newer than supported by this executable (v{})",
curr_version
"Database version is newer than supported by this executable (v{} > v{})",
curr_version, DB_VERSION
);
}
}
// Setup PRAGMA
conn.execute_batch(STARTUP_SQL)?;