solana/runtime/src/serde_snapshot/legacy.rs

210 lines
7.5 KiB
Rust

use {super::*, solana_measure::measure::Measure, std::cell::RefCell};
// Serializable version of AccountStorageEntry for snapshot format
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
pub(super) struct SerializableAccountStorageEntry {
id: AppendVecId,
accounts: SerializableAppendVec,
count_and_status: (usize, AccountStorageStatus),
}
impl From<&AccountStorageEntry> for SerializableAccountStorageEntry {
fn from(rhs: &AccountStorageEntry) -> Self {
Self {
id: rhs.id,
accounts: SerializableAppendVec::from(&rhs.accounts),
..Self::default()
}
}
}
impl Into<AccountStorageEntry> for SerializableAccountStorageEntry {
fn into(self) -> AccountStorageEntry {
AccountStorageEntry::new_empty_map(self.id, self.accounts.current_len)
}
}
// Serializable version of AppendVec for snapshot format
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
struct SerializableAppendVec {
current_len: usize,
}
impl From<&AppendVec> for SerializableAppendVec {
fn from(rhs: &AppendVec) -> SerializableAppendVec {
SerializableAppendVec {
current_len: rhs.len(),
}
}
}
impl Into<AppendVec> for SerializableAppendVec {
fn into(self) -> AppendVec {
AppendVec::new_empty_map(self.current_len)
}
}
// Serialization of AppendVec requires serialization of u64 to
// eight byte vector which is then itself serialized to the stream
impl Serialize for SerializableAppendVec {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
const LEN: usize = std::mem::size_of::<usize>();
let mut buf = [0u8; LEN];
serialize_into(Cursor::new(&mut buf[..]), &(self.current_len as u64))
.map_err(serde::ser::Error::custom)?;
serializer.serialize_bytes(&buf)
}
}
// Deserialization of AppendVec requires deserialization
// of eight byte vector from which u64 is then deserialized
impl<'de> Deserialize<'de> for SerializableAppendVec {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
struct SerializableAppendVecVisitor;
impl<'a> Visitor<'a> for SerializableAppendVecVisitor {
type Value = SerializableAppendVec;
fn expecting(&self, formatter: &mut Formatter) -> FormatResult {
formatter.write_str("Expecting SerializableAppendVec")
}
fn visit_bytes<E>(self, data: &[u8]) -> std::result::Result<Self::Value, E>
where
E: Error,
{
const LEN: u64 = std::mem::size_of::<usize>() as u64;
let mut rd = Cursor::new(&data[..]);
let current_len: usize = deserialize_from(&mut rd).map_err(Error::custom)?;
if rd.position() != LEN {
Err(Error::custom("SerializableAppendVec: unexpected length"))
} else {
Ok(SerializableAppendVec { current_len })
}
}
}
deserializer.deserialize_bytes(SerializableAppendVecVisitor)
}
}
pub(super) struct Context {}
impl<'a> TypeContext<'a> for Context {
type SerializableAccountStorageEntry = SerializableAccountStorageEntry;
fn serialize_bank_rc_fields<S: serde::ser::Serializer>(
serializer: S,
serializable_bank: &SerializableBankRc<'a, Self>,
) -> std::result::Result<S::Ok, S::Error>
where
Self: std::marker::Sized,
{
// as there is no deserialize_bank_rc_fields(), do not emit the u64
// size field here and have serialize_accounts_db_fields() emit two
// u64 size fields instead
SerializableAccountsDB::<'a, Self> {
accounts_db: &*serializable_bank.bank_rc.accounts.accounts_db,
slot: serializable_bank.bank_rc.slot,
account_storage_entries: serializable_bank.snapshot_storages,
phantom: std::marker::PhantomData::default(),
}
.serialize(serializer)
}
fn serialize_accounts_db_fields<S: serde::ser::Serializer>(
serializer: S,
serializable_db: &SerializableAccountsDB<'a, Self>,
) -> std::result::Result<S::Ok, S::Error>
where
Self: std::marker::Sized,
{
// sample write version before serializing storage entries
let version = serializable_db
.accounts_db
.write_version
.load(Ordering::Relaxed);
// (1st of 3 elements) write the list of account storage entry lists out as a map
let entry_count = RefCell::<usize>::new(0);
let entries =
serialize_iter_as_map(serializable_db.account_storage_entries.iter().map(|x| {
*entry_count.borrow_mut() += x.len();
(
x.first().unwrap().slot,
serialize_iter_as_seq(
x.iter()
.map(|x| Self::SerializableAccountStorageEntry::from(x.as_ref())),
),
)
}));
let slot_hash = (
serializable_db.slot,
serializable_db
.accounts_db
.bank_hashes
.read()
.unwrap()
.get(&serializable_db.slot)
.unwrap_or_else(|| panic!("No bank_hashes entry for slot {}", serializable_db.slot))
.clone(),
);
let mut serialize_account_storage_timer = Measure::start("serialize_account_storage_ms");
let result = (
&MAX_ACCOUNTS_DB_STREAM_SIZE,
&MAX_ACCOUNTS_DB_STREAM_SIZE,
&entries,
&version,
&slot_hash,
)
.serialize(serializer);
serialize_account_storage_timer.stop();
datapoint_info!(
"serialize_account_storage_ms",
("duration", serialize_account_storage_timer.as_ms(), i64),
("num_entries", *entry_count.borrow(), i64),
);
result
}
fn deserialize_accounts_db_fields<R>(
mut stream: &mut BufReader<R>,
) -> Result<AccountDBFields<Self::SerializableAccountStorageEntry>, IoError>
where
R: Read,
{
// read and discard two u64 byte vector lengths
let serialized_len = MAX_ACCOUNTS_DB_STREAM_SIZE;
let serialized_len = min(
serialized_len,
deserialize_from(&mut stream).map_err(accountsdb_to_io_error)?,
);
let serialized_len = min(
serialized_len,
deserialize_from(&mut stream).map_err(accountsdb_to_io_error)?,
);
// (1st of 3 elements) read in map of slots to account storage entries
let storage: HashMap<Slot, Vec<Self::SerializableAccountStorageEntry>> = bincode::config()
.limit(serialized_len)
.deserialize_from(&mut stream)
.map_err(accountsdb_to_io_error)?;
// (2nd of 3 elements) read in write version
let version: u64 = deserialize_from(&mut stream)
.map_err(|e| format!("write version deserialize error: {}", e.to_string()))
.map_err(accountsdb_to_io_error)?;
// (3rd of 3 elements) read in (slot, bank hashes) pair
let (slot, bank_hash_info): (Slot, BankHashInfo) = deserialize_from(&mut stream)
.map_err(|e| format!("bank hashes deserialize error: {}", e.to_string()))
.map_err(accountsdb_to_io_error)?;
Ok(AccountDBFields(storage, version, slot, bank_hash_info))
}
}