-
Notifications
You must be signed in to change notification settings - Fork 9
Move ChecksumHandle and its methods into their own module
#472
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,247 @@ | ||
| module Database.LSMTree.Internal.ChecksumHandle | ||
| ( | ||
| -- * Checksum handles | ||
| -- $checksum-handles | ||
| ChecksumHandle (..), | ||
| makeHandle, | ||
| readChecksum, | ||
| dropCache, | ||
| closeHandle, | ||
| writeToHandle, | ||
| -- * Specialised writers | ||
| writeRawPage, | ||
| writeRawOverflowPages, | ||
| writeBlob, | ||
| copyBlob, | ||
| writeFilter, | ||
| writeIndexHeader, | ||
| writeIndexChunk, | ||
| writeIndexFinal, | ||
| ) where | ||
|
|
||
| import Control.Monad.Class.MonadSTM (MonadSTM (..)) | ||
| import Control.Monad.Class.MonadThrow (MonadThrow) | ||
| import Control.Monad.Primitive | ||
| import Data.BloomFilter (Bloom) | ||
| import qualified Data.ByteString.Lazy as BSL | ||
| import Data.Primitive.PrimVar | ||
| import Data.Word (Word64) | ||
| import Database.LSMTree.Internal.BlobRef (BlobSpan (..), RawBlobRef) | ||
| import qualified Database.LSMTree.Internal.BlobRef as BlobRef | ||
| import Database.LSMTree.Internal.BloomFilter (bloomFilterToLBS) | ||
| import Database.LSMTree.Internal.Chunk (Chunk) | ||
| import qualified Database.LSMTree.Internal.Chunk as Chunk (toByteString) | ||
| import Database.LSMTree.Internal.CRC32C (CRC32C) | ||
| import qualified Database.LSMTree.Internal.CRC32C as CRC | ||
| import Database.LSMTree.Internal.Entry | ||
| import Database.LSMTree.Internal.IndexCompact (IndexCompact) | ||
| import qualified Database.LSMTree.Internal.IndexCompact as Index | ||
| import Database.LSMTree.Internal.Paths (ForBlob (..), ForFilter (..), | ||
| ForIndex (..), ForKOps (..)) | ||
| import qualified Database.LSMTree.Internal.RawBytes as RB | ||
| import Database.LSMTree.Internal.RawOverflowPage (RawOverflowPage) | ||
| import qualified Database.LSMTree.Internal.RawOverflowPage as RawOverflowPage | ||
| import Database.LSMTree.Internal.RawPage (RawPage) | ||
| import qualified Database.LSMTree.Internal.RawPage as RawPage | ||
| import Database.LSMTree.Internal.Serialise | ||
| import qualified System.FS.API as FS | ||
| import System.FS.API | ||
| import qualified System.FS.BlockIO.API as FS | ||
| import System.FS.BlockIO.API (HasBlockIO) | ||
|
|
||
| {------------------------------------------------------------------------------- | ||
| ChecksumHandle | ||
| -------------------------------------------------------------------------------} | ||
|
|
||
| {- $checksum-handles | ||
| A handle ('ChecksumHandle') that maintains a running CRC32 checksum. | ||
| -} | ||
|
|
||
| -- | Tracks the checksum of a (write mode) file handle. | ||
| data ChecksumHandle s h = ChecksumHandle !(FS.Handle h) !(PrimVar s CRC32C) | ||
|
|
||
| {-# SPECIALISE makeHandle :: | ||
| HasFS IO h | ||
| -> FS.FsPath | ||
| -> IO (ChecksumHandle RealWorld h) #-} | ||
| makeHandle :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> FS.FsPath | ||
| -> m (ChecksumHandle (PrimState m) h) | ||
| makeHandle fs path = | ||
| ChecksumHandle | ||
| <$> FS.hOpen fs path (FS.WriteMode FS.MustBeNew) | ||
| <*> newPrimVar CRC.initialCRC32C | ||
|
|
||
| {-# SPECIALISE readChecksum :: | ||
| ChecksumHandle RealWorld h | ||
| -> IO CRC32C #-} | ||
| readChecksum :: | ||
| PrimMonad m | ||
| => ChecksumHandle (PrimState m) h | ||
| -> m CRC32C | ||
| readChecksum (ChecksumHandle _h checksum) = readPrimVar checksum | ||
|
|
||
| dropCache :: HasBlockIO m h -> ChecksumHandle (PrimState m) h -> m () | ||
| dropCache hbio (ChecksumHandle h _) = FS.hDropCacheAll hbio h | ||
|
|
||
| closeHandle :: HasFS m h -> ChecksumHandle (PrimState m) h -> m () | ||
| closeHandle fs (ChecksumHandle h _checksum) = FS.hClose fs h | ||
|
|
||
| {-# SPECIALISE writeToHandle :: | ||
| HasFS IO h | ||
| -> ChecksumHandle RealWorld h | ||
| -> BSL.ByteString | ||
| -> IO () #-} | ||
| writeToHandle :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ChecksumHandle (PrimState m) h | ||
| -> BSL.ByteString | ||
| -> m () | ||
| writeToHandle fs (ChecksumHandle h checksum) lbs = do | ||
| crc <- readPrimVar checksum | ||
| (_, crc') <- CRC.hPutAllChunksCRC32C fs h lbs crc | ||
| writePrimVar checksum crc' | ||
|
|
||
| {------------------------------------------------------------------------------- | ||
| Specialised Writers for ChecksumHandle | ||
| -------------------------------------------------------------------------------} | ||
|
|
||
| {-# SPECIALISE writeRawPage :: | ||
| HasFS IO h | ||
| -> ForKOps (ChecksumHandle RealWorld h) | ||
| -> RawPage | ||
| -> IO () #-} | ||
| writeRawPage :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ForKOps (ChecksumHandle (PrimState m) h) | ||
| -> RawPage | ||
| -> m () | ||
| writeRawPage hfs kOpsHandle = | ||
| writeToHandle hfs (unForKOps kOpsHandle) | ||
| . BSL.fromStrict | ||
| . RB.unsafePinnedToByteString -- 'RawPage' is guaranteed to be pinned | ||
| . RawPage.rawPageRawBytes | ||
|
|
||
| {-# SPECIALISE writeRawOverflowPages :: | ||
| HasFS IO h | ||
| -> ForKOps (ChecksumHandle RealWorld h) | ||
| -> [RawOverflowPage] | ||
| -> IO () #-} | ||
| writeRawOverflowPages :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ForKOps (ChecksumHandle (PrimState m) h) | ||
| -> [RawOverflowPage] | ||
| -> m () | ||
| writeRawOverflowPages hfs kOpsHandle = | ||
| writeToHandle hfs (unForKOps kOpsHandle) | ||
| . BSL.fromChunks | ||
| . map (RawOverflowPage.rawOverflowPageToByteString) | ||
|
|
||
| {-# SPECIALISE writeBlob :: | ||
| HasFS IO h | ||
| -> PrimVar RealWorld Word64 | ||
| -> ForBlob (ChecksumHandle RealWorld h) | ||
| -> SerialisedBlob | ||
| -> IO BlobSpan #-} | ||
| writeBlob :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> PrimVar (PrimState m) Word64 | ||
| -> ForBlob (ChecksumHandle (PrimState m) h) | ||
| -> SerialisedBlob | ||
| -> m BlobSpan | ||
| writeBlob hfs blobOffset blobHandle blob = do | ||
| -- NOTE: This is different from BlobFile.writeBlob. This is because BlobFile | ||
| -- internalises a regular Handle, rather than a ChecksumHandle. These two | ||
| -- functions cannot be easily unified, because BlobFile.writeBlob permits | ||
| -- writing blobs to arbitrary positions in the blob file, whereas, by the | ||
| -- very nature of CRC32 checksums, ChecksumHandle.writeBlob only supports | ||
| -- sequential writes. | ||
| let size = sizeofBlob64 blob | ||
| offset <- readPrimVar blobOffset | ||
| modifyPrimVar blobOffset (+size) | ||
| let SerialisedBlob rb = blob | ||
| let lbs = BSL.fromStrict $ RB.toByteString rb | ||
| writeToHandle hfs (unForBlob blobHandle) lbs | ||
| return (BlobSpan offset (fromIntegral size)) | ||
|
|
||
| {-# SPECIALISE copyBlob :: | ||
| HasFS IO h | ||
| -> PrimVar RealWorld Word64 | ||
| -> ForBlob (ChecksumHandle RealWorld h) | ||
| -> RawBlobRef IO h | ||
| -> IO BlobSpan #-} | ||
| copyBlob :: | ||
| (MonadSTM m, MonadThrow m, PrimMonad m) | ||
| => HasFS m h | ||
| -> PrimVar (PrimState m) Word64 | ||
| -> ForBlob (ChecksumHandle (PrimState m) h) | ||
| -> RawBlobRef m h | ||
| -> m BlobSpan | ||
| copyBlob hfs blobOffset blobHandle blobref = do | ||
| blob <- BlobRef.readRawBlobRef hfs blobref | ||
| writeBlob hfs blobOffset blobHandle blob | ||
|
|
||
| {-# SPECIALISE writeFilter :: | ||
| HasFS IO h | ||
| -> ForFilter (ChecksumHandle RealWorld h) | ||
| -> Bloom SerialisedKey | ||
| -> IO () #-} | ||
| writeFilter :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ForFilter (ChecksumHandle (PrimState m) h) | ||
| -> Bloom SerialisedKey | ||
| -> m () | ||
| writeFilter hfs filterHandle bf = | ||
| writeToHandle hfs (unForFilter filterHandle) (bloomFilterToLBS bf) | ||
|
|
||
| {-# SPECIALISE writeIndexHeader :: | ||
| HasFS IO h | ||
| -> ForIndex (ChecksumHandle RealWorld h) | ||
| -> IO () #-} | ||
| writeIndexHeader :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ForIndex (ChecksumHandle (PrimState m) h) | ||
| -> m () | ||
| writeIndexHeader hfs indexHandle = | ||
| writeToHandle hfs (unForIndex indexHandle) $ | ||
| Index.headerLBS | ||
|
|
||
| {-# SPECIALISE writeIndexChunk :: | ||
| HasFS IO h | ||
| -> ForIndex (ChecksumHandle RealWorld h) | ||
| -> Chunk | ||
| -> IO () #-} | ||
| writeIndexChunk :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ForIndex (ChecksumHandle (PrimState m) h) | ||
| -> Chunk | ||
| -> m () | ||
| writeIndexChunk hfs indexHandle chunk = | ||
| writeToHandle hfs (unForIndex indexHandle) $ | ||
| BSL.fromStrict $ Chunk.toByteString chunk | ||
|
|
||
| {-# SPECIALISE writeIndexFinal :: | ||
| HasFS IO h | ||
| -> ForIndex (ChecksumHandle RealWorld h) | ||
| -> NumEntries | ||
| -> IndexCompact | ||
| -> IO () #-} | ||
| writeIndexFinal :: | ||
| (MonadSTM m, PrimMonad m) | ||
| => HasFS m h | ||
| -> ForIndex (ChecksumHandle (PrimState m) h) | ||
| -> NumEntries | ||
| -> IndexCompact | ||
| -> m () | ||
| writeIndexFinal hfs indexHandle numEntries index = | ||
| writeToHandle hfs (unForIndex indexHandle) $ | ||
| Index.finalLBS numEntries index | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where functions like
writeRawPagewould previously select the correct handle from theRunBuildersuch asforRunKOps runBuilderHandles, the newnewRawPagecould in theory be passed anyChecksumHandle. It's probably not a problem in practice, as the tests would catch incorrect usage. Still, if you think it's a good idea we could introduce some type safety by adding some newtypes, such asnewtype KOpsHandle s h = KOpsHandle (ChecksumHandle s h)Thinking along those same lines,
writeBlobandcopyBlobare currently passed a variable holding the offset into the file: this could also be a bogus variable with no connection to the blob file. Maybe for the blob handle, we can introducedata BlobHandle s h = BlobHandle !(PrimVar s Word64) !(ChecksumHandle s h)instead of a newtype around just theChecksumHandlepartThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be useful. I took them out of the wrapper because otherwise I'd need additional handles for two nonexistent files. Wrapping them up individually would indeed solve that. Would you like me to implement that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can implement it, or leave a TODO, what you prefer