{-# LANGUAGE TypeFamilies #-}
{-# OPTIONS_GHC -Wno-partial-fields #-}
{-# OPTIONS_HADDOCK not-home #-}
module Database.LSMTree.Internal.WriteBufferBlobs (
WriteBufferBlobs (..),
new,
open,
addBlob,
mkRawBlobRef,
mkWeakBlobRef,
FilePointer (..)
) where
import Control.DeepSeq (NFData (..))
import Control.Monad (void)
import Control.Monad.Class.MonadThrow
import Control.Monad.Primitive (PrimMonad, PrimState)
import Control.RefCount
import Data.Primitive.PrimVar as P
import Data.Word (Word64)
import Database.LSMTree.Internal.BlobFile
import qualified Database.LSMTree.Internal.BlobFile as BlobFile
import Database.LSMTree.Internal.BlobRef (RawBlobRef (..),
WeakBlobRef (..))
import Database.LSMTree.Internal.Serialise
import qualified System.FS.API as FS
import System.FS.API (HasFS)
data WriteBufferBlobs m h =
WriteBufferBlobs {
forall (m :: * -> *) h. WriteBufferBlobs m h -> Ref (BlobFile m h)
blobFile :: !(Ref (BlobFile m h))
, forall (m :: * -> *) h. WriteBufferBlobs m h -> FilePointer m
blobFilePointer :: !(FilePointer m)
, forall (m :: * -> *) h. WriteBufferBlobs m h -> RefCounter m
writeBufRefCounter :: !(RefCounter m)
}
instance NFData h => NFData (WriteBufferBlobs m h) where
rnf :: WriteBufferBlobs m h -> ()
rnf (WriteBufferBlobs Ref (BlobFile m h)
a FilePointer m
b RefCounter m
c) = Ref (BlobFile m h) -> ()
forall a. NFData a => a -> ()
rnf Ref (BlobFile m h)
a () -> () -> ()
forall a b. a -> b -> b
`seq` FilePointer m -> ()
forall a. NFData a => a -> ()
rnf FilePointer m
b () -> () -> ()
forall a b. a -> b -> b
`seq` RefCounter m -> ()
forall a. NFData a => a -> ()
rnf RefCounter m
c
instance RefCounted m (WriteBufferBlobs m h) where
getRefCounter :: WriteBufferBlobs m h -> RefCounter m
getRefCounter = WriteBufferBlobs m h -> RefCounter m
forall (m :: * -> *) h. WriteBufferBlobs m h -> RefCounter m
writeBufRefCounter
{-# SPECIALISE new :: HasFS IO h -> FS.FsPath -> IO (Ref (WriteBufferBlobs IO h)) #-}
new ::
(PrimMonad m, MonadMask m)
=> HasFS m h
-> FS.FsPath
-> m (Ref (WriteBufferBlobs m h))
new :: forall (m :: * -> *) h.
(PrimMonad m, MonadMask m) =>
HasFS m h -> FsPath -> m (Ref (WriteBufferBlobs m h))
new HasFS m h
fs FsPath
blobFileName = HasFS m h
-> FsPath -> AllowExisting -> m (Ref (WriteBufferBlobs m h))
forall (m :: * -> *) h.
(PrimMonad m, MonadMask m) =>
HasFS m h
-> FsPath -> AllowExisting -> m (Ref (WriteBufferBlobs m h))
open HasFS m h
fs FsPath
blobFileName AllowExisting
FS.MustBeNew
{-# SPECIALISE open :: HasFS IO h -> FS.FsPath -> FS.AllowExisting -> IO (Ref (WriteBufferBlobs IO h)) #-}
open ::
(PrimMonad m, MonadMask m)
=> HasFS m h
-> FS.FsPath
-> FS.AllowExisting
-> m (Ref (WriteBufferBlobs m h))
open :: forall (m :: * -> *) h.
(PrimMonad m, MonadMask m) =>
HasFS m h
-> FsPath -> AllowExisting -> m (Ref (WriteBufferBlobs m h))
open HasFS m h
fs FsPath
blobFileName AllowExisting
blobFileAllowExisting = do
m (Ref (BlobFile m h))
-> (Ref (BlobFile m h) -> m ())
-> (Ref (BlobFile m h) -> m (Ref (WriteBufferBlobs m h)))
-> m (Ref (WriteBufferBlobs m h))
forall a b c. m a -> (a -> m b) -> (a -> m c) -> m c
forall (m :: * -> *) a b c.
MonadCatch m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracketOnError
(HasFS m h -> FsPath -> OpenMode -> m (Ref (BlobFile m h))
forall (m :: * -> *) h.
(PrimMonad m, MonadCatch m, HasCallStack) =>
HasFS m h -> FsPath -> OpenMode -> m (Ref (BlobFile m h))
openBlobFile HasFS m h
fs FsPath
blobFileName (AllowExisting -> OpenMode
FS.ReadWriteMode AllowExisting
blobFileAllowExisting))
Ref (BlobFile m h) -> m ()
forall (m :: * -> *) obj.
(RefCounted m obj, PrimMonad m, MonadMask m, HasCallStack) =>
Ref obj -> m ()
releaseRef
(HasFS m h -> Ref (BlobFile m h) -> m (Ref (WriteBufferBlobs m h))
forall (m :: * -> *) h.
(PrimMonad m, MonadMask m) =>
HasFS m h -> Ref (BlobFile m h) -> m (Ref (WriteBufferBlobs m h))
fromBlobFile HasFS m h
fs)
{-# SPECIALISE fromBlobFile :: HasFS IO h -> Ref (BlobFile IO h) -> IO (Ref (WriteBufferBlobs IO h)) #-}
fromBlobFile ::
(PrimMonad m, MonadMask m)
=> HasFS m h
-> Ref (BlobFile m h)
-> m (Ref (WriteBufferBlobs m h))
fromBlobFile :: forall (m :: * -> *) h.
(PrimMonad m, MonadMask m) =>
HasFS m h -> Ref (BlobFile m h) -> m (Ref (WriteBufferBlobs m h))
fromBlobFile HasFS m h
fs Ref (BlobFile m h)
blobFile = do
FilePointer m
blobFilePointer <- m (FilePointer m)
forall (m :: * -> *). PrimMonad m => m (FilePointer m)
newFilePointer
Word64
blobFileSize <- Ref (BlobFile m h) -> (BlobFile m h -> m Word64) -> m Word64
forall (m :: * -> *) obj a.
(PrimMonad m, MonadThrow m, HasCallStack) =>
Ref obj -> (obj -> m a) -> m a
withRef Ref (BlobFile m h)
blobFile ((BlobFile m h -> m Word64) -> m Word64)
-> (BlobFile m h -> m Word64) -> m Word64
forall a b. (a -> b) -> a -> b
$ HasFS m h -> HasCallStack => Handle h -> m Word64
forall (m :: * -> *) h.
HasFS m h -> HasCallStack => Handle h -> m Word64
FS.hGetSize HasFS m h
fs (Handle h -> m Word64)
-> (BlobFile m h -> Handle h) -> BlobFile m h -> m Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. BlobFile m h -> Handle h
forall (m :: * -> *) h. BlobFile m h -> Handle h
blobFileHandle
m Word64 -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m Word64 -> m ()) -> (Word64 -> m Word64) -> Word64 -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. FilePointer m -> Int -> m Word64
forall (m :: * -> *).
PrimMonad m =>
FilePointer m -> Int -> m Word64
updateFilePointer FilePointer m
blobFilePointer (Int -> m Word64) -> (Word64 -> Int) -> Word64 -> m Word64
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Word64 -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64 -> m ()) -> Word64 -> m ()
forall a b. (a -> b) -> a -> b
$ Word64
blobFileSize
m ()
-> (RefCounter m -> WriteBufferBlobs m h)
-> m (Ref (WriteBufferBlobs m h))
forall (m :: * -> *) obj.
(RefCounted m obj, PrimMonad m, HasCallStack) =>
m () -> (RefCounter m -> obj) -> m (Ref obj)
newRef (Ref (BlobFile m h) -> m ()
forall (m :: * -> *) obj.
(RefCounted m obj, PrimMonad m, MonadMask m, HasCallStack) =>
Ref obj -> m ()
releaseRef Ref (BlobFile m h)
blobFile) ((RefCounter m -> WriteBufferBlobs m h)
-> m (Ref (WriteBufferBlobs m h)))
-> (RefCounter m -> WriteBufferBlobs m h)
-> m (Ref (WriteBufferBlobs m h))
forall a b. (a -> b) -> a -> b
$ \RefCounter m
writeBufRefCounter ->
WriteBufferBlobs {
Ref (BlobFile m h)
blobFile :: Ref (BlobFile m h)
blobFile :: Ref (BlobFile m h)
blobFile,
FilePointer m
blobFilePointer :: FilePointer m
blobFilePointer :: FilePointer m
blobFilePointer,
RefCounter m
writeBufRefCounter :: RefCounter m
writeBufRefCounter :: RefCounter m
writeBufRefCounter
}
{-# SPECIALISE addBlob :: HasFS IO h -> Ref (WriteBufferBlobs IO h) -> SerialisedBlob -> IO BlobSpan #-}
addBlob :: (PrimMonad m, MonadThrow m)
=> HasFS m h
-> Ref (WriteBufferBlobs m h)
-> SerialisedBlob
-> m BlobSpan
addBlob :: forall (m :: * -> *) h.
(PrimMonad m, MonadThrow m) =>
HasFS m h
-> Ref (WriteBufferBlobs m h) -> SerialisedBlob -> m BlobSpan
addBlob HasFS m h
fs (DeRef WriteBufferBlobs {Ref (BlobFile m h)
blobFile :: forall (m :: * -> *) h. WriteBufferBlobs m h -> Ref (BlobFile m h)
blobFile :: Ref (BlobFile m h)
blobFile, FilePointer m
blobFilePointer :: forall (m :: * -> *) h. WriteBufferBlobs m h -> FilePointer m
blobFilePointer :: FilePointer m
blobFilePointer}) SerialisedBlob
blob = do
let blobsize :: Int
blobsize = SerialisedBlob -> Int
sizeofBlob SerialisedBlob
blob
Word64
bloboffset <- FilePointer m -> Int -> m Word64
forall (m :: * -> *).
PrimMonad m =>
FilePointer m -> Int -> m Word64
updateFilePointer FilePointer m
blobFilePointer Int
blobsize
HasFS m h -> Ref (BlobFile m h) -> SerialisedBlob -> Word64 -> m ()
forall (m :: * -> *) h.
(MonadThrow m, PrimMonad m) =>
HasFS m h -> Ref (BlobFile m h) -> SerialisedBlob -> Word64 -> m ()
BlobFile.writeBlob HasFS m h
fs Ref (BlobFile m h)
blobFile SerialisedBlob
blob Word64
bloboffset
BlobSpan -> m BlobSpan
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return BlobSpan {
blobSpanOffset :: Word64
blobSpanOffset = Word64
bloboffset,
blobSpanSize :: Word32
blobSpanSize = Int -> Word32
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
blobsize
}
mkRawBlobRef :: Ref (WriteBufferBlobs m h)
-> BlobSpan
-> RawBlobRef m h
mkRawBlobRef :: forall (m :: * -> *) h.
Ref (WriteBufferBlobs m h) -> BlobSpan -> RawBlobRef m h
mkRawBlobRef (DeRef WriteBufferBlobs {blobFile :: forall (m :: * -> *) h. WriteBufferBlobs m h -> Ref (BlobFile m h)
blobFile = DeRef BlobFile m h
blobfile}) BlobSpan
blobspan =
RawBlobRef {
rawBlobRefFile :: BlobFile m h
rawBlobRefFile = BlobFile m h
blobfile,
rawBlobRefSpan :: BlobSpan
rawBlobRefSpan = BlobSpan
blobspan
}
mkWeakBlobRef :: Ref (WriteBufferBlobs m h)
-> BlobSpan
-> WeakBlobRef m h
mkWeakBlobRef :: forall (m :: * -> *) h.
Ref (WriteBufferBlobs m h) -> BlobSpan -> WeakBlobRef m h
mkWeakBlobRef (DeRef WriteBufferBlobs {Ref (BlobFile m h)
blobFile :: forall (m :: * -> *) h. WriteBufferBlobs m h -> Ref (BlobFile m h)
blobFile :: Ref (BlobFile m h)
blobFile}) BlobSpan
blobspan =
WeakBlobRef {
weakBlobRefFile :: WeakRef (BlobFile m h)
weakBlobRefFile = Ref (BlobFile m h) -> WeakRef (BlobFile m h)
forall obj. Ref obj -> WeakRef obj
mkWeakRef Ref (BlobFile m h)
blobFile,
weakBlobRefSpan :: BlobSpan
weakBlobRefSpan = BlobSpan
blobspan
}
newtype FilePointer m = FilePointer (PrimVar (PrimState m) Int)
instance NFData (FilePointer m) where
rnf :: FilePointer m -> ()
rnf (FilePointer PrimVar (PrimState m) Int
var) = PrimVar (PrimState m) Int
var PrimVar (PrimState m) Int -> () -> ()
forall a b. a -> b -> b
`seq` ()
{-# SPECIALISE newFilePointer :: IO (FilePointer IO) #-}
newFilePointer :: PrimMonad m => m (FilePointer m)
newFilePointer :: forall (m :: * -> *). PrimMonad m => m (FilePointer m)
newFilePointer = PrimVar (PrimState m) Int -> FilePointer m
forall (m :: * -> *). PrimVar (PrimState m) Int -> FilePointer m
FilePointer (PrimVar (PrimState m) Int -> FilePointer m)
-> m (PrimVar (PrimState m) Int) -> m (FilePointer m)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Int -> m (PrimVar (PrimState m) Int)
forall (m :: * -> *) a.
(PrimMonad m, Prim a) =>
a -> m (PrimVar (PrimState m) a)
P.newPrimVar Int
0
{-# SPECIALISE updateFilePointer :: FilePointer IO -> Int -> IO Word64 #-}
updateFilePointer :: PrimMonad m => FilePointer m -> Int -> m Word64
updateFilePointer :: forall (m :: * -> *).
PrimMonad m =>
FilePointer m -> Int -> m Word64
updateFilePointer (FilePointer PrimVar (PrimState m) Int
var) Int
n = Int -> Word64
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int -> Word64) -> m Int -> m Word64
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> PrimVar (PrimState m) Int -> Int -> m Int
forall (m :: * -> *).
PrimMonad m =>
PrimVar (PrimState m) Int -> Int -> m Int
P.fetchAddInt PrimVar (PrimState m) Int
var Int
n