diff --git a/ledger/src/blockstore.rs b/ledger/src/blockstore.rs index 0c0486c94e..b90cc5dd2e 100644 --- a/ledger/src/blockstore.rs +++ b/ledger/src/blockstore.rs @@ -124,6 +124,7 @@ pub struct Blockstore { active_transaction_status_index: RwLock, rewards_cf: LedgerColumn, _blocktime_cf: LedgerColumn, + perf_samples_cf: LedgerColumn, last_root: Arc>, insert_shreds_lock: Arc>, pub new_shreds_signals: Vec>, @@ -282,6 +283,7 @@ impl Blockstore { // This column is created (but never populated) in order to maintain compatibility with // newer versions of Blockstore. let _blocktime_cf = db.column(); + let perf_samples_cf = db.column(); let db = Arc::new(db); @@ -327,6 +329,7 @@ impl Blockstore { active_transaction_status_index: RwLock::new(active_transaction_status_index), rewards_cf, _blocktime_cf, + perf_samples_cf, new_shreds_signals: vec![], completed_slots_senders: vec![], insert_shreds_lock: Arc::new(Mutex::new(())), @@ -2281,6 +2284,22 @@ impl Blockstore { .collect()) } + pub fn get_recent_perf_samples(&self, num: usize) -> Result> { + Ok(self + .db + .iter::(IteratorMode::End)? + .take(num) + .map(|(slot, data)| { + let perf_sample = deserialize(&data).unwrap(); + (slot, perf_sample) + }) + .collect()) + } + + pub fn write_perf_sample(&self, index: Slot, perf_sample: &PerfSample) -> Result<()> { + self.perf_samples_cf.put(index, perf_sample) + } + /// Returns the entry vector for the slot starting with `shred_start_index` pub fn get_slot_entries(&self, slot: Slot, shred_start_index: u64) -> Result> { self.get_slot_entries_with_shred_info(slot, shred_start_index, false) @@ -6716,6 +6735,38 @@ pub mod tests { Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); } + #[test] + fn test_write_get_perf_samples() { + let blockstore_path = get_tmp_ledger_path!(); + { + let blockstore = Blockstore::open(&blockstore_path).unwrap(); + let num_entries: usize = 10; + let mut perf_samples: Vec<(Slot, PerfSample)> = vec![]; + for x in 1..num_entries + 1 { + perf_samples.push(( + x as u64 * 50, + PerfSample { + num_transactions: 1000 + x as u64, + num_slots: 50, + sample_period_secs: 20, + }, + )); + } + for (slot, sample) in perf_samples.iter() { + blockstore.write_perf_sample(*slot, sample).unwrap(); + } + for x in 0..num_entries { + let mut expected_samples = perf_samples[num_entries - 1 - x..].to_vec(); + expected_samples.sort_by(|a, b| b.0.cmp(&a.0)); + assert_eq!( + blockstore.get_recent_perf_samples(x + 1).unwrap(), + expected_samples + ); + } + } + Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction"); + } + #[test] fn test_lowest_slot() { let blockstore_path = get_tmp_ledger_path!(); diff --git a/ledger/src/blockstore/blockstore_purge.rs b/ledger/src/blockstore/blockstore_purge.rs index a20cfdcd47..42bbed7cbb 100644 --- a/ledger/src/blockstore/blockstore_purge.rs +++ b/ledger/src/blockstore/blockstore_purge.rs @@ -137,6 +137,10 @@ impl Blockstore { & self .db .delete_range_cf::(&mut write_batch, from_slot, to_slot) + .is_ok() + & self + .db + .delete_range_cf::(&mut write_batch, from_slot, to_slot) .is_ok(); let mut w_active_transaction_status_index = self.active_transaction_status_index.write().unwrap(); @@ -231,6 +235,10 @@ impl Blockstore { && self ._blocktime_cf .compact_range(from_slot, to_slot) + .unwrap_or(false) + && self + .perf_samples_cf + .compact_range(from_slot, to_slot) .unwrap_or(false); compact_timer.stop(); if !result { diff --git a/ledger/src/blockstore_db.rs b/ledger/src/blockstore_db.rs index d71a55fdad..94df2359ff 100644 --- a/ledger/src/blockstore_db.rs +++ b/ledger/src/blockstore_db.rs @@ -51,6 +51,8 @@ const TRANSACTION_STATUS_INDEX_CF: &str = "transaction_status_index"; const REWARDS_CF: &str = "rewards"; /// Column family for Blocktime const BLOCKTIME_CF: &str = "blocktime"; +/// Column family for Performance Samples +const PERF_SAMPLES_CF: &str = "perf_samples"; #[derive(Error, Debug)] pub enum BlockstoreError { @@ -137,6 +139,10 @@ pub mod columns { #[derive(Debug)] /// The blocktime column pub struct Blocktime; + + #[derive(Debug)] + /// The performance samples column + pub struct PerfSamples; } pub enum AccessType { @@ -197,7 +203,7 @@ impl Rocks { ) -> Result { use columns::{ AddressSignatures, Blocktime, DeadSlots, DuplicateSlots, ErasureMeta, Index, Orphans, - Rewards, Root, ShredCode, ShredData, SlotMeta, TransactionStatus, + PerfSamples, Rewards, Root, ShredCode, ShredData, SlotMeta, TransactionStatus, TransactionStatusIndex, }; @@ -233,6 +239,8 @@ impl Rocks { let rewards_cf_descriptor = ColumnFamilyDescriptor::new(Rewards::NAME, get_cf_options()); let blocktime_cf_descriptor = ColumnFamilyDescriptor::new(Blocktime::NAME, get_cf_options()); + let perf_samples_cf_descriptor = + ColumnFamilyDescriptor::new(PerfSamples::NAME, get_cf_options()); let cfs = vec![ (SlotMeta::NAME, meta_cf_descriptor), @@ -252,6 +260,7 @@ impl Rocks { ), (Rewards::NAME, rewards_cf_descriptor), (Blocktime::NAME, blocktime_cf_descriptor), + (PerfSamples::NAME, perf_samples_cf_descriptor), ]; // Open the database @@ -290,7 +299,7 @@ impl Rocks { fn columns(&self) -> Vec<&'static str> { use columns::{ AddressSignatures, Blocktime, DeadSlots, DuplicateSlots, ErasureMeta, Index, Orphans, - Rewards, Root, ShredCode, ShredData, SlotMeta, TransactionStatus, + PerfSamples, Rewards, Root, ShredCode, ShredData, SlotMeta, TransactionStatus, TransactionStatusIndex, }; @@ -309,6 +318,7 @@ impl Rocks { TransactionStatusIndex::NAME, Rewards::NAME, Blocktime::NAME, + PerfSamples::NAME, ] } @@ -542,6 +552,14 @@ impl TypedColumn for columns::Blocktime { type Type = UnixTimestamp; } +impl SlotColumn for columns::PerfSamples {} +impl ColumnName for columns::PerfSamples { + const NAME: &'static str = PERF_SAMPLES_CF; +} +impl TypedColumn for columns::PerfSamples { + type Type = blockstore_meta::PerfSample; +} + impl Column for columns::ShredCode { type Index = (u64, u64); diff --git a/ledger/src/blockstore_meta.rs b/ledger/src/blockstore_meta.rs index 911ac375fe..01df93e85a 100644 --- a/ledger/src/blockstore_meta.rs +++ b/ledger/src/blockstore_meta.rs @@ -243,6 +243,13 @@ pub struct AddressSignatureMeta { pub writeable: bool, } +#[derive(Clone, Debug, Default, Deserialize, Serialize, PartialEq)] +pub struct PerfSample { + pub num_transactions: u64, + pub num_slots: u64, + pub sample_period_secs: u16, +} + #[cfg(test)] mod test { use super::*;