Decouple accounts hash calculation from snapshot hash (#9507)

This commit is contained in:
sakridge
2020-04-16 15:12:20 -07:00
committed by GitHub
parent 425b4fe6dd
commit 66abe45ea1
11 changed files with 179 additions and 93 deletions

View File

@ -1,6 +1,6 @@
//! The `bank_forks` module implments BankForks a DAG of checkpointed Banks
use crate::snapshot_package::{SnapshotPackageSendError, SnapshotPackageSender};
use crate::snapshot_package::{AccountsPackageSendError, AccountsPackageSender};
use crate::snapshot_utils::{self, SnapshotError};
use log::*;
use solana_measure::measure::Measure;
@ -27,7 +27,7 @@ pub enum CompressionType {
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SnapshotConfig {
// Generate a new snapshot every this many slots
pub snapshot_interval_slots: usize,
pub snapshot_interval_slots: u64,
// Where to store the latest packaged snapshot
pub snapshot_package_output_path: PathBuf,
@ -43,8 +43,8 @@ pub enum BankForksError {
#[error("snapshot error")]
SnapshotError(#[from] SnapshotError),
#[error("snapshot package send error")]
SnapshotPackageSendError(#[from] SnapshotPackageSendError),
#[error("accounts package send error")]
AccountsPackageSendError(#[from] AccountsPackageSendError),
}
type Result<T> = std::result::Result<T, BankForksError>;
@ -54,6 +54,9 @@ pub struct BankForks {
root: Slot,
pub snapshot_config: Option<SnapshotConfig>,
last_snapshot_slot: Slot,
pub accounts_hash_interval_slots: Slot,
last_accounts_hash_slot: Slot,
}
impl Index<u64> for BankForks {
@ -74,6 +77,8 @@ impl BankForks {
root: 0,
snapshot_config: None,
last_snapshot_slot: bank_slot,
accounts_hash_interval_slots: std::u64::MAX,
last_accounts_hash_slot: bank_slot,
}
}
@ -159,6 +164,8 @@ impl BankForks {
working_bank,
snapshot_config: None,
last_snapshot_slot: root,
accounts_hash_interval_slots: std::u64::MAX,
last_accounts_hash_slot: root,
}
}
@ -178,7 +185,7 @@ impl BankForks {
pub fn set_root(
&mut self,
root: Slot,
snapshot_package_sender: &Option<SnapshotPackageSender>,
accounts_package_sender: &Option<AccountsPackageSender>,
) {
let old_epoch = self.root_bank().epoch();
self.root = root;
@ -209,43 +216,46 @@ impl BankForks {
.last()
.map(|bank| bank.transaction_count())
.unwrap_or(0);
// Generate each snapshot at a fixed interval
// Calculate the accounts hash at a fixed interval
let mut is_root_bank_squashed = false;
if self.snapshot_config.is_some() && snapshot_package_sender.is_some() {
let config = self.snapshot_config.as_ref().unwrap();
let mut banks = vec![root_bank];
let parents = root_bank.parents();
banks.extend(parents.iter());
for bank in banks.iter() {
let bank_slot = bank.slot();
if bank.block_height() % (config.snapshot_interval_slots as u64) == 0 {
// Generate a snapshot if snapshots are configured and it's been an appropriate number
// of banks since the last snapshot
if bank_slot > self.last_snapshot_slot {
bank.squash();
is_root_bank_squashed = bank_slot == root;
let mut snapshot_time = Measure::start("total-snapshot-ms");
let r = self.generate_snapshot(
bank_slot,
&bank.src.roots(),
snapshot_package_sender.as_ref().unwrap(),
);
if r.is_err() {
warn!(
"Error generating snapshot for bank: {}, err: {:?}",
bank_slot, r
);
} else {
self.last_snapshot_slot = bank_slot;
}
let mut banks = vec![root_bank];
let parents = root_bank.parents();
banks.extend(parents.iter());
for bank in banks.iter() {
let bank_slot = bank.slot();
if bank.block_height() % self.accounts_hash_interval_slots == 0
&& bank_slot > self.last_accounts_hash_slot
{
self.last_accounts_hash_slot = bank_slot;
bank.squash();
is_root_bank_squashed = bank_slot == root;
// Cleanup outdated snapshots
self.purge_old_snapshots();
snapshot_time.stop();
inc_new_counter_info!("total-snapshot-ms", snapshot_time.as_ms() as usize);
bank.clean_accounts();
bank.update_accounts_hash();
if self.snapshot_config.is_some() && accounts_package_sender.is_some() {
// Generate an accounts package
let mut snapshot_time = Measure::start("total-snapshot-ms");
let r = self.generate_accounts_package(
bank_slot,
&bank.src.roots(),
accounts_package_sender.as_ref().unwrap(),
);
if r.is_err() {
warn!(
"Error generating snapshot for bank: {}, err: {:?}",
bank_slot, r
);
} else {
self.last_snapshot_slot = bank_slot;
}
break;
// Cleanup outdated snapshots
self.purge_old_snapshots();
snapshot_time.stop();
inc_new_counter_info!("total-snapshot-ms", snapshot_time.as_ms() as usize);
}
break;
}
}
if !is_root_bank_squashed {
@ -282,11 +292,11 @@ impl BankForks {
}
}
pub fn generate_snapshot(
pub fn generate_accounts_package(
&self,
root: Slot,
slots_to_snapshot: &[Slot],
snapshot_package_sender: &SnapshotPackageSender,
accounts_package_sender: &AccountsPackageSender,
) -> Result<()> {
let config = self.snapshot_config.as_ref().unwrap();
@ -319,8 +329,7 @@ impl BankForks {
config.compression.clone(),
)?;
// Send the package to the packaging thread
snapshot_package_sender.send(package)?;
accounts_package_sender.send(package)?;
Ok(())
}
@ -338,6 +347,10 @@ impl BankForks {
pub fn snapshot_config(&self) -> &Option<SnapshotConfig> {
&self.snapshot_config
}
pub fn set_accounts_hash_interval_slots(&mut self, accounts_interval_slots: u64) {
self.accounts_hash_interval_slots = accounts_interval_slots;
}
}
#[cfg(test)]

View File

@ -8,13 +8,14 @@ use std::{
};
use tempfile::TempDir;
pub type SnapshotPackageSender = Sender<SnapshotPackage>;
pub type SnapshotPackageReceiver = Receiver<SnapshotPackage>;
pub type SnapshotPackageSendError = SendError<SnapshotPackage>;
pub type AccountsPackageSender = Sender<AccountsPackage>;
pub type AccountsPackageReceiver = Receiver<AccountsPackage>;
pub type AccountsPackageSendError = SendError<AccountsPackage>;
#[derive(Debug)]
pub struct SnapshotPackage {
pub struct AccountsPackage {
pub root: Slot,
pub block_height: Slot,
pub slot_deltas: Vec<BankSlotDelta>,
pub snapshot_links: TempDir,
pub storages: SnapshotStorages,
@ -23,9 +24,10 @@ pub struct SnapshotPackage {
pub compression: CompressionType,
}
impl SnapshotPackage {
impl AccountsPackage {
pub fn new(
root: Slot,
block_height: u64,
slot_deltas: Vec<BankSlotDelta>,
snapshot_links: TempDir,
storages: SnapshotStorages,
@ -35,6 +37,7 @@ impl SnapshotPackage {
) -> Self {
Self {
root,
block_height,
slot_deltas,
snapshot_links,
storages,

View File

@ -1,6 +1,6 @@
use crate::bank_forks::CompressionType;
use crate::hardened_unpack::{unpack_snapshot, UnpackError};
use crate::snapshot_package::SnapshotPackage;
use crate::snapshot_package::AccountsPackage;
use bincode::serialize_into;
use bzip2::bufread::BzDecoder;
use flate2::read::GzDecoder;
@ -93,7 +93,7 @@ pub fn package_snapshot<P: AsRef<Path>, Q: AsRef<Path>>(
snapshot_package_output_path: P,
snapshot_storages: SnapshotStorages,
compression: CompressionType,
) -> Result<SnapshotPackage> {
) -> Result<AccountsPackage> {
// Hard link all the snapshots we need for this package
let snapshot_hard_links_dir = tempfile::tempdir_in(snapshot_path)?;
@ -104,8 +104,8 @@ pub fn package_snapshot<P: AsRef<Path>, Q: AsRef<Path>>(
snapshot_storages.len()
);
// Any errors from this point on will cause the above SnapshotPackage to drop, clearing
// any temporary state created for the SnapshotPackage (like the snapshot_hard_links_dir)
// Any errors from this point on will cause the above AccountsPackage to drop, clearing
// any temporary state created for the AccountsPackage (like the snapshot_hard_links_dir)
snapshot_files.copy_snapshot_directory(snapshot_hard_links_dir.path())?;
let snapshot_package_output_file = get_snapshot_archive_path(
@ -114,8 +114,9 @@ pub fn package_snapshot<P: AsRef<Path>, Q: AsRef<Path>>(
&compression,
);
let package = SnapshotPackage::new(
let package = AccountsPackage::new(
bank.slot(),
bank.block_height(),
bank.src.slot_deltas(slots_to_snapshot),
snapshot_hard_links_dir,
snapshot_storages,
@ -136,7 +137,7 @@ fn get_compression_ext(compression: &CompressionType) -> (&'static str, &'static
}
}
pub fn archive_snapshot_package(snapshot_package: &SnapshotPackage) -> Result<()> {
pub fn archive_snapshot_package(snapshot_package: &AccountsPackage) -> Result<()> {
info!(
"Generating snapshot archive for slot {}",
snapshot_package.root
@ -354,8 +355,6 @@ pub fn add_snapshot<P: AsRef<Path>>(
bank: &Bank,
snapshot_storages: &[SnapshotStorage],
) -> Result<SlotSnapshotPaths> {
bank.clean_accounts();
bank.update_accounts_hash();
let slot = bank.slot();
// snapshot_path/slot
let slot_snapshot_dir = get_bank_snapshot_dir(snapshot_path, slot);