66{-# LANGUAGE FlexibleInstances #-}
77{-# LANGUAGE GADTs #-}
88{-# LANGUAGE GeneralizedNewtypeDeriving #-}
9+ {-# LANGUAGE LambdaCase #-}
910{-# LANGUAGE MultiParamTypeClasses #-}
1011{-# LANGUAGE QuantifiedConstraints #-}
1112{-# LANGUAGE RankNTypes #-}
1213{-# LANGUAGE ScopedTypeVariables #-}
1314{-# LANGUAGE StandaloneDeriving #-}
1415{-# LANGUAGE TypeOperators #-}
1516{-# LANGUAGE UndecidableInstances #-}
17+ {-# LANGUAGE ViewPatterns #-}
1618
1719-- | The data structure that holds the cached ledger states.
1820module Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq
@@ -54,7 +56,6 @@ module Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq
5456
5557import Cardano.Ledger.BaseTypes
5658import Control.ResourceRegistry
57- import qualified Data.Bifunctor as B
5859import Data.Function (on )
5960import Data.Word
6061import GHC.Generics
@@ -183,8 +184,11 @@ empty' ::
183184 m (LedgerSeq m l )
184185empty' st = empty (forgetLedgerTables st) (ltprj st)
185186
187+ -- | Close all 'LedgerTablesHandle' in this 'LedgerSeq', in particular that on
188+ -- the anchor.
186189closeLedgerSeq :: Monad m => LedgerSeq m l -> m ()
187- closeLedgerSeq = mapM_ (close . tables) . toOldestFirst . getLedgerSeq
190+ closeLedgerSeq (LedgerSeq l) =
191+ mapM_ (close . tables) $ AS. anchor l : AS. toOldestFirst l
188192
189193{- ------------------------------------------------------------------------------
190194 Apply blocks
@@ -193,15 +197,14 @@ closeLedgerSeq = mapM_ (close . tables) . toOldestFirst . getLedgerSeq
193197-- | Apply a block on top of the ledger state and extend the LedgerSeq with
194198-- the result ledger state.
195199--
196- -- The @fst@ component of the result should be closed as it contains the pruned
197- -- states.
200+ -- The @fst@ component of the result should be run to close the pruned states.
198201reapplyThenPush ::
199202 (IOLike m , ApplyBlock l blk ) =>
200203 ResourceRegistry m ->
201204 LedgerDbCfg l ->
202205 blk ->
203206 LedgerSeq m l ->
204- m (LedgerSeq m l , LedgerSeq m l )
207+ m (m () , LedgerSeq m l )
205208reapplyThenPush rr cfg ap db =
206209 (\ current' -> prune (LedgerDbPruneKeeping (ledgerDbCfgSecParam cfg)) $ extend current' db)
207210 <$> reapplyBlock (ledgerDbCfgComputeLedgerEvents cfg) (ledgerDbCfg cfg) ap rr db
@@ -229,30 +232,38 @@ reapplyBlock evs cfg b _rr db = do
229232-- | Prune older ledger states until at we have at most @k@ volatile states in
230233-- the LedgerDB, plus the one stored at the anchor.
231234--
232- -- The @fst@ component of the returned value has to be @close@ed.
235+ -- The @fst@ component of the returned value is an action closing the pruned
236+ -- ledger states.
233237--
234238-- >>> ldb = LedgerSeq $ AS.fromOldestFirst l0 [l1, l2, l3]
235239-- >>> ldb' = LedgerSeq $ AS.fromOldestFirst l1 [l2, l3]
236240-- >>> snd (prune (LedgerDbPruneKeeping (SecurityParam (unsafeNonZero 2))) ldb) == ldb'
237241-- True
238242prune ::
239- GetTip l =>
243+ ( Monad m , GetTip l ) =>
240244 LedgerDbPrune ->
241245 LedgerSeq m l ->
242- (LedgerSeq m l , LedgerSeq m l )
243- prune ( LedgerDbPruneKeeping ( SecurityParam k)) ( LedgerSeq ldb) =
244- if toEnum nvol <= unNonZero k
245- then ( LedgerSeq $ Empty ( AS. anchor ldb ), LedgerSeq ldb)
246- else
247- -- We remove the new anchor from the @fst@ component so that its handle is
248- -- not closed.
249- B. bimap ( LedgerSeq . dropNewest 1 ) LedgerSeq $ AS. splitAt (nvol - fromEnum (unNonZero k) ) ldb
250- where
251- nvol = AS. length ldb
252- prune LedgerDbPruneAll ( LedgerSeq ldb) =
253- B. bimap ( LedgerSeq . dropNewest 1 ) LedgerSeq $ AS. splitAt nvol ldb
246+ (m () , LedgerSeq m l )
247+ prune howToPrune ( LedgerSeq ldb) = case howToPrune of
248+ LedgerDbPruneKeeping ( SecurityParam ( fromEnum . unNonZero -> k))
249+ | nvol <= k -> ( pure ( ) , LedgerSeq ldb)
250+ | otherwise -> (closeButHead before, LedgerSeq after)
251+ where
252+ nvol = AS. length ldb
253+ (before, after) = AS. splitAt (nvol - k ) ldb
254+ LedgerDbPruneAll ->
255+ (closeButHead before, LedgerSeq after)
256+ where
257+ (before, after) = (ldb, AS. Empty ( AS. headAnchor ldb))
254258 where
255- nvol = AS. length ldb
259+ -- Above, we split @ldb@ into two sequences @before@ and @after@ such that
260+ -- @AS.headAnchor before == AS.anchor after@. We want to close all handles of
261+ -- @ldb@ not present in @after@, which are none if @before@ is empty, and all
262+ -- (in particular the anchor) of @before@ apart from the the head of @before@
263+ -- if @before@ is non-empty.
264+ closeButHead = \ case
265+ AS. Empty _ -> pure ()
266+ toPrune AS. :> _ -> closeLedgerSeq (LedgerSeq toPrune)
256267
257268-- NOTE: we must inline 'prune' otherwise we get unexplained thunks in
258269-- 'LedgerSeq' and thus a space leak. Alternatively, we could disable the
@@ -296,9 +307,9 @@ extend newState =
296307-- >>> AS.anchor ldb' == l3 && AS.toOldestFirst ldb' == []
297308-- True
298309pruneToImmTipOnly ::
299- GetTip l =>
310+ ( Monad m , GetTip l ) =>
300311 LedgerSeq m l ->
301- (LedgerSeq m l , LedgerSeq m l )
312+ (m () , LedgerSeq m l )
302313pruneToImmTipOnly = prune LedgerDbPruneAll
303314
304315{- ------------------------------------------------------------------------------
0 commit comments