1use {
2 crate::{
3 accounts::Accounts,
4 accounts_db::SnapshotStorages,
5 bank::{Bank, BankSlotDelta},
6 rent_collector::RentCollector,
7 snapshot_archive_info::{SnapshotArchiveInfo, SnapshotArchiveInfoGetter},
8 snapshot_utils::{
9 self, ArchiveFormat, BankSnapshotInfo, Result, SnapshotVersion,
10 TMP_BANK_SNAPSHOT_PREFIX,
11 },
12 },
13 log::*,
14 solana_sdk::{
15 clock::Slot, genesis_config::ClusterType, hash::Hash, sysvar::epoch_schedule::EpochSchedule,
16 },
17 std::{
18 fs,
19 path::{Path, PathBuf},
20 sync::{Arc, Mutex},
21 },
22 tempfile::TempDir,
23};
24
25pub type PendingAccountsPackage = Arc<Mutex<Option<AccountsPackage>>>;
28
29pub type PendingSnapshotPackage = Arc<Mutex<Option<SnapshotPackage>>>;
32
33#[derive(Debug)]
34pub struct AccountsPackage {
35 pub slot: Slot,
36 pub block_height: Slot,
37 pub slot_deltas: Vec<BankSlotDelta>,
38 pub snapshot_links: TempDir,
39 pub snapshot_storages: SnapshotStorages,
40 pub archive_format: ArchiveFormat,
41 pub snapshot_version: SnapshotVersion,
42 pub full_snapshot_archives_dir: PathBuf,
43 pub incremental_snapshot_archives_dir: PathBuf,
44 pub expected_capitalization: u64,
45 pub accounts_hash_for_testing: Option<Hash>,
46 pub cluster_type: ClusterType,
47 pub snapshot_type: Option<SnapshotType>,
48 pub accounts: Arc<Accounts>,
49 pub epoch_schedule: EpochSchedule,
50 pub rent_collector: RentCollector,
51}
52
53impl AccountsPackage {
54 #[allow(clippy::too_many_arguments)]
56 pub fn new(
57 bank: &Bank,
58 bank_snapshot_info: &BankSnapshotInfo,
59 bank_snapshots_dir: impl AsRef<Path>,
60 slot_deltas: Vec<BankSlotDelta>,
61 full_snapshot_archives_dir: impl AsRef<Path>,
62 incremental_snapshot_archives_dir: impl AsRef<Path>,
63 snapshot_storages: SnapshotStorages,
64 archive_format: ArchiveFormat,
65 snapshot_version: SnapshotVersion,
66 accounts_hash_for_testing: Option<Hash>,
67 snapshot_type: Option<SnapshotType>,
68 ) -> Result<Self> {
69 info!(
70 "Package snapshot for bank {} has {} account storage entries (snapshot type: {:?})",
71 bank.slot(),
72 snapshot_storages.len(),
73 snapshot_type,
74 );
75
76 if let Some(SnapshotType::IncrementalSnapshot(incremental_snapshot_base_slot)) =
77 snapshot_type
78 {
79 assert!(
80 bank.slot() > incremental_snapshot_base_slot,
81 "Incremental snapshot base slot must be less than the bank being snapshotted!"
82 );
83 }
84
85 let snapshot_links = tempfile::Builder::new()
87 .prefix(&format!("{}{}-", TMP_BANK_SNAPSHOT_PREFIX, bank.slot()))
88 .tempdir_in(bank_snapshots_dir)?;
89 {
90 let snapshot_hardlink_dir = snapshot_links
91 .path()
92 .join(bank_snapshot_info.slot.to_string());
93 fs::create_dir_all(&snapshot_hardlink_dir)?;
94 let file_name =
95 snapshot_utils::path_to_file_name_str(&bank_snapshot_info.snapshot_path)?;
96 fs::hard_link(
97 &bank_snapshot_info.snapshot_path,
98 &snapshot_hardlink_dir.join(file_name),
99 )?;
100 }
101
102 Ok(Self {
103 slot: bank.slot(),
104 block_height: bank.block_height(),
105 slot_deltas,
106 snapshot_links,
107 snapshot_storages,
108 archive_format,
109 snapshot_version,
110 full_snapshot_archives_dir: full_snapshot_archives_dir.as_ref().to_path_buf(),
111 incremental_snapshot_archives_dir: incremental_snapshot_archives_dir
112 .as_ref()
113 .to_path_buf(),
114 expected_capitalization: bank.capitalization(),
115 accounts_hash_for_testing,
116 cluster_type: bank.cluster_type(),
117 snapshot_type,
118 accounts: bank.accounts(),
119 epoch_schedule: *bank.epoch_schedule(),
120 rent_collector: bank.rent_collector().clone(),
121 })
122 }
123}
124
125pub struct SnapshotPackage {
126 pub snapshot_archive_info: SnapshotArchiveInfo,
127 pub block_height: Slot,
128 pub slot_deltas: Vec<BankSlotDelta>,
129 pub snapshot_links: TempDir,
130 pub snapshot_storages: SnapshotStorages,
131 pub snapshot_version: SnapshotVersion,
132 pub snapshot_type: SnapshotType,
133}
134
135impl SnapshotPackage {
136 pub fn new(accounts_package: AccountsPackage, accounts_hash: Hash) -> Self {
137 assert!(
138 accounts_package.snapshot_type.is_some(),
139 "Cannot make a SnapshotPackage from an AccountsPackage when SnapshotType is None!"
140 );
141
142 let mut snapshot_storages = accounts_package.snapshot_storages;
143 let snapshot_archive_path = match accounts_package.snapshot_type.unwrap() {
144 SnapshotType::FullSnapshot => snapshot_utils::build_full_snapshot_archive_path(
145 accounts_package.full_snapshot_archives_dir,
146 accounts_package.slot,
147 &accounts_hash,
148 accounts_package.archive_format,
149 ),
150 SnapshotType::IncrementalSnapshot(incremental_snapshot_base_slot) => {
151 snapshot_storages.retain(|storages| {
152 storages
153 .first() .map(|storage| storage.slot() > incremental_snapshot_base_slot)
155 .unwrap_or_default()
156 });
157 assert!(
158 snapshot_storages.iter().all(|storage| storage
159 .iter()
160 .all(|entry| entry.slot() > incremental_snapshot_base_slot)),
161 "Incremental snapshot package must only contain storage entries where slot > incremental snapshot base slot (i.e. full snapshot slot)!"
162 );
163 snapshot_utils::build_incremental_snapshot_archive_path(
164 accounts_package.incremental_snapshot_archives_dir,
165 incremental_snapshot_base_slot,
166 accounts_package.slot,
167 &accounts_hash,
168 accounts_package.archive_format,
169 )
170 }
171 };
172
173 Self {
174 snapshot_archive_info: SnapshotArchiveInfo {
175 path: snapshot_archive_path,
176 slot: accounts_package.slot,
177 hash: accounts_hash,
178 archive_format: accounts_package.archive_format,
179 },
180 block_height: accounts_package.block_height,
181 slot_deltas: accounts_package.slot_deltas,
182 snapshot_links: accounts_package.snapshot_links,
183 snapshot_storages,
184 snapshot_version: accounts_package.snapshot_version,
185 snapshot_type: accounts_package.snapshot_type.unwrap(),
186 }
187 }
188}
189
190impl SnapshotArchiveInfoGetter for SnapshotPackage {
191 fn snapshot_archive_info(&self) -> &SnapshotArchiveInfo {
192 &self.snapshot_archive_info
193 }
194}
195
196#[derive(Clone, Copy, Debug, Eq, PartialEq)]
199pub enum SnapshotType {
200 FullSnapshot,
201 IncrementalSnapshot(Slot),
202}
203
204impl SnapshotType {
205 pub fn is_full_snapshot(&self) -> bool {
206 matches!(self, SnapshotType::FullSnapshot)
207 }
208 pub fn is_incremental_snapshot(&self) -> bool {
209 matches!(self, SnapshotType::IncrementalSnapshot(_))
210 }
211}
212
213#[inline(always)]
216pub fn retain_max_n_elements<T>(v: &mut Vec<T>, n: usize) {
217 if v.len() > n {
218 let to_truncate = v.len() - n;
219 v.rotate_left(to_truncate);
220 v.truncate(n);
221 }
222}