Skip to content

Commit d54c3f3

Browse files
authored
Merge pull request #1886 from IntersectMBO/1843-limit-cache-at-tip
1843 - limit cache when close to tip
2 parents 0b7c281 + 26346a2 commit d54c3f3

File tree

8 files changed

+178
-104
lines changed

8 files changed

+178
-104
lines changed

cardano-db-sync/src/Cardano/DbSync/Api/Ledger.hs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,11 @@ migrateBootstrapUTxO syncEnv = do
7979
where
8080
trce = getTrace syncEnv
8181

82-
storeUTxOFromLedger :: (MonadBaseControl IO m, MonadIO m) => SyncEnv -> ExtLedgerState CardanoBlock -> ExceptT SyncNodeError (ReaderT SqlBackend m) ()
82+
storeUTxOFromLedger ::
83+
(MonadBaseControl IO m, MonadIO m) =>
84+
SyncEnv ->
85+
ExtLedgerState CardanoBlock ->
86+
ExceptT SyncNodeError (ReaderT SqlBackend m) ()
8387
storeUTxOFromLedger env st = case ledgerState st of
8488
LedgerStateBabbage bts -> storeUTxO env (getUTxO bts)
8589
LedgerStateConway stc -> storeUTxO env (getUTxO stc)

cardano-db-sync/src/Cardano/DbSync/Cache.hs

