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

WIP: Downgrade schema v5 to v4 #2685

Closed

Conversation

winksaville
Copy link
Contributor

No description provided.

@winksaville winksaville marked this pull request as draft October 7, 2021 04:25
@winksaville
Copy link
Contributor Author

@michaelsproul, initial stab at downgrade, still need to add the db downgrade cli command, but would appreciate it if you could spare a few minutes to catch obvious errors.

Copy link
Member

@michaelsproul michaelsproul left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good!

Just one suggestion

Thanks for taking the time to implement this 😊

beacon_node/beacon_chain/src/schema_change.rs Outdated Show resolved Hide resolved
@michaelsproul michaelsproul added the work-in-progress PR is a work-in-progress label Oct 7, 2021
@winksaville
Copy link
Contributor Author

@michaelsproul , I added commit "Initial stab at a database_manager Ui", when you have time please take look.

Questions:

  • Is the sub-command database_manager OK?
  • Is open_as_is the right direction for "opening" the database?
  • What do you advise is the proper way to initialize the parameters to open_as_is?

Txs!

@michaelsproul
Copy link
Member

Is the sub-command database_manager OK?

Yep! We can alias it easily enough at the CLI to lighthouse db if we want

Is open_as_is the right direction for "opening" the database?

Yeah, although you could keep open the same and just pass a no-op schema upgrade like |_, _, _| Ok(()).

What do you advise is the proper way to initialize the parameters to open_as_is?

This one's a bit trickier. Currently the DB is only opened from the BN subcommand, so its config file parsing is embedded into the BN config, e.g. here:

/// Name of the directory inside the data directory where the main "hot" DB is located.
pub db_name: String,
/// Path where the freezer database will be located.
pub freezer_db_path: Option<PathBuf>,

To avoid getting entangled in that I think we could have 3 separate flags for the database_manager:

  • --datadir for setting the datadir. The best utility for determining this is get_data_dir in the BN directory, so you may need to make database_manager depend on beacon_node. Set the hot DB path to $datadir/beacon/chain_db.
  • --freezer-dir for setting the freezer DB. If not provided it should default to $datadir/beacon/freezer_db.
  • --slots-per-restore-point, default 2048.

