-
Notifications
You must be signed in to change notification settings - Fork 0
feat(hot)!: add table for journal hashes #70
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,25 +80,9 @@ mod utils; | |
|
|
||
| use signet_hot::{ | ||
| model::{HotKv, HotKvError, HotKvWrite}, | ||
| tables::{ | ||
| AccountChangeSets, AccountsHistory, Bytecodes, HeaderNumbers, Headers, NUM_TABLES, | ||
| PlainAccountState, PlainStorageState, StorageChangeSets, StorageHistory, Table, | ||
| }, | ||
| tables::{NUM_TABLES, STANDARD_TABLES}, | ||
| }; | ||
|
|
||
| /// The known table names, used to pre-populate the FSI cache at open time. | ||
| const KNOWN_TABLE_NAMES: [&str; NUM_TABLES] = [ | ||
| Headers::NAME, | ||
| HeaderNumbers::NAME, | ||
| Bytecodes::NAME, | ||
| PlainAccountState::NAME, | ||
| PlainStorageState::NAME, | ||
| AccountsHistory::NAME, | ||
| AccountChangeSets::NAME, | ||
| StorageHistory::NAME, | ||
| StorageChangeSets::NAME, | ||
| ]; | ||
|
|
||
| /// 1 KB in bytes | ||
| pub const KILOBYTE: usize = 1024; | ||
| /// 1 MB in bytes | ||
|
|
@@ -458,13 +442,41 @@ fn create_tables_and_populate_cache(env: &Environment) -> Result<FsiCache, MdbxE | |
| Ok(FsiCache::new(known)) | ||
| } | ||
|
|
||
| /// Read FSI entries for all known tables from the metadata table. | ||
| /// Read FSI entries for all standard tables from the metadata table. | ||
| /// | ||
| /// Iterates [`STANDARD_TABLES`] and reads each table's on-disk FSI. Missing | ||
| /// entries fall back to the compile-time-expected FSI inferred from the | ||
| /// table's [`StandardTable`] metadata via [`FixedSizeInfo::from_create_args`] | ||
| /// (the same mapping used by [`Tx::queue_raw_create`] when persisting FSI | ||
| /// for a newly-created table), so opening a database written by an older | ||
| /// binary that pre-dates one or more tables succeeds. The next RW open | ||
| /// creates any missing table and persists its FSI normally. | ||
| /// | ||
| /// [`StandardTable`]: signet_hot::tables::StandardTable | ||
| fn read_known_fsi<K: signet_libmdbx::TransactionKind>( | ||
| tx: &Tx<K>, | ||
| ) -> Result<[(&'static str, FixedSizeInfo); NUM_TABLES], MdbxError> { | ||
| let mut known = [("", FixedSizeInfo::None); NUM_TABLES]; | ||
| for (i, &name) in KNOWN_TABLE_NAMES.iter().enumerate() { | ||
| known[i] = (name, tx.read_fsi_from_table(name)?); | ||
| for (index, table) in STANDARD_TABLES.iter().enumerate() { | ||
| let fsi = match tx.read_fsi_from_table(table.name) { | ||
| Ok(fsi) => fsi, | ||
| Err(MdbxError::UnknownTable(_)) => { | ||
| let expected = | ||
| FixedSizeInfo::from_create_args(table.dual_key_size, table.fixed_val_size); | ||
| tracing::warn!( | ||
| target: "storage::db::mdbx", | ||
| table = table.name, | ||
| ?expected, | ||
| "FSI metadata entry missing for known table; falling back to compile-time \ | ||
| expected value. Fires once per open per missing table until a RW open \ | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this info belongs in a comment? 🤔 |
||
| creates the table and persists its FSI; RO-only consumers of a \ | ||
| pre-upgrade database will see this on every open." | ||
| ); | ||
| expected | ||
| } | ||
| Err(error) => return Err(error), | ||
| }; | ||
| known[index] = (table.name, fsi); | ||
| } | ||
| Ok(known) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -142,6 +142,28 @@ impl<K: TransactionKind + WriteMarker> Tx<K> { | |
|
|
||
| Ok(()) | ||
| } | ||
|
|
||
| /// Removes a table from the environment as if it had never been created: | ||
| /// drops the named sub-database and erases its FSI metadata entry. Used | ||
| /// by tests to simulate a database written by an older binary that | ||
| /// pre-dates the table. Does not invalidate the in-memory `FsiCache`; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we still control all significant running copies of the binaries, so we could choose not to implement migration logic/tests here. worth discussing whether we need this complexity yet |
||
| /// callers must reopen the parent `DatabaseEnv` after commit. | ||
| /// | ||
| /// # Safety | ||
| /// | ||
| /// Caller must ensure no [`Cursor`] or other references to `table` | ||
| /// exist for the lifetime of this transaction. See | ||
| /// [`signet_libmdbx::tx::Tx::drop_db`]. | ||
| #[cfg(test)] | ||
| pub(crate) unsafe fn forget_table(&self, table: &'static str) -> Result<(), MdbxError> { | ||
| let metadata = self.inner.open_db(None)?; | ||
| self.inner | ||
| .del(metadata, fsi_name_to_key(table).as_slice(), None) | ||
| .map_err(MdbxError::Mdbx)?; | ||
| let db = self.inner.open_db(Some(table))?; | ||
| // SAFETY: forwarded from this function's safety contract. | ||
| unsafe { self.inner.drop_db(db) }.map_err(MdbxError::Mdbx) | ||
| } | ||
| } | ||
|
|
||
| fn fsi_name_to_key(name: &'static str) -> B256 { | ||
|
|
@@ -288,22 +310,14 @@ macro_rules! impl_hot_kv_write { | |
| dual_key: Option<usize>, | ||
| fixed_val: Option<usize>, | ||
| ) -> Result<(), Self::Error> { | ||
| let mut flags = signet_libmdbx::DatabaseFlags::default(); | ||
| let fsi = FixedSizeInfo::from_create_args(dual_key, fixed_val); | ||
|
|
||
| let mut fsi = FixedSizeInfo::None; | ||
|
|
||
| if let Some(key2_size) = dual_key { | ||
| let mut flags = signet_libmdbx::DatabaseFlags::default(); | ||
| if fsi.is_dupsort() { | ||
| flags.set(signet_libmdbx::DatabaseFlags::DUP_SORT, true); | ||
| if let Some(value_size) = fixed_val { | ||
| flags.set(signet_libmdbx::DatabaseFlags::DUP_FIXED, true); | ||
| fsi = FixedSizeInfo::DupFixed { | ||
| key2_size, | ||
| total_size: key2_size + value_size, | ||
| }; | ||
| } else { | ||
| // DUPSORT without DUP_FIXED - variable value size | ||
| fsi = FixedSizeInfo::DupSort { key2_size }; | ||
| } | ||
| } | ||
| if fsi.is_dup_fixed() { | ||
| flags.set(signet_libmdbx::DatabaseFlags::DUP_FIXED, true); | ||
| } | ||
|
|
||
| self.inner.create_db(Some(table), flags)?; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could rewrite this loop as a
try_for_each()?