fix migration system, better errors (#2661)

This commit is contained in:
Tomasz Drwięga 2016-10-18 16:34:58 +02:00 committed by Gav Wood
parent e0778fc069
commit 1df84a8e28
2 changed files with 25 additions and 13 deletions

View File

@ -43,13 +43,15 @@ pub enum Error {
/// Returned when current version cannot be read or guessed. /// Returned when current version cannot be read or guessed.
UnknownDatabaseVersion, UnknownDatabaseVersion,
/// Migration does not support existing pruning algorithm. /// Migration does not support existing pruning algorithm.
UnsuportedPruningMethod, UnsupportedPruningMethod,
/// Existing DB is newer than the known one. /// Existing DB is newer than the known one.
FutureDBVersion, FutureDBVersion,
/// Migration is not possible. /// Migration is not possible.
MigrationImpossible, MigrationImpossible,
/// Migration unexpectadly failed. /// Migration unexpectadly failed.
MigrationFailed, MigrationFailed,
/// Internal migration error.
Internal(MigrationError),
/// Migration was completed succesfully, /// Migration was completed succesfully,
/// but there was a problem with io. /// but there was a problem with io.
Io(IoError), Io(IoError),
@ -59,10 +61,11 @@ impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> { fn fmt(&self, f: &mut Formatter) -> Result<(), FmtError> {
let out = match *self { let out = match *self {
Error::UnknownDatabaseVersion => "Current database version cannot be read".into(), Error::UnknownDatabaseVersion => "Current database version cannot be read".into(),
Error::UnsuportedPruningMethod => "Unsupported pruning method for database migration. Delete DB and resync.".into(), Error::UnsupportedPruningMethod => "Unsupported pruning method for database migration. Delete DB and resync.".into(),
Error::FutureDBVersion => "Database was created with newer client version. Upgrade your client or delete DB and resync.".into(), Error::FutureDBVersion => "Database was created with newer client version. Upgrade your client or delete DB and resync.".into(),
Error::MigrationImpossible => format!("Database migration to version {} is not possible.", CURRENT_VERSION), Error::MigrationImpossible => format!("Database migration to version {} is not possible.", CURRENT_VERSION),
Error::MigrationFailed => "Database migration unexpectedly failed".into(), Error::MigrationFailed => "Database migration unexpectedly failed".into(),
Error::Internal(ref err) => format!("{}", err),
Error::Io(ref err) => format!("Unexpected io error on DB migration: {}.", err), Error::Io(ref err) => format!("Unexpected io error on DB migration: {}.", err),
}; };
@ -80,7 +83,7 @@ impl From<MigrationError> for Error {
fn from(err: MigrationError) -> Self { fn from(err: MigrationError) -> Self {
match err { match err {
MigrationError::Io(e) => Error::Io(e), MigrationError::Io(e) => Error::Io(e),
_ => Error::MigrationFailed, _ => Error::Internal(err),
} }
} }
} }
@ -336,7 +339,7 @@ mod legacy {
let res = match pruning { let res = match pruning {
Algorithm::Archive => manager.add_migration(migrations::state::ArchiveV7::default()), Algorithm::Archive => manager.add_migration(migrations::state::ArchiveV7::default()),
Algorithm::OverlayRecent => manager.add_migration(migrations::state::OverlayRecentV7::default()), Algorithm::OverlayRecent => manager.add_migration(migrations::state::OverlayRecentV7::default()),
_ => return Err(Error::UnsuportedPruningMethod), _ => return Err(Error::UnsupportedPruningMethod),
}; };
try!(res.map_err(|_| Error::MigrationImpossible)); try!(res.map_err(|_| Error::MigrationImpossible));

View File

@ -20,6 +20,7 @@ mod tests;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::fs; use std::fs;
use std::fmt;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use ::kvdb::{CompactionProfile, Database, DatabaseConfig, DBTransaction}; use ::kvdb::{CompactionProfile, Database, DatabaseConfig, DBTransaction};
@ -96,6 +97,17 @@ pub enum Error {
Custom(String), Custom(String),
} }
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Error::CannotAddMigration => write!(f, "Cannot add migration"),
Error::MigrationImpossible => write!(f, "Migration impossible"),
Error::Io(ref err) => write!(f, "{}", err),
Error::Custom(ref err) => write!(f, "{}", err),
}
}
}
impl From<::std::io::Error> for Error { impl From<::std::io::Error> for Error {
fn from(e: ::std::io::Error) -> Self { fn from(e: ::std::io::Error) -> Self {
Error::Io(e) Error::Io(e)
@ -110,6 +122,8 @@ impl From<String> for Error {
/// A generalized migration from the given db to a destination db. /// A generalized migration from the given db to a destination db.
pub trait Migration: 'static { pub trait Migration: 'static {
/// Number of columns in the database before the migration.
fn pre_columns(&self) -> Option<u32> { self.columns() }
/// Number of columns in database after the migration. /// Number of columns in database after the migration.
fn columns(&self) -> Option<u32>; fn columns(&self) -> Option<u32>;
/// Version of the database after the migration. /// Version of the database after the migration.
@ -201,6 +215,7 @@ impl Manager {
Some(last) => migration.version() > last.version(), Some(last) => migration.version() > last.version(),
None => true, None => true,
}; };
match is_new { match is_new {
true => Ok(self.migrations.push(Box::new(migration))), true => Ok(self.migrations.push(Box::new(migration))),
false => Err(Error::CannotAddMigration), false => Err(Error::CannotAddMigration),
@ -211,9 +226,11 @@ impl Manager {
/// and producing a path where the final migration lives. /// and producing a path where the final migration lives.
pub fn execute(&mut self, old_path: &Path, version: u32) -> Result<PathBuf, Error> { pub fn execute(&mut self, old_path: &Path, version: u32) -> Result<PathBuf, Error> {
let config = self.config.clone(); let config = self.config.clone();
let columns = self.no_of_columns_at(version);
let migrations = self.migrations_from(version); let migrations = self.migrations_from(version);
if migrations.is_empty() { return Err(Error::MigrationImpossible) }; if migrations.is_empty() { return Err(Error::MigrationImpossible) };
let columns = migrations.iter().find(|m| m.version() == version).and_then(|m| m.pre_columns());
let mut db_config = DatabaseConfig { let mut db_config = DatabaseConfig {
max_open_files: 64, max_open_files: 64,
cache_size: None, cache_size: None,
@ -273,14 +290,6 @@ impl Manager {
fn migrations_from(&mut self, version: u32) -> Vec<&mut Box<Migration>> { fn migrations_from(&mut self, version: u32) -> Vec<&mut Box<Migration>> {
self.migrations.iter_mut().filter(|m| m.version() > version).collect() self.migrations.iter_mut().filter(|m| m.version() > version).collect()
} }
fn no_of_columns_at(&self, version: u32) -> Option<u32> {
let migration = self.migrations.iter().find(|m| m.version() == version);
match migration {
Some(m) => m.columns(),
None => None
}
}
} }
/// Prints a dot every `max` ticks /// Prints a dot every `max` ticks