@@ -25,7 +25,6 @@ import Control.Monad.Except
25
25
import Control.Monad.Trans (lift )
26
26
import Control.ResourceRegistry
27
27
import Control.Tracer
28
- import Data.Bifunctor (first )
29
28
import qualified Data.Foldable as Foldable
30
29
import Data.Functor.Contravariant ((>$<) )
31
30
import Data.Kind (Type )
@@ -83,24 +82,29 @@ mkInitDb ::
83
82
Complete LedgerDbArgs m blk ->
84
83
Complete V1. LedgerDbFlavorArgs m ->
85
84
ResolveBlock m blk ->
86
- InitDB (DbChangelog' blk , BackingStore' m blk ) m blk
85
+ InitDB (DbChangelog' blk , ResourceKey m , BackingStore' m blk ) m blk
87
86
mkInitDb args bss getBlock =
88
87
InitDB
89
88
{ initFromGenesis = do
90
89
st <- lgrGenesis
91
90
let genesis = forgetLedgerTables st
92
91
chlog = DbCh. empty genesis
93
- (_ , backingStore) <-
92
+ (bsKey , backingStore) <-
94
93
allocate
95
94
lgrRegistry
96
95
(\ _ -> newBackingStore bsTracer baArgs lgrHasFS' genesis (projectLedgerTables st))
97
96
bsClose
98
- pure (chlog, backingStore)
97
+ pure (chlog, bsKey, backingStore)
99
98
, initFromSnapshot =
100
99
runExceptT
101
- . loadSnapshot bsTracer baArgs (configCodec . getExtLedgerCfg . ledgerDbCfg $ lgrConfig) lgrHasFS'
102
- , closeDb = bsClose . snd
103
- , initReapplyBlock = \ cfg blk (chlog, bstore) -> do
100
+ . loadSnapshot
101
+ bsTracer
102
+ baArgs
103
+ (configCodec . getExtLedgerCfg . ledgerDbCfg $ lgrConfig)
104
+ lgrHasFS'
105
+ lgrRegistry
106
+ , closeDb = \ (_, r, _) -> void $ release r
107
+ , initReapplyBlock = \ cfg blk (chlog, r, bstore) -> do
104
108
! chlog' <- reapplyThenPush cfg blk (readKeySets bstore) chlog
105
109
-- It's OK to flush without a lock here, since the `LedgerDB` has not
106
110
-- finished initializing, only this thread has access to the backing
@@ -113,10 +117,10 @@ mkInitDb args bss getBlock =
113
117
mapM_ (flushIntoBackingStore bstore) toFlush
114
118
pure toKeep
115
119
else pure chlog'
116
- pure (chlog'', bstore)
117
- , currentTip = ledgerState . current . fst
118
- , pruneDb = pure . first pruneToImmTipOnly
119
- , mkLedgerDb = \ (db, lgrBackingStore ) -> do
120
+ pure (chlog'', r, bstore)
121
+ , currentTip = \ (ch, _, _) -> ledgerState . current $ ch
122
+ , pruneDb = \ (ch, r, bs) -> pure ( pruneToImmTipOnly ch, r, bs)
123
+ , mkLedgerDb = \ (db, ldbBackingStoreKey, ldbBackingStore ) -> do
120
124
(varDB, prevApplied) <-
121
125
(,) <$> newTVarIO db <*> newTVarIO Set. empty
122
126
flushLock <- mkLedgerDBLock
@@ -125,7 +129,8 @@ mkInitDb args bss getBlock =
125
129
let env =
126
130
LedgerDBEnv
127
131
{ ldbChangelog = varDB
128
- , ldbBackingStore = lgrBackingStore
132
+ , ldbBackingStore = ldbBackingStore
133
+ , ldbBackingStoreKey = ldbBackingStoreKey
129
134
, ldbLock = flushLock
130
135
, ldbPrevApplied = prevApplied
131
136
, ldbForkers = forkers
@@ -329,13 +334,14 @@ implCloseDB (LDBHandle varState) = do
329
334
-- Idempotent
330
335
LedgerDBClosed -> return Nothing
331
336
LedgerDBOpen env -> do
337
+ -- By writing this tvar, we already make sure that no
338
+ -- forkers can perform operations other than closing, as
339
+ -- they rely on accessing the LedgerDB, which is now closed.
332
340
writeTVar varState LedgerDBClosed
333
341
return $ Just env
334
342
335
343
-- Only when the LedgerDB was open
336
- whenJust mbOpenEnv $ \ env -> do
337
- closeAllForkers env
338
- bsClose (ldbBackingStore env)
344
+ whenJust mbOpenEnv $ void . release . ldbBackingStoreKey
339
345
340
346
mkInternals ::
341
347
( IOLike m
@@ -351,7 +357,7 @@ mkInternals h =
351
357
, push = getEnv1 h implIntPush
352
358
, reapplyThenPushNOW = getEnv1 h implIntReapplyThenPush
353
359
, wipeLedgerDB = getEnv h $ void . destroySnapshots . snapshotsFs . ldbHasFS
354
- , closeLedgerDB = getEnv h $ bsClose . ldbBackingStore
360
+ , closeLedgerDB = getEnv h $ void . release . ldbBackingStoreKey
355
361
, truncateSnapshots = getEnv h $ void . implIntTruncateSnapshots . ldbHasFS
356
362
, getNumLedgerTablesHandles = pure 0
357
363
}
@@ -482,6 +488,10 @@ data LedgerDBEnv m l blk = LedgerDBEnv
482
488
, ldbBackingStore :: ! (LedgerBackingStore m l )
483
489
-- ^ Handle to the ledger's backing store, containing the parts that grow too
484
490
-- big for in-memory residency
491
+ , ldbBackingStoreKey :: ! (ResourceKey m )
492
+ -- ^ When deallocating the backing store upon closing the LedgerDB
493
+ -- (via the ChainDB shutting down), we will release the backing
494
+ -- store with this action.
485
495
, ldbLock :: ! (LedgerDBLock m )
486
496
-- ^ The flush lock to the 'BackingStore'. This lock is crucial when it
487
497
-- comes to keeping the data in memory consistent with the data on-disk.
@@ -512,6 +522,18 @@ data LedgerDBEnv m l blk = LedgerDBEnv
512
522
-- ^ Open forkers.
513
523
--
514
524
-- INVARIANT: a forker is open iff its 'ForkerKey' is in this 'Map.
525
+ --
526
+ -- The resources that could possibly be held by these forkers will
527
+ -- be released by each one of the client's registries. This means
528
+ -- that for example ChainSelection will, upon closing its registry,
529
+ -- release its forker and any resources associated.
530
+ --
531
+ -- Upon closing the LedgerDB we will overwrite this variable such
532
+ -- that existing forkers can only be closed, as closing doesn't
533
+ -- involve accessing this map (other than possibly removing the
534
+ -- forker from it if the map still exists).
535
+ --
536
+ -- As the LedgerDB should outlive any clients, this is fine.
515
537
, ldbNextForkerKey :: ! (StrictTVar m ForkerKey )
516
538
, ldbSnapshotPolicy :: ! SnapshotPolicy
517
539
, ldbTracer :: ! (Tracer m (TraceEvent blk ))
@@ -691,21 +713,6 @@ newForkerByRollback ::
691
713
newForkerByRollback h rr n = getEnv h $ \ ldbEnv -> do
692
714
withReadLock (ldbLock ldbEnv) (acquireAtTarget ldbEnv (Left n) >>= traverse (newForker h ldbEnv rr))
693
715
694
- -- | Close all open block and header 'Forker's.
695
- closeAllForkers ::
696
- IOLike m =>
697
- LedgerDBEnv m l blk ->
698
- m ()
699
- closeAllForkers ldbEnv =
700
- do
701
- forkerEnvs <- atomically $ do
702
- forkerEnvs <- Map. elems <$> readTVar forkersVar
703
- writeTVar forkersVar Map. empty
704
- return forkerEnvs
705
- mapM_ closeForkerEnv forkerEnvs
706
- where
707
- forkersVar = ldbForkers ldbEnv
708
-
709
716
-- | Acquire both a value handle and a db changelog at the tip. Holds a read lock
710
717
-- while doing so.
711
718
acquireAtTarget ::
@@ -784,7 +791,7 @@ newForker h ldbEnv rr dblog = readLocked $ do
784
791
-- read access we acquired above.
785
792
modifyTVar (ldbForkers ldbEnv) $ Map. insert forkerKey forkerEnv
786
793
traceWith (foeTracer forkerEnv) ForkerOpen
787
- pure $ mkForker h (ldbQueryBatchSize ldbEnv) forkerKey
794
+ pure $ mkForker h (ldbQueryBatchSize ldbEnv) forkerKey forkerEnv
788
795
789
796
mkForker ::
790
797
( IOLike m
@@ -795,10 +802,11 @@ mkForker ::
795
802
LedgerDBHandle m l blk ->
796
803
QueryBatchSize ->
797
804
ForkerKey ->
805
+ ForkerEnv m l blk ->
798
806
Forker m l blk
799
- mkForker h qbs forkerKey =
807
+ mkForker h qbs forkerKey forkerEnv =
800
808
Forker
801
- { forkerClose = implForkerClose h forkerKey
809
+ { forkerClose = implForkerClose h forkerKey forkerEnv
802
810
, forkerReadTables = getForkerEnv1 h forkerKey implForkerReadTables
803
811
, forkerRangeReadTables = getForkerEnv1 h forkerKey (implForkerRangeReadTables qbs)
804
812
, forkerGetLedgerState = getForkerEnvSTM h forkerKey implForkerGetLedgerState
@@ -807,18 +815,27 @@ mkForker h qbs forkerKey =
807
815
, forkerCommit = getForkerEnvSTM h forkerKey implForkerCommit
808
816
}
809
817
818
+ -- | This function receives an environment instead of reading it from
819
+ -- the DB such that we can close the forker even if the LedgerDB is
820
+ -- closed. In fact this should never happen as clients of the LedgerDB
821
+ -- (which are the ones opening forkers) should never outlive the
822
+ -- LedgerDB.
810
823
implForkerClose ::
811
824
IOLike m =>
812
825
LedgerDBHandle m l blk ->
813
826
ForkerKey ->
827
+ ForkerEnv m l blk ->
814
828
m ()
815
- implForkerClose (LDBHandle varState) forkerKey = do
816
- envMay <-
829
+ implForkerClose (LDBHandle varState) forkerKey env = do
830
+ frk <-
817
831
atomically $
818
832
readTVar varState >>= \ case
819
833
LedgerDBClosed -> pure Nothing
820
834
LedgerDBOpen ldbEnv -> do
821
835
stateTVar
822
836
(ldbForkers ldbEnv)
823
- (Map. updateLookupWithKey (\ _ _ -> Nothing ) forkerKey)
824
- whenJust envMay closeForkerEnv
837
+ (\ m -> Map. updateLookupWithKey (\ _ _ -> Nothing ) forkerKey m)
838
+ case frk of
839
+ Nothing -> pure ()
840
+ Just e -> traceWith (foeTracer e) DanglingForkerClosed
841
+ closeForkerEnv env
0 commit comments