#[cfg(feature = "stable-abi")]
use solana_frozen_abi_macro::{StableAbi, StableAbiSample, frozen_abi};
use {
solana_accounts_db::{
account_storage_entry::AccountStorageEntry, accounts_db::AccountsFileId,
accounts_file::AccountsFile,
},
solana_clock::Slot,
std::sync::Arc,
wincode::{SchemaRead, SchemaWrite},
};
#[repr(u8)]
#[cfg_attr(feature = "stable-abi", derive(StableAbi, StableAbiSample))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, SchemaRead, SchemaWrite)]
pub enum StorageListItem {
AppendVec {
id: AccountsFileId,
slot: Slot,
},
Split {
has_data_file: bool,
id: AccountsFileId,
slot: Slot,
},
}
const _: () = assert!(size_of::<StorageListItem>() == 16);
#[cfg_attr(
feature = "stable-abi",
derive(StableAbi, StableAbiSample, PartialEq),
frozen_abi(
abi_digest = "DPaA5tV2PU6rbtFswCwHXGTprqYu3u2hBEZ5vzCEtLZe",
abi_serializer = "wincode",
test_roundtrip = "eq_and_wire"
)
)]
#[derive(Debug, SchemaRead, SchemaWrite)]
pub struct StoragesList {
pub items: Vec<StorageListItem>,
}
impl StoragesList {
pub fn new_from_storages(snapshot_storages: &[Arc<AccountStorageEntry>]) -> Self {
let items = snapshot_storages
.iter()
.map(|storage| {
let slot = storage.slot();
let id = storage.id();
match &storage.accounts {
AccountsFile::AppendVec(_) => StorageListItem::AppendVec { slot, id },
AccountsFile::Split(split) => StorageListItem::Split {
slot,
id,
has_data_file: split.data_file().is_some(),
},
}
})
.collect();
Self { items }
}
}
impl From<LegacyStoragesList> for StoragesList {
fn from(legacy: LegacyStoragesList) -> StoragesList {
let items = legacy
.items
.into_iter()
.map(|legacy_item| StorageListItem::AppendVec {
slot: legacy_item.slot,
id: legacy_item.id,
})
.collect();
StoragesList { items }
}
}
#[repr(C)]
#[cfg_attr(feature = "stable-abi", derive(StableAbi, StableAbiSample, PartialEq))]
#[derive(Debug, SchemaRead, SchemaWrite)]
pub struct LegacyStorageListItem {
pub slot: Slot,
pub id: AccountsFileId,
}
#[cfg_attr(
feature = "stable-abi",
derive(StableAbi, StableAbiSample, PartialEq),
frozen_abi(
abi_digest = "4FjJ2aGVW2RSNq5XQBAMG3q13KcCJxKihG3TtXGQzoRv",
abi_serializer = "wincode",
test_roundtrip = "eq_and_wire"
)
)]
#[derive(Debug, SchemaRead, SchemaWrite)]
pub struct LegacyStoragesList {
pub items: Vec<LegacyStorageListItem>,
}
#[cfg(test)]
mod tests {
use {
super::*,
crate::serde_snapshot::{deserialize_wincode_from, serialize_into},
std::io::Cursor,
};
#[test]
fn test_roundtrip_storages_list() {
let list = StoragesList {
items: vec![
StorageListItem::AppendVec { slot: 0, id: 0 },
StorageListItem::AppendVec { slot: 7, id: 42 },
StorageListItem::Split {
slot: 11,
id: 13,
has_data_file: false,
},
StorageListItem::Split {
slot: Slot::MAX,
id: AccountsFileId::MAX,
has_data_file: true,
},
],
};
let mut buf = Vec::new();
serialize_into(Cursor::new(&mut buf), &list).unwrap();
let decoded: StoragesList = deserialize_wincode_from(Cursor::new(&buf)).unwrap();
assert_eq!(decoded.items, list.items);
}
#[test]
fn test_from_legacy_storages_list() {
let legacy_list = LegacyStoragesList {
items: vec![
LegacyStorageListItem { slot: 7, id: 42 },
LegacyStorageListItem { slot: 11, id: 13 },
LegacyStorageListItem {
slot: Slot::MAX,
id: AccountsFileId::MAX,
},
],
};
let mut buf = Vec::new();
serialize_into(Cursor::new(&mut buf), &legacy_list).unwrap();
let expected_current: Vec<_> = legacy_list
.items
.iter()
.map(|item| StorageListItem::AppendVec {
slot: item.slot,
id: item.id,
})
.collect();
let decoded: LegacyStoragesList = deserialize_wincode_from(Cursor::new(&buf)).unwrap();
let actual_current = StoragesList::from(decoded);
assert_eq!(actual_current.items, expected_current);
}
}