Lines changed: 140 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ module Cardano.DbSync.Cache (
2222
queryStakeAddrWithCache,
2323
queryTxIdWithCache,
2424
rollbackCache,
25+
optimiseCaches,
2526
tryUpdateCacheTx,
2627

2728
-- * CacheStatistics
@@ -80,6 +81,26 @@ rollbackCache (ActiveCache cache) blockId = do
8081
atomically $ modifyTVar (cTxIds cache) FIFO.cleanupCache
8182
void $ rollbackMapEpochInCache cache blockId
8283

84+
-- | When syncing and we get within 2 minutes of the tip, we can optimise the caches
85+
-- and set the flag to True on ActiveCache.leaving the following caches as they are:
86+
-- cPools, cPrevBlock, Cstats, cEpoch
87+
optimiseCaches :: MonadIO m => CacheStatus -> ReaderT SqlBackend m ()
88+
optimiseCaches cache =
89+
case cache of
90+
NoCache -> pure ()
91+
ActiveCache c ->
92+
withCacheOptimisationCheck c (pure ()) $
93+
liftIO $ do
94+
-- empty caches not to be used anymore
95+
atomically $ modifyTVar (cTxIds c) FIFO.cleanupCache
96+
atomically $ writeTVar (cStake c) (StakeCache Map.empty (LRU.empty 0))
97+
atomically $ modifyTVar (cDatum c) (LRU.optimise 0)
98+
-- empty then limit the capacity of the cache
99+
atomically $ writeTVar (cMultiAssets c) (LRU.empty 50000)
100+
-- set the flag to True
101+
atomically $ writeTVar (cIsCacheOptimised c) True
102+
pure ()
103+
83104
getCacheStatistics :: CacheStatus -> IO CacheStatistics
84105
getCacheStatistics cs =
85106
case cs of
@@ -150,34 +171,36 @@ queryStakeAddrWithCacheRetBs ::
150171
queryStakeAddrWithCacheRetBs _trce cache cacheUA ra@(Ledger.RewardAccount _ cred) = do
151172
let bs = Ledger.serialiseRewardAccount ra
152173
case cache of
153-
NoCache -> do
154-
mapLeft (,bs) <$> resolveStakeAddress bs
174+
NoCache -> rsStkAdrrs bs
155175
ActiveCache ci -> do
156-
stakeCache <- liftIO $ readTVarIO (cStake ci)
157-
case queryStakeCache cred stakeCache of
158-
Just (addrId, stakeCache') -> do
159-
liftIO $ hitCreds (cStats ci)
160-
case cacheUA of
161-
EvictAndUpdateCache -> do
162-
liftIO $ atomically $ writeTVar (cStake ci) $ deleteStakeCache cred stakeCache'
163-
pure $ Right addrId
164-
_other -> do
165-
liftIO $ atomically $ writeTVar (cStake ci) stakeCache'
166-
pure $ Right addrId
167-
Nothing -> do
168-
queryRes <- mapLeft (,bs) <$> resolveStakeAddress bs
169-
liftIO $ missCreds (cStats ci)
170-
case queryRes of
171-
Left _ -> pure queryRes
172-
Right stakeAddrsId -> do
173-
let !stakeCache' = case cacheUA of
174-
UpdateCache -> stakeCache {scLruCache = LRU.insert cred stakeAddrsId (scLruCache stakeCache)}
175-
UpdateCacheStrong -> stakeCache {scStableCache = Map.insert cred stakeAddrsId (scStableCache stakeCache)}
176-
_ -> stakeCache
177-
liftIO $
178-
atomically $
179-
writeTVar (cStake ci) stakeCache'
180-
pure $ Right stakeAddrsId
176+
withCacheOptimisationCheck ci (rsStkAdrrs bs) $ do
177+
stakeCache <- liftIO $ readTVarIO (cStake ci)
178+
case queryStakeCache cred stakeCache of
179+
Just (addrId, stakeCache') -> do
180+
liftIO $ hitCreds (cStats ci)
181+
case cacheUA of
182+
EvictAndUpdateCache -> do
183+
liftIO $ atomically $ writeTVar (cStake ci) $ deleteStakeCache cred stakeCache'
184+
pure $ Right addrId
185+
_other -> do
186+
liftIO $ atomically $ writeTVar (cStake ci) stakeCache'
187+
pure $ Right addrId
188+
Nothing -> do
189+
queryRes <- mapLeft (,bs) <$> resolveStakeAddress bs
190+
liftIO $ missCreds (cStats ci)
191+
case queryRes of
192+
Left _ -> pure queryRes
193+
Right stakeAddrsId -> do
194+
let !stakeCache' = case cacheUA of
195+
UpdateCache -> stakeCache {scLruCache = LRU.insert cred stakeAddrsId (scLruCache stakeCache)}
196+
UpdateCacheStrong -> stakeCache {scStableCache = Map.insert cred stakeAddrsId (scStableCache stakeCache)}
197+
_otherwise -> stakeCache
198+
liftIO $
199+
atomically $
200+
writeTVar (cStake ci) stakeCache'
201+
pure $ Right stakeAddrsId
202+
where
203+
rsStkAdrrs bs = mapLeft (,bs) <$> resolveStakeAddress bs
181204

182205
-- | True if it was found in LRU
183206
queryStakeCache :: StakeCred -> StakeCache -> Maybe (DB.StakeAddressId, StakeCache)
@@ -306,26 +329,29 @@ queryMAWithCache ::
306329
ReaderT SqlBackend m (Either (ByteString, ByteString) DB.MultiAssetId)
307330
queryMAWithCache cache policyId asset =
308331
case cache of
309-
NoCache -> do
332+
NoCache -> queryDb
333+
ActiveCache ci -> do
334+
withCacheOptimisationCheck ci queryDb $ do
335+
mp <- liftIO $ readTVarIO (cMultiAssets ci)
336+
case LRU.lookup (policyId, asset) mp of
337+
Just (maId, mp') -> do
338+
liftIO $ hitMAssets (cStats ci)
339+
liftIO $ atomically $ writeTVar (cMultiAssets ci) mp'
340+
pure $ Right maId
341+
Nothing -> do
342+
liftIO $ missMAssets (cStats ci)
343+
-- miss. The lookup doesn't change the cache on a miss.
344+
let !policyBs = Generic.unScriptHash $ policyID policyId
345+
let !assetNameBs = Generic.unAssetName asset
346+
maId <- maybe (Left (policyBs, assetNameBs)) Right <$> DB.queryMultiAssetId policyBs assetNameBs
347+
whenRight maId $
348+
liftIO . atomically . modifyTVar (cMultiAssets ci) . LRU.insert (policyId, asset)
349+
pure maId
350+
where
351+
queryDb = do
310352
let !policyBs = Generic.unScriptHash $ policyID policyId
311353
let !assetNameBs = Generic.unAssetName asset
312354
maybe (Left (policyBs, assetNameBs)) Right <$> DB.queryMultiAssetId policyBs assetNameBs
313-
ActiveCache ci -> do
314-
mp <- liftIO $ readTVarIO (cMultiAssets ci)
315-
case LRU.lookup (policyId, asset) mp of
316-
Just (maId, mp') -> do
317-
liftIO $ hitMAssets (cStats ci)
318-
liftIO $ atomically $ writeTVar (cMultiAssets ci) mp'
319-
pure $ Right maId
320-
Nothing -> do
321-
liftIO $ missMAssets (cStats ci)
322-
-- miss. The lookup doesn't change the cache on a miss.
323-
let !policyBs = Generic.unScriptHash $ policyID policyId
324-
let !assetNameBs = Generic.unAssetName asset
325-
maId <- maybe (Left (policyBs, assetNameBs)) Right <$> DB.queryMultiAssetId policyBs assetNameBs
326-
whenRight maId $
327-
liftIO . atomically . modifyTVar (cMultiAssets ci) . LRU.insert (policyId, asset)
328-
pure maId
329355

330356
queryPrevBlockWithCache ::
331357
MonadIO m =>
@@ -364,42 +390,42 @@ queryTxIdWithCache ::
364390
queryTxIdWithCache cache txIdLedger = do
365391
case cache of
366392
-- Direct database query if no cache.
367-
NoCache -> DB.queryTxId txHash
368-
ActiveCache cacheInternal -> do
369-
-- Read current cache state.
370-
cacheTx <- liftIO $ readTVarIO (cTxIds cacheInternal)
371-
372-
case FIFO.lookup txIdLedger cacheTx of
373-
-- Cache hit, return the transaction ID.
374-
Just txId -> do
375-
liftIO $ hitTxIds (cStats cacheInternal)
376-
pure $ Right txId
377-
-- Cache miss.
378-
Nothing -> do
379-
eTxId <- DB.queryTxId txHash
380-
liftIO $ missTxIds (cStats cacheInternal)
381-
case eTxId of
382-
Right txId -> do
383-
-- Update cache.
384-
liftIO $ atomically $ modifyTVar (cTxIds cacheInternal) $ FIFO.insert txIdLedger txId
385-
-- Return ID after updating cache.
386-
pure $ Right txId
387-
-- Return lookup failure.
388-
Left _ -> pure $ Left $ DB.DbLookupTxHash txHash
393+
NoCache -> qTxHash
394+
ActiveCache ci ->
395+
withCacheOptimisationCheck ci qTxHash $ do
396+
-- Read current cache state.
397+
cacheTx <- liftIO $ readTVarIO (cTxIds ci)
398+
399+
case FIFO.lookup txIdLedger cacheTx of
400+
-- Cache hit, return the transaction ID.
401+
Just txId -> do
402+
liftIO $ hitTxIds (cStats ci)
403+
pure $ Right txId
404+
-- Cache miss.
405+
Nothing -> do
406+
eTxId <- qTxHash
407+
liftIO $ missTxIds (cStats ci)
408+
case eTxId of
409+
Right txId -> do
410+
-- Update cache.
411+
liftIO $ atomically $ modifyTVar (cTxIds ci) $ FIFO.insert txIdLedger txId
412+
-- Return ID after updating cache.
413+
pure $ Right txId
414+
-- Return lookup failure.
415+
Left _ -> pure $ Left $ DB.DbLookupTxHash txHash
389416
where
390417
txHash = Generic.unTxHash txIdLedger
418+
qTxHash = DB.queryTxId txHash
391419

392420
tryUpdateCacheTx ::
393421
MonadIO m =>
394422
CacheStatus ->
395423
Ledger.TxId StandardCrypto ->
396424
DB.TxId ->
397425
m ()
398-
tryUpdateCacheTx cache ledgerTxId txId = do
399-
case cache of
400-
NoCache -> pure ()
401-
ActiveCache ci -> do
402-
liftIO $ atomically $ modifyTVar (cTxIds ci) $ FIFO.insert ledgerTxId txId
426+
tryUpdateCacheTx (ActiveCache ci) ledgerTxId txId =
427+
liftIO $ atomically $ modifyTVar (cTxIds ci) $ FIFO.insert ledgerTxId txId
428+
tryUpdateCacheTx _ _ _ = pure ()
403429

404430
insertBlockAndCache ::
405431
(MonadIO m, MonadBaseControl IO m) =>
@@ -408,13 +434,16 @@ insertBlockAndCache ::
408434
ReaderT SqlBackend m DB.BlockId
409435
insertBlockAndCache cache block =
410436
case cache of
411-
NoCache -> DB.insertBlock block
412-
ActiveCache ci -> do
413-
bid <- DB.insertBlock block
414-
liftIO $ do
415-
missPrevBlock (cStats ci)
416-
atomically $ writeTVar (cPrevBlock ci) $ Just (bid, DB.blockHash block)
417-
pure bid
437+
NoCache -> insBlck
438+
ActiveCache ci ->
439+
withCacheOptimisationCheck ci insBlck $ do
440+
bid <- insBlck
441+
liftIO $ do
442+
missPrevBlock (cStats ci)
443+
atomically $ writeTVar (cPrevBlock ci) $ Just (bid, DB.blockHash block)
444+
pure bid
445+
where
446+
insBlck = DB.insertBlock block
418447

419448
queryDatum ::
420449
MonadIO m =>
@@ -423,18 +452,21 @@ queryDatum ::
423452
ReaderT SqlBackend m (Maybe DB.DatumId)
424453
queryDatum cache hsh = do
425454
case cache of
426-
NoCache -> DB.queryDatum $ Generic.dataHashToBytes hsh
455+
NoCache -> queryDtm
427456
ActiveCache ci -> do
428-
mp <- liftIO $ readTVarIO (cDatum ci)
429-
case LRU.lookup hsh mp of
430-
Just (datumId, mp') -> do
431-
liftIO $ hitDatum (cStats ci)
432-
liftIO $ atomically $ writeTVar (cDatum ci) mp'
433-
pure $ Just datumId
434-
Nothing -> do
435-
liftIO $ missDatum (cStats ci)
436-
-- miss. The lookup doesn't change the cache on a miss.
437-
DB.queryDatum $ Generic.dataHashToBytes hsh
457+
withCacheOptimisationCheck ci queryDtm $ do
458+
mp <- liftIO $ readTVarIO (cDatum ci)
459+
case LRU.lookup hsh mp of
460+
Just (datumId, mp') -> do
461+
liftIO $ hitDatum (cStats ci)
462+
liftIO $ atomically $ writeTVar (cDatum ci) mp'
463+
pure $ Just datumId
464+
Nothing -> do
465+
liftIO $ missDatum (cStats ci)
466+
-- miss. The lookup doesn't change the cache on a miss.
467+
queryDtm
468+
where
469+
queryDtm = DB.queryDatum $ Generic.dataHashToBytes hsh
438470

439471
-- This assumes the entry is not cached.
440472
insertDatumAndCache ::
@@ -447,12 +479,25 @@ insertDatumAndCache cache hsh dt = do
447479
datumId <- DB.insertDatum dt
448480
case cache of
449481
NoCache -> pure datumId
450-
ActiveCache ci -> do
451-
liftIO $
452-
atomically $
453-
modifyTVar (cDatum ci) $
454-
LRU.insert hsh datumId
455-
pure datumId
482+
ActiveCache ci ->
483+
withCacheOptimisationCheck ci (pure datumId) $ do
484+
liftIO $
485+
atomically $
486+
modifyTVar (cDatum ci) $
487+
LRU.insert hsh datumId
488+
pure datumId
489+
490+
withCacheOptimisationCheck ::
491+
MonadIO m =>
492+
CacheInternal ->
493+
m a -> -- Action to perform if cache is optimised
494+
m a -> -- Action to perform if cache is not optimised
495+
m a
496+
withCacheOptimisationCheck ci ifOptimised ifNotOptimised = do
497+
isCachedOptimised <- liftIO $ readTVarIO (cIsCacheOptimised ci)
498+
if isCachedOptimised
499+
then ifOptimised
500+
else ifNotOptimised
456501

457502
-- Stakes
458503
hitCreds :: StrictTVar IO CacheStatistics -> IO ()

cardano-db-sync/src/Cardano/DbSync/Cache/LRU.hs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ module Cardano.DbSync.Cache.LRU (
55
LRUCache (..),
66
empty,
77
cleanup,
8+
optimise,
89
trim,
910
insert,
1011
fromList,
@@ -46,6 +47,14 @@ cleanup cache =
4647
, cQueue = OrdPSQ.empty
4748
}
4849

50+
optimise :: Word64 -> LRUCache k v -> LRUCache k v
51+
optimise capacity cache =
52+
cache
53+
{ cCapacity = capacity
54+
, cTick = 0
55+
, cQueue = OrdPSQ.empty
56+
}
57+
4958
-- trim ensures the cache size does not exceed its capacity.
5059
-- It removes the least recently used item if the cache is over capacity.
5160
trim :: Ord k => LRUCache k v -> LRUCache k v

cardano-db-sync/src/Cardano/DbSync/Cache/Types.hs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ data StakeCache = StakeCache
6060
, scLruCache :: !(LRUCache StakeCred DB.StakeAddressId)
6161
}
6262

63-
-- 'CacheStatus' enables functions in this module to be called even if the cache has not been initialized.
63+
-- | 'CacheStatus' enables functions in this module to be called even if the cache has not been initialized.
6464
-- This is used during genesis insertions, where the cache is not yet initiated, and when the user has disabled the cache functionality.
6565
data CacheStatus
6666
= NoCache
@@ -74,7 +74,8 @@ data CacheAction
7474
deriving (Eq)
7575

7676
data CacheInternal = CacheInternal
77-
{ cStake :: !(StrictTVar IO StakeCache)
77+
{ cIsCacheOptimised :: !(StrictTVar IO Bool)
78+
, cStake :: !(StrictTVar IO StakeCache)
7879
, cPools :: !(StrictTVar IO StakePoolCache)
7980
, cDatum :: !(StrictTVar IO (LRUCache DataHash DB.DatumId))
8081
, cMultiAssets :: !(StrictTVar IO (LRUCache (PolicyID StandardCrypto, AssetName) DB.MultiAssetId))
@@ -129,6 +130,7 @@ data CacheEpoch = CacheEpoch
129130
textShowStats :: CacheStatus -> IO Text
130131
textShowStats NoCache = pure "NoCache"
131132
textShowStats (ActiveCache ic) = do
133+
isCacheOptimised <- readTVarIO $ cIsCacheOptimised ic
132134
stats <- readTVarIO $ cStats ic
133135
stakeHashRaws <- readTVarIO (cStake ic)
134136
pools <- readTVarIO (cPools ic)
@@ -138,6 +140,7 @@ textShowStats (ActiveCache ic) = do
138140
pure $
139141
mconcat
140142
[ "\nCache Statistics:"
143+
, "\n Caches Optimised: " <> textShow isCacheOptimised
141144
, "\n Stake Addresses: "
142145
, "cache sizes: "
143146
, textShow (Map.size $ scStableCache stakeHashRaws)
@@ -211,6 +214,7 @@ useNoCache = NoCache
211214

212215
newEmptyCache :: MonadIO m => CacheCapacity -> m CacheStatus
213216
newEmptyCache CacheCapacity {..} = liftIO $ do
217+
cIsCacheOptimised <- newTVarIO False
214218
cStake <- newTVarIO (StakeCache Map.empty (LRU.empty cacheCapacityStake))
215219
cPools <- newTVarIO Map.empty
216220
cDatum <- newTVarIO (LRU.empty cacheCapacityDatum)
@@ -222,7 +226,8 @@ newEmptyCache CacheCapacity {..} = liftIO $ do
222226

223227
pure . ActiveCache $
224228
CacheInternal
225-
{ cStake = cStake
229+
{ cIsCacheOptimised = cIsCacheOptimised
230+
, cStake = cStake
226231
, cPools = cPools
227232
, cDatum = cDatum
228233
, cMultiAssets = cMultiAssets

0 commit comments

Comments
 (0)