-
Notifications
You must be signed in to change notification settings - Fork 629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Restructure TrieStorage and implement correct semantics for state proofs #9350
Merged
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
136587f
Restructure TrieStorage and implement correct semantics for state pro…
robin-near e3a4c8a
Merge remote-tracking branch 'origin/master' into HEAD
robin-near 4645a50
Address comments.
robin-near 7f9e848
Merge branch 'master' into proof2
robin-near File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
use near_o11y::metrics::prometheus; | ||
use near_o11y::metrics::prometheus::core::{GenericCounter, GenericGauge}; | ||
use near_primitives::errors::StorageError; | ||
use near_primitives::hash::CryptoHash; | ||
use near_primitives::shard_layout::ShardUId; | ||
use near_vm_runner::logic::TrieNodesCount; | ||
use std::collections::HashMap; | ||
use std::sync::Arc; | ||
|
||
use crate::{metrics, TrieStorage}; | ||
|
||
/// Deterministic cache to store trie nodes that have been accessed so far | ||
/// during the processing of a single chunk. | ||
/// | ||
/// This cache's correctness is critical as it contributes to the gas | ||
/// accounting of storage operations during contract execution. For that | ||
/// reason, a new TrieChunkCache must be created at the beginning of a chunk's | ||
/// execution, and the db_read_nodes and mem_read_nodes must be taken into | ||
/// account whenever a storage operation is performed to calculate what kind | ||
/// of operation it was. | ||
/// | ||
/// Note that we don't have a size limit for values in the chunk cache. There | ||
/// are two reasons: | ||
/// - for nodes, value size is an implementation detail. If we change | ||
/// internal representation of a node (e.g. change `memory_usage` field | ||
/// from `RawTrieNodeWithSize`), this would have to be a protocol upgrade. | ||
/// - total size of all values is limited by the runtime fees. More | ||
/// thoroughly: | ||
/// - number of nodes is limited by receipt gas limit / touching trie | ||
/// node fee ~= 500 Tgas / 16 Ggas = 31_250; | ||
/// - size of trie keys and values is limited by receipt gas limit / | ||
/// lowest per byte fee (`storage_read_value_byte`) ~= | ||
/// (500 * 10**12 / 5611005) / 2**20 ~= 85 MB. | ||
/// All values are given as of 16/03/2022. We may consider more precise limit | ||
/// for the chunk cache as well. | ||
/// | ||
/// Note that in general, it is NOT true that all storage access is either a | ||
/// db read or mem read. It can also be a flat storage read, which is not | ||
/// tracked via TrieChunkCache. | ||
pub struct TrieChunkCache { | ||
/// Whether the cache is enabled. By default it is not, but it can be | ||
/// turned on or off on the fly. | ||
enable: bool, | ||
/// Cache of trie node hash -> trie node body, or a leaf value hash -> | ||
/// leaf value. | ||
cache: HashMap<CryptoHash, Arc<[u8]>>, | ||
/// The number of times a key was accessed by reading from the underlying | ||
/// storage. (This does not necessarily mean it was accessed from *disk*, | ||
/// as the underlying storage layer may have a best-effort cache.) | ||
db_read_nodes: u64, | ||
/// The number of times a key was accessed when it was deterministically | ||
/// already cached during the processing of this chunk. | ||
mem_read_nodes: u64, | ||
/// Prometheus metrics. It's optional - in testing it can be None. | ||
metrics: Option<TrieChunkCacheMetrics>, | ||
} | ||
|
||
struct TrieChunkCacheMetrics { | ||
chunk_cache_hits: GenericCounter<prometheus::core::AtomicU64>, | ||
chunk_cache_misses: GenericCounter<prometheus::core::AtomicU64>, | ||
chunk_cache_size: GenericGauge<prometheus::core::AtomicI64>, | ||
} | ||
|
||
impl TrieChunkCache { | ||
/// Constructs a new cache. By default it is not enabled. | ||
/// The optional parameter is passed in if prometheus metrics are desired. | ||
pub fn new(shard_uid_and_is_view: Option<(ShardUId, bool)>) -> Self { | ||
let metrics = shard_uid_and_is_view.map(|(shard_uid, is_view)| { | ||
let mut buffer = itoa::Buffer::new(); | ||
let shard_id = buffer.format(shard_uid.shard_id); | ||
|
||
let metrics_labels: [&str; 2] = [&shard_id, if is_view { "1" } else { "0" }]; | ||
TrieChunkCacheMetrics { | ||
chunk_cache_hits: metrics::CHUNK_CACHE_HITS.with_label_values(&metrics_labels), | ||
chunk_cache_misses: metrics::CHUNK_CACHE_MISSES.with_label_values(&metrics_labels), | ||
chunk_cache_size: metrics::CHUNK_CACHE_SIZE.with_label_values(&metrics_labels), | ||
} | ||
}); | ||
Self { enable: false, cache: HashMap::new(), db_read_nodes: 0, mem_read_nodes: 0, metrics } | ||
} | ||
|
||
pub fn set_enabled(&mut self, enabled: bool) { | ||
self.enable = enabled; | ||
} | ||
|
||
pub fn retrieve_trie_node_with_cache( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I see the confusion. I'll just simplify the name and add a comment. |
||
&mut self, | ||
hash: &CryptoHash, | ||
storage: &dyn TrieStorage, | ||
) -> Result<Arc<[u8]>, StorageError> { | ||
if let Some(node) = self.cache.get(hash) { | ||
self.mem_read_nodes += 1; | ||
if let Some(metrics) = &self.metrics { | ||
metrics.chunk_cache_hits.inc(); | ||
} | ||
Ok(node.clone()) | ||
} else { | ||
self.db_read_nodes += 1; | ||
if let Some(metrics) = &self.metrics { | ||
metrics.chunk_cache_misses.inc(); | ||
} | ||
let node = storage.retrieve_raw_bytes(hash)?; | ||
|
||
if self.enable { | ||
self.cache.insert(*hash, node.clone()); | ||
if let Some(metrics) = &self.metrics { | ||
metrics.chunk_cache_size.set(self.cache.len() as i64); | ||
} | ||
} | ||
Ok(node) | ||
} | ||
} | ||
|
||
pub fn get_trie_nodes_count(&self) -> TrieNodesCount { | ||
TrieNodesCount { db_reads: self.db_read_nodes, mem_reads: self.mem_read_nodes } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed offline - please consider
TrieAccountingCache
because it handles both deterministic cache and computing access metrics.