fix(db): use the correct state version for databases without a state version file (#7385)
* If there's an existing database with no version file, give it version 25.0.0 * Creating the RocksDB database makes a temporary change to the default database version
This commit is contained in:
parent
798b271279
commit
c116cff5f0
|
@ -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
|
||||
|
@ -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")?;
|
||||
|
||||
Ok(Some(Version::new(
|
||||
DATABASE_FORMAT_VERSION,
|
||||
minor.parse()?,
|
||||
patch.parse()?,
|
||||
)))
|
||||
return 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.
|
||||
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.
|
||||
|
|
|
@ -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,
|
||||
|
@ -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}"
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue