From 55dbe5df294d63484850ab941b9ee80396efe0e7 Mon Sep 17 00:00:00 2001 From: Vladimir Petrzhikovskii Date: Thu, 18 Apr 2024 16:43:31 +0200 Subject: [PATCH] refactor(strider): ask `BlockStuffAug` instead of `BlockStuff` in provider --- core/src/block_strider/mod.rs | 10 ++--- core/src/block_strider/provider.rs | 15 ++++--- core/src/block_strider/state_applier.rs | 39 +++++++++++------- core/src/block_strider/subscriber.rs | 22 +++++----- .../test_provider/archive_provider.rs | 12 +++--- core/src/block_strider/test_provider/mod.rs | 22 ++++++---- core/tests/00001 | Bin core/tests/empty_block.bin | Bin 0 -> 9945 bytes 8 files changed, 70 insertions(+), 50 deletions(-) mode change 100755 => 100644 core/tests/00001 create mode 100644 core/tests/empty_block.bin diff --git a/core/src/block_strider/mod.rs b/core/src/block_strider/mod.rs index c5f3108bf..900ff3500 100644 --- a/core/src/block_strider/mod.rs +++ b/core/src/block_strider/mod.rs @@ -22,7 +22,7 @@ use crate::block_strider::state_applier::ShardStateUpdater; use provider::BlockProvider; use state::BlockStriderState; use subscriber::BlockSubscriber; -use tycho_block_util::block::BlockStuff; +use tycho_block_util::block::BlockStuffAug; use tycho_block_util::state::MinRefMcStateTracker; use tycho_storage::Storage; use tycho_util::FastDashMap; @@ -221,7 +221,7 @@ where .boxed() } - async fn fetch_next_master_block(&self) -> Option { + async fn fetch_next_master_block(&self) -> Option { let last_traversed_master_block = self.state.load_last_traversed_master_block_id(); tracing::debug!(?last_traversed_master_block, "Fetching next master block"); loop { @@ -242,7 +242,7 @@ where } } - async fn fetch_block(&self, block_id: &BlockId) -> Result { + async fn fetch_block(&self, block_id: &BlockId) -> Result { loop { match self.provider.get_block(block_id).await { Some(Ok(block)) => break Ok(block), @@ -259,7 +259,7 @@ where } struct BlocksGraph { - block_store_map: FastDashMap, + block_store_map: FastDashMap, connections: FastDashMap, bottom_blocks: Vec, } @@ -273,7 +273,7 @@ impl BlocksGraph { } } - fn store_block(&self, block: BlockStuff) { + fn store_block(&self, block: BlockStuffAug) { self.block_store_map.insert(*block.id(), block); } diff --git a/core/src/block_strider/provider.rs b/core/src/block_strider/provider.rs index 3eb079631..34a65f3f4 100644 --- a/core/src/block_strider/provider.rs +++ b/core/src/block_strider/provider.rs @@ -3,9 +3,9 @@ use futures_util::future::BoxFuture; use std::future::Future; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; -use tycho_block_util::block::BlockStuff; +use tycho_block_util::block::BlockStuffAug; -pub type OptionalBlockStuff = Option>; +pub type OptionalBlockStuff = Option>; /// Block provider *MUST* validate the block before returning it. pub trait BlockProvider: Send + Sync + 'static { @@ -154,10 +154,13 @@ mod test { .is_none()); } - fn get_empty_block() -> BlockStuff { - let block = "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"; - let block = everscale_types::boc::BocRepr::decode_base64(block).unwrap(); - BlockStuff::with_block(get_default_block_id(), block) + fn get_empty_block() -> BlockStuffAug { + let block_data = include_bytes!("../../tests/empty_block.bin"); + let block = everscale_types::boc::BocRepr::decode(block_data).unwrap(); + BlockStuffAug::new( + BlockStuff::with_block(get_default_block_id(), block), + block_data.as_slice(), + ) } fn get_default_block_id() -> BlockId { diff --git a/core/src/block_strider/state_applier.rs b/core/src/block_strider/state_applier.rs index 3fd7aa0c8..e34f356bf 100644 --- a/core/src/block_strider/state_applier.rs +++ b/core/src/block_strider/state_applier.rs @@ -5,7 +5,7 @@ use std::sync::Arc; use anyhow::{Context, Result}; use futures_util::FutureExt; -use tycho_block_util::block::BlockStuff; +use tycho_block_util::block::{BlockStuff, BlockStuffAug}; use tycho_block_util::state::{MinRefMcStateTracker, ShardStateStuff}; use tycho_storage::{BlockHandle, BlockMetaData, Storage}; @@ -43,8 +43,8 @@ where fn handle_block( &self, - block: &BlockStuff, - _state: Option<&ShardStateStuff>, + block: &BlockStuffAug, + _state: Option<&Arc>, ) -> Self::HandleBlockFut { tracing::info!(id = ?block.id(), "applying block"); let block = block.clone(); @@ -53,7 +53,7 @@ where let subscriber = self.state_subscriber.clone(); async move { - let block_h = Self::get_block_handle(&block, &storage)?; + let block_h = Self::get_block_handle(&block, &storage).await?; let (prev_id, _prev_id_2) = block //todo: handle merge .construct_prev_id() @@ -69,7 +69,7 @@ where let new_state = Self::compute_and_store_state_update( &block, &min_ref_mc_state_tracker, - storage, + &storage, &block_h, prev_state, ) @@ -103,6 +103,12 @@ where let elapsed = start.elapsed(); metrics::histogram!("tycho_subscriber_handle_block_seconds").record(elapsed); + block_h.meta().set_is_applied(); + storage + .block_handle_storage() + .store_handle(&block_h) + .context("Failed to store block handle")?; + Ok(()) } .boxed() @@ -113,17 +119,20 @@ impl ShardStateUpdater where S: BlockSubscriber, { - fn get_block_handle(block: &BlockStuff, storage: &Arc) -> Result> { + async fn get_block_handle( + block: &BlockStuffAug, + storage: &Arc, + ) -> Result> { let info = block .block() .info .load() .context("Failed to load block info")?; - let (block_h, _) = storage - .block_handle_storage() - .create_or_load_handle( - block.id(), + let h = storage + .block_storage() + .store_block_data( + block, BlockMetaData { is_key_block: info.key_block, gen_utime: info.gen_utime, @@ -138,18 +147,18 @@ where .context("Failed to process master ref")?, }, ) - .context("Failed to create or load block handle")?; + .await?; - Ok(block_h) + Ok(h.handle) } async fn compute_and_store_state_update( block: &BlockStuff, min_ref_mc_state_tracker: &MinRefMcStateTracker, - storage: Arc, + storage: &Arc, block_h: &Arc, prev_state: Arc, - ) -> Result { + ) -> Result> { let update = block .block() .load_state_update() @@ -169,7 +178,7 @@ where .await .context("Failed to store new state")?; - Ok(new_state) + Ok(Arc::new(new_state)) } } diff --git a/core/src/block_strider/subscriber.rs b/core/src/block_strider/subscriber.rs index f9c5da4bd..d95543a0b 100644 --- a/core/src/block_strider/subscriber.rs +++ b/core/src/block_strider/subscriber.rs @@ -1,7 +1,9 @@ -use futures_util::future; use std::future::Future; +use std::sync::Arc; + +use futures_util::future; -use tycho_block_util::block::BlockStuff; +use tycho_block_util::block::BlockStuffAug; use tycho_block_util::state::ShardStateStuff; pub trait BlockSubscriber: Send + Sync + 'static { @@ -9,8 +11,8 @@ pub trait BlockSubscriber: Send + Sync + 'static { fn handle_block( &self, - block: &BlockStuff, - state: Option<&ShardStateStuff>, + block: &BlockStuffAug, + state: Option<&Arc>, ) -> Self::HandleBlockFut; } @@ -19,8 +21,8 @@ impl BlockSubscriber for Box { fn handle_block( &self, - block: &BlockStuff, - state: Option<&ShardStateStuff>, + block: &BlockStuffAug, + state: Option<&Arc>, ) -> Self::HandleBlockFut { ::handle_block(self, block, state) } @@ -36,8 +38,8 @@ impl BlockSubscriber for FanoutBlockSu fn handle_block( &self, - block: &BlockStuff, - state: Option<&ShardStateStuff>, + block: &BlockStuffAug, + state: Option<&Arc>, ) -> Self::HandleBlockFut { let left = self.left.handle_block(block, state); let right = self.right.handle_block(block, state); @@ -60,8 +62,8 @@ pub mod test { fn handle_block( &self, - block: &BlockStuff, - _state: Option<&ShardStateStuff>, + block: &BlockStuffAug, + _state: Option<&Arc>, ) -> Self::HandleBlockFut { tracing::info!("handling block: {:?}", block.id()); future::ready(Ok(())) diff --git a/core/src/block_strider/test_provider/archive_provider.rs b/core/src/block_strider/test_provider/archive_provider.rs index 3310dcf32..c7fd739e2 100644 --- a/core/src/block_strider/test_provider/archive_provider.rs +++ b/core/src/block_strider/test_provider/archive_provider.rs @@ -10,7 +10,7 @@ use futures_util::FutureExt; use sha2::Digest; use tycho_block_util::archive::{ArchiveEntryId, ArchiveReader}; -use tycho_block_util::block::BlockStuff; +use tycho_block_util::block::{BlockStuff, BlockStuffAug}; use crate::block_strider::provider::{BlockProvider, OptionalBlockStuff}; @@ -33,10 +33,12 @@ impl BlockProvider for ArchiveProvider { } fn get_block<'a>(&'a self, block_id: &'a BlockId) -> Self::GetBlockFut<'a> { - futures_util::future::ready( - self.get_block_by_id(block_id) - .map(|b| (Ok(BlockStuff::with_block(*block_id, b)))), - ) + futures_util::future::ready(self.get_block_by_id(block_id).map(|b| { + Ok(BlockStuffAug::new( + BlockStuff::with_block(*block_id, b.clone()), + everscale_types::boc::BocRepr::encode(b).unwrap(), + )) + })) .boxed() } } diff --git a/core/src/block_strider/test_provider/mod.rs b/core/src/block_strider/test_provider/mod.rs index 94a4585c6..13db51306 100644 --- a/core/src/block_strider/test_provider/mod.rs +++ b/core/src/block_strider/test_provider/mod.rs @@ -9,7 +9,7 @@ use everscale_types::models::{ }; use everscale_types::prelude::HashBytes; use std::collections::HashMap; -use tycho_block_util::block::BlockStuff; +use tycho_block_util::block::{BlockStuff, BlockStuffAug}; pub mod archive_provider; @@ -26,18 +26,22 @@ impl BlockProvider for TestBlockProvider { .iter() .find(|id| id.seqno == prev_block_id.seqno + 1); futures_util::future::ready(next_id.and_then(|id| { - self.blocks - .get(id) - .map(|b| Ok(BlockStuff::with_block(*id, b.clone()))) + self.blocks.get(id).map(|b| { + Ok(BlockStuffAug::new( + BlockStuff::with_block(*id, b.clone()), + everscale_types::boc::BocRepr::encode(b).unwrap(), + )) + }) })) } fn get_block(&self, id: &BlockId) -> Self::GetBlockFut<'_> { - futures_util::future::ready( - self.blocks - .get(id) - .map(|b| Ok(BlockStuff::with_block(*id, b.clone()))), - ) + futures_util::future::ready(self.blocks.get(id).map(|b| { + Ok(BlockStuffAug::new( + BlockStuff::with_block(*id, b.clone()), + everscale_types::boc::BocRepr::encode(b).unwrap(), + )) + })) } } diff --git a/core/tests/00001 b/core/tests/00001 old mode 100755 new mode 100644 diff --git a/core/tests/empty_block.bin b/core/tests/empty_block.bin new file mode 100644 index 0000000000000000000000000000000000000000..b18ea1e7c70d277bc6c165988a5aceb0f860ae35 GIT binary patch literal 9945 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