| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  | //! The `ledger_cleanup_service` drops older ledger data to limit disk space usage
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-02 19:49:31 -06:00
										 |  |  | use solana_ledger::blockstore::{Blockstore, PurgeType};
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  | use solana_ledger::blockstore_db::Result as BlockstoreResult;
 | 
					
						
							|  |  |  | use solana_measure::measure::Measure;
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  | use solana_sdk::clock::{Slot, DEFAULT_TICKS_PER_SLOT, TICKS_PER_DAY};
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  | use std::string::ToString;
 | 
					
						
							|  |  |  | use std::sync::atomic::{AtomicBool, Ordering};
 | 
					
						
							|  |  |  | use std::sync::mpsc::{Receiver, RecvTimeoutError};
 | 
					
						
							|  |  |  | use std::sync::Arc;
 | 
					
						
							|  |  |  | use std::thread;
 | 
					
						
							|  |  |  | use std::thread::{Builder, JoinHandle};
 | 
					
						
							|  |  |  | use std::time::Duration;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-09 16:36:44 -07:00
										 |  |  | // - To try and keep the RocksDB size under 400GB:
 | 
					
						
							|  |  |  | //   Seeing about 1600b/shred, using 2000b/shred for margin, so 200m shreds can be stored in 400gb.
 | 
					
						
							|  |  |  | //   at 5k shreds/slot at 50k tps, this is 500k slots (~5 hours).
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  | //   At idle, 60 shreds/slot this is about 4m slots (18 days)
 | 
					
						
							| 
									
										
										
										
											2019-12-18 11:50:09 -08:00
										 |  |  | // This is chosen to allow enough time for
 | 
					
						
							|  |  |  | // - A validator to download a snapshot from a peer and boot from it
 | 
					
						
							|  |  |  | // - To make sure that if a validator needs to reboot from its own snapshot, it has enough slots locally
 | 
					
						
							|  |  |  | //   to catch back up to where it was when it stopped
 | 
					
						
							| 
									
										
										
										
											2020-04-09 16:36:44 -07:00
										 |  |  | pub const DEFAULT_MAX_LEDGER_SHREDS: u64 = 200_000_000;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Allow down to 50m, or 3.5 days at idle, 1hr at 50k load, around ~100GB
 | 
					
						
							|  |  |  | pub const DEFAULT_MIN_MAX_LEDGER_SHREDS: u64 = 50_000_000;
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Check for removing slots at this interval so we don't purge too often
 | 
					
						
							|  |  |  | // and starve other blockstore users.
 | 
					
						
							|  |  |  | pub const DEFAULT_PURGE_SLOT_INTERVAL: u64 = 512;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  | // Compacting at a slower interval than purging helps keep IOPS down.
 | 
					
						
							|  |  |  | // Once a day should be ample
 | 
					
						
							|  |  |  | const DEFAULT_COMPACTION_SLOT_INTERVAL: u64 = TICKS_PER_DAY / DEFAULT_TICKS_PER_SLOT;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  | pub struct LedgerCleanupService {
 | 
					
						
							|  |  |  |     t_cleanup: JoinHandle<()>,
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | impl LedgerCleanupService {
 | 
					
						
							|  |  |  |     pub fn new(
 | 
					
						
							| 
									
										
										
										
											2019-12-18 11:50:09 -08:00
										 |  |  |         new_root_receiver: Receiver<Slot>,
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |         blockstore: Arc<Blockstore>,
 | 
					
						
							| 
									
										
										
										
											2020-03-31 17:21:19 -07:00
										 |  |  |         max_ledger_shreds: u64,
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |         exit: &Arc<AtomicBool>,
 | 
					
						
							|  |  |  |     ) -> Self {
 | 
					
						
							| 
									
										
										
										
											2019-07-24 17:28:08 -07:00
										 |  |  |         info!(
 | 
					
						
							|  |  |  |             "LedgerCleanupService active. Max Ledger Slots {}",
 | 
					
						
							| 
									
										
										
										
											2020-03-31 17:21:19 -07:00
										 |  |  |             max_ledger_shreds
 | 
					
						
							| 
									
										
										
										
											2019-07-24 17:28:08 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |         let exit = exit.clone();
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         let mut last_purge_slot = 0;
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |         let mut last_compaction_slot = 0;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |         let t_cleanup = Builder::new()
 | 
					
						
							|  |  |  |             .name("solana-ledger-cleanup".to_string())
 | 
					
						
							|  |  |  |             .spawn(move || loop {
 | 
					
						
							|  |  |  |                 if exit.load(Ordering::Relaxed) {
 | 
					
						
							|  |  |  |                     break;
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2019-12-18 11:50:09 -08:00
										 |  |  |                 if let Err(e) = Self::cleanup_ledger(
 | 
					
						
							|  |  |  |                     &new_root_receiver,
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |                     &blockstore,
 | 
					
						
							| 
									
										
										
										
											2020-03-31 17:21:19 -07:00
										 |  |  |                     max_ledger_shreds,
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                     &mut last_purge_slot,
 | 
					
						
							|  |  |  |                     DEFAULT_PURGE_SLOT_INTERVAL,
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |                     &mut last_compaction_slot,
 | 
					
						
							|  |  |  |                     DEFAULT_COMPACTION_SLOT_INTERVAL,
 | 
					
						
							| 
									
										
										
										
											2019-12-18 11:50:09 -08:00
										 |  |  |                 ) {
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |                     match e {
 | 
					
						
							| 
									
										
										
										
											2020-01-02 20:50:43 -07:00
										 |  |  |                         RecvTimeoutError::Disconnected => break,
 | 
					
						
							|  |  |  |                         RecvTimeoutError::Timeout => (),
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |                     }
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             })
 | 
					
						
							|  |  |  |             .unwrap();
 | 
					
						
							|  |  |  |         Self { t_cleanup }
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |     fn find_slots_to_clean(
 | 
					
						
							|  |  |  |         blockstore: &Arc<Blockstore>,
 | 
					
						
							|  |  |  |         root: Slot,
 | 
					
						
							|  |  |  |         max_ledger_shreds: u64,
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |     ) -> (bool, Slot, Slot, u64) {
 | 
					
						
							|  |  |  |         let mut total_slots = Vec::new();
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         let mut iterate_time = Measure::start("iterate_time");
 | 
					
						
							|  |  |  |         let mut total_shreds = 0;
 | 
					
						
							|  |  |  |         let mut first_slot = 0;
 | 
					
						
							|  |  |  |         for (i, (slot, meta)) in blockstore.slot_meta_iterator(0).unwrap().enumerate() {
 | 
					
						
							|  |  |  |             if i == 0 {
 | 
					
						
							|  |  |  |                 first_slot = slot;
 | 
					
						
							|  |  |  |                 debug!("purge: searching from slot: {}", slot);
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             // Not exact since non-full slots will have holes
 | 
					
						
							|  |  |  |             total_shreds += meta.received;
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |             total_slots.push((slot, meta.received));
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |             if slot > root {
 | 
					
						
							|  |  |  |                 break;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         iterate_time.stop();
 | 
					
						
							|  |  |  |         info!(
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |             "first_slot={} total_slots={} total_shreds={} max_ledger_shreds={}, {}",
 | 
					
						
							|  |  |  |             first_slot,
 | 
					
						
							|  |  |  |             total_slots.len(),
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |             total_shreds,
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |             max_ledger_shreds,
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |             iterate_time
 | 
					
						
							|  |  |  |         );
 | 
					
						
							|  |  |  |         if (total_shreds as u64) < max_ledger_shreds {
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |             return (false, 0, 0, total_shreds);
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         let mut num_shreds_to_clean = 0;
 | 
					
						
							|  |  |  |         let mut lowest_cleanup_slot = total_slots[0].0;
 | 
					
						
							|  |  |  |         for (slot, num_shreds) in total_slots.iter().rev() {
 | 
					
						
							|  |  |  |             num_shreds_to_clean += *num_shreds as u64;
 | 
					
						
							|  |  |  |             if num_shreds_to_clean > max_ledger_shreds {
 | 
					
						
							|  |  |  |                 lowest_cleanup_slot = *slot;
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                 break;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |         (true, first_slot, lowest_cleanup_slot, total_shreds)
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     fn receive_new_roots(new_root_receiver: &Receiver<Slot>) -> Result<Slot, RecvTimeoutError> {
 | 
					
						
							|  |  |  |         let mut root = new_root_receiver.recv_timeout(Duration::from_secs(1))?;
 | 
					
						
							|  |  |  |         // Get the newest root
 | 
					
						
							|  |  |  |         while let Ok(new_root) = new_root_receiver.try_recv() {
 | 
					
						
							|  |  |  |             root = new_root;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  |         Ok(root)
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 11:54:03 -07:00
										 |  |  |     pub fn cleanup_ledger(
 | 
					
						
							| 
									
										
										
										
											2019-12-18 11:50:09 -08:00
										 |  |  |         new_root_receiver: &Receiver<Slot>,
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |         blockstore: &Arc<Blockstore>,
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         max_ledger_shreds: u64,
 | 
					
						
							|  |  |  |         last_purge_slot: &mut u64,
 | 
					
						
							|  |  |  |         purge_interval: u64,
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |         last_compaction_slot: &mut u64,
 | 
					
						
							|  |  |  |         compaction_interval: u64,
 | 
					
						
							| 
									
										
										
										
											2020-01-02 20:50:43 -07:00
										 |  |  |     ) -> Result<(), RecvTimeoutError> {
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         let root = Self::receive_new_roots(new_root_receiver)?;
 | 
					
						
							|  |  |  |         if root - *last_purge_slot <= purge_interval {
 | 
					
						
							|  |  |  |             return Ok(());
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2020-04-24 15:04:23 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         let disk_utilization_pre = blockstore.storage_size();
 | 
					
						
							|  |  |  |         info!(
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |             "purge: last_root={}, last_purge_slot={}, purge_interval={}, last_compaction_slot={}, disk_utilization={:?}",
 | 
					
						
							|  |  |  |             root, last_purge_slot, purge_interval, last_compaction_slot, disk_utilization_pre
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         );
 | 
					
						
							| 
									
										
										
										
											2020-06-29 14:44:35 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         *last_purge_slot = root;
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |         let (slots_to_clean, purge_first_slot, lowest_cleanup_slot, total_shreds) =
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |             Self::find_slots_to_clean(&blockstore, root, max_ledger_shreds);
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         if slots_to_clean {
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |             let mut compact_first_slot = std::u64::MAX;
 | 
					
						
							|  |  |  |             if lowest_cleanup_slot.saturating_sub(*last_compaction_slot) > compaction_interval {
 | 
					
						
							|  |  |  |                 compact_first_slot = *last_compaction_slot;
 | 
					
						
							|  |  |  |                 *last_compaction_slot = lowest_cleanup_slot;
 | 
					
						
							|  |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |             let purge_complete = Arc::new(AtomicBool::new(false));
 | 
					
						
							|  |  |  |             let blockstore = blockstore.clone();
 | 
					
						
							|  |  |  |             let purge_complete1 = purge_complete.clone();
 | 
					
						
							|  |  |  |             let _t_purge = Builder::new()
 | 
					
						
							|  |  |  |                 .name("solana-ledger-purge".to_string())
 | 
					
						
							|  |  |  |                 .spawn(move || {
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                     let mut slot_update_time = Measure::start("slot_update");
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |                     *blockstore.lowest_cleanup_slot.write().unwrap() = lowest_cleanup_slot;
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                     slot_update_time.stop();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |                     info!(
 | 
					
						
							|  |  |  |                         "purging data from slots {} to {}",
 | 
					
						
							|  |  |  |                         purge_first_slot, lowest_cleanup_slot
 | 
					
						
							|  |  |  |                     );
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-29 14:44:35 -07:00
										 |  |  |                     let mut purge_time = Measure::start("purge_slots");
 | 
					
						
							|  |  |  |                     blockstore.purge_slots(
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |                         purge_first_slot,
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |                         lowest_cleanup_slot,
 | 
					
						
							| 
									
										
										
										
											2020-06-02 19:49:31 -06:00
										 |  |  |                         PurgeType::PrimaryIndex,
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                     );
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |                     purge_time.stop();
 | 
					
						
							|  |  |  |                     info!("{}", purge_time);
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |                     if compact_first_slot < lowest_cleanup_slot {
 | 
					
						
							|  |  |  |                         info!(
 | 
					
						
							|  |  |  |                             "compacting data from slots {} to {}",
 | 
					
						
							|  |  |  |                             compact_first_slot, lowest_cleanup_slot
 | 
					
						
							|  |  |  |                         );
 | 
					
						
							|  |  |  |                         if let Err(err) =
 | 
					
						
							|  |  |  |                             blockstore.compact_storage(compact_first_slot, lowest_cleanup_slot)
 | 
					
						
							|  |  |  |                         {
 | 
					
						
							|  |  |  |                             // This error is not fatal and indicates an internal error?
 | 
					
						
							|  |  |  |                             error!(
 | 
					
						
							|  |  |  |                                 "Error: {:?}; Couldn't compact storage from {:?} to {:?}",
 | 
					
						
							|  |  |  |                                 err, compact_first_slot, lowest_cleanup_slot
 | 
					
						
							|  |  |  |                             );
 | 
					
						
							|  |  |  |                         }
 | 
					
						
							|  |  |  |                     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |                     purge_complete1.store(true, Ordering::Relaxed);
 | 
					
						
							|  |  |  |                 })
 | 
					
						
							|  |  |  |                 .unwrap();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // Keep pulling roots off `new_root_receiver` while purging to avoid channel buildup
 | 
					
						
							|  |  |  |             while !purge_complete.load(Ordering::Relaxed) {
 | 
					
						
							|  |  |  |                 if let Err(err) = Self::receive_new_roots(new_root_receiver) {
 | 
					
						
							|  |  |  |                     debug!("receive_new_roots: {}", err);
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                 }
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |                 thread::sleep(Duration::from_secs(1));
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |             }
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-12-06 22:32:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         let disk_utilization_post = blockstore.storage_size();
 | 
					
						
							|  |  |  |         Self::report_disk_metrics(disk_utilization_pre, disk_utilization_post, total_shreds);
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         Ok(())
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-12-06 22:32:45 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-12 15:24:39 -07:00
										 |  |  |     fn report_disk_metrics(
 | 
					
						
							|  |  |  |         pre: BlockstoreResult<u64>,
 | 
					
						
							|  |  |  |         post: BlockstoreResult<u64>,
 | 
					
						
							|  |  |  |         total_shreds: u64,
 | 
					
						
							|  |  |  |     ) {
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         if let (Ok(pre), Ok(post)) = (pre, post) {
 | 
					
						
							| 
									
										
										
										
											2020-05-12 15:24:39 -07:00
										 |  |  |             datapoint_info!(
 | 
					
						
							| 
									
										
										
										
											2019-12-10 19:12:49 -05:00
										 |  |  |                 "ledger_disk_utilization",
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |                 ("disk_utilization_pre", pre as i64, i64),
 | 
					
						
							|  |  |  |                 ("disk_utilization_post", post as i64, i64),
 | 
					
						
							| 
									
										
										
										
											2020-05-12 15:24:39 -07:00
										 |  |  |                 ("disk_utilization_delta", (pre as i64 - post as i64), i64),
 | 
					
						
							|  |  |  |                 ("total_shreds", total_shreds, i64),
 | 
					
						
							| 
									
										
										
										
											2019-12-10 19:12:49 -05:00
										 |  |  |             );
 | 
					
						
							|  |  |  |         }
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |     }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-13 11:12:09 -07:00
										 |  |  |     pub fn join(self) -> thread::Result<()> {
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |         self.t_cleanup.join()
 | 
					
						
							|  |  |  |     }
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | #[cfg(test)]
 | 
					
						
							|  |  |  | mod tests {
 | 
					
						
							|  |  |  |     use super::*;
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |     use solana_ledger::blockstore::make_many_slot_entries;
 | 
					
						
							| 
									
										
										
										
											2019-11-13 08:14:09 -07:00
										 |  |  |     use solana_ledger::get_tmp_ledger_path;
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |     use std::sync::mpsc::channel;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_cleanup() {
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         solana_logger::setup();
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |         let blockstore_path = get_tmp_ledger_path!();
 | 
					
						
							|  |  |  |         let blockstore = Blockstore::open(&blockstore_path).unwrap();
 | 
					
						
							| 
									
										
										
										
											2019-09-03 21:32:51 -07:00
										 |  |  |         let (shreds, _) = make_many_slot_entries(0, 50, 5);
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |         blockstore.insert_shreds(shreds, None, false).unwrap();
 | 
					
						
							|  |  |  |         let blockstore = Arc::new(blockstore);
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |         let (sender, receiver) = channel();
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         //send a signal to kill all but 5 shreds, which will be in the newest slots
 | 
					
						
							|  |  |  |         let mut last_purge_slot = 0;
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |         let mut last_compaction_slot = 0;
 | 
					
						
							| 
									
										
										
										
											2019-12-18 11:50:09 -08:00
										 |  |  |         sender.send(50).unwrap();
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         LedgerCleanupService::cleanup_ledger(
 | 
					
						
							|  |  |  |             &receiver,
 | 
					
						
							|  |  |  |             &blockstore,
 | 
					
						
							|  |  |  |             5,
 | 
					
						
							|  |  |  |             &mut last_purge_slot,
 | 
					
						
							|  |  |  |             10,
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |             &mut last_compaction_slot,
 | 
					
						
							|  |  |  |             10,
 | 
					
						
							| 
									
										
										
										
											2020-05-24 21:41:54 -07:00
										 |  |  |         )
 | 
					
						
							|  |  |  |         .unwrap();
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |         //check that 0-40 don't exist
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |         blockstore
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |             .slot_meta_iterator(0)
 | 
					
						
							|  |  |  |             .unwrap()
 | 
					
						
							|  |  |  |             .for_each(|(slot, _)| assert!(slot > 40));
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-01-13 14:13:52 -07:00
										 |  |  |         drop(blockstore);
 | 
					
						
							|  |  |  |         Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-12-18 10:29:46 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |     #[test]
 | 
					
						
							|  |  |  |     fn test_cleanup_speed() {
 | 
					
						
							|  |  |  |         solana_logger::setup();
 | 
					
						
							|  |  |  |         let blockstore_path = get_tmp_ledger_path!();
 | 
					
						
							|  |  |  |         let mut blockstore = Blockstore::open(&blockstore_path).unwrap();
 | 
					
						
							|  |  |  |         blockstore.set_no_compaction(true);
 | 
					
						
							|  |  |  |         let blockstore = Arc::new(blockstore);
 | 
					
						
							|  |  |  |         let (sender, receiver) = channel();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let mut first_insert = Measure::start("first_insert");
 | 
					
						
							|  |  |  |         let initial_slots = 50;
 | 
					
						
							|  |  |  |         let initial_entries = 5;
 | 
					
						
							|  |  |  |         let (shreds, _) = make_many_slot_entries(0, initial_slots, initial_entries);
 | 
					
						
							|  |  |  |         blockstore.insert_shreds(shreds, None, false).unwrap();
 | 
					
						
							|  |  |  |         first_insert.stop();
 | 
					
						
							|  |  |  |         info!("{}", first_insert);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         let mut last_purge_slot = 0;
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |         let mut last_compaction_slot = 0;
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |         let mut slot = initial_slots;
 | 
					
						
							|  |  |  |         let mut num_slots = 6;
 | 
					
						
							|  |  |  |         for _ in 0..5 {
 | 
					
						
							|  |  |  |             let mut insert_time = Measure::start("insert time");
 | 
					
						
							|  |  |  |             let batch_size = 2;
 | 
					
						
							|  |  |  |             let batches = num_slots / batch_size;
 | 
					
						
							|  |  |  |             for i in 0..batches {
 | 
					
						
							|  |  |  |                 let (shreds, _) = make_many_slot_entries(slot + i * batch_size, batch_size, 5);
 | 
					
						
							|  |  |  |                 blockstore.insert_shreds(shreds, None, false).unwrap();
 | 
					
						
							|  |  |  |                 if i % 100 == 0 {
 | 
					
						
							|  |  |  |                     info!("inserting..{} of {}", i, batches);
 | 
					
						
							|  |  |  |                 }
 | 
					
						
							|  |  |  |             }
 | 
					
						
							|  |  |  |             insert_time.stop();
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             let mut time = Measure::start("purge time");
 | 
					
						
							|  |  |  |             sender.send(slot + num_slots).unwrap();
 | 
					
						
							|  |  |  |             LedgerCleanupService::cleanup_ledger(
 | 
					
						
							|  |  |  |                 &receiver,
 | 
					
						
							|  |  |  |                 &blockstore,
 | 
					
						
							|  |  |  |                 initial_slots,
 | 
					
						
							|  |  |  |                 &mut last_purge_slot,
 | 
					
						
							|  |  |  |                 10,
 | 
					
						
							| 
									
										
										
										
											2020-06-04 21:06:06 -07:00
										 |  |  |                 &mut last_compaction_slot,
 | 
					
						
							|  |  |  |                 10,
 | 
					
						
							| 
									
										
										
										
											2020-03-30 19:02:12 -07:00
										 |  |  |             )
 | 
					
						
							|  |  |  |             .unwrap();
 | 
					
						
							|  |  |  |             time.stop();
 | 
					
						
							|  |  |  |             info!(
 | 
					
						
							|  |  |  |                 "slot: {} size: {} {} {}",
 | 
					
						
							|  |  |  |                 slot, num_slots, insert_time, time
 | 
					
						
							|  |  |  |             );
 | 
					
						
							|  |  |  |             slot += num_slots;
 | 
					
						
							|  |  |  |             num_slots *= 2;
 | 
					
						
							|  |  |  |         }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         drop(blockstore);
 | 
					
						
							|  |  |  |         Blockstore::destroy(&blockstore_path).expect("Expected successful database destruction");
 | 
					
						
							|  |  |  |     }
 | 
					
						
							| 
									
										
										
										
											2019-07-20 13:13:55 -07:00
										 |  |  | }
 |