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

Prepare release v0.14.0 "Hakuna Matata" 🐗 🦁 #3594

Merged
merged 2 commits into from
Oct 16, 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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@

### Added

### Changed

### Removed

### Fixed

## Forest v0.14.0 "Hakuna Matata"

### Breaking

### Added

- [#3422](https://github.com/ChainSafe/forest/issues/3422) Add NV21 (Watermelon)
support for calibration network.

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "forest-filecoin"
version = "0.13.0"
version = "0.14.0"
authors = ["ChainSafe Systems <[email protected]>"]
repository = "https://github.com/ChainSafe/forest"
edition = "2021"
Expand Down
62 changes: 50 additions & 12 deletions src/db/migration/migration_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ use semver::Version;
use tracing::info;

use super::v0_12_1::Migration0_12_1_0_13_0;
use super::void_migration::MigrationVoid;

/// Migration trait. It is expected that the [`MigrationOperation::migrate`] method will pick up the relevant database
/// existing under `chain_data_path` and create a new migration database in the same directory.
pub(super) trait MigrationOperation {
fn new(from: Version, to: Version) -> Self
where
Self: Sized;
/// Performs pre-migration checks. This is the place to check if the database is in a valid
/// state and if the migration can be performed. Note that some of the higher-level checks
/// (like checking if the database exists) are performed by the [`Migration`].
Expand All @@ -32,6 +36,8 @@ pub(super) trait MigrationOperation {
/// Performs post-migration checks. This is the place to check if the migration database is
/// ready to be used by Forest and renamed into a versioned database.
fn post_checks(&self, chain_data_path: &Path) -> anyhow::Result<()>;
/// Returns the name of the temporary database that will be created during the migration.
fn temporary_db_name(&self) -> String;
}

/// Migrations map. The key is the starting version and the value is the tuple of the target version
Expand All @@ -48,15 +54,18 @@ type MigrationsMap = MultiMap<Version, (Version, Migrator)>;
/// The usage is:
/// `<FROM version> -> <TO version> @ <Migrator object>`
macro_rules! create_migrations {
($($from:literal -> $to:literal @ $migration:path),* $(,)?) => {
($($from:literal -> $to:literal @ $migration:tt),* $(,)?) => {
pub(super) static MIGRATIONS: Lazy<MigrationsMap> = Lazy::new(|| {
MigrationsMap::from_iter(
[
$((
Version::from_str($from).unwrap(),
(
Version::from_str($to).unwrap(),
Arc::new($migration) as _,
Arc::new($migration::new(
$from.parse().expect("invalid <from> version"),
$to.parse().expect("invalid <to> version")))
as _,
)),
)*
]
Expand All @@ -68,6 +77,7 @@ pub(super) static MIGRATIONS: Lazy<MigrationsMap> = Lazy::new(|| {

create_migrations!(
"0.12.1" -> "0.13.0" @ Migration0_12_1_0_13_0,
"0.13.0" -> "0.14.0" @ MigrationVoid,
);

pub struct Migration {
Expand Down Expand Up @@ -259,6 +269,17 @@ mod tests {
fn post_checks(&self, _chain_data_path: &Path) -> anyhow::Result<()> {
Ok(())
}

fn new(_from: Version, _to: Version) -> Self
where
Self: Sized,
{
Self {}
}

fn temporary_db_name(&self) -> String {
"".into()
}
}

#[test]
Expand Down Expand Up @@ -385,37 +406,54 @@ mod tests {
}
}

struct SimpleMigration0_1_0_0_2_0;
struct SimpleMigration0_1_0_0_2_0 {
from: Version,
to: Version,
}

impl MigrationOperation for SimpleMigration0_1_0_0_2_0 {
fn pre_checks(&self, chain_data_path: &Path) -> anyhow::Result<()> {
let path = chain_data_path.join("0.1.0");
let path = chain_data_path.join(self.from.to_string());
if !path.exists() {
anyhow::bail!("0.1.0 does not exist");
anyhow::bail!("{} does not exist", self.from);
}
Ok(())
}

fn migrate(&self, chain_data_path: &Path) -> anyhow::Result<PathBuf> {
fs::create_dir(chain_data_path.join("migration_0_1_0_0_2_0")).unwrap();
Ok(chain_data_path.join("migration_0_1_0_0_2_0"))
let temp_db_path = chain_data_path.join(self.temporary_db_name());
fs::create_dir(&temp_db_path).unwrap();
Ok(temp_db_path)
}

fn post_checks(&self, chain_data_path: &Path) -> anyhow::Result<()> {
let path = chain_data_path.join("migration_0_1_0_0_2_0");
let path = chain_data_path.join(self.temporary_db_name());
if !path.exists() {
anyhow::bail!("migration_0_1_0_0_2_0 does not exist");
anyhow::bail!("{} does not exist", path.display());
}
Ok(())
}

fn new(from: Version, to: Version) -> Self
where
Self: Sized,
{
Self { from, to }
}

fn temporary_db_name(&self) -> String {
format!("migration_{}_{}", self.from, self.to).replace('.', "_")
}
}

#[test]
fn test_migration_map_migration() {
let from = Version::new(0, 1, 0);
let to = Version::new(0, 2, 0);
let migration = Migration {
from: Version::new(0, 1, 0),
to: Version::new(0, 2, 0),
migrator: Arc::new(SimpleMigration0_1_0_0_2_0),
from: from.clone(),
to: to.clone(),
migrator: Arc::new(SimpleMigration0_1_0_0_2_0::new(from, to)),
};

let temp_dir = TempDir::new().unwrap();
Expand Down
1 change: 1 addition & 0 deletions src/db/migration/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
mod db_migration;
mod migration_map;
mod v0_12_1;
mod void_migration;

pub use db_migration::DbMigration;
30 changes: 21 additions & 9 deletions src/db/migration/v0_12_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@
//! coming from the rolling database and ParityDb.

use fs_extra::dir::CopyOptions;
use semver::Version;
use std::path::{Path, PathBuf};
use tracing::info;

use super::migration_map::MigrationOperation;

#[derive(Default)]
pub(super) struct Migration0_12_1_0_13_0;

/// Temporary database path for the migration.
const MIGRATION_DB_0_12_1_0_13_0: &str = "migration_0_12_1_to_0_13_0";
pub(super) struct Migration0_12_1_0_13_0 {
from: Version,
to: Version,
}

/// Migrates the database from version 0.12.1 to 0.13.0
/// This migration is needed because the `Settings` column in the `ParityDb` table changed to
Expand All @@ -29,9 +29,9 @@ impl MigrationOperation for Migration0_12_1_0_13_0 {
}

fn migrate(&self, chain_data_path: &Path) -> anyhow::Result<PathBuf> {
let source_db = chain_data_path.join("0.12.1");
let source_db = chain_data_path.join(self.from.to_string());

let temp_db_path = chain_data_path.join(MIGRATION_DB_0_12_1_0_13_0);
let temp_db_path = chain_data_path.join(self.temporary_db_name());
if temp_db_path.exists() {
info!(
"removing old temporary database {temp_db_path}",
Expand Down Expand Up @@ -137,14 +137,26 @@ impl MigrationOperation for Migration0_12_1_0_13_0 {
}

fn post_checks(&self, chain_data_path: &Path) -> anyhow::Result<()> {
if !chain_data_path.join(MIGRATION_DB_0_12_1_0_13_0).exists() {
let temp_db_name = self.temporary_db_name();
if !chain_data_path.join(&temp_db_name).exists() {
anyhow::bail!(
"migration database {} does not exist",
chain_data_path.join(MIGRATION_DB_0_12_1_0_13_0).display()
chain_data_path.join(temp_db_name).display()
);
}
Ok(())
}

fn new(from: Version, to: Version) -> Self
where
Self: Sized,
{
Self { from, to }
}

fn temporary_db_name(&self) -> String {
format!("migration_{}_{}", self.from, self.to).replace('.', "_")
}
}

/// Database settings from Forest `v0.12.1`
Expand Down
107 changes: 107 additions & 0 deletions src/db/migration/void_migration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
// Copyright 2019-2023 ChainSafe Systems
// SPDX-License-Identifier: Apache-2.0, MIT

//! Migration logic from any version that requires no migration logic.

use fs_extra::dir::CopyOptions;
use semver::Version;
use std::path::{Path, PathBuf};
use tracing::info;

use super::migration_map::MigrationOperation;

pub(super) struct MigrationVoid {
from: Version,
to: Version,
}

impl MigrationOperation for MigrationVoid {
fn pre_checks(&self, _chain_data_path: &Path) -> anyhow::Result<()> {
Ok(())
}

fn migrate(&self, chain_data_path: &Path) -> anyhow::Result<PathBuf> {
let source_db = chain_data_path.join(self.from.to_string());

let temp_db_path = chain_data_path.join(self.temporary_db_name());
if temp_db_path.exists() {
info!(
"removing old temporary database {temp_db_path}",
temp_db_path = temp_db_path.display()
);
std::fs::remove_dir_all(&temp_db_path)?;
}

info!(
"copying old database from {source_db} to {temp_db_path}",
source_db = source_db.display(),
temp_db_path = temp_db_path.display()
);
fs_extra::copy_items(
&[source_db.as_path()],
temp_db_path.clone(),
&CopyOptions::default().copy_inside(true),
)?;

Ok(temp_db_path)
}

fn post_checks(&self, chain_data_path: &Path) -> anyhow::Result<()> {
let temp_db_name = self.temporary_db_name();
if !chain_data_path.join(&temp_db_name).exists() {
anyhow::bail!(
"migration database {} does not exist",
chain_data_path.join(temp_db_name).display()
);
}
Ok(())
}

fn new(from: Version, to: Version) -> Self
where
Self: Sized,
{
Self { from, to }
}

fn temporary_db_name(&self) -> String {
format!("migration_{}_{}", self.from, self.to).replace('.', "_")
}
}

#[cfg(test)]
mod test {
use super::*;
use semver::Version;
use tempfile::TempDir;

#[test]
fn test_migration_void() {
let migration = MigrationVoid::new(Version::new(1, 0, 0), Version::new(1, 0, 1));
let chain_data_path = TempDir::new().unwrap();

// create a file in the temporary database directory, under a directory (to ensure that the
// directory is copied recursively).
let content_dir = chain_data_path.path().join("1.0.0").join("R'lyeh");
std::fs::create_dir_all(&content_dir).unwrap();

let content_file = content_dir.join("cthulhu");
let chant = "ph'nglui mglw'nafh Cthulhu R'lyeh wgah'nagl fhtagn";
std::fs::write(content_file, chant).unwrap();

let path = chain_data_path.path();
migration.pre_checks(path).unwrap();
let temp_db_path = migration.migrate(path).unwrap();
migration.post_checks(path).unwrap();

// check that the temporary database directory exists and contains the file with the
// expected content.
let temp_db_content_dir = temp_db_path.join("R'lyeh");
let temp_db_content_file = temp_db_content_dir.join("cthulhu");
assert!(temp_db_content_file.exists());
assert_eq!(
std::fs::read_to_string(temp_db_content_file).unwrap(),
chant
);
}
}