11{-# LANGUAGE DeriveAnyClass #-}
22{-# LANGUAGE DeriveGeneric #-}
33{-# LANGUAGE FlexibleContexts #-}
4+ {-# LANGUAGE LambdaCase #-}
45{-# LANGUAGE NamedFieldPuns #-}
56{-# LANGUAGE ScopedTypeVariables #-}
67{-# LANGUAGE StandaloneDeriving #-}
@@ -18,6 +19,7 @@ module Ouroboros.Consensus.Storage.LedgerDB.V1.Forker
1819 , implForkerReadTables
1920 ) where
2021
22+ import Control.ResourceRegistry
2123import Control.Tracer
2224import qualified Data.Map.Strict as Map
2325import Data.Semigroup
@@ -40,15 +42,25 @@ import Ouroboros.Consensus.Storage.LedgerDB.V1.DiffSeq
4042 , numInserts
4143 )
4244import qualified Ouroboros.Consensus.Storage.LedgerDB.V1.DiffSeq as DS
45+ import Ouroboros.Consensus.Storage.LedgerDB.V1.Lock
4346import Ouroboros.Consensus.Util.IOLike
4447
4548{- ------------------------------------------------------------------------------
4649 Forkers
4750-------------------------------------------------------------------------------}
4851
4952data ForkerEnv m l blk = ForkerEnv
50- { foeBackingStoreValueHandle :: ! (LedgerBackingStoreValueHandle m l )
51- -- ^ Local, consistent view of backing store
53+ { foeBackingStoreValueHandle ::
54+ ! ( StrictMVar
55+ m
56+ ( Either
57+ (LedgerDBLock m , LedgerBackingStore m l , ResourceRegistry m )
58+ (LedgerBackingStoreValueHandle m l )
59+ )
60+ )
61+ -- ^ Either the ingredients to create a value handle or a value handle, i.e. a
62+ -- local, consistent view of backing store. Use 'getValueHandle' to promote
63+ -- this if needed.
5264 , foeChangelog :: ! (StrictTVar m (DbChangelog l ))
5365 -- ^ In memory db changelog, 'foeBackingStoreValueHandle' must refer to
5466 -- the anchor of this changelog.
@@ -77,32 +89,58 @@ deriving instance
7789 Close
7890-------------------------------------------------------------------------------}
7991
80- closeForkerEnv :: ForkerEnv m l blk -> m ()
81- closeForkerEnv ForkerEnv {foeBackingStoreValueHandle} = bsvhClose foeBackingStoreValueHandle
92+ closeForkerEnv :: IOLike m => ForkerEnv m l blk -> m ()
93+ closeForkerEnv ForkerEnv {foeBackingStoreValueHandle} = do
94+ either (\ (l, _, _) -> atomically . unsafeReleaseReadAccess $ l) bsvhClose
95+ =<< takeMVar foeBackingStoreValueHandle
8296
8397{- ------------------------------------------------------------------------------
8498 Acquiring consistent views
8599-------------------------------------------------------------------------------}
86100
101+ -- | Get the value handle in a forker, creating it on demand if this is the
102+ -- first time we access the tables.
103+ getValueHandle :: (GetTip l , IOLike m ) => ForkerEnv m l blk -> m (LedgerBackingStoreValueHandle m l )
104+ getValueHandle ForkerEnv {foeBackingStoreValueHandle, foeChangelog} =
105+ modifyMVar foeBackingStoreValueHandle $ \ case
106+ r@ (Right bsvh) -> pure (r, bsvh)
107+ Left (l, bs, rr) -> do
108+ -- bsvhClose is idempotent, so we let the resource call it even if the value
109+ -- handle might have been closed somewhere else
110+ (_, bsvh) <- allocate rr (\ _ -> bsValueHandle bs) bsvhClose
111+ dblogSlot <- getTipSlot . changelogLastFlushedState <$> readTVarIO foeChangelog
112+ if bsvhAtSlot bsvh == dblogSlot
113+ then do
114+ atomically $ unsafeReleaseReadAccess l
115+ pure (Right bsvh, bsvh)
116+ else
117+ bsvhClose bsvh
118+ >> error
119+ ( " Critical error: Value handles are created at "
120+ <> show (bsvhAtSlot bsvh)
121+ <> " while the db changelog is at "
122+ <> show dblogSlot
123+ <> " . There is either a race condition or a logic bug"
124+ )
125+
87126implForkerReadTables ::
88- (MonadSTM m , HasLedgerTables l , GetTip l ) =>
127+ (IOLike m , HasLedgerTables l , GetTip l ) =>
89128 ForkerEnv m l blk ->
90129 LedgerTables l KeysMK ->
91130 m (LedgerTables l ValuesMK )
92131implForkerReadTables env ks = do
93132 traceWith (foeTracer env) ForkerReadTablesStart
94133 chlog <- readTVarIO (foeChangelog env)
95- unfwd <- readKeySetsWith lvh (changelogLastFlushedState chlog) ks
134+ bsvh <- getValueHandle env
135+ unfwd <- readKeySetsWith bsvh (changelogLastFlushedState chlog) ks
96136 case forwardTableKeySets chlog unfwd of
97137 Left _err -> error " impossible!"
98138 Right vs -> do
99139 traceWith (foeTracer env) ForkerReadTablesEnd
100140 pure vs
101- where
102- lvh = foeBackingStoreValueHandle env
103141
104142implForkerRangeReadTables ::
105- (MonadSTM m , HasLedgerTables l ) =>
143+ (IOLike m , GetTip l , HasLedgerTables l ) =>
106144 QueryBatchSize ->
107145 ForkerEnv m l blk ->
108146 RangeQueryPrevious l ->
@@ -132,12 +170,11 @@ implForkerRangeReadTables qbs env rq0 = do
132170 nrequested = 1 + max (BackingStore. rqCount rq) (1 + maxDeletes)
133171
134172 let st = changelogLastFlushedState ldb
135- values <- BackingStore. bsvhRangeRead lvh st (rq{BackingStore. rqCount = nrequested})
173+ bsvh <- getValueHandle env
174+ values <- BackingStore. bsvhRangeRead bsvh st (rq{BackingStore. rqCount = nrequested})
136175 traceWith (foeTracer env) ForkerRangeReadTablesEnd
137176 pure $ ltliftA2 (doFixupReadResult nrequested) diffs values
138177 where
139- lvh = foeBackingStoreValueHandle env
140-
141178 rq = BackingStore. RangeQuery rq1 (fromIntegral $ defaultQueryBatchSize qbs)
142179
143180 rq1 = case rq0 of
@@ -230,15 +267,15 @@ implForkerGetLedgerState env = current <$> readTVar (foeChangelog env)
230267-- | Obtain statistics for a combination of backing store value handle and
231268-- changelog.
232269implForkerReadStatistics ::
233- (MonadSTM m , HasLedgerTables l , GetTip l ) =>
270+ (IOLike m , HasLedgerTables l , GetTip l ) =>
234271 ForkerEnv m l blk ->
235272 m (Maybe Forker. Statistics )
236273implForkerReadStatistics env = do
237274 traceWith (foeTracer env) ForkerReadStatistics
238275 dblog <- readTVarIO (foeChangelog env)
239-
276+ bsvh <- getValueHandle env
240277 let seqNo = getTipSlot $ changelogLastFlushedState dblog
241- BackingStore. Statistics {sequenceNumber = seqNo', numEntries = n} <- bsvhStat lbsvh
278+ BackingStore. Statistics {sequenceNumber = seqNo', numEntries = n} <- bsvhStat bsvh
242279 if seqNo /= seqNo'
243280 then
244281 error $
@@ -265,8 +302,6 @@ implForkerReadStatistics env = do
265302 Forker. Statistics
266303 { ledgerTableSize = n + nInserts - nDeletes
267304 }
268- where
269- lbsvh = foeBackingStoreValueHandle env
270305
271306implForkerPush ::
272307 (MonadSTM m , GetTip l , HasLedgerTables l ) =>
0 commit comments