Skip to content
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

Reduce memory consumption of RecentBlockCache #2102

Merged
merged 12 commits into from
Dec 1, 2023
22 changes: 20 additions & 2 deletions crates/shared/src/recent_block_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,8 +292,14 @@ where

let mut mutexed = self.mutexed.lock().unwrap();
mutexed.insert(cache_miss_block, chunk.iter().cloned(), fetched);
for key in found_keys {
mutexed.recently_used.cache_set(key, ());
if block.is_some() {
// Only if a block number was specified the caller actually cared about the most
// accurate data for these keys. Only in that case we want to be nice and
// remember the key for future background updates of the cached
// liquidity.
for key in found_keys {
mutexed.recently_used.cache_set(key, ());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We also call cache_set in get. Should the same logic apply there? (also a 🤓 reminder that having this cache_set in two code paths is error prone)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I'm not sure how we can get around the 2 cache_set()s nicely though.
If we only have a single one at the end of the main function we'll not remember any keys for background updates when we time out requests after having to fetch all liquidity fresh when we restart the system.
Will leave the 2 cache_set() for now and keep thinking about ways to improve that.

}
}
}

Expand Down Expand Up @@ -382,6 +388,18 @@ where
fn remove_cached_blocks_older_than(&mut self, oldest_to_keep: u64) {
tracing::debug!("dropping blocks older than {} from cache", oldest_to_keep);
self.entries = self.entries.split_off(&(oldest_to_keep, K::first_ord()));

// Iterate from newest block to oldest block and only keep the most recent
// liquidity around to reduce memory consumption.
let mut cached_keys = HashSet::new();
for ((_block, key), values) in self.entries.iter_mut().rev() {
if !cached_keys.insert(key) {
*values = vec![];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that for new entries this vector is getting longer and longer for some reason (ie a bug with the BalancerPoolFetcher)?

Since we are now iterating over all entries anyways, maybe we can log the number of total values remaining after pruning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible that for new entries this vector is getting longer and longer for some reason (ie a bug with the BalancerPoolFetcher)?

I have no evidence that this is impossible. I also had the hunch that we could have a bug along those lines so I temporarily had an assertion verifying that all values are unique and it didn't cause any crashes in my 5 minutes test so I'd say we probably don't have an issues with that.

Since we are now iterating over all entries anyways, maybe we can log the number of total values remaining after pruning?

Makes sense, will add that.

}
}
// Afterwards drop all entries that are now empty.
self.entries.retain(|_, values| !values.is_empty());

self.cached_most_recently_at_block
.retain(|_, block| *block >= oldest_to_keep);
tracing::debug!(
Expand Down
Loading