Skip to content

Commit b2e70b8

Browse files
committed
LedgerDB.V2: make sure to actually close handles
1 parent 1886094 commit b2e70b8

File tree

4 files changed

+55
-31
lines changed

4 files changed

+55
-31
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
### Patch
2+
3+
- Changed the V2 LedgerDB `LedgerTablesHandle`s to actually be closed in all
4+
cases. With the current (only) backend (in-memory), this doesn't matter, but
5+
on-disk backends (like LSM trees) need this.

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/LedgerDB/V2.hs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,12 +85,12 @@ mkInitDb args flavArgs getBlock =
8585
, closeDb = closeLedgerSeq
8686
, initReapplyBlock = \a b c -> do
8787
(x, y) <- reapplyThenPush lgrRegistry a b c
88-
closeLedgerSeq x
88+
x
8989
pure y
9090
, currentTip = ledgerState . current
9191
, pruneDb = \lseq -> do
92-
let (LedgerSeq rel, dbPrunedToImmDBTip) = pruneToImmTipOnly lseq
93-
mapM_ (close . tables) (AS.toOldestFirst rel)
92+
let (rel, dbPrunedToImmDBTip) = pruneToImmTipOnly lseq
93+
rel
9494
pure dbPrunedToImmDBTip
9595
, mkLedgerDb = \lseq -> do
9696
varDB <- newTVarIO lseq

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/LedgerDB/V2/Forker.hs

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ implForkerCommit env = do
143143
LedgerSeq lseq <- readTVar foeLedgerSeq
144144
let intersectionSlot = getTipSlot $ state $ AS.anchor lseq
145145
let predicate = (== getTipHash (state (AS.anchor lseq))) . getTipHash . state
146-
(discardedBySelection, LedgerSeq discardedByPruning) <- do
146+
closeDiscarded <- do
147147
stateTVar
148148
foeSwitchVar
149149
( \(LedgerSeq olddb) -> fromMaybe theImpossible $ do
@@ -153,17 +153,25 @@ implForkerCommit env = do
153153
-- Join the prefix of the selection with the sequence in the forker
154154
newdb <- AS.join (const $ const True) olddb' lseq
155155
-- Prune the resulting sequence to keep @k@ states
156-
let (l, s) = prune (LedgerDbPruneKeeping (foeSecurityParam env)) (LedgerSeq newdb)
157-
pure ((toClose, l), s)
156+
let (closePruned, s) = prune (LedgerDbPruneKeeping (foeSecurityParam env)) (LedgerSeq newdb)
157+
closeDiscarded = do
158+
closePruned
159+
-- Do /not/ close the anchor of @toClose@, as that is also the
160+
-- tip of @olddb'@ which will be used in @newdb@.
161+
case toClose of
162+
AS.Empty _ -> pure ()
163+
_ AS.:< closeOld' -> closeLedgerSeq (LedgerSeq closeOld')
164+
-- Finally, close the anchor of @lseq@ (which is a duplicate of
165+
-- the head of @olddb'@).
166+
close $ tables $ AS.anchor lseq
167+
pure (closeDiscarded, s)
158168
)
159169

160170
-- We are discarding the previous value in the TVar because we had accumulated
161171
-- actions for closing the states pushed to the forker. As we are committing
162172
-- those we have to close the ones discarded in this function and forget about
163173
-- those releasing actions.
164-
writeTVar foeResourcesToRelease $
165-
mapM_ (close . tables) $
166-
AS.toOldestFirst discardedBySelection ++ AS.toOldestFirst discardedByPruning
174+
writeTVar foeResourcesToRelease closeDiscarded
167175
where
168176
ForkerEnv
169177
{ foeLedgerSeq

ouroboros-consensus/src/ouroboros-consensus/Ouroboros/Consensus/Storage/LedgerDB/V2/LedgerSeq.hs

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@
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.
1820
module Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq
@@ -54,7 +56,6 @@ module Ouroboros.Consensus.Storage.LedgerDB.V2.LedgerSeq
5456

5557
import Cardano.Ledger.BaseTypes
5658
import Control.ResourceRegistry
57-
import qualified Data.Bifunctor as B
5859
import Data.Function (on)
5960
import Data.Word
6061
import GHC.Generics
@@ -183,8 +184,11 @@ empty' ::
183184
m (LedgerSeq m l)
184185
empty' st = empty (forgetLedgerTables st) (ltprj st)
185186

187+
-- | Close all 'LedgerTablesHandle' in this 'LedgerSeq', in particular that on
188+
-- the anchor.
186189
closeLedgerSeq :: 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.
198201
reapplyThenPush ::
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)
205208
reapplyThenPush 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
238242
prune ::
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
298309
pruneToImmTipOnly ::
299-
GetTip l =>
310+
(Monad m, GetTip l) =>
300311
LedgerSeq m l ->
301-
(LedgerSeq m l, LedgerSeq m l)
312+
(m (), LedgerSeq m l)
302313
pruneToImmTipOnly = prune LedgerDbPruneAll
303314

304315
{-------------------------------------------------------------------------------

0 commit comments

Comments
 (0)