@@ -83,6 +83,7 @@ pub use data::Storage;
83
83
84
84
/// Encapuslate access to the blocks table for a chain.
85
85
mod data {
86
+ use crate :: diesel:: dsl:: IntervalDsl ;
86
87
use diesel:: sql_types:: { Array , Binary , Bool , Nullable } ;
87
88
use diesel:: { connection:: SimpleConnection , insert_into} ;
88
89
use diesel:: { delete, prelude:: * , sql_query} ;
@@ -104,7 +105,7 @@ mod data {
104
105
use graph:: prelude:: transaction_receipt:: LightTransactionReceipt ;
105
106
use graph:: prelude:: web3:: types:: H256 ;
106
107
use graph:: prelude:: {
107
- serde_json as json, BlockNumber , BlockPtr , CachedEthereumCall , Error , StoreError ,
108
+ serde_json as json, BlockNumber , BlockPtr , CachedEthereumCall , Error , Logger , StoreError ,
108
109
} ;
109
110
use std:: collections:: HashMap ;
110
111
use std:: convert:: TryFrom ;
@@ -1398,6 +1399,126 @@ mod data {
1398
1399
}
1399
1400
}
1400
1401
1402
+ pub fn clear_stale_call_cache (
1403
+ & self ,
1404
+ conn : & mut PgConnection ,
1405
+ logger : & Logger ,
1406
+ ttl_days : i32 ,
1407
+ ) -> Result < ( ) , Error > {
1408
+ // Delete cache entries in batches since there could be thousands of cache entries per contract
1409
+ let mut total_deleted = 0 ;
1410
+ let batch_size = 5000 ;
1411
+
1412
+ match self {
1413
+ Storage :: Shared => {
1414
+ use public:: eth_call_cache as cache;
1415
+ use public:: eth_call_meta as meta;
1416
+
1417
+ let stale_contracts = meta:: table
1418
+ . select ( meta:: contract_address)
1419
+ . filter (
1420
+ meta:: accessed_at
1421
+ . lt ( diesel:: dsl:: date ( diesel:: dsl:: now - ttl_days. days ( ) ) ) ,
1422
+ )
1423
+ . get_results :: < Vec < u8 > > ( conn) ?;
1424
+
1425
+ if stale_contracts. is_empty ( ) {
1426
+ return Ok ( ( ) ) ;
1427
+ }
1428
+
1429
+ loop {
1430
+ let next_batch = cache:: table
1431
+ . select ( cache:: id)
1432
+ . filter ( cache:: contract_address. eq_any ( & stale_contracts) )
1433
+ . limit ( batch_size as i64 )
1434
+ . get_results :: < Vec < u8 > > ( conn) ?;
1435
+ let deleted_count =
1436
+ diesel:: delete ( cache:: table. filter ( cache:: id. eq_any ( & next_batch) ) )
1437
+ . execute ( conn) ?;
1438
+
1439
+ total_deleted += deleted_count;
1440
+
1441
+ if deleted_count < batch_size {
1442
+ break ;
1443
+ }
1444
+ }
1445
+
1446
+ graph:: slog:: info!(
1447
+ logger,
1448
+ "Cleaned call cache: deleted {} entries for {} contracts" ,
1449
+ total_deleted,
1450
+ stale_contracts. len( )
1451
+ ) ;
1452
+
1453
+ diesel:: delete (
1454
+ meta:: table. filter ( meta:: contract_address. eq_any ( & stale_contracts) ) ,
1455
+ )
1456
+ . execute ( conn) ?;
1457
+
1458
+ Ok ( ( ) )
1459
+ }
1460
+ Storage :: Private ( Schema {
1461
+ call_cache,
1462
+ call_meta,
1463
+ ..
1464
+ } ) => {
1465
+ let select_query = format ! (
1466
+ "SELECT contract_address FROM {} \
1467
+ WHERE accessed_at < CURRENT_DATE - interval '{} days'",
1468
+ call_meta. qname, ttl_days
1469
+ ) ;
1470
+
1471
+ #[ derive( QueryableByName ) ]
1472
+ struct ContractAddress {
1473
+ #[ diesel( sql_type = Bytea ) ]
1474
+ contract_address : Vec < u8 > ,
1475
+ }
1476
+
1477
+ let all_stale_contracts: Vec < Vec < u8 > > = sql_query ( select_query)
1478
+ . load :: < ContractAddress > ( conn) ?
1479
+ . into_iter ( )
1480
+ . map ( |row| row. contract_address )
1481
+ . collect ( ) ;
1482
+
1483
+ if all_stale_contracts. is_empty ( ) {
1484
+ graph:: slog:: info!( logger, "Cleaned call cache: no stale entries found" ) ;
1485
+ return Ok ( ( ) ) ;
1486
+ }
1487
+
1488
+ loop {
1489
+ let delete_cache_query = format ! (
1490
+ "DELETE FROM {} WHERE id IN (
1491
+ SELECT id FROM {}
1492
+ WHERE contract_address = ANY($1)
1493
+ LIMIT {}
1494
+ )" ,
1495
+ call_cache. qname, call_cache. qname, batch_size
1496
+ ) ;
1497
+
1498
+ let deleted_count = sql_query ( delete_cache_query)
1499
+ . bind :: < Array < Bytea > , _ > ( & all_stale_contracts)
1500
+ . execute ( conn) ?;
1501
+
1502
+ total_deleted += deleted_count;
1503
+
1504
+ if deleted_count < batch_size {
1505
+ break ;
1506
+ }
1507
+ }
1508
+
1509
+ let delete_meta_query = format ! (
1510
+ "DELETE FROM {} WHERE contract_address = ANY($1)" ,
1511
+ call_meta. qname
1512
+ ) ;
1513
+ sql_query ( delete_meta_query)
1514
+ . bind :: < Array < Bytea > , _ > ( & all_stale_contracts)
1515
+ . execute ( conn) ?;
1516
+
1517
+ Ok ( ( ) )
1518
+ }
1519
+ }
1520
+ }
1521
+
1401
1522
pub ( super ) fn update_accessed_at (
1402
1523
& self ,
1403
1524
conn : & mut PgConnection ,
@@ -2508,6 +2629,12 @@ impl ChainStoreTrait for ChainStore {
2508
2629
Ok ( ( ) )
2509
2630
}
2510
2631
2632
+ async fn clear_stale_call_cache ( & self , ttl_days : i32 ) -> Result < ( ) , Error > {
2633
+ let conn = & mut * self . get_conn ( ) ?;
2634
+ self . storage
2635
+ . clear_stale_call_cache ( conn, & self . logger , ttl_days)
2636
+ }
2637
+
2511
2638
async fn transaction_receipts_in_block (
2512
2639
& self ,
2513
2640
block_hash : & H256 ,
0 commit comments