Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(db): use the correct state version for databases without a state version file #7385

Merged
merged 2 commits into from
Aug 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 38 additions & 13 deletions zebra-state/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,12 @@ pub fn database_format_version_in_code() -> Version {
}

/// Returns the full semantic version of the on-disk database.
///
/// Typically, the version is read from a version text file.
///
/// If there is an existing on-disk database, but no version file, returns `Ok(Some(major.0.0))`.
/// (This happens even if the database directory was just newly created.)
///
/// If there is no existing on-disk database, returns `Ok(None)`.
///
/// This is the format of the data on disk, the minor and patch versions
Expand All @@ -318,25 +324,44 @@ pub fn database_format_version_on_disk(
) -> Result<Option<Version>, BoxError> {
let version_path = config.version_file_path(network);

let version = match fs::read_to_string(version_path) {
Ok(version) => version,
let disk_version_file = match fs::read_to_string(version_path) {
Ok(version) => Some(version),
Err(e) if e.kind() == ErrorKind::NotFound => {
// If the version file doesn't exist, don't guess the version.
// (It will end up being the version in code, once the database is created.)
return Ok(None);
// If the version file doesn't exist, don't guess the version yet.
None
}
Err(e) => Err(e)?,
};

let (minor, patch) = version
.split_once('.')
.ok_or("invalid database format version file")?;
// The database has a version file on disk
if let Some(version) = disk_version_file {
let (minor, patch) = version
.split_once('.')
.ok_or("invalid database format version file")?;

return Ok(Some(Version::new(
DATABASE_FORMAT_VERSION,
minor.parse()?,
patch.parse()?,
)));
}

Ok(Some(Version::new(
DATABASE_FORMAT_VERSION,
minor.parse()?,
patch.parse()?,
)))
let db_path = config.db_path(network);

// There's no version file on disk, so we need to guess the version
// based on the database content
match fs::metadata(db_path) {
// But there is a database on disk, so it has the current major version with no upgrades.
// If the database directory was just newly created, we also return this version.
Ok(_metadata) => Ok(Some(Version::new(DATABASE_FORMAT_VERSION, 0, 0))),

// There's no version file and no database on disk, so it's a new database.
// It will be created with the current version,
// but temporarily return the default version above until the version file is written.
upbqdn marked this conversation as resolved.
Show resolved Hide resolved
Err(e) if e.kind() == ErrorKind::NotFound => Ok(None),

Err(e) => Err(e)?,
}
}

/// Writes `changed_version` to the on-disk database after the format is changed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use DbFormatChange::*;

use crate::{
config::write_database_format_version_to_disk,
constants::DATABASE_FORMAT_VERSION,
database_format_version_in_code, database_format_version_on_disk,
service::finalized_state::{DiskWriteBatch, ZebraDb},
Config,
Expand Down Expand Up @@ -478,8 +479,12 @@ impl DbFormatChange {
.expect("unable to read database format version file path");
let running_version = database_format_version_in_code();

let default_new_version = Some(Version::new(DATABASE_FORMAT_VERSION, 0, 0));

// The database version isn't empty any more, because we've created the RocksDB database
// and acquired its lock. (If it is empty, we have a database locking bug.)
assert_eq!(
disk_version, None,
disk_version, default_new_version,
"can't overwrite the format version in an existing database:\n\
disk: {disk_version:?}\n\
running: {running_version}"
Expand Down
4 changes: 4 additions & 0 deletions zebra-state/src/service/finalized_state/zebra_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ impl ZebraDb {
// Open the database and do initial checks.
let mut db = ZebraDb {
format_change_handle: None,
// After the database directory is created, a newly created database temporarily
// changes to the default database version. Then we set the correct version in the
// upgrade thread. We need to do the version change in this order, because the version
// file can only be changed while we hold the RocksDB database lock.
db: DiskDb::new(config, network),
};

Expand Down