The StoreConfig can be constructed with default values for its other fields (they're not really relevant):

let store_config = StoreConfig {
    slots_per_restore_point, /* from CLI or 2048 */
    ..StoreConfig::default()
};

Finally, for the ChainSpec, that's best sourced from a network configuration. So we should have a --network flag, which can be parsed by get_eth2_network_config (also in beacon_node). Given a NetworkConfig we can get the ChainSpec using chain_spec:

/// Construct a consolidated `ChainSpec` from the YAML config.
pub fn chain_spec<E: EthSpec>(&self) -> Result<ChainSpec, String> {
ChainSpec::from_config::<E>(&self.config).ok_or_else(|| {
format!(
"YAML configuration incompatible with spec constants for {}",
E::spec_name()
)
})
}

Sorry, I know that's a lot! Hope that helps!

@winksaville winksaville force-pushed the Downgrade-schema-v5-to-v4 branch 2 times, most recently from 32711d5 to cea2f22 Compare October 10, 2021 19:10
HotColdDB::open_as_is(hot_path.as_path(), cold_path.as_path(), config, spec, log)?;
let schema_version = db.load_schema_version()?;

println!("database version: {:?}", schema_version);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelsproul have I done something wrong, why is schema_version None?

wink@3900x:~/prgs/ethereum/myrepos/lighthouse (Downgrade-schema-v5-to-v4)
$ cargo run --bin lighthouse db -v
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/lighthouse db -v`
Running database manager for mainnet network
database version: None

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks OK to me. Are you running this against a database that already exists?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's a new database in a the tempdir.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense then, open_as_is never writes the schema version because that happens when the migration runs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelsproul I've got a solution, open_as_is now returns db and schema version. Does that work for you?

It now returns both the db and and its schema_version.

Now we get the expected schema_version:
```
wink@3900x:~/prgs/ethereum/myrepos/lighthouse (Downgrade-schema-v5-to-v4)
$ cargo run --bin lighthouse db -v
    Finished dev [unoptimized + debuginfo] target(s) in 0.21s
     Running `target/debug/lighthouse db -v`
Running database manager for mainnet network
database version: SchemaVersion(5)
```
Cannot figure out how to invoke migrate_schema as it's a generic function
that must implement the `pub trait BeaconChainTypes`. The two only places
where migrate_schema is called are:

 - Recursively in the implementation itself in
   beacon_node/beacon_chain/src/schema_change.rs

 - beacon_node/store/srch/hot_cold_store.rs::open where it's passed
   as a fn parameter in a call from
   beacon_node/client/src/builder.rs::disk_store

Example:
```
  wink@3900x:~/prgs/ethereum/myrepos/lighthouse (Downgrade-schema-v5-to-v4)
  $ cargo run --bin lighthouse db dg
      Finished dev [unoptimized + debuginfo] target(s) in 0.20s
       Running `target/debug/lighthouse db dg`
  Running database manager for mainnet network
  downgrade database version 5 to 4
```
Comment on lines 144 to 156
// Cannot figure out how to invoke migrate_schema as it's a generic function
// that must implement the `pub trait BeaconChainTypes`. The two only places
// where migrate_schema is called are:
//
// - Recursively in the implementation itself in
// beacon_node/beacon_chain/src/schema_change.rs
//
// - beacon_node/store/srch/hot_cold_store.rs::open where it's passed
// as a fn parameter in a call from
// beacon_node/client/src/builder.rs::disk_store

//migrate_schema::Witness<TSlotClock, TEth1Backend, TEthSpec, THotStore, TColdStore>(_db, datadir.path(), from, to)?;
//migrate_schema::<_>(_db, datadir.path(), from, to)?;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelsproul, started working on downgrade and I can't figure out how to call migrate_schema. needs "Witness" magic which is way beyond my rust knowledge :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah this is a little bit clunky for our purposes but we can work around it by providing (arbitrary) types for the SlotClock and Eth1Chain like this:

migrate_schema::<Witness<SystemTimeSlotClock, CachingEth1Backend<E>, E, LevelDB<E>, LevelDB<E>>(..)

Type inference should be able to work out the rest if we just hint the first two:

migrate_schema::<Witness<SystemTimeSlotClock, CachingEth1Backend<E>, _, _, _>(..)

Witness, SystemTimeSlotClock and CachingEth1Backend will also need to be imported from their respective crates. Let us know if you have issues

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@michaelsproul , it is now "working", TYVM!

Could you provide a link or background information on what is going on and why this works?

I saw that @paulhauner added this code in #542 and the indirect call in open was so there wouldn't be a circular code. But I didn't see anything explaining the need for a Witness other than in the code we see:

/// An empty struct used to "witness" all the `BeaconChainTypes` traits. It has no user-facing
/// functionality and only exists to satisfy the type system.
pub struct Witness<TSlotClock, TEth1Backend, TEthSpec, THotStore, TColdStore>(
    PhantomData<(TSlotClock, TEth1Backend, TEthSpec, THotStore, TColdStore)>,
);

Which doesn't help me with why we have to go to a lot of trouble to convince the type system this call is Ok.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's all in aid of the BeaconChainBuilder, which allows us to build BeaconChains instantiated with various concrete types for the different components (the slot clock, the eth1 backend, the database, and most importantly the EthSpec which chooses between minimal and mainnet presets).

In the builder's case we don't need to specify the witness type manually because it can be inferred by the compiler when the builder methods are called. E.g. the testing_slot_clock method is specialised to TSlotClock = TestingSlotClock so if the compiler sees a builder.testing_slot_clock(..) call it can infer that the slot clock type is TestingSlotClock.

The reason migrate_schema is a bit unwieldy is because it was moved from within the store crate (where it didn't care about witnesses) to the beacon_chain crate, in order to get access to the ValidatorPubkeyCache. For better or for worse, the ValidatorPubkeyCache is parametrised by <T: BeaconChainTypes>, so that ripples up to the top-level. Until now migrate_schema was only called from the builder/beacon chain where a witness was already known.

I think the manual type hint is an OK solution for now, as it avoids us having to refactor (unrelated) code in the ValidatorPubkeyCache and gives migrate_schema the flexibility to interact with other types parametrised by a witness in future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree it's.OK for now, but it's the first time that neither me, rust-analyzer or rustc could figure out the right type hints. Which really makes me feel something isn't right. Probably with more rust experience I could have figured it out, but if a refactoring would make it more obvious I'd say it would be worth it. But, again, I agree not in this PR.

These are unconditional and maybe used without needing having to
declare using a feature.
Thanks to Michael Sproul for providing the necessary type information
it now "works":
```
wink@3900x:~/prgs/ethereum/myrepos/lighthouse (Downgrade-schema-v5-to-v4)
$ cargo run --bin lighthouse db dg
    Finished dev [unoptimized + debuginfo] target(s) in 0.20s
     Running `target/debug/lighthouse db dg`
Running database manager for mainnet network
downgrade database version 5 to 4
Oct 13 22:21:36.313 INFO migrate_schema: from=5 to=4, module: beacon_chain::schema_change:25
Oct 13 22:21:36.313 INFO Dowgrade v5 to v4, module: beacon_chain::schema_change:100
Oct 13 22:21:36.313 INFO Dowgrade v5 to v4: db.store_schema_version=4, module: beacon_chain::schema_change:127
Oct 13 22:21:36.313 INFO Dowgrade v5 to v4 completed, module: beacon_chain::schema_change:130
```
@michaelsproul
Copy link
Member

Thanks for the great work on this @winksaville. I've implemented an updated version of the database_manager with some more features in a new PR (#3129) and we'll have some DB downgrades built atop that coming soon!

I'll close this PR in favour of the new one

bors bot pushed a commit that referenced this pull request Apr 1, 2022
## Proposed Changes

Add a `lighthouse db` command with three initial subcommands:

- `lighthouse db version`: print the database schema version.
- `lighthouse db migrate --to N`: manually upgrade (or downgrade!) the database to a different version.
- `lighthouse db inspect --column C`: log the key and size in bytes of every value in a given `DBColumn`.

This PR lays the groundwork for other changes, namely:

- Mark's fast-deposit sync (#2915), for which I think we should implement a database downgrade (from v9 to v8).
- My `tree-states` work, which already implements a downgrade (v10 to v8).
- Standalone purge commands like `lighthouse db purge-dht` per #2824.

## Additional Info

I updated the `strum` crate to 0.24.0, which necessitated some changes in the network code to remove calls to deprecated methods.

Thanks to @winksaville for the motivation, and implementation work that I used as a source of inspiration (#2685).
bors bot pushed a commit that referenced this pull request Apr 1, 2022
## Proposed Changes

Add a `lighthouse db` command with three initial subcommands:

- `lighthouse db version`: print the database schema version.
- `lighthouse db migrate --to N`: manually upgrade (or downgrade!) the database to a different version.
- `lighthouse db inspect --column C`: log the key and size in bytes of every value in a given `DBColumn`.

This PR lays the groundwork for other changes, namely:

- Mark's fast-deposit sync (#2915), for which I think we should implement a database downgrade (from v9 to v8).
- My `tree-states` work, which already implements a downgrade (v10 to v8).
- Standalone purge commands like `lighthouse db purge-dht` per #2824.

## Additional Info

I updated the `strum` crate to 0.24.0, which necessitated some changes in the network code to remove calls to deprecated methods.

Thanks to @winksaville for the motivation, and implementation work that I used as a source of inspiration (#2685).
paulhauner pushed a commit to paulhauner/lighthouse that referenced this pull request Apr 4, 2022
## Proposed Changes

Add a `lighthouse db` command with three initial subcommands:

- `lighthouse db version`: print the database schema version.
- `lighthouse db migrate --to N`: manually upgrade (or downgrade!) the database to a different version.
- `lighthouse db inspect --column C`: log the key and size in bytes of every value in a given `DBColumn`.

This PR lays the groundwork for other changes, namely:

- Mark's fast-deposit sync (sigp#2915), for which I think we should implement a database downgrade (from v9 to v8).
- My `tree-states` work, which already implements a downgrade (v10 to v8).
- Standalone purge commands like `lighthouse db purge-dht` per sigp#2824.

## Additional Info

I updated the `strum` crate to 0.24.0, which necessitated some changes in the network code to remove calls to deprecated methods.

Thanks to @winksaville for the motivation, and implementation work that I used as a source of inspiration (sigp#2685).
paulhauner pushed a commit to paulhauner/lighthouse that referenced this pull request May 6, 2022
## Proposed Changes

Add a `lighthouse db` command with three initial subcommands:

- `lighthouse db version`: print the database schema version.
- `lighthouse db migrate --to N`: manually upgrade (or downgrade!) the database to a different version.
- `lighthouse db inspect --column C`: log the key and size in bytes of every value in a given `DBColumn`.

This PR lays the groundwork for other changes, namely:

- Mark's fast-deposit sync (sigp#2915), for which I think we should implement a database downgrade (from v9 to v8).
- My `tree-states` work, which already implements a downgrade (v10 to v8).
- Standalone purge commands like `lighthouse db purge-dht` per sigp#2824.

## Additional Info

I updated the `strum` crate to 0.24.0, which necessitated some changes in the network code to remove calls to deprecated methods.

Thanks to @winksaville for the motivation, and implementation work that I used as a source of inspiration (sigp#2685).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
work-in-progress PR is a work-in-progress
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants