Skip to content

Commit 2e46573

Browse files
committed
store: Use adaptive batch size for call cache eviction
The inner deletion loop in clear_stale_call_cache used a hardcoded batch size of 10,000. Replace it with AdaptiveBatchSize that starts at 100 and self-tunes based on actual query duration, avoiding both excessive lock contention on large caches and unnecessary round-trips on small ones.
1 parent 0c9940a commit 2e46573

2 files changed

Lines changed: 27 additions & 10 deletions

File tree

store/postgres/src/chain_store.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,10 @@ mod data {
159159
use std::iter::FromIterator;
160160
use std::str::FromStr;
161161

162+
use std::time::Instant;
163+
162164
use crate::transaction_receipt::RawTransactionReceipt;
165+
use crate::vid_batcher::AdaptiveBatchSize;
163166

164167
use super::JsonBlock;
165168

@@ -1649,12 +1652,12 @@ mod data {
16491652
) -> Result<(), Error> {
16501653
let mut total_calls: usize = 0;
16511654
let mut total_contracts: i64 = 0;
1652-
// We process contracts in batches to avoid loading too many entries into memory
1653-
// at once. Each contract can have many calls, so we also delete calls in batches.
1654-
// Note: The batch sizes were chosen based on experimentation. Potentially, they
1655-
// could be made configurable via ENV vars.
1655+
// We process contracts in batches to avoid loading too many
1656+
// entries into memory at once. Each contract can have many
1657+
// calls, so we delete calls in adaptive batches that
1658+
// self-tune based on query duration.
16561659
let contracts_batch_size: i64 = 2000;
1657-
let cache_batch_size: usize = 10000;
1660+
let mut batch_size = AdaptiveBatchSize::with_size(100);
16581661

16591662
// Limits the number of contracts to process if ttl_max_contracts is set.
16601663
// Used also to adjust the final batch size, so we don't process more
@@ -1704,20 +1707,23 @@ mod data {
17041707
}
17051708

17061709
loop {
1710+
let current_size = batch_size.size;
1711+
let start = Instant::now();
17071712
let next_batch = cache::table
17081713
.select(cache::id)
17091714
.filter(cache::contract_address.eq_any(&stale_contracts))
1710-
.limit(cache_batch_size as i64)
1715+
.limit(current_size)
17111716
.get_results::<Vec<u8>>(conn)
17121717
.await?;
17131718
let deleted_count =
17141719
diesel::delete(cache::table.filter(cache::id.eq_any(&next_batch)))
17151720
.execute(conn)
17161721
.await?;
1722+
batch_size.adapt(start.elapsed());
17171723

17181724
total_calls += deleted_count;
17191725

1720-
if deleted_count < cache_batch_size {
1726+
if (deleted_count as i64) < current_size {
17211727
break;
17221728
}
17231729
}
@@ -1754,11 +1760,11 @@ mod data {
17541760
SELECT id
17551761
FROM {}
17561762
WHERE contract_address = ANY($1)
1757-
LIMIT {}
1763+
LIMIT $2
17581764
)
17591765
DELETE FROM {} USING targets
17601766
WHERE {}.id = targets.id",
1761-
call_cache.qname, cache_batch_size, call_cache.qname, call_cache.qname
1767+
call_cache.qname, call_cache.qname, call_cache.qname
17621768
);
17631769

17641770
let delete_meta_query = format!(
@@ -1806,14 +1812,18 @@ mod data {
18061812
}
18071813

18081814
loop {
1815+
let current_size = batch_size.size;
1816+
let start = Instant::now();
18091817
let deleted_count = sql_query(&delete_cache_query)
18101818
.bind::<Array<Bytea>, _>(&stale_contracts)
1819+
.bind::<BigInt, _>(current_size)
18111820
.execute(conn)
18121821
.await?;
1822+
batch_size.adapt(start.elapsed());
18131823

18141824
total_calls += deleted_count;
18151825

1816-
if deleted_count < cache_batch_size {
1826+
if (deleted_count as i64) < current_size {
18171827
break;
18181828
}
18191829
}

store/postgres/src/vid_batcher.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ pub(crate) struct AdaptiveBatchSize {
3535
}
3636

3737
impl AdaptiveBatchSize {
38+
pub fn with_size(size: i64) -> Self {
39+
Self {
40+
size,
41+
target: ENV_VARS.store.batch_target_duration,
42+
}
43+
}
44+
3845
pub fn new(table: &Table) -> Self {
3946
let size = if table.columns.iter().any(|col| col.is_list()) {
4047
INITIAL_BATCH_SIZE_LIST

0 commit comments

Comments
 (0)