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

Modularize beacon node backend #4718

Merged
merged 133 commits into from
Jan 23, 2025

Conversation

eserilev
Copy link
Collaborator

@eserilev eserilev commented Sep 9, 2023

Issue Addressed

#4669

Proposed Changes

Modularize the beacon node backend to make it easier to add new database implementations

Additional Info

The existing KeyValueStore trait already does some abstraction, however the codebases assumes the KV store is always LevelDB.

I created a BeaconNodeBackend type that implements the KeyValueStore and ItemStore traits. I then replaced all references of LevelDb to the new BeaconNodeBackend type. Within the BeaconNodeBackend type I used the cfg macro which should allow us to switch between different database implementations via config changes.

@eserilev eserilev changed the title [WIP] Modularize beacon node backend Modularize beacon node backend Sep 9, 2023
@eserilev
Copy link
Collaborator Author

eserilev commented Jan 30, 2024

I'm currently working on adding Redb to the beacon node backend. Here are some notes I've taken so far on my work

Redb

Theres a few difference's between LevelDB and Redb that I'll describe below

fsync

Info about redb transaction durability can be found here
https://docs.rs/redb/latest/redb/enum.Durability.html#

For now I translate WriteOptions.sync = true to be Durability::Immediate and WriteOptions.sync = false to be Durability::Eventual

We could decide to use Paranoid instead of Immediate, but I think the additional guarantees of Paranoid are probably unecessary for our use case.

Compaction

LevelDB allows for compacting over a range of values. Redb only allows for compacting the full db. It seems like our LevelDB implementation compacts across all keys in the DB. If thats the case we should be all good here.

Tables

Redb introduces the concept of tables. We can either use one table for everything, or spin up tables by column name. I'm currently going down the path of spinning up tables by column name. This causes issues with do_atomically. We may need to make changes to this function to also accept a col: &str as an argument.

@michaelsproul michaelsproul added the v6.1.0 New release c. Q1 2025 label Jan 19, 2025
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 really good, I think we're getting close!

I just had a few questions and some suggested cosmetic changes

beacon_node/src/cli.rs Outdated Show resolved Hide resolved
beacon_node/store/src/database/leveldb_impl.rs Outdated Show resolved Hide resolved
Comment on lines 279 to 298
let results = store.hot_db.iter_column_from::<Vec<u8>>(
DBColumn::LightClientUpdate,
&start_period.to_le_bytes(),
move |sync_committee_bytes, _| match u64::from_ssz_bytes(sync_committee_bytes) {
Ok(sync_committee_period) => {
if sync_committee_period >= start_period + count {
return false;
}
true
}
Err(e) => {
error!(
log,
"Error decoding sync committee bytes from the db";
"error" => ?e
);
false
}
},
);
Copy link
Member

Choose a reason for hiding this comment

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

Why is this change required? It seems we had to remove an assert to get the test related to this method to pass

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I've removed this change and updated iter_column_from to not take in a predicate anymore

Copy link
Member

Choose a reason for hiding this comment

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

Heh, I think Jimmy wanted the predicate for data column stuff, but looks like we can probably just use take_while chained onto the iter_column_from. We can reassess in the context of his PR.

beacon_node/http_api/tests/tests.rs Show resolved Hide resolved
beacon_node/store/src/database/redb_impl.rs Outdated Show resolved Hide resolved
beacon_node/store/src/hot_cold_store.rs Outdated Show resolved Hide resolved
Comment on lines +1286 to +1289
pub fn delete_batch(&self, col: DBColumn, ops: Vec<Hash256>) -> Result<(), Error> {
let new_ops: HashSet<&[u8]> = ops.iter().map(|v| v.as_slice()).collect();
self.hot_db.delete_batch(col, new_ops)
}
Copy link
Member

Choose a reason for hiding this comment

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

I feel like if we use do_atomically in delete_temp_states we don't need delete_batch?

Copy link
Collaborator Author

@eserilev eserilev Jan 22, 2025

Choose a reason for hiding this comment

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

delete_temp_states was very slow w/ redb because we were deleting data across multiple columns via do_atomically. This meant we were opening/closing database tables a bunch of times. delete_batch was added to do deletions across a single column.

Another option could be to ensure db operations in do_atomically are ordered by DBColumn so that we only open/close the table once per set of column operations.

maybe the API could look something like

pub fn do_atomically(&self, ops_batch: HashMap<DBColumn, Vec<KeyValueStoreOp>>)

lmk what you think

Copy link
Member

Choose a reason for hiding this comment

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

Ok, makes sense. Let's leave delete_batch for now and we can work on improving the API to optimise redb further

beacon_node/store/src/hot_cold_store.rs Outdated Show resolved Hide resolved
beacon_node/store/src/lib.rs Outdated Show resolved Hide resolved
database_manager/src/cli.rs Outdated Show resolved Hide resolved
@michaelsproul michaelsproul added waiting-on-author The reviewer has suggested changes and awaits thier implementation. and removed ready-for-review The code is ready for review labels Jan 21, 2025
@michaelsproul michaelsproul added ready-for-merge This PR is ready to merge. and removed waiting-on-author The reviewer has suggested changes and awaits thier implementation. labels Jan 23, 2025
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.

SEND IT!

@michaelsproul
Copy link
Member

@mergify queue

Copy link

mergify bot commented Jan 23, 2025

queue

✅ The pull request has been merged automatically

The pull request has been merged automatically at a1b7d61

mergify bot added a commit that referenced this pull request Jan 23, 2025
@mergify mergify bot merged commit a1b7d61 into sigp:unstable Jan 23, 2025
31 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
database ready-for-merge This PR is ready to merge. v6.1.0 New release c. Q1 2025
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants