@@ -24,13 +24,16 @@ import Control.RAWLock
24
24
import qualified Control.RAWLock as RAWLock
25
25
import Control.ResourceRegistry
26
26
import Control.Tracer
27
+ import Data.Foldable (traverse_ )
27
28
import qualified Data.Foldable as Foldable
28
29
import Data.Functor.Contravariant ((>$<) )
29
30
import Data.Kind (Type )
30
31
import Data.Map (Map )
31
32
import qualified Data.Map.Strict as Map
32
33
import Data.Set (Set )
33
34
import qualified Data.Set as Set
35
+ import Data.Traversable (for )
36
+ import Data.Tuple (Solo (.. ))
34
37
import Data.Void
35
38
import Data.Word
36
39
import GHC.Generics
@@ -193,19 +196,17 @@ mkInternals ::
193
196
mkInternals bss h =
194
197
TestInternals
195
198
{ takeSnapshotNOW = \ whereTo suff -> getEnv h $ \ env -> do
196
- st <-
197
- ( case whereTo of
199
+ let selectWhereTo = case whereTo of
198
200
TakeAtImmutableTip -> anchorHandle
199
201
TakeAtVolatileTip -> currentHandle
200
- )
201
- <$> readTVarIO (ldbSeq env)
202
- Monad. void $
203
- takeSnapshot
204
- (configCodec . getExtLedgerCfg . ledgerDbCfg $ ldbCfg env)
205
- (LedgerDBSnapshotEvent >$< ldbTracer env)
206
- (ldbHasFS env)
207
- suff
208
- st
202
+ withStateRef env (MkSolo . selectWhereTo) $ \ (MkSolo st) ->
203
+ Monad. void $
204
+ takeSnapshot
205
+ (configCodec . getExtLedgerCfg . ledgerDbCfg $ ldbCfg env)
206
+ (LedgerDBSnapshotEvent >$< ldbTracer env)
207
+ (ldbHasFS env)
208
+ suff
209
+ st
209
210
, push = \ st -> withRegistry $ \ reg -> do
210
211
eFrk <- newForkerAtTarget h reg VolatileTip
211
212
case eFrk of
@@ -368,13 +369,13 @@ implTryTakeSnapshot ::
368
369
implTryTakeSnapshot bss env mTime nrBlocks =
369
370
if onDiskShouldTakeSnapshot (ldbSnapshotPolicy env) (uncurry (flip diffTime) <$> mTime) nrBlocks
370
371
then do
371
- Monad. void
372
- . takeSnapshot
373
- (configCodec . getExtLedgerCfg . ledgerDbCfg $ ldbCfg env)
374
- ( LedgerDBSnapshotEvent >$< ldbTracer env)
375
- (ldbHasFS env)
376
- . anchorHandle
377
- =<< readTVarIO (ldbSeq env)
372
+ withStateRef env ( MkSolo . anchorHandle) $ \ ( MkSolo st) ->
373
+ Monad. void $
374
+ takeSnapshot
375
+ (configCodec . getExtLedgerCfg . ledgerDbCfg $ ldbCfg env)
376
+ ( LedgerDBSnapshotEvent >$< ldbTracer env)
377
+ (ldbHasFS env)
378
+ st
378
379
Monad. void $
379
380
trimSnapshots
380
381
(LedgerDBSnapshotEvent >$< ldbTracer env)
@@ -457,6 +458,19 @@ data LedgerDBEnv m l blk = LedgerDBEnv
457
458
, ldbResolveBlock :: ! (ResolveBlock m blk )
458
459
, ldbQueryBatchSize :: ! QueryBatchSize
459
460
, ldbOpenHandlesLock :: ! (RAWLock m LDBLock )
461
+ -- ^ While holding a read lock (at least), all handles in the 'ldbSeq' are
462
+ -- guaranteed to be open. During this time, the handle can be duplicated and
463
+ -- then be used independently, see 'getStateRef' and 'withStateRef'.
464
+ --
465
+ -- Therefore, closing any handles which were previously in 'ldbSeq' requires
466
+ -- acquiring a write lock. Concretely, both of the following approaches are
467
+ -- fine:
468
+ --
469
+ -- * Modify 'ldbSeq' without any locking, and then close the removed handles
470
+ -- while holding a write lock. See e.g. 'closeForkerEnv'.
471
+ --
472
+ -- * Modify 'ldbSeq' while holding a write lock, and then close the removed
473
+ -- handles without any locking.
460
474
}
461
475
deriving Generic
462
476
@@ -546,8 +560,36 @@ getEnvSTM (LDBHandle varState) f =
546
560
Acquiring consistent views
547
561
-------------------------------------------------------------------------------}
548
562
549
- -- | This function must hold the 'LDBLock' such that handles are not released
550
- -- before they are duplicated.
563
+ -- | Get a 'StateRef' from the 'LedgerSeq' in the 'LedgerDBEnv', with the
564
+ -- 'LedgerTablesHandle' having been duplicated (such that the original can be
565
+ -- closed). The caller is responsible for closing the handle.
566
+ --
567
+ -- For more flexibility, an arbitrary 'Traversable' of the 'StateRef' can be
568
+ -- returned; for the simple use case of getting a single 'StateRef', use @t ~
569
+ -- 'Solo'@.
570
+ getStateRef ::
571
+ (IOLike m , Traversable t ) =>
572
+ LedgerDBEnv m l blk ->
573
+ (LedgerSeq m l -> t (StateRef m l )) ->
574
+ m (t (StateRef m l ))
575
+ getStateRef ldbEnv project =
576
+ RAWLock. withReadAccess (ldbOpenHandlesLock ldbEnv) $ \ LDBLock -> do
577
+ tst <- project <$> readTVarIO (ldbSeq ldbEnv)
578
+ for tst $ \ st -> do
579
+ tables' <- duplicate $ tables st
580
+ pure st{tables = tables'}
581
+
582
+ -- | Like 'StateRef', but takes care of closing the handle when the given action
583
+ -- returns or errors.
584
+ withStateRef ::
585
+ (IOLike m , Traversable t ) =>
586
+ LedgerDBEnv m l blk ->
587
+ (LedgerSeq m l -> t (StateRef m l )) ->
588
+ (t (StateRef m l ) -> m a ) ->
589
+ m a
590
+ withStateRef ldbEnv project =
591
+ bracket (getStateRef ldbEnv project) (traverse_ (close . tables))
592
+
551
593
acquireAtTarget ::
552
594
( HeaderHash l ~ HeaderHash blk
553
595
, IOLike m
@@ -557,41 +599,28 @@ acquireAtTarget ::
557
599
) =>
558
600
LedgerDBEnv m l blk ->
559
601
Either Word64 (Target (Point blk )) ->
560
- LDBLock ->
561
602
m (Either GetForkerError (StateRef m l ))
562
- acquireAtTarget ldbEnv (Right VolatileTip ) _ = do
563
- l <- readTVarIO (ldbSeq ldbEnv)
564
- let StateRef st tbs = currentHandle l
565
- t <- duplicate tbs
566
- pure $ Right $ StateRef st t
567
- acquireAtTarget ldbEnv (Right ImmutableTip ) _ = do
568
- l <- readTVarIO (ldbSeq ldbEnv)
569
- let StateRef st tbs = anchorHandle l
570
- t <- duplicate tbs
571
- pure $ Right $ StateRef st t
572
- acquireAtTarget ldbEnv (Right (SpecificPoint pt)) _ = do
573
- dblog <- readTVarIO (ldbSeq ldbEnv)
574
- let immTip = getTip $ anchor dblog
575
- case currentHandle <$> rollback pt dblog of
576
- Nothing
577
- | pointSlot pt < pointSlot immTip -> pure $ Left $ PointTooOld Nothing
578
- | otherwise -> pure $ Left PointNotOnChain
579
- Just (StateRef st tbs) ->
580
- Right . StateRef st <$> duplicate tbs
581
- acquireAtTarget ldbEnv (Left n) _ = do
582
- dblog <- readTVarIO (ldbSeq ldbEnv)
583
- case currentHandle <$> rollbackN n dblog of
584
- Nothing ->
585
- return $
586
- Left $
603
+ acquireAtTarget ldbEnv target =
604
+ getStateRef ldbEnv $ \ l -> case target of
605
+ Right VolatileTip -> pure $ currentHandle l
606
+ Right ImmutableTip -> pure $ anchorHandle l
607
+ Right (SpecificPoint pt) -> do
608
+ let immTip = getTip $ anchor l
609
+ case rollback pt l of
610
+ Nothing
611
+ | pointSlot pt < pointSlot immTip -> throwError $ PointTooOld Nothing
612
+ | otherwise -> throwError PointNotOnChain
613
+ Just t' -> pure $ currentHandle t'
614
+ Left n -> case rollbackN n l of
615
+ Nothing ->
616
+ throwError $
587
617
PointTooOld $
588
- Just $
618
+ Just
589
619
ExceededRollback
590
- { rollbackMaximum = maxRollback dblog
620
+ { rollbackMaximum = maxRollback l
591
621
, rollbackRequested = n
592
622
}
593
- Just (StateRef st tbs) ->
594
- Right . StateRef st <$> duplicate tbs
623
+ Just l' -> pure $ currentHandle l'
595
624
596
625
newForkerAtTarget ::
597
626
( HeaderHash l ~ HeaderHash blk
@@ -605,8 +634,8 @@ newForkerAtTarget ::
605
634
ResourceRegistry m ->
606
635
Target (Point blk ) ->
607
636
m (Either GetForkerError (Forker m l blk ))
608
- newForkerAtTarget h rr pt = getEnv h $ \ ldbEnv@ LedgerDBEnv {ldbOpenHandlesLock = lock} ->
609
- RAWLock. withReadAccess lock ( acquireAtTarget ldbEnv (Right pt) ) >>= traverse (newForker h ldbEnv rr)
637
+ newForkerAtTarget h rr pt = getEnv h $ \ ldbEnv ->
638
+ acquireAtTarget ldbEnv (Right pt) >>= traverse (newForker h ldbEnv rr)
610
639
611
640
newForkerByRollback ::
612
641
( HeaderHash l ~ HeaderHash blk
@@ -620,8 +649,8 @@ newForkerByRollback ::
620
649
ResourceRegistry m ->
621
650
Word64 ->
622
651
m (Either GetForkerError (Forker m l blk ))
623
- newForkerByRollback h rr n = getEnv h $ \ ldbEnv@ LedgerDBEnv {ldbOpenHandlesLock = lock} -> do
624
- RAWLock. withReadAccess lock ( acquireAtTarget ldbEnv (Left n) ) >>= traverse (newForker h ldbEnv rr)
652
+ newForkerByRollback h rr n = getEnv h $ \ ldbEnv ->
653
+ acquireAtTarget ldbEnv (Left n) >>= traverse (newForker h ldbEnv rr)
625
654
626
655
-- | Close all open 'Forker's.
627
656
closeAllForkers ::
0 commit comments