Skip to content

Commit

Permalink
add access timestamp to StateCacheEntry
Browse files Browse the repository at this point in the history
  • Loading branch information
msmouse committed Feb 11, 2025
1 parent 65e0b40 commit c64a48e
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 32 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions storage/aptosdb/src/state_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -859,22 +859,26 @@ impl StateStore {
}

// TODO(aldenhu): cache changes here, should consume it.
// Use dummy access_time_secs = 0, since `cache` is not going to persist.
let old_entry = cache
.insert(
(*key).clone(),
StateCacheEntry::from_state_update_ref(update),
StateCacheEntry::from_state_update_ref(update, 0),
)
.unwrap_or_else(|| {
// n.b. all updated state items must be read and recorded in the state cache,
// otherwise we can't calculate the correct usage. The is_untracked() hack
// is to allow some db tests without real execution layer to pass.
assert!(ignore_state_cache_miss, "Must cache read.");
StateCacheEntry::NonExistent
StateCacheEntry::NonExistent {
access_time_secs: 0,
}
});

if let StateCacheEntry::Value {
version: old_version,
value: _,
access_time_secs: _,
} = old_entry
{
// The value at `old_version` can be pruned once the pruning window hits
Expand Down
1 change: 1 addition & 0 deletions storage/storage-interface/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ rust-version = { workspace = true }
anyhow = { workspace = true }
aptos-crypto = { workspace = true }
aptos-experimental-layered-map = { workspace = true }
aptos-infallible = { workspace = true }
aptos-metrics-core = { workspace = true }
aptos-scratchpad = { workspace = true }
aptos-secure-net = { workspace = true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{
DbReader,
};
use anyhow::Result;
use aptos_infallible::duration_since_epoch;
use aptos_metrics_core::TimerHelper;
use aptos_types::{
state_store::{
Expand Down Expand Up @@ -87,6 +88,9 @@ pub struct CachedStateView {

/// State values (with update versions) read across the lifetime of the state view.
memorized: ShardedStateCache,

/// access timestamp for uncached entries
access_time_secs: u32,
}

impl Debug for CachedStateView {
Expand Down Expand Up @@ -115,6 +119,7 @@ impl CachedStateView {
reader,
memorized: ShardedStateCache::new_empty(state.version()),
speculative: state.into_delta(persisted_state),
access_time_secs: duration_since_epoch().as_secs() as u32,
}
}

Expand All @@ -127,6 +132,7 @@ impl CachedStateView {
reader: Arc::new(DummyDbReader),
memorized: ShardedStateCache::new_empty(None),
speculative: state.make_delta(state),
access_time_secs: 0,
}
}

Expand Down Expand Up @@ -172,6 +178,7 @@ impl CachedStateView {
reader: _,
speculative: _,
memorized,
access_time_secs: _,
} = self;

memorized
Expand All @@ -184,14 +191,17 @@ impl CachedStateView {
fn get_uncached(&self, state_key: &StateKey) -> Result<StateCacheEntry> {
let ret = if let Some(update) = self.speculative.get_state_update(state_key) {
// found in speculative state, can be either a new value or a deletion
update.to_state_value_with_version()
update.to_state_value_with_version(self.access_time_secs)
} else if let Some(base_version) = self.base_version() {
StateCacheEntry::from_tuple_opt(
StateCacheEntry::from_db_tuple_opt(
self.reader
.get_state_value_with_version_by_version(state_key, base_version)?,
self.access_time_secs,
)
} else {
StateCacheEntry::NonExistent
StateCacheEntry::NonExistent {
access_time_secs: self.access_time_secs,
}
};

Ok(ret)
Expand Down
50 changes: 23 additions & 27 deletions storage/storage-interface/src/state_store/versioned_state_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ pub struct StateUpdate {
}

impl StateUpdate {
pub fn to_state_value_with_version(&self) -> StateCacheEntry {
pub fn to_state_value_with_version(&self, access_time_secs: u32) -> StateCacheEntry {
use StateCacheEntry::*;

match &self.value {
None => NonExistent,
None => NonExistent { access_time_secs },
Some(value) => Value {
access_time_secs,
version: self.version,
value: value.clone(),
},
Expand All @@ -44,62 +45,57 @@ impl<'kv> StateUpdateRef<'kv> {

#[derive(Clone, Debug)]
pub enum StateCacheEntry {
/// Not indicating if the value ever existed and deleted.
NonExistent,
/// NOT indicating whether the value never existed or deleted.
NonExistent { access_time_secs: u32 },
/// A creation or modification.
Value { version: Version, value: StateValue },
Value {
access_time_secs: u32,
version: Version,
value: StateValue,
},
}

impl StateCacheEntry {
// TODO(aldenhu): update DbReader interface to return this type directly.
pub fn from_tuple_opt(tuple_opt: Option<(Version, StateValue)>) -> Self {
pub fn from_db_tuple_opt(
tuple_opt: Option<(Version, StateValue)>,
access_time_secs: u32,
) -> Self {
match tuple_opt {
None => Self::NonExistent,
Some((version, value)) => Self::Value { version, value },
}
}

pub fn from_state_write_ref(version: Version, value_opt: Option<&StateValue>) -> Self {
match value_opt {
None => Self::NonExistent,
Some(value) => Self::Value {
None => Self::NonExistent { access_time_secs },
Some((version, value)) => Self::Value {
access_time_secs,
version,
value: value.clone(),
value,
},
}
}

pub fn from_state_update_ref(state_update_ref: &StateUpdateRef) -> Self {
pub fn from_state_update_ref(state_update_ref: &StateUpdateRef, access_time_secs: u32) -> Self {
match state_update_ref.value {
None => Self::NonExistent,
None => Self::NonExistent { access_time_secs },
Some(value) => Self::Value {
access_time_secs,
version: state_update_ref.version,
value: value.clone(),
},
}
}

pub fn as_state_value_opt(&self) -> Option<&StateValue> {
match self {
Self::NonExistent => None,
Self::Value { value, .. } => Some(value),
}
}

pub fn to_state_value_opt(&self) -> Option<StateValue> {
self.state_value_ref_opt().cloned()
}

pub fn state_value_ref_opt(&self) -> Option<&StateValue> {
match self {
Self::NonExistent => None,
Self::NonExistent { .. } => None,
Self::Value { value, .. } => Some(value),
}
}

pub fn into_state_value_opt(self) -> Option<StateValue> {
match self {
Self::NonExistent => None,
Self::NonExistent { .. } => None,
Self::Value { value, .. } => Some(value),
}
}
Expand Down

0 comments on commit c64a48e

Please sign in to comment.