@@ -13,8 +13,10 @@ module Database.LSMTree.Internal.BlobRef (
1313 , deRefWeakBlobRef
1414 , deRefWeakBlobRefs
1515 , WeakBlobRefInvalid (.. )
16+ , rawToWeakBlobRef
1617 , removeReference
1718 , removeReferences
19+ , readRawBlobRef
1820 , readBlob
1921 , readBlobIOOp
2022 ) where
@@ -25,9 +27,9 @@ import Control.Monad.Class.MonadThrow (Exception, MonadMask,
2527 MonadThrow (.. ), bracket , throwIO )
2628import Control.Monad.Primitive
2729import qualified Control.RefCount as RC
28- import Data.Coerce (coerce )
2930import qualified Data.Primitive.ByteArray as P (MutableByteArray )
3031import qualified Data.Vector as V
32+ import qualified Data.Vector.Mutable as VM
3133import Database.LSMTree.Internal.BlobFile (BlobFile (.. ), BlobSpan (.. ))
3234import qualified Database.LSMTree.Internal.BlobFile as BlobFile
3335import Database.LSMTree.Internal.Serialise (SerialisedBlob (.. ))
@@ -54,8 +56,8 @@ data RawBlobRef m h = RawBlobRef {
5456instance NFData h => NFData (RawBlobRef m h ) where
5557 rnf (RawBlobRef a b) = rnf a `seq` rnf b
5658
57- blobRefSpanSize :: RawBlobRef m h -> Int
58- blobRefSpanSize = fromIntegral . blobSpanSize . rawBlobRefSpan
59+ blobRefSpanSize :: StrongBlobRef m h -> Int
60+ blobRefSpanSize = fromIntegral . blobSpanSize . strongBlobRefSpan
5961
6062-- | A \"weak\" reference to a blob within a blob file. These are the ones we
6163-- can return in the public API and can outlive their parent table.
@@ -67,8 +69,33 @@ blobRefSpanSize = fromIntegral . blobSpanSize . rawBlobRefSpan
6769--
6870-- See 'Database.LSMTree.Common.BlobRef' for more info.
6971--
70- newtype WeakBlobRef m h = WeakBlobRef (RawBlobRef m h )
71- deriving newtype (Show , NFData )
72+ data WeakBlobRef m h = WeakBlobRef {
73+ weakBlobRefFile :: {-# NOUNPACK #-} ! (BlobFile m h )
74+ , weakBlobRefSpan :: {-# UNPACK #-} ! BlobSpan
75+ }
76+ deriving stock (Show )
77+
78+ -- | A \"strong\" reference to a blob within a blob file. The blob file remains
79+ -- open while the strong reference is live. Thus it is safe to do I\/O to
80+ -- retrieve the blob based on the reference. Strong references must be released
81+ -- using 'releaseBlobRef' when no longer in use (e.g. after completing I\/O).
82+ --
83+ data StrongBlobRef m h = StrongBlobRef {
84+ strongBlobRefFile :: {-# NOUNPACK #-} ! (BlobFile m h )
85+ , strongBlobRefSpan :: {-# UNPACK #-} ! BlobSpan
86+ }
87+ deriving stock (Show )
88+
89+ -- | Convert a 'RawBlobRef' to a 'WeakBlobRef'.
90+ rawToWeakBlobRef :: RawBlobRef m h -> WeakBlobRef m h
91+ rawToWeakBlobRef RawBlobRef {rawBlobRefFile, rawBlobRefSpan} =
92+ -- This doesn't need to really do anything, becuase the raw version
93+ -- does not maintain an independent ref count, and the weak one does
94+ -- not either.
95+ WeakBlobRef {
96+ weakBlobRefFile = rawBlobRefFile,
97+ weakBlobRefSpan = rawBlobRefSpan
98+ }
7299
73100-- | The 'WeakBlobRef' now points to a blob that is no longer available.
74101newtype WeakBlobRefInvalid = WeakBlobRefInvalid Int
@@ -77,7 +104,7 @@ newtype WeakBlobRefInvalid = WeakBlobRefInvalid Int
77104
78105{-# SPECIALISE withWeakBlobRef ::
79106 WeakBlobRef IO h
80- -> (RawBlobRef IO h -> IO a)
107+ -> (StrongBlobRef IO h -> IO a)
81108 -> IO a #-}
82109-- | 'WeakBlobRef's are weak references. They do not keep the blob file open.
83110-- Dereference a 'WeakBlobRef' to a strong 'BlobRef' to allow I\/O using
@@ -89,82 +116,98 @@ newtype WeakBlobRefInvalid = WeakBlobRefInvalid Int
89116withWeakBlobRef ::
90117 (MonadMask m , PrimMonad m )
91118 => WeakBlobRef m h
92- -> (RawBlobRef m h -> m a )
119+ -> (StrongBlobRef m h -> m a )
93120 -> m a
94121withWeakBlobRef wref = bracket (deRefWeakBlobRef wref) removeReference
95122
96123{-# SPECIALISE withWeakBlobRefs ::
97124 V.Vector (WeakBlobRef IO h)
98- -> (V.Vector (RawBlobRef IO h) -> IO a)
125+ -> (V.Vector (StrongBlobRef IO h) -> IO a)
99126 -> IO a #-}
100127-- | The same as 'withWeakBlobRef' but for many references in one go.
101128--
102129withWeakBlobRefs ::
103130 (MonadMask m , PrimMonad m )
104131 => V. Vector (WeakBlobRef m h )
105- -> (V. Vector (RawBlobRef m h ) -> m a )
132+ -> (V. Vector (StrongBlobRef m h ) -> m a )
106133 -> m a
107134withWeakBlobRefs wrefs = bracket (deRefWeakBlobRefs wrefs) removeReferences
108135
109136{-# SPECIALISE deRefWeakBlobRef ::
110137 WeakBlobRef IO h
111- -> IO (RawBlobRef IO h) #-}
138+ -> IO (StrongBlobRef IO h) #-}
112139deRefWeakBlobRef ::
113140 (MonadThrow m , PrimMonad m )
114141 => WeakBlobRef m h
115- -> m (RawBlobRef m h )
116- deRefWeakBlobRef ( WeakBlobRef ref) = do
117- ok <- RC. upgradeWeakReference (blobFileRefCounter (rawBlobRefFile ref) )
142+ -> m (StrongBlobRef m h )
143+ deRefWeakBlobRef WeakBlobRef {weakBlobRefFile, weakBlobRefSpan} = do
144+ ok <- RC. upgradeWeakReference (blobFileRefCounter weakBlobRefFile )
118145 when (not ok) $ throwIO (WeakBlobRefInvalid 0 )
119- pure ref
146+ return StrongBlobRef {
147+ strongBlobRefFile = weakBlobRefFile,
148+ strongBlobRefSpan = weakBlobRefSpan
149+ }
120150
121151{-# SPECIALISE deRefWeakBlobRefs ::
122152 V.Vector (WeakBlobRef IO h)
123- -> IO (V.Vector (RawBlobRef IO h)) #-}
153+ -> IO (V.Vector (StrongBlobRef IO h)) #-}
124154deRefWeakBlobRefs ::
125155 forall m h .
126156 (MonadMask m , PrimMonad m )
127157 => V. Vector (WeakBlobRef m h )
128- -> m (V. Vector (RawBlobRef m h ))
158+ -> m (V. Vector (StrongBlobRef m h ))
129159deRefWeakBlobRefs wrefs = do
130- let refs :: V. Vector (RawBlobRef m h )
131- refs = coerce wrefs -- safely coerce away the newtype wrappers
132- V. iforM_ wrefs $ \ i (WeakBlobRef ref) -> do
133- ok <- RC. upgradeWeakReference (blobFileRefCounter (rawBlobRefFile ref))
134- when (not ok) $ do
135- -- drop refs on the previous ones taken successfully so far
136- V. mapM_ removeReference (V. take i refs)
137- throwIO (WeakBlobRefInvalid i)
138- pure refs
139-
140- {-# SPECIALISE removeReference :: RawBlobRef IO h -> IO () #-}
141- removeReference :: (MonadMask m , PrimMonad m ) => RawBlobRef m h -> m ()
142- removeReference = BlobFile. removeReference . rawBlobRefFile
143-
144- {-# SPECIALISE removeReferences :: V.Vector (RawBlobRef IO h) -> IO () #-}
145- removeReferences :: (MonadMask m , PrimMonad m ) => V. Vector (RawBlobRef m h ) -> m ()
160+ refs <- VM. new (V. length wrefs)
161+ V. iforM_ wrefs $ \ i WeakBlobRef {weakBlobRefFile, weakBlobRefSpan} -> do
162+ ok <- RC. upgradeWeakReference (blobFileRefCounter weakBlobRefFile)
163+ if ok
164+ then VM. write refs i StrongBlobRef {
165+ strongBlobRefFile = weakBlobRefFile,
166+ strongBlobRefSpan = weakBlobRefSpan
167+ }
168+ else do
169+ -- drop refs on the previous ones taken successfully so far
170+ VM. mapM_ removeReference (VM. take i refs)
171+ throwIO (WeakBlobRefInvalid i)
172+ V. unsafeFreeze refs
173+
174+ {-# SPECIALISE removeReference :: StrongBlobRef IO h -> IO () #-}
175+ removeReference :: (MonadMask m , PrimMonad m ) => StrongBlobRef m h -> m ()
176+ removeReference = BlobFile. removeReference . strongBlobRefFile
177+
178+ {-# SPECIALISE removeReferences :: V.Vector (StrongBlobRef IO h) -> IO () #-}
179+ removeReferences :: (MonadMask m , PrimMonad m ) => V. Vector (StrongBlobRef m h ) -> m ()
146180removeReferences = V. mapM_ removeReference
147181
182+ {-# INLINE readRawBlobRef #-}
183+ readRawBlobRef ::
184+ (MonadThrow m , PrimMonad m )
185+ => HasFS m h
186+ -> RawBlobRef m h
187+ -> m SerialisedBlob
188+ readRawBlobRef fs RawBlobRef {rawBlobRefFile, rawBlobRefSpan} =
189+ BlobFile. readBlobFile fs rawBlobRefFile rawBlobRefSpan
190+
148191{-# SPECIALISE readBlob ::
149192 HasFS IO h
150- -> RawBlobRef IO h
193+ -> StrongBlobRef IO h
151194 -> IO SerialisedBlob #-}
152195readBlob ::
153196 (MonadThrow m , PrimMonad m )
154197 => HasFS m h
155- -> RawBlobRef m h
198+ -> StrongBlobRef m h
156199 -> m SerialisedBlob
157- readBlob fs RawBlobRef {rawBlobRefFile, rawBlobRefSpan } =
158- BlobFile. readBlobFile fs rawBlobRefFile rawBlobRefSpan
200+ readBlob fs StrongBlobRef {strongBlobRefFile, strongBlobRefSpan } =
201+ BlobFile. readBlobFile fs strongBlobRefFile strongBlobRefSpan
159202
160203readBlobIOOp ::
161204 P. MutableByteArray s -> Int
162- -> RawBlobRef m h
205+ -> StrongBlobRef m h
163206 -> FS. IOOp s h
164207readBlobIOOp buf bufoff
165- RawBlobRef {
166- rawBlobRefFile = BlobFile {blobFileHandle},
167- rawBlobRefSpan = BlobSpan {blobSpanOffset, blobSpanSize}
208+ StrongBlobRef {
209+ strongBlobRefFile = BlobFile {blobFileHandle},
210+ strongBlobRefSpan = BlobSpan {blobSpanOffset, blobSpanSize}
168211 } =
169212 FS. IOOpRead
170213 blobFileHandle
0 commit comments