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: don't panic when the database is created by a higher version executable binary #2877

Merged
merged 2 commits into from
Jul 30, 2021
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
15 changes: 13 additions & 2 deletions ckb-bin/src/subcommand/migrate.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use ckb_app_config::{ExitCode, MigrateArgs};
use ckb_launcher::migrate::Migrate;
use std::cmp::Ordering;

use crate::helper::prompt;

Expand All @@ -13,15 +14,25 @@ pub fn migrate(args: MigrateArgs) -> Result<(), ExitCode> {
})?;

if let Some(db) = read_only_db {
let db_status = migrate.check(&db);
if matches!(db_status, Ordering::Greater) {
eprintln!(
"The database is created by a higher version CKB executable binary, \n\
so that the current CKB executable binary couldn't open this database.\n\
Please download the latest CKB executable binary."
);
return Err(ExitCode::Failure);
}

if args.check {
if migrate.check(&db) {
if matches!(db_status, Ordering::Less) {
return Ok(());
} else {
return Err(ExitCode::Cli);
}
}

if !migrate.check(&db) {
if matches!(db_status, Ordering::Equal) {
return Ok(());
}

Expand Down
31 changes: 23 additions & 8 deletions db-migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@
use ckb_db::{ReadOnlyDB, RocksDB};
use ckb_db_schema::{COLUMN_META, META_TIP_HEADER_KEY, MIGRATION_VERSION_KEY};
use ckb_error::{Error, InternalErrorKind};
use ckb_logger::{error, info};
use ckb_logger::{debug, error, info};
use console::Term;
pub use indicatif::{HumanDuration, MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle};
use std::cmp::Ordering;
use std::collections::BTreeMap;
use std::sync::Arc;

Expand Down Expand Up @@ -32,10 +33,15 @@ impl Migrations {
.insert(migration.version().to_string(), migration);
}

/// Check whether database requires migration
/// Check if database's version is matched with the executable binary version.
///
/// Return true if migration is required
pub fn check(&self, db: &ReadOnlyDB) -> bool {
/// Returns
/// - Less: The database version is less than the matched version of the executable binary.
/// Requires migration.
/// - Equal: The database version is matched with the executable binary version.
/// - Greater: The database version is greater than the matched version of the executable binary.
/// Requires upgrade the executable binary.
pub fn check(&self, db: &ReadOnlyDB) -> Ordering {
let db_version = match db
.get_pinned_default(MIGRATION_VERSION_KEY)
.expect("get the version of database")
Expand All @@ -46,15 +52,24 @@ impl Migrations {
None => {
// if version is none, but db is not empty
// patch 220464f
return self.is_non_empty_rdb(db);
if self.is_non_empty_rdb(db) {
return Ordering::Less;
} else {
return Ordering::Equal;
}
}
};
debug!("current database version [{}]", db_version);

self.migrations
let latest_version = self
.migrations
.values()
.last()
.map(|m| m.version() > db_version.as_str())
.unwrap_or(false)
.unwrap_or_else(|| panic!("should have at least one version"))
.version();
debug!("latest database version [{}]", latest_version);
doitian marked this conversation as resolved.
Show resolved Hide resolved

db_version.as_str().cmp(latest_version)
}

/// Check if the migrations will consume a lot of time.
Expand Down
12 changes: 10 additions & 2 deletions util/launcher/src/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use ckb_db::{ReadOnlyDB, RocksDB};
use ckb_db_migration::{DefaultMigration, Migrations};
use ckb_db_schema::{COLUMNS, COLUMN_META};
use ckb_error::Error;
use std::cmp::Ordering;
use std::path::PathBuf;

const INIT_DB_VERSION: &str = "20191127135521";
Expand Down Expand Up @@ -37,8 +38,15 @@ impl Migrate {
ReadOnlyDB::open_cf(&self.path, vec![COLUMN_META])
}

/// Return true if migration is required
pub fn check(&self, db: &ReadOnlyDB) -> bool {
/// Check if database's version is matched with the executable binary version.
///
/// Returns
/// - Less: The database version is less than the matched version of the executable binary.
/// Requires migration.
/// - Equal: The database version is matched with the executable binary version.
/// - Greater: The database version is greater than the matched version of the executable binary.
/// Requires upgrade the executable binary.
pub fn check(&self, db: &ReadOnlyDB) -> Ordering {
self.migrations.check(&db)
}

Expand Down
75 changes: 48 additions & 27 deletions util/launcher/src/shared_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use ckb_db::RocksDB;
use ckb_db_schema::COLUMNS;
use ckb_error::{Error, InternalErrorKind};
use ckb_freezer::Freezer;
use ckb_logger::info;
use ckb_notify::{NotifyController, NotifyService, PoolTransactionEntry};
use ckb_proposal_table::ProposalTable;
use ckb_proposal_table::ProposalView;
Expand All @@ -27,6 +28,7 @@ use ckb_types::core::HeaderView;
use ckb_types::packed::Byte32;
use ckb_verification::cache::init_cache;
use p2p::SessionId as PeerIndex;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use std::sync::atomic::AtomicBool;
Expand All @@ -51,43 +53,62 @@ pub fn open_or_create_db(
) -> Result<RocksDB, ExitCode> {
let migrate = Migrate::new(&config.path);

let mut db_exist = false;
let read_only_db = migrate.open_read_only_db().map_err(|e| {
eprintln!("migrate error {}", e);
ExitCode::Failure
})?;

// migration prompt
{
let read_only_db = migrate.open_read_only_db().map_err(|e| {
eprintln!("migrate error {}", e);
ExitCode::Failure
})?;

if let Some(db) = read_only_db {
db_exist = true;

if migrate.require_expensive(&db) {
if let Some(db) = read_only_db {
match migrate.check(&db) {
Ordering::Greater => {
eprintln!(
"For optimal performance, CKB wants to migrate the data into new format.\n\
You can use the old version CKB if you don't want to do the migration.\n\
We strongly recommended you to use the latest stable version of CKB, \
since the old versions may have unfixed vulnerabilities.\n\
Run `\"{}\" migrate -C \"{}\"` and confirm by typing \"YES\" to migrate the data.\n\
We strongly recommend that you backup the data directory before migration.",
bin_name,
root_dir.display()
"The database is created by a higher version CKB executable binary, \n\
so that the current CKB executable binary couldn't open this database.\n\
Please download the latest CKB executable binary."
);
return Err(ExitCode::Failure);
Err(ExitCode::Failure)
}
}
}
Ordering::Equal => Ok(RocksDB::open(config, COLUMNS)),
Ordering::Less => {
if migrate.require_expensive(&db) {
eprintln!(
"For optimal performance, CKB wants to migrate the data into new format.\n\
You can use the old version CKB if you don't want to do the migration.\n\
We strongly recommended you to use the latest stable version of CKB, \
since the old versions may have unfixed vulnerabilities.\n\
Run `\"{}\" migrate -C \"{}\"` and confirm by typing \"YES\" to migrate the data.\n\
We strongly recommend that you backup the data directory before migration.",
bin_name,
root_dir.display()
);
Err(ExitCode::Failure)
} else {
info!("process fast migrations ...");

let bulk_load_db_db = migrate.open_bulk_load_db().map_err(|e| {
eprintln!("migrate error {}", e);
ExitCode::Failure
})?;

if let Some(db) = bulk_load_db_db {
migrate.migrate(db).map_err(|err| {
eprintln!("Run error: {:?}", err);
ExitCode::Failure
})?;
}

let db = RocksDB::open(config, COLUMNS);
if !db_exist {
Ok(RocksDB::open(config, COLUMNS))
}
}
}
} else {
let db = RocksDB::open(config, COLUMNS);
migrate.init_db_version(&db).map_err(|e| {
eprintln!("migrate init_db_version error {}", e);
ExitCode::Failure
})?;
Ok(db)
}

Ok(db)
}

impl SharedBuilder {
Expand Down