Skip to content

Commit

Permalink
feat: print deltas in flat storage display tool (#8840)
Browse files Browse the repository at this point in the history
Because we use shard uids in flat storage status keys, more proper way to display flat storage info is to iterate over status column and retrieve all contents by it. Iterating over shard ids for final head is not technically correct as flat storage heads not necessarily are equal to final head.

Also adding pretty-printing for deltas.
  • Loading branch information
Longarithm committed Apr 27, 2023
1 parent 1183b61 commit ab1c3b4
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 21 deletions.
13 changes: 11 additions & 2 deletions core/store/src/flat/delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ use std::sync::Arc;
use super::{store_helper, BlockInfo};
use crate::{CryptoHash, StoreUpdate};

#[derive(Debug)]
pub struct FlatStateDelta {
pub metadata: FlatStateDeltaMetadata,
pub changes: FlatStateChanges,
}

#[derive(BorshSerialize, BorshDeserialize, Debug)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, Copy)]
pub struct FlatStateDeltaMetadata {
pub block: BlockInfo,
}
Expand All @@ -35,7 +36,7 @@ impl KeyForFlatStateDelta {
}
/// Delta of the state for some shard and block, stores mapping from keys to value refs or None, if key was removed in
/// this block.
#[derive(BorshSerialize, BorshDeserialize, Clone, Default, Debug, PartialEq, Eq)]
#[derive(BorshSerialize, BorshDeserialize, Clone, Default, PartialEq, Eq)]
pub struct FlatStateChanges(pub(crate) HashMap<Vec<u8>, Option<ValueRef>>);

impl<T> From<T> for FlatStateChanges
Expand All @@ -47,6 +48,14 @@ where
}
}

impl std::fmt::Debug for FlatStateChanges {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FlatStateChanges")
.field("changes", &near_fmt::Slice(&Vec::from_iter(self.0.iter())))
.finish()
}
}

impl FlatStateChanges {
/// Returns `Some(Option<ValueRef>)` from delta for the given key. If key is not present, returns None.
pub fn get(&self, key: &[u8]) -> Option<Option<ValueRef>> {
Expand Down
8 changes: 4 additions & 4 deletions core/store/src/flat/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,11 @@ impl FlatStorage {
store_helper::set_flat_storage_status(
&mut store_update,
shard_uid,
FlatStorageStatus::Ready(FlatStorageReadyStatus { flat_head: block.clone() }),
FlatStorageStatus::Ready(FlatStorageReadyStatus { flat_head: *block }),
);

guard.metrics.set_flat_head_height(block.height);
guard.flat_head = block.clone();
guard.flat_head = *block;

// Remove old deltas from disk and memory.
// Do it for each head update separately to ensure that old data is removed properly if node was
Expand Down Expand Up @@ -352,7 +352,7 @@ mod tests {

impl MockChain {
fn get_block_info(&self, block_hash: &CryptoHash) -> BlockInfo {
self.blocks.get(block_hash).unwrap().clone()
*self.blocks.get(block_hash).unwrap()
}

fn block_hash(height: BlockHeight) -> CryptoHash {
Expand Down Expand Up @@ -423,7 +423,7 @@ mod tests {
}

fn get_block(&self, height: BlockHeight) -> BlockInfo {
self.blocks[&self.height_to_hashes[&height]].clone()
self.blocks[&self.height_to_hashes[&height]]
}

/// create a new block on top the current chain head, return the new block hash
Expand Down
2 changes: 1 addition & 1 deletion core/store/src/flat/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub enum FlatStateValue {
// TODO(8243): add variant here for the inlined value
}

#[derive(BorshSerialize, BorshDeserialize, Debug, Clone, PartialEq, Eq)]
#[derive(BorshSerialize, BorshDeserialize, Debug, Copy, Clone, PartialEq, Eq)]
pub struct BlockInfo {
pub hash: CryptoHash,
pub height: BlockHeight,
Expand Down
57 changes: 43 additions & 14 deletions tools/flat-storage/src/commands.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use borsh::BorshDeserialize;
/// Tools for modifying flat storage - should be used only for experimentation & debugging.
use clap::Parser;
use near_chain::{
Expand All @@ -6,7 +7,7 @@ use near_chain::{
};
use near_epoch_manager::EpochManagerAdapter;
use near_primitives::{state::ValueRef, trie_key::trie_key_parsers::parse_account_id_from_raw_key};
use near_store::flat::{store_helper, FlatStorageStatus};
use near_store::flat::{store_helper, FlatStateDelta, FlatStateDeltaMetadata, FlatStorageStatus};
use near_store::{Mode, NodeStorage, ShardUId, Store, StoreOpener};
use nearcore::{load_config, NearConfig, NightshadeRuntime};
use std::{path::PathBuf, sync::Arc, time::Duration};
Expand Down Expand Up @@ -62,6 +63,35 @@ pub struct VerifyCmd {
shard_id: u64,
}

fn print_delta(store: &Store, shard_uid: ShardUId, metadata: FlatStateDeltaMetadata) {
let changes =
store_helper::get_delta_changes(store, shard_uid, metadata.block.hash).unwrap().unwrap();
println!("{:?}", FlatStateDelta { metadata, changes });
}

fn print_deltas(store: &Store, shard_uid: ShardUId) {
let deltas_metadata = store_helper::get_all_deltas_metadata(store, shard_uid).unwrap();
let num_deltas = deltas_metadata.len();
println!("Deltas: {}", num_deltas);

if num_deltas <= 10 {
for delta_metadata in deltas_metadata {
print_delta(store, shard_uid, delta_metadata);
}
} else {
let (first_deltas, last_deltas) = deltas_metadata.split_at(5);

for delta_metadata in first_deltas {
print_delta(store, shard_uid, *delta_metadata);
}
println!("... skipped {} deltas ...", num_deltas - 10);
let (_, last_deltas) = last_deltas.split_at(last_deltas.len() - 5);
for delta_metadata in last_deltas {
print_delta(store, shard_uid, *delta_metadata);
}
}
}

impl FlatStorageCommand {
fn get_db(
opener: &StoreOpener,
Expand All @@ -78,30 +108,29 @@ impl FlatStorageCommand {
}

pub fn run(&self, home_dir: &PathBuf) -> anyhow::Result<()> {
let near_config =
load_config(home_dir, near_chain_configs::GenesisValidationMode::Full).unwrap();
let near_config = load_config(home_dir, near_chain_configs::GenesisValidationMode::Full)?;
let opener = NodeStorage::opener(home_dir, false, &near_config.config.store, None);

match &self.subcmd {
SubCommand::View => {
let (_, hot_runtime, chain_store, hot_store) =
let (.., hot_store) =
Self::get_db(&opener, home_dir, &near_config, near_store::Mode::ReadOnly);
let tip = chain_store.final_head().unwrap();
let shards = hot_runtime.num_shards(&tip.epoch_id).unwrap();
println!("DB version: {:?}", hot_store.get_db_version());
println!("Current final tip @{:?} - shards: {:?}", tip.height, shards);
println!("DB version: {:?}", hot_store.get_db_version()?);
for item in hot_store.iter(store_helper::FlatStateColumn::Status.to_db_col()) {
let (bytes_shard_uid, status) = item?;
let shard_uid = ShardUId::try_from(bytes_shard_uid.as_ref()).unwrap();
let status = FlatStorageStatus::try_from_slice(&status)?;

for shard in 0..shards {
let shard_uid = hot_runtime.shard_id_to_uid(shard, &tip.epoch_id)?;
match store_helper::get_flat_storage_status(&hot_store, shard_uid) {
match status {
FlatStorageStatus::Ready(ready_status) => {
println!(
"Shard: {shard:?} - flat storage @{:?}",
ready_status.flat_head.height
"Shard: {shard_uid:?} - flat storage @{:?} ({})",
ready_status.flat_head.height, ready_status.flat_head.hash,
);
print_deltas(&hot_store, shard_uid);
}
status => {
println!("Shard: {shard:?} - no flat storage: {status:?}");
println!("Shard: {shard_uid:?} - no flat storage: {status:?}");
}
}
}
Expand Down

0 comments on commit ab1c3b4

Please sign in to comment.