@@ -54,7 +54,6 @@ module Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq
5454
5555import Cardano.Ledger.BaseTypes
5656import Control.ResourceRegistry
57- import qualified Data.Bifunctor as B
5857import Data.Function (on )
5958import Data.Word
6059import GHC.Generics
@@ -183,8 +182,11 @@ empty' ::
183182 m (LedgerSeq m l )
184183empty' st = empty (forgetLedgerTables st) (ltprj st)
185184
185+ -- | Close all 'LedgerTablesHandle' in this 'LedgerSeq', in particular that on
186+ -- the anchor.
186187closeLedgerSeq :: Monad m => LedgerSeq m l -> m ()
187- closeLedgerSeq = mapM_ (close . tables) . toOldestFirst . getLedgerSeq
188+ closeLedgerSeq (LedgerSeq l) =
189+ mapM_ (close . tables) $ AS. anchor l : AS. toOldestFirst l
188190
189191{- ------------------------------------------------------------------------------
190192 Apply blocks
@@ -193,15 +195,14 @@ closeLedgerSeq = mapM_ (close . tables) . toOldestFirst . getLedgerSeq
193195-- | Apply a block on top of the ledger state and extend the LedgerSeq with
194196-- the result ledger state.
195197--
196- -- The @fst@ component of the result should be closed as it contains the pruned
197- -- states.
198+ -- The @fst@ component of the result should be run to close the pruned states.
198199reapplyThenPush ::
199200 (IOLike m , ApplyBlock l blk ) =>
200201 ResourceRegistry m ->
201202 LedgerDbCfg l ->
202203 blk ->
203204 LedgerSeq m l ->
204- m (LedgerSeq m l , LedgerSeq m l )
205+ m (m () , LedgerSeq m l )
205206reapplyThenPush rr cfg ap db =
206207 (\ current' -> prune (LedgerDbPruneKeeping (ledgerDbCfgSecParam cfg)) $ extend current' db)
207208 <$> reapplyBlock (ledgerDbCfgComputeLedgerEvents cfg) (ledgerDbCfg cfg) ap rr db
@@ -229,31 +230,22 @@ reapplyBlock evs cfg b _rr db = do
229230-- | Prune older ledger states until at we have at most @k@ volatile states in
230231-- the LedgerDB, plus the one stored at the anchor.
231232--
232- -- The @fst@ component of the returned value has to be @close@ed.
233+ -- The @fst@ component of the returned value is an action closing the pruned
234+ -- ledger states.
233235--
234236-- >>> ldb = LedgerSeq $ AS.fromOldestFirst l0 [l1, l2, l3]
235237-- >>> ldb' = LedgerSeq $ AS.fromOldestFirst l1 [l2, l3]
236238-- >>> snd (prune (LedgerDbPruneKeeping (SecurityParam (unsafeNonZero 2))) ldb) == ldb'
237239-- True
238240prune ::
239- GetTip l =>
241+ ( Monad m , GetTip l ) =>
240242 LedgerDbPrune ->
241243 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
254- where
255- nvol = AS. length ldb
256-
244+ (m () , LedgerSeq m l )
245+ prune (LedgerDbPruneKeeping (SecurityParam k)) =
246+ pruneAt (fromIntegral (unNonZero k))
247+ prune LedgerDbPruneAll =
248+ pruneAt 0
257249-- NOTE: we must inline 'prune' otherwise we get unexplained thunks in
258250-- 'LedgerSeq' and thus a space leak. Alternatively, we could disable the
259251-- @-fstrictness@ optimisation (enabled by default for -O1). See
@@ -263,6 +255,35 @@ prune LedgerDbPruneAll (LedgerSeq ldb) =
263255-- needed anymore.
264256{-# INLINE prune #-}
265257
258+ pruneAt ::
259+ (Monad m , GetTip l ) =>
260+ -- | New maximum length of the 'LedgerSeq'.
261+ Int ->
262+ LedgerSeq m l ->
263+ (m () , LedgerSeq m l )
264+ pruneAt i (LedgerSeq ldb)
265+ | nvol <= i = (pure () , LedgerSeq ldb)
266+ | otherwise = (closePruned, LedgerSeq after)
267+ where
268+ (toPrune, after) = AS. splitAt (nvol - i) ldb
269+
270+ -- By construction (see the docs of 'AS.splitAt'), @AS.anchor after ==
271+ -- AS.headAnchor toPrune@. Therefore, we must not close the handle
272+ -- corresponding to the head of @toPrune@.
273+ closePruned = case toPrune of
274+ -- If @toPrune@ is empty, then we have nothing to prune (in particular /not/
275+ -- the anchor).
276+ AS. Empty _ -> pure ()
277+ -- Otherwise, the head of @toPrune@ is the anchor @after@, which we don't
278+ -- want to close. All other handles in @toPrune@ (in particular its anchor)
279+ -- are to be closed.
280+ toPrune' AS. :> _ -> closeLedgerSeq (LedgerSeq toPrune')
281+
282+ nvol = AS. length ldb
283+
284+ -- Cargo-culted from 'prune' above.
285+ {-# INLINE pruneAt #-}
286+
266287-- | Extending the LedgerDB with a valid ledger state.
267288--
268289-- >>> ldb = LedgerSeq $ AS.fromOldestFirst l0 [l1, l2, l3]
@@ -296,9 +317,9 @@ extend newState =
296317-- >>> AS.anchor ldb' == l3 && AS.toOldestFirst ldb' == []
297318-- True
298319pruneToImmTipOnly ::
299- GetTip l =>
320+ ( Monad m , GetTip l ) =>
300321 LedgerSeq m l ->
301- (LedgerSeq m l , LedgerSeq m l )
322+ (m () , LedgerSeq m l )
302323pruneToImmTipOnly = prune LedgerDbPruneAll
303324
304325{- ------------------------------------------------------------------------------
0 commit comments