Skip to content

Commit 7b33c4e

Browse files
committed
ImmutableDB.Iterator: allocate handles in the ResourceRegistry
Fixes #1543. The ChainDB.Iterators and ChainDB.Readers use ImmutableDB.Iterators internally. Both take a ResourceRegistry to allocate the ImmutableDB.Iterator in so that the ImmutableDB.Iterator and the open handle it contains is closed when an exception occurs. If an exception occurs at the wrong time while opening an ImmutableDB.Iterator, after opening the handle, we might leak the handle. Fix this by directly allocating the handle in the ResourceRegistry instead of the ImmutableDB.Iterator that refers to the handle.
1 parent ac8a58e commit 7b33c4e

File tree

6 files changed

+154
-121
lines changed

6 files changed

+154
-121
lines changed

ouroboros-consensus/src/Ouroboros/Storage/ChainDB/Impl/ImmDB.hs

Lines changed: 14 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ import Ouroboros.Network.Point (WithOrigin (..))
8080
import Ouroboros.Consensus.Block (GetHeader (..), IsEBB (..))
8181
import Ouroboros.Consensus.Util.IOLike
8282
import Ouroboros.Consensus.Util.Orphans ()
83-
import Ouroboros.Consensus.Util.ResourceRegistry (ResourceRegistry,
84-
allocateEither, unsafeRelease)
83+
import Ouroboros.Consensus.Util.ResourceRegistry (ResourceRegistry)
8584

8685
import Ouroboros.Storage.ChainDB.API (ChainDB)
8786
import Ouroboros.Storage.ChainDB.API hiding (ChainDB (..),
@@ -417,14 +416,10 @@ appendBlock db@ImmDB{..} b = withDB db $ \imm -> case isEBB (getHeader b) of
417416
Streaming
418417
-------------------------------------------------------------------------------}
419418

420-
-- | Wrapper around 'ImmDB.stream' that 'allocate's the iterator in the
421-
-- 'ResourceRegistry' so that 'ImmDB.iteratorClose' is registered as the
422-
-- clean-up action. Translates the requested 'BlockComponent' into the
423-
-- 'ImmDB.BlockComponent' the ImmutableDB understands.
424-
--
425-
-- When the returned iterator is closed, it will be 'release'd from the
426-
-- 'ResourceRegistry'.
427-
registeredStream
419+
-- | Wrapper around 'ImmDB.stream' that translates the requested
420+
-- 'BlockComponent' into the 'ImmDB.BlockComponent' the ImmutableDB
421+
-- understands.
422+
openIterator
428423
:: forall m blk b. (IOLike m, HasHeader blk)
429424
=> ImmDB m blk
430425
-> ResourceRegistry m
@@ -433,20 +428,8 @@ registeredStream
433428
-> Maybe (SlotNo, HeaderHash blk)
434429
-> m (Either (ImmDB.WrongBoundError (HeaderHash blk))
435430
(ImmDB.Iterator (HeaderHash blk) m b))
436-
registeredStream db registry blockComponent start end = do
437-
errOrKeyAndIt <- allocateEither registry
438-
(\_key -> withDB db $ \imm ->
439-
ImmDB.stream imm blockComponent' start end)
440-
(iteratorClose db)
441-
return $ case errOrKeyAndIt of
442-
Left e -> Left e
443-
-- The iterator will be used by a thread that is unknown to the registry
444-
-- (which, after all, is entirely internal to the chain DB). This means
445-
-- that the registry cannot guarantee that the iterator will be live for
446-
-- the duration of that thread, and indeed, it may not be: the chain DB
447-
-- might be closed before that thread terminates. We will deal with this
448-
-- in the chain DB itself (throw ClosedDBError exception).
449-
Right (key, it) -> Right it { ImmDB.iteratorClose = unsafeRelease key }
431+
openIterator db registry blockComponent start end =
432+
withDB db $ \imm -> ImmDB.stream imm registry blockComponent' start end
450433
where
451434
blockComponent' = translateToRawDB (parse db) (addHdrEnv db) blockComponent
452435

@@ -489,29 +472,29 @@ stream db registry blockComponent from to = runExceptT $ do
489472
case from of
490473
StreamFromExclusive pt@BlockPoint { atSlot = slot, withHash = hash } -> do
491474
when (pointSlot pt > slotNoAtTip) $ throwError $ MissingBlock pt
492-
it <- openRegisteredStream (Just (slot, hash)) end
475+
it <- openStream (Just (slot, hash)) end
493476
-- Skip the first block, as the bound is exclusive
494477
void $ lift $ iteratorNext db it
495478
return it
496479
StreamFromExclusive GenesisPoint ->
497-
openRegisteredStream Nothing end
480+
openStream Nothing end
498481
StreamFromInclusive pt@BlockPoint { atSlot = slot, withHash = hash } -> do
499482
when (pointSlot pt > slotNoAtTip) $ throwError $ MissingBlock pt
500-
openRegisteredStream (Just (slot, hash)) end
483+
openStream (Just (slot, hash)) end
501484
StreamFromInclusive GenesisPoint ->
502485
throwM NoGenesisBlock
503486
where
504-
openRegisteredStream
487+
openStream
505488
:: Maybe (SlotNo, HeaderHash blk)
506489
-> Maybe (SlotNo, HeaderHash blk)
507490
-> ExceptT (UnknownRange blk)
508491
m
509492
(ImmDB.Iterator (HeaderHash blk) m b)
510-
openRegisteredStream start end = ExceptT $
493+
openStream start end = ExceptT $
511494
bimap toUnknownRange (fmap snd . stopAt to) <$>
512495
-- 'stopAt' needs to know the hash of each streamed block, so we \"Get\"
513496
-- it in addition to @b@, but we drop it afterwards.
514-
registeredStream db registry ((,) <$> GetHash <*> blockComponent) start end
497+
openIterator db registry ((,) <$> GetHash <*> blockComponent) start end
515498
where
516499
toUnknownRange :: ImmDB.WrongBoundError (HeaderHash blk) -> UnknownRange blk
517500
toUnknownRange e
@@ -570,7 +553,7 @@ streamAfter
570553
(ImmDB.WrongBoundError (HeaderHash blk))
571554
(ImmDB.Iterator (HeaderHash blk) m b))
572555
streamAfter db registry blockComponent low =
573-
registeredStream db registry blockComponent low' Nothing >>= \case
556+
openIterator db registry blockComponent low' Nothing >>= \case
574557
Left err -> return $ Left err
575558
Right itr -> do
576559
case low of

ouroboros-consensus/src/Ouroboros/Storage/ImmutableDB/API.hs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import Data.ByteString.Builder (Builder)
2222
import GHC.Generics (Generic)
2323
import GHC.Stack (HasCallStack)
2424

25+
import Ouroboros.Consensus.Util.ResourceRegistry (ResourceRegistry)
26+
2527
import Ouroboros.Storage.Common
2628
import Ouroboros.Storage.ImmutableDB.Types
2729
import Ouroboros.Storage.Util.ErrorHandling (ErrorHandling)
@@ -197,7 +199,8 @@ data ImmutableDB hash m = ImmutableDB
197199
-- prematurely closed with 'iteratorClose'.
198200
, stream
199201
:: forall b. HasCallStack
200-
=> BlockComponent (ImmutableDB hash m) b
202+
=> ResourceRegistry m
203+
-> BlockComponent (ImmutableDB hash m) b
201204
-> Maybe (SlotNo, hash)
202205
-> Maybe (SlotNo, hash)
203206
-> m (Either (WrongBoundError hash)

0 commit comments

Comments
 (0)