mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-01 10:35:05 -05:00
Co-authored-by: Bjerg <onbjerg@users.noreply.github.com> Co-authored-by: Roman Krasiuk <rokrassyuk@gmail.com> Co-authored-by: joshieDo <ranriver@protonmail.com> Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de> Co-authored-by: Oliver Nordbjerg <hi@notbjerg.me> Co-authored-by: Thomas Coratger <thomas.coratger@gmail.com>
118 lines
4.2 KiB
Rust
118 lines
4.2 KiB
Rust
//! Database version utils.
|
|
|
|
use std::{
|
|
fs, io,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
/// The name of the file that contains the version of the database.
|
|
pub const DB_VERSION_FILE_NAME: &str = "database.version";
|
|
/// The version of the database stored in the [DB_VERSION_FILE_NAME] file in the same directory as
|
|
/// database.
|
|
pub const DB_VERSION: u64 = 2;
|
|
|
|
/// Error when checking a database version using [check_db_version_file]
|
|
#[derive(thiserror::Error, Debug)]
|
|
pub enum DatabaseVersionError {
|
|
/// Unable to determine the version of the database; the file is missing.
|
|
#[error("unable to determine the version of the database, file is missing")]
|
|
MissingFile,
|
|
/// Unable to determine the version of the database; the file is malformed.
|
|
#[error("unable to determine the version of the database, file is malformed")]
|
|
MalformedFile,
|
|
/// Breaking database change detected.
|
|
///
|
|
/// Your database version is incompatible with the latest database version.
|
|
#[error(
|
|
"breaking database change detected: your database version (v{version}) \
|
|
is incompatible with the latest database version (v{DB_VERSION})"
|
|
)]
|
|
VersionMismatch {
|
|
/// The detected version in the database.
|
|
version: u64,
|
|
},
|
|
/// IO error occurred while reading the database version file.
|
|
#[error("IO error occurred while reading {path}: {err}")]
|
|
IORead {
|
|
/// The encountered IO error.
|
|
err: io::Error,
|
|
/// The path to the database version file.
|
|
path: PathBuf,
|
|
},
|
|
}
|
|
|
|
/// Checks the database version file with [DB_VERSION_FILE_NAME] name.
|
|
///
|
|
/// Returns [Ok] if file is found and has one line which equals to [DB_VERSION].
|
|
/// Otherwise, returns different [DatabaseVersionError] error variants.
|
|
pub fn check_db_version_file<P: AsRef<Path>>(db_path: P) -> Result<(), DatabaseVersionError> {
|
|
let version = get_db_version(db_path)?;
|
|
if version != DB_VERSION {
|
|
return Err(DatabaseVersionError::VersionMismatch { version })
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Returns the database version from file with [DB_VERSION_FILE_NAME] name.
|
|
///
|
|
/// Returns [Ok] if file is found and contains a valid version.
|
|
/// Otherwise, returns different [DatabaseVersionError] error variants.
|
|
pub fn get_db_version<P: AsRef<Path>>(db_path: P) -> Result<u64, DatabaseVersionError> {
|
|
let version_file_path = db_version_file_path(db_path);
|
|
match fs::read_to_string(&version_file_path) {
|
|
Ok(raw_version) => {
|
|
Ok(raw_version.parse::<u64>().map_err(|_| DatabaseVersionError::MalformedFile)?)
|
|
}
|
|
Err(err) if err.kind() == io::ErrorKind::NotFound => Err(DatabaseVersionError::MissingFile),
|
|
Err(err) => Err(DatabaseVersionError::IORead { err, path: version_file_path }),
|
|
}
|
|
}
|
|
|
|
/// Creates a database version file with [DB_VERSION_FILE_NAME] name containing [DB_VERSION] string.
|
|
///
|
|
/// This function will create a file if it does not exist,
|
|
/// and will entirely replace its contents if it does.
|
|
pub fn create_db_version_file<P: AsRef<Path>>(db_path: P) -> io::Result<()> {
|
|
fs::write(db_version_file_path(db_path), DB_VERSION.to_string())
|
|
}
|
|
|
|
/// Returns a database version file path.
|
|
pub fn db_version_file_path<P: AsRef<Path>>(db_path: P) -> PathBuf {
|
|
db_path.as_ref().join(DB_VERSION_FILE_NAME)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::{check_db_version_file, db_version_file_path, DatabaseVersionError};
|
|
use assert_matches::assert_matches;
|
|
use std::fs;
|
|
use tempfile::tempdir;
|
|
|
|
#[test]
|
|
fn missing_file() {
|
|
let dir = tempdir().unwrap();
|
|
|
|
let result = check_db_version_file(&dir);
|
|
assert_matches!(result, Err(DatabaseVersionError::MissingFile));
|
|
}
|
|
|
|
#[test]
|
|
fn malformed_file() {
|
|
let dir = tempdir().unwrap();
|
|
fs::write(db_version_file_path(&dir), "invalid-version").unwrap();
|
|
|
|
let result = check_db_version_file(&dir);
|
|
assert_matches!(result, Err(DatabaseVersionError::MalformedFile));
|
|
}
|
|
|
|
#[test]
|
|
fn version_mismatch() {
|
|
let dir = tempdir().unwrap();
|
|
fs::write(db_version_file_path(&dir), "0").unwrap();
|
|
|
|
let result = check_db_version_file(&dir);
|
|
assert_matches!(result, Err(DatabaseVersionError::VersionMismatch { version: 0 }));
|
|
}
|
|
}
|