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

readonly for migrate check #2629

Merged
merged 2 commits into from
Mar 25, 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
2 changes: 1 addition & 1 deletion ckb-bin/src/subcommand/migrate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pub fn migrate(args: MigrateArgs, async_handle: Handle) -> Result<(), ExitCode>
}
}

let (_shared, _table) = builder.build().map_err(|err| {
let (_shared, _table) = builder.consensus(args.consensus).build().map_err(|err| {
eprintln!("Run error: {:?}", err);
ExitCode::Failure
})?;
Expand Down
6 changes: 3 additions & 3 deletions db-migration/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
//! TODO(doc): @quake
use ckb_db::RocksDB;
use ckb_db::{ReadOnlyDB, RocksDB};
use ckb_db_schema::MIGRATION_VERSION_KEY;
use ckb_error::{Error, InternalErrorKind};
use ckb_logger::{error, info};
Expand Down Expand Up @@ -35,7 +35,7 @@ impl Migrations {
/// Check whether database requires migration
///
/// Return true if migration is required
pub fn check(&self, db: &RocksDB) -> bool {
pub fn check(&self, db: &ReadOnlyDB) -> bool {
let db_version = match db
.get_pinned_default(MIGRATION_VERSION_KEY)
.expect("get the version of database")
Expand All @@ -54,7 +54,7 @@ impl Migrations {
}

/// Check if the migrations will consume a lot of time.
pub fn expensive(&self, db: &RocksDB) -> bool {
pub fn expensive(&self, db: &ReadOnlyDB) -> bool {
let db_version = match db
.get_pinned_default(MIGRATION_VERSION_KEY)
.expect("get the version of database")
Expand Down
2 changes: 2 additions & 0 deletions db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,14 @@ use std::{fmt, result};

pub mod db;
pub mod iter;
pub mod read_only_db;
pub mod snapshot;
pub mod transaction;
pub mod write_batch;

pub use crate::db::RocksDB;
pub use crate::iter::DBIterator;
pub use crate::read_only_db::ReadOnlyDB;
pub use crate::snapshot::RocksDBSnapshot;
pub use crate::transaction::{RocksDBTransaction, RocksDBTransactionSnapshot};
pub use crate::write_batch::RocksDBWriteBatch;
Expand Down
76 changes: 76 additions & 0 deletions db/src/read_only_db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
//! ReadOnlyDB wrapper base on rocksdb read_only_open mode
use crate::{internal_error, Result};
use ckb_logger::info;
use rocksdb::ops::{GetPinned, Open};
use rocksdb::{DBPinnableSlice, Options, ReadOnlyDB as RawReadOnlyDB};
use std::path::Path;
use std::sync::Arc;

/// ReadOnlyDB wrapper
pub struct ReadOnlyDB {
pub(crate) inner: Arc<RawReadOnlyDB>,
}

impl ReadOnlyDB {
/// The behavior is similar to DB::Open,
/// except that it opens DB in read-only mode.
/// One big difference is that when opening the DB as read-only,
/// you don't need to specify all Column Families
/// -- you can only open a subset of Column Families.
pub fn open<P: AsRef<Path>>(path: P) -> Result<Option<Self>> {
let opts = Options::default();
RawReadOnlyDB::open(&opts, path).map_or_else(
|err| {
let err_str = err.as_ref();
// notice: err msg difference
if err_str.starts_with("NotFound")
&& err_str.ends_with("does not exist")
{
Ok(None)
} else if err_str.starts_with("Corruption:") {
info!(
"DB corrupted: {}.\n\
Try ckb db-repair command to repair DB.\n\
Note: Currently there is a limitation that un-flushed column families will be lost after repair.\
This would happen even if the DB is in healthy state.\n\
See https://github.com/facebook/rocksdb/wiki/RocksDB-Repairer for detail",
err_str
);
Err(internal_error("DB corrupted"))
} else {
Err(internal_error(format!(
"failed to open the database: {}",
err
)))
}
},
|db| {
Ok(Some(ReadOnlyDB {
inner: Arc::new(db),
}))
},
)
}

/// Return the value associated with a key using RocksDB's PinnableSlice from the default column
/// so as to avoid unnecessary memory copy.
pub fn get_pinned_default(&self, key: &[u8]) -> Result<Option<DBPinnableSlice>> {
self.inner.get_pinned(&key).map_err(internal_error)
}
}

#[cfg(test)]
mod tests {
use super::ReadOnlyDB;

#[test]
fn test_open_read_only_not_exist() {
let tmp_dir = tempfile::Builder::new()
.prefix("test_open_read_only_not_exist")
.tempdir()
.unwrap();

let db = ReadOnlyDB::open(&tmp_dir);
assert!(matches!(db, Ok(x) if x.is_none()))
}
}
6 changes: 3 additions & 3 deletions shared/src/shared.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ckb_chain_spec::consensus::Consensus;
use ckb_chain_spec::SpecError;
use ckb_constant::store::TX_INDEX_UPPER_BOUND;
use ckb_constant::sync::MAX_TIP_AGE;
use ckb_db::{Direction, IteratorMode, RocksDB};
use ckb_db::{Direction, IteratorMode, ReadOnlyDB, RocksDB};
use ckb_db_migration::{DefaultMigration, Migrations};
use ckb_db_schema::COLUMN_BLOCK_BODY;
use ckb_db_schema::{COLUMNS, COLUMN_NUMBER_HASH};
Expand Down Expand Up @@ -569,15 +569,15 @@ impl SharedBuilder {
///
/// Return true if migration is required
pub fn migration_check(&self) -> bool {
RocksDB::prepare_for_bulk_load_open(&self.db_config.path, COLUMNS)
ReadOnlyDB::open(&self.db_config.path)
.unwrap_or_else(|err| panic!("{}", err))
.map(|db| self.migrations.check(&db))
.unwrap_or(false)
}

/// Check whether database requires expensive migrations.
pub fn require_expensive_migrations(&self) -> bool {
RocksDB::prepare_for_bulk_load_open(&self.db_config.path, COLUMNS)
ReadOnlyDB::open(&self.db_config.path)
.unwrap_or_else(|err| panic!("{}", err))
.map(|db| self.migrations.expensive(&db))
.unwrap_or(false)
Expand Down
2 changes: 2 additions & 0 deletions util/app-config/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ pub struct PeerIDArgs {
pub struct MigrateArgs {
/// The parsed `ckb.toml.`
pub config: Box<CKBAppConfig>,
/// Loaded consensus.
pub consensus: Consensus,
/// Check whether it is required to do migration instead of really perform the migration.
pub check: bool,
/// Do migration without interactive prompt.
Expand Down
2 changes: 2 additions & 0 deletions util/app-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,14 @@ impl Setup {

/// `migrate` subcommand has one `flags` arg, trigger this arg with "--check"
pub fn migrate<'m>(self, matches: &ArgMatches<'m>) -> Result<MigrateArgs, ExitCode> {
let consensus = self.consensus()?;
let config = self.config.into_ckb()?;
let check = matches.is_present(cli::ARG_MIGRATE_CHECK);
let force = matches.is_present(cli::ARG_FORCE);

Ok(MigrateArgs {
config,
consensus,
check,
force,
})
Expand Down