Skip to content

Commit 3e105b5

Browse files
committed
Introduce a new BlobFile abstraction
Not yet used in this patch. Also move the BlobSpan defintion to this module.
1 parent d45f32c commit 3e105b5

File tree

3 files changed

+98
-11
lines changed

3 files changed

+98
-11
lines changed

lsm-tree.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ library
119119
Database.LSMTree.Internal
120120
Database.LSMTree.Internal.Assertions
121121
Database.LSMTree.Internal.BitMath
122+
Database.LSMTree.Internal.BlobFile
122123
Database.LSMTree.Internal.BlobRef
123124
Database.LSMTree.Internal.BloomFilter
124125
Database.LSMTree.Internal.BloomFilterQuery1
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
{-# LANGUAGE DeriveAnyClass #-}
2+
{-# LANGUAGE DeriveGeneric #-}
3+
{-# LANGUAGE DerivingStrategies #-}
4+
{- HLINT ignore "Use unless" -}
5+
6+
module Database.LSMTree.Internal.BlobFile (
7+
BlobFile (..)
8+
, BlobSpan (..)
9+
, removeReference
10+
, newBlobFile
11+
, readBlobFile
12+
) where
13+
14+
import Control.DeepSeq (NFData (..))
15+
import Control.Monad.Class.MonadThrow (MonadThrow, MonadMask)
16+
import Control.Monad.Primitive (PrimMonad)
17+
import Control.RefCount (RefCounter)
18+
import qualified Control.RefCount as RC
19+
import qualified Data.Primitive.ByteArray as P (newPinnedByteArray,
20+
unsafeFreezeByteArray)
21+
import Data.Word (Word32, Word64)
22+
import qualified Database.LSMTree.Internal.RawBytes as RB
23+
import Database.LSMTree.Internal.Serialise (SerialisedBlob (..))
24+
import qualified System.FS.API as FS
25+
import System.FS.API (HasFS)
26+
import qualified System.FS.BlockIO.API as FS
27+
28+
-- | An open handle to a file containing blobs.
29+
--
30+
-- This is a reference counted object. Upon finalisation, the file is closed
31+
-- and deleted.
32+
--
33+
data BlobFile m h = BlobFile {
34+
blobFileHandle :: {-# UNPACK #-} !(FS.Handle h),
35+
blobFileRefCounter :: {-# UNPACK #-} !(RefCounter m)
36+
}
37+
deriving stock (Show)
38+
39+
instance NFData h => NFData (BlobFile m h) where
40+
rnf (BlobFile a b) = rnf a `seq` rnf b
41+
42+
-- | The location of a blob inside a blob file.
43+
data BlobSpan = BlobSpan {
44+
blobSpanOffset :: {-# UNPACK #-} !Word64
45+
, blobSpanSize :: {-# UNPACK #-} !Word32
46+
}
47+
deriving stock (Show, Eq)
48+
49+
instance NFData BlobSpan where
50+
rnf (BlobSpan a b) = rnf a `seq` rnf b
51+
52+
removeReference ::
53+
(MonadMask m, PrimMonad m)
54+
=> BlobFile m h
55+
-> m ()
56+
removeReference BlobFile{blobFileRefCounter} =
57+
RC.removeReference blobFileRefCounter
58+
59+
-- | Adopt an existing open file handle to make a 'BlobFile'. The file must at
60+
-- least be open for reading (but may or may not be open for writing).
61+
--
62+
-- The finaliser will close and delete the file.
63+
--
64+
newBlobFile ::
65+
PrimMonad m
66+
=> HasFS m h
67+
-> FS.Handle h
68+
-> m (BlobFile m h)
69+
newBlobFile fs blobFileHandle = do
70+
let finaliser = do
71+
FS.hClose fs blobFileHandle
72+
FS.removeFile fs (FS.handlePath blobFileHandle)
73+
blobFileRefCounter <- RC.mkRefCounter1 (Just finaliser)
74+
return BlobFile {
75+
blobFileHandle,
76+
blobFileRefCounter
77+
}
78+
79+
{-# SPECIALISE readBlobFile :: HasFS IO h -> BlobFile IO h -> BlobSpan -> IO SerialisedBlob #-}
80+
readBlobFile ::
81+
(MonadThrow m, PrimMonad m)
82+
=> HasFS m h
83+
-> BlobFile m h
84+
-> BlobSpan
85+
-> m SerialisedBlob
86+
readBlobFile fs BlobFile {blobFileHandle}
87+
BlobSpan {blobSpanOffset, blobSpanSize} = do
88+
let off = FS.AbsOffset blobSpanOffset
89+
len :: Int
90+
len = fromIntegral blobSpanSize
91+
mba <- P.newPinnedByteArray len
92+
_ <- FS.hGetBufExactlyAt fs blobFileHandle mba 0
93+
(fromIntegral len :: FS.ByteCount) off
94+
ba <- P.unsafeFreezeByteArray mba
95+
let !rb = RB.fromByteArray 0 len ba
96+
return (SerialisedBlob rb)

src/Database/LSMTree/Internal/BlobRef.hs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import Data.Coerce (coerce)
3030
import qualified Data.Primitive.ByteArray as P (MutableByteArray,
3131
newPinnedByteArray, unsafeFreezeByteArray)
3232
import qualified Data.Vector as V
33-
import Data.Word (Word32, Word64)
33+
import Database.LSMTree.Internal.BlobFile (BlobSpan (..))
3434
import qualified Database.LSMTree.Internal.RawBytes as RB
3535
import Database.LSMTree.Internal.Serialise (SerialisedBlob (..))
3636
import qualified System.FS.API as FS
@@ -51,16 +51,6 @@ data BlobRef m h = BlobRef {
5151
instance NFData h => NFData (BlobRef m h) where
5252
rnf (BlobRef a b c) = rnf a `seq` rnf b `seq` rnf c
5353

54-
-- | Location of a blob inside a blob file.
55-
data BlobSpan = BlobSpan {
56-
blobSpanOffset :: {-# UNPACK #-} !Word64
57-
, blobSpanSize :: {-# UNPACK #-} !Word32
58-
}
59-
deriving stock (Show, Eq)
60-
61-
instance NFData BlobSpan where
62-
rnf (BlobSpan a b) = rnf a `seq` rnf b
63-
6454
blobRefSpanSize :: BlobRef m h -> Int
6555
blobRefSpanSize = fromIntegral . blobSpanSize . blobRefSpan
6656

0 commit comments

Comments
 (0)