|
|
@@ -431,13 +431,7 @@ impl AppendVec {
|
|
|
let path = path.into();
|
|
|
let new = Self::new_from_file_unchecked(path, current_len, storage_access)?;
|
|
|
|
|
|
- let (sanitized, num_accounts) = new.sanitize_layout_and_length();
|
|
|
- if !sanitized {
|
|
|
- return Err(AccountsFileError::AppendVecError(
|
|
|
- AppendVecError::IncorrectLayout(new.path.clone()),
|
|
|
- ));
|
|
|
- }
|
|
|
-
|
|
|
+ let num_accounts = new.sanitize_layout_and_length()?;
|
|
|
Ok((new, num_accounts))
|
|
|
}
|
|
|
|
|
|
@@ -476,14 +470,8 @@ impl AppendVec {
|
|
|
current_len,
|
|
|
new.path.display(),
|
|
|
);
|
|
|
- let (sanitized, _num_accounts) = new.sanitize_layout_and_length();
|
|
|
- if sanitized {
|
|
|
- Ok(new)
|
|
|
- } else {
|
|
|
- Err(AccountsFileError::AppendVecError(
|
|
|
- AppendVecError::IncorrectLayout(new.path.clone()),
|
|
|
- ))
|
|
|
- }
|
|
|
+ let _num_accounts = new.sanitize_layout_and_length()?;
|
|
|
+ Ok(new)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -558,7 +546,8 @@ impl AppendVec {
|
|
|
Self::new_from_file_unchecked(path, file_size as usize, StorageAccess::default())
|
|
|
}
|
|
|
|
|
|
- fn sanitize_layout_and_length(&self) -> (bool, usize) {
|
|
|
+ /// Checks that all accounts layout is correct and returns the number of accounts.
|
|
|
+ fn sanitize_layout_and_length(&self) -> Result<usize> {
|
|
|
// This discards allocated accounts immediately after check at each loop iteration.
|
|
|
//
|
|
|
// This code should not reuse AppendVec.accounts() method as the current form or
|
|
|
@@ -574,13 +563,16 @@ impl AppendVec {
|
|
|
}
|
|
|
last_offset = account.offset() + account.stored_size();
|
|
|
num_accounts += 1;
|
|
|
- });
|
|
|
- if !matches {
|
|
|
- return (false, num_accounts);
|
|
|
- }
|
|
|
+ })?;
|
|
|
let aligned_current_len = u64_align!(self.current_len.load(Ordering::Acquire));
|
|
|
|
|
|
- (last_offset == aligned_current_len, num_accounts)
|
|
|
+ if !matches || last_offset != aligned_current_len {
|
|
|
+ return Err(AccountsFileError::AppendVecError(
|
|
|
+ AppendVecError::IncorrectLayout(self.path.clone()),
|
|
|
+ ));
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(num_accounts)
|
|
|
}
|
|
|
|
|
|
/// Get a reference to the data at `offset` of `size` bytes if that slice
|
|
|
@@ -996,7 +988,7 @@ impl AppendVec {
|
|
|
pub fn scan_accounts_without_data(
|
|
|
&self,
|
|
|
mut callback: impl for<'local> FnMut(Offset, StoredAccountInfoWithoutData<'local>),
|
|
|
- ) {
|
|
|
+ ) -> Result<()> {
|
|
|
self.scan_stored_accounts_no_data(|stored_account| {
|
|
|
let offset = stored_account.offset();
|
|
|
let account = StoredAccountInfoWithoutData {
|
|
|
@@ -1022,7 +1014,7 @@ impl AppendVec {
|
|
|
pub fn scan_accounts(
|
|
|
&self,
|
|
|
mut callback: impl for<'local> FnMut(Offset, StoredAccountInfo<'local>),
|
|
|
- ) {
|
|
|
+ ) -> Result<()> {
|
|
|
self.scan_accounts_stored_meta(|stored_account_meta| {
|
|
|
let offset = stored_account_meta.offset();
|
|
|
let account = StoredAccountInfo {
|
|
|
@@ -1045,7 +1037,7 @@ impl AppendVec {
|
|
|
pub fn scan_accounts_stored_meta(
|
|
|
&self,
|
|
|
mut callback: impl for<'local> FnMut(StoredAccountMeta<'local>),
|
|
|
- ) {
|
|
|
+ ) -> Result<()> {
|
|
|
match &self.backing {
|
|
|
AppendVecFileBacking::Mmap(_mmap) => {
|
|
|
let mut offset = 0;
|
|
|
@@ -1074,7 +1066,7 @@ impl AppendVec {
|
|
|
// Buffer for account data that doesn't fit within the stack allocated buffer.
|
|
|
// This will be re-used for each account that doesn't fit within the stack allocated buffer.
|
|
|
let mut data_overflow_buffer = vec![];
|
|
|
- while let Ok(BufferedReaderStatus::Success) = reader.read() {
|
|
|
+ while let BufferedReaderStatus::Success = reader.read()? {
|
|
|
let (offset, bytes_subset) = reader.get_offset_and_data();
|
|
|
let (meta, next) = Self::get_type::<StoredMeta>(bytes_subset, 0).unwrap();
|
|
|
let (account_meta, next) =
|
|
|
@@ -1147,6 +1139,7 @@ impl AppendVec {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ Ok(())
|
|
|
}
|
|
|
|
|
|
/// Calculate the amount of storage required for an account with the passed
|
|
|
@@ -1212,14 +1205,17 @@ impl AppendVec {
|
|
|
/// `data` is completely ignored, for example.
|
|
|
/// Also, no references have to be maintained/returned from an iterator function.
|
|
|
/// This fn can operate on a batch of data at once.
|
|
|
- pub fn scan_pubkeys(&self, mut callback: impl FnMut(&Pubkey)) {
|
|
|
+ pub fn scan_pubkeys(&self, mut callback: impl FnMut(&Pubkey)) -> Result<()> {
|
|
|
self.scan_stored_accounts_no_data(|account| {
|
|
|
callback(account.pubkey());
|
|
|
- });
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
/// Iterate over all accounts and call `callback` with the fixed sized portion of each account.
|
|
|
- fn scan_stored_accounts_no_data(&self, mut callback: impl FnMut(StoredAccountNoData)) {
|
|
|
+ fn scan_stored_accounts_no_data(
|
|
|
+ &self,
|
|
|
+ mut callback: impl FnMut(StoredAccountNoData),
|
|
|
+ ) -> Result<()> {
|
|
|
let self_len = self.len();
|
|
|
match &self.backing {
|
|
|
AppendVecFileBacking::Mmap(mmap) => {
|
|
|
@@ -1262,7 +1258,7 @@ impl AppendVec {
|
|
|
file,
|
|
|
mem::size_of::<StoredMeta>() + mem::size_of::<AccountMeta>(),
|
|
|
);
|
|
|
- while let Ok(BufferedReaderStatus::Success) = reader.read() {
|
|
|
+ while let BufferedReaderStatus::Success = reader.read()? {
|
|
|
let (offset, bytes) = reader.get_offset_and_data();
|
|
|
let (stored_meta, next) = Self::get_type::<StoredMeta>(bytes, 0).unwrap();
|
|
|
let (account_meta, _) = Self::get_type::<AccountMeta>(bytes, next).unwrap();
|
|
|
@@ -1288,6 +1284,7 @@ impl AppendVec {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ Ok(())
|
|
|
}
|
|
|
|
|
|
/// Copy each account metadata, account and hash to the internal buffer.
|
|
|
@@ -1663,7 +1660,8 @@ pub mod tests {
|
|
|
let mut count = 0;
|
|
|
self.scan_stored_accounts_no_data(|_| {
|
|
|
count += 1;
|
|
|
- });
|
|
|
+ })
|
|
|
+ .expect("must scan accounts storage");
|
|
|
count
|
|
|
}
|
|
|
}
|
|
|
@@ -1739,7 +1737,8 @@ pub mod tests {
|
|
|
assert_eq!(&recovered, account);
|
|
|
assert_eq!(v.pubkey(), pubkey);
|
|
|
index += 1;
|
|
|
- });
|
|
|
+ })
|
|
|
+ .expect("must scan accounts storage");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1786,7 +1785,8 @@ pub mod tests {
|
|
|
let recovered = v.to_account_shared_data();
|
|
|
assert_eq!(recovered, account.1);
|
|
|
sample += 1;
|
|
|
- });
|
|
|
+ })
|
|
|
+ .expect("must scan accounts storage");
|
|
|
trace!("sequential read time: {} ms", now.elapsed().as_millis());
|
|
|
}
|
|
|
|
|
|
@@ -2196,10 +2196,12 @@ pub mod tests {
|
|
|
modify_fn,
|
|
|
|append_vec, pubkeys, _account_offsets, _accounts| {
|
|
|
let mut i = 0;
|
|
|
- append_vec.scan_pubkeys(|pubkey| {
|
|
|
- assert_eq!(pubkey, pubkeys.get(i).unwrap());
|
|
|
- i += 1;
|
|
|
- });
|
|
|
+ append_vec
|
|
|
+ .scan_pubkeys(|pubkey| {
|
|
|
+ assert_eq!(pubkey, pubkeys.get(i).unwrap());
|
|
|
+ i += 1;
|
|
|
+ })
|
|
|
+ .expect("must scan accounts storage");
|
|
|
assert_eq!(i, pubkeys.len());
|
|
|
},
|
|
|
)
|
|
|
@@ -2282,22 +2284,24 @@ pub mod tests {
|
|
|
modify_fn,
|
|
|
|append_vec, pubkeys, account_offsets, accounts| {
|
|
|
let mut i = 0;
|
|
|
- append_vec.scan_stored_accounts_no_data(|stored_account| {
|
|
|
- let pubkey = pubkeys.get(i).unwrap();
|
|
|
- let account = accounts.get(i).unwrap();
|
|
|
- let offset = account_offsets.get(i).unwrap();
|
|
|
-
|
|
|
- assert_eq!(
|
|
|
- stored_account.stored_size,
|
|
|
- aligned_stored_size(account.data().len()),
|
|
|
- );
|
|
|
- assert_eq!(stored_account.offset(), *offset);
|
|
|
- assert_eq!(stored_account.pubkey(), pubkey);
|
|
|
- assert_eq!(stored_account.lamports(), account.lamports());
|
|
|
- assert_eq!(stored_account.data_len(), account.data().len() as u64);
|
|
|
-
|
|
|
- i += 1;
|
|
|
- });
|
|
|
+ append_vec
|
|
|
+ .scan_stored_accounts_no_data(|stored_account| {
|
|
|
+ let pubkey = pubkeys.get(i).unwrap();
|
|
|
+ let account = accounts.get(i).unwrap();
|
|
|
+ let offset = account_offsets.get(i).unwrap();
|
|
|
+
|
|
|
+ assert_eq!(
|
|
|
+ stored_account.stored_size,
|
|
|
+ aligned_stored_size(account.data().len()),
|
|
|
+ );
|
|
|
+ assert_eq!(stored_account.offset(), *offset);
|
|
|
+ assert_eq!(stored_account.pubkey(), pubkey);
|
|
|
+ assert_eq!(stored_account.lamports(), account.lamports());
|
|
|
+ assert_eq!(stored_account.data_len(), account.data().len() as u64);
|
|
|
+
|
|
|
+ i += 1;
|
|
|
+ })
|
|
|
+ .expect("must scan accounts storage");
|
|
|
assert_eq!(i, accounts.len());
|
|
|
},
|
|
|
)
|