diff --git a/core/src/repair_weight.rs b/core/src/repair_weight.rs index 12e7db38d5..9ebe46f3c5 100644 --- a/core/src/repair_weight.rs +++ b/core/src/repair_weight.rs @@ -310,7 +310,7 @@ impl RepairWeight { // Attempts to chain the orphan subtree rooted at `orphan_tree_root` // to any earlier subtree with new any ancestry information in `blockstore`. - // Returns the earliest known ancestor of `heavest_tree_root`. + // Returns the earliest known ancestor of `heaviest_tree_root`. fn update_orphan_ancestors( &mut self, blockstore: &Blockstore, diff --git a/docs/src/implemented-proposals/persistent-account-storage.md b/docs/src/implemented-proposals/persistent-account-storage.md index b41765e903..7cd6e3fda5 100644 --- a/docs/src/implemented-proposals/persistent-account-storage.md +++ b/docs/src/implemented-proposals/persistent-account-storage.md @@ -4,9 +4,9 @@ title: Persistent Account Storage ## Persistent Account Storage -The set of Accounts represent the current computed state of all the transactions that have been processed by a validator. Each validator needs to maintain this entire set. Each block that is proposed by the network represents a change to this set, and since each block is a potential rollback point the changes need to be reversible. +The set of accounts represent the current computed state of all the transactions that have been processed by a validator. Each validator needs to maintain this entire set. Each block that is proposed by the network represents a change to this set, and since each block is a potential rollback point, the changes need to be reversible. -Persistent storage like NVMEs are 20 to 40 times cheaper than DDR. The problem with persistent storage is that write and read performance is much slower than DDR and care must be taken in how data is read or written to. Both reads and writes can be split between multiple storage drives and accessed in parallel. This design proposes a data structure that allows for concurrent reads and concurrent writes of storage. Writes are optimized by using an AppendVec data structure, which allows a single writer to append while allowing access to many concurrent readers. The accounts index maintains a pointer to a spot where the account was appended to every fork, thus removing the need for explicit checkpointing of state. +Persistent storage like NVMEs are 20 to 40 times cheaper than DDR. The problem with persistent storage is that write and read performance is much slower than DDR. Care must be taken in how data is read or written to. Both reads and writes can be split between multiple storage drives and accessed in parallel. This design proposes a data structure that allows for concurrent reads and concurrent writes of storage. Writes are optimized by using an AppendVec data structure, which allows a single writer to append while allowing access to many concurrent readers. The accounts index maintains a pointer to a spot where the account was appended to every fork, thus removing the need for explicit checkpointing of state. ## AppendVec diff --git a/runtime/src/accounts.rs b/runtime/src/accounts.rs index 598d5a3bcc..66914f506f 100644 --- a/runtime/src/accounts.rs +++ b/runtime/src/accounts.rs @@ -37,11 +37,6 @@ use std::{ sync::{Arc, Mutex}, }; -#[derive(Default, Debug, AbiExample)] -pub(crate) struct ReadonlyLock { - lock_count: Mutex, -} - #[derive(Debug, Default, AbiExample)] pub struct AccountLocks { write_locks: HashSet, @@ -1041,8 +1036,6 @@ pub fn update_accounts_bench(accounts: &Accounts, pubkeys: &[Pubkey], slot: u64) #[cfg(test)] mod tests { - // TODO: all the bank tests are bank specific, issue: 2194 - use super::*; use crate::rent_collector::RentCollector; use solana_sdk::{ diff --git a/runtime/src/accounts_cache.rs b/runtime/src/accounts_cache.rs index ce70a3c677..8ee6054c9b 100644 --- a/runtime/src/accounts_cache.rs +++ b/runtime/src/accounts_cache.rs @@ -58,8 +58,8 @@ impl SlotCacheInner { self.cache .get(pubkey) // 1) Maybe can eventually use a Cow to avoid a clone on every read - // 2) Popping is only safe if its guaranteed only replay/banking threads - // are reading from the AccountsDb + // 2) Popping is only safe if it's guaranteed that only + // replay/banking threads are reading from the AccountsDb .map(|account_ref| account_ref.value().clone()) } diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index 6fd302fc03..c46e364c2e 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -5002,7 +5002,6 @@ impl AccountsDb { #[cfg(test)] pub mod tests { - // TODO: all the bank tests are bank specific, issue: 2194 use super::*; use crate::{ accounts_hash::MERKLE_FANOUT, accounts_index::tests::*, accounts_index::RefCount, diff --git a/runtime/src/accounts_hash.rs b/runtime/src/accounts_hash.rs index 2959c4ff57..9af37532f1 100644 --- a/runtime/src/accounts_hash.rs +++ b/runtime/src/accounts_hash.rs @@ -91,7 +91,7 @@ impl CumulativeOffset { } } -// Allow retreiving &[start..end] from a logical src: Vec, where src is really Vec> (or later Vec>>) +// Allow retrieving &[start..end] from a logical src: Vec, where src is really Vec> (or later Vec>>) // This model prevents callers from having to flatten which saves both working memory and time. #[derive(Default, Debug)] pub struct CumulativeOffsets { @@ -618,7 +618,6 @@ impl AccountsHash { #[cfg(test)] pub mod tests { - // TODO: all the bank tests are bank specific, issue: 2194 use super::*; use std::str::FromStr; diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index 14e50620c0..f9ded43cb1 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -306,7 +306,7 @@ impl AccountsIndex { // First we show that for any bank `B` that is a descendant of // the current `max_root`, it must be true that and `B.ancestors.contains(max_root)`, - // regardless of the pattern of `squash()` behavior, `where` `ancestors` is the set + // regardless of the pattern of `squash()` behavior, where `ancestors` is the set // of ancestors that is tracked in each bank. // // Proof: At startup, if starting from a snapshot, generate_index() adds all banks @@ -338,7 +338,7 @@ impl AccountsIndex { // BankForks before the `set_root`. // // This means by the guarantees of `R_descendants` described above, because - // `R_new` is an ancestor of `B`, and `R < R_new < B`, then B.ancestors.contains(R_new)`. + // `R_new` is an ancestor of `B`, and `R < R_new < B`, then `B.ancestors.contains(R_new)`. // // Now until the next `set_root`, any new banks constructed from `new_from_parent` will // also have `max_root == R_new` in their ancestor set, so the claim holds for those descendants diff --git a/runtime/src/append_vec.rs b/runtime/src/append_vec.rs index 02aade79cc..5263da62fb 100644 --- a/runtime/src/append_vec.rs +++ b/runtime/src/append_vec.rs @@ -1,3 +1,6 @@ +//! Persistent storage for accounts. For more information, see: +//! https://docs.solana.com/implemented-proposals/persistent-account-storage + use log::*; use memmap2::MmapMut; use serde::{Deserialize, Serialize}; @@ -132,7 +135,7 @@ impl Drop for AppendVec { if let Err(_e) = remove_file(&self.path) { // promote this to panic soon. // disabled due to many false positive warnings while running tests. - // blocked by rpc's updrade to jsonrpc v17 + // blocked by rpc's upgrade to jsonrpc v17 //error!("AppendVec failed to remove {:?}: {:?}", &self.path, e); } } @@ -165,10 +168,14 @@ impl AppendVec { }) .unwrap(); + // Theoretical performance optimization: write a zero to the end of + // the file so that we won't have to resize it later, which may be + // expensive. data.seek(SeekFrom::Start((size - 1) as u64)).unwrap(); data.write_all(&[0]).unwrap(); data.seek(SeekFrom::Start(0)).unwrap(); data.flush().unwrap(); + //UNSAFE: Required to create a Mmap let map = unsafe { MmapMut::map_mut(&data) }; let map = map.unwrap_or_else(|e| {