Skip to content

Commit 642aff3

Browse files
committed
FEAT
1 parent b55a199 commit 642aff3

File tree

6 files changed

+41
-14
lines changed

6 files changed

+41
-14
lines changed

src/Database/LSMTree/Internal/BloomFilter.hs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import qualified Data.Primitive as P
2828
import qualified Data.Vector as V
2929
import qualified Data.Vector.Primitive as VP
3030
import Data.Word (Word32, Word64, byteSwap32)
31+
import Text.Printf (printf)
3132

3233
import Control.Exception (assert)
3334
import Control.Monad (void, when)
@@ -242,23 +243,25 @@ bloomFilterToLBS bf =
242243

243244
{-# SPECIALISE bloomFilterFromFile ::
244245
HasFS IO h
246+
-> Bloom.Salt
245247
-> Handle h
246248
-> IO (Bloom a) #-}
247249
-- | Read a 'Bloom' from a file.
248250
--
249251
bloomFilterFromFile ::
250252
(PrimMonad m, MonadCatch m)
251253
=> HasFS m h
254+
-> Bloom.Salt -- ^ Expected salt
252255
-> Handle h -- ^ The open file, in read mode
253256
-> m (Bloom a)
254-
bloomFilterFromFile hfs h = do
257+
bloomFilterFromFile hfs expectedSalt h = do
255258
header <- rethrowEOFError "Doesn't contain a header" $
256259
hGetByteArrayExactly hfs h 24
257260

258261
let !version = P.indexByteArray header 0 :: Word32
259262
!nhashes = P.indexByteArray header 1 :: Word32
260263
!nbits = P.indexByteArray header 1 :: Word64
261-
!salt = P.indexByteArray header 2 :: Word64
264+
!salt = P.indexByteArray header 2 :: Bloom.Salt
262265

263266
when (version /= bloomFilterVersion) $ throwFormatError $
264267
if byteSwap32 version == bloomFilterVersion
@@ -268,8 +271,12 @@ bloomFilterFromFile hfs h = do
268271
when (nbits <= 0) $ throwFormatError "Length is zero"
269272

270273
-- limit to 2^48 bits
271-
when (nbits >= 0x1_0000_0000_0000) $ throwFormatError "Too large bloomfilter"
272-
--TODO: get max size from bloomfilter lib
274+
when (nbits >= fromIntegral Bloom.maxSizeBits) $ throwFormatError "Too large bloomfilter"
275+
276+
when (expectedSalt /= salt) $ throwFormatError $
277+
printf "Expected salt does not match actual salt: %d /= %d"
278+
expectedSalt
279+
salt
273280

274281
-- read the filter data from the file directly into the bloom filter
275282
bloom <-

src/Database/LSMTree/Internal/Run.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import Control.Monad.Class.MonadSTM (MonadSTM (..))
3636
import Control.Monad.Class.MonadThrow
3737
import Control.Monad.Primitive
3838
import Control.RefCount
39+
import qualified Data.BloomFilter.Hash as Bloom
3940
import qualified Data.ByteString.Short as SBS
4041
import Data.Foldable (for_)
4142
import Database.LSMTree.Internal.BlobFile
@@ -268,6 +269,7 @@ fromWriteBuffer fs hbio sessionSalt params fsPaths buffer blobs = do
268269
-> HasBlockIO IO h
269270
-> RunDataCaching
270271
-> IndexType
272+
-> Bloom.Salt
271273
-> RunFsPaths
272274
-> IO (Ref (Run IO h)) #-}
273275
-- | Load a previously written run from disk, checking each file's checksum
@@ -293,10 +295,11 @@ openFromDisk ::
293295
-> HasBlockIO m h
294296
-> RunDataCaching
295297
-> IndexType
298+
-> Bloom.Salt -- ^ Expected salt
296299
-> RunFsPaths
297300
-> m (Ref (Run m h))
298301
-- TODO: make exception safe
299-
openFromDisk fs hbio runRunDataCaching indexType runRunFsPaths = do
302+
openFromDisk fs hbio runRunDataCaching indexType expectedSalt runRunFsPaths = do
300303
expectedChecksums <-
301304
CRC.expectValidFile fs (runChecksumsPath runRunFsPaths) CRC.FormatChecksumsFile
302305
. fromChecksumsFile
@@ -311,7 +314,7 @@ openFromDisk fs hbio runRunDataCaching indexType runRunFsPaths = do
311314
let filterPath = forRunFilterRaw paths
312315
checkCRC CacheRunData (forRunFilterRaw expectedChecksums) filterPath
313316
runFilter <- FS.withFile fs filterPath FS.ReadMode $
314-
bloomFilterFromFile fs
317+
bloomFilterFromFile fs expectedSalt
315318

316319
(runNumEntries, runIndex) <-
317320
CRC.expectValidFile fs (forRunIndexRaw paths) CRC.FormatIndexFile

src/Database/LSMTree/Internal/Snapshot.hs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ import Control.Monad.Class.MonadThrow (MonadMask, bracket,
4444
bracketOnError)
4545
import Control.Monad.Primitive (PrimMonad)
4646
import Control.RefCount
47+
import qualified Data.BloomFilter.Hash as Bloom
4748
import Data.Foldable (sequenceA_, traverse_)
4849
import Data.String (IsString)
4950
import Data.Text (Text)
@@ -585,9 +586,10 @@ snapshotRun hfs hbio snapUc reg (NamedSnapshotDir targetDir) run = do
585586
-> ActionRegistry IO
586587
-> NamedSnapshotDir
587588
-> ActiveDir
589+
-> Bloom.Salt
588590
-> SnapshotRun
589591
-> IO (Ref (Run IO h)) #-}
590-
-- | @'openRun' _ _ uniqCounter _ sourceDir targetDir snaprun@ takes all run
592+
-- | @'openRun' _ _ uniqCounter _ sourceDir targetDir _ snaprun@ takes all run
591593
-- files that are referenced by @snaprun@, and hard links them from @sourceDir@
592594
-- into @targetDir@ with new, unique names (using @uniqCounter@). Each set of
593595
-- (hard linked) files that represents a run is opened and verified, returning
@@ -602,10 +604,12 @@ openRun ::
602604
-> ActionRegistry m
603605
-> NamedSnapshotDir
604606
-> ActiveDir
607+
-> Bloom.Salt
605608
-> SnapshotRun
606609
-> m (Ref (Run m h))
607610
openRun hfs hbio uc reg
608611
(NamedSnapshotDir sourceDir) (ActiveDir targetDir)
612+
expectedSalt
609613
SnapshotRun {
610614
snapRunNumber = runNum,
611615
snapRunCaching = caching,
@@ -617,7 +621,7 @@ openRun hfs hbio uc reg
617621
hardLinkRunFiles hfs hbio reg sourcePaths targetPaths
618622

619623
withRollback reg
620-
(Run.openFromDisk hfs hbio caching indexType targetPaths)
624+
(Run.openFromDisk hfs hbio caching indexType expectedSalt targetPaths)
621625
releaseRef
622626

623627
{-------------------------------------------------------------------------------

src/Database/LSMTree/Internal/Unsafe.hs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,11 +1536,11 @@ openTableFromSnapshot policyOveride sesh snap label resolve =
15361536
openWriteBuffer reg resolve hfs hbio uc activeDir snapWriteBufferPaths
15371537

15381538
-- Hard link runs into the active directory,
1539-
snapLevels' <- traverse (openRun hfs hbio uc reg snapDir activeDir) snapLevels
1539+
snapLevels' <- traverse (openRun hfs hbio uc reg snapDir activeDir (Paths.getSessionSalt salt)) snapLevels
15401540
unionLevel <- case mTreeOpt of
15411541
Nothing -> pure NoUnion
15421542
Just mTree -> do
1543-
snapTree <- traverse (openRun hfs hbio uc reg snapDir activeDir) mTree
1543+
snapTree <- traverse (openRun hfs hbio uc reg snapDir activeDir (Paths.getSessionSalt salt)) mTree
15441544
mt <- fromSnapMergingTree hfs hbio salt uc resolve activeDir reg snapTree
15451545
isStructurallyEmpty mt >>= \case
15461546
True ->

test/Test/Database/LSMTree/Internal/BloomFilter.hs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
module Test.Database.LSMTree.Internal.BloomFilter (tests) where
22

33
import Control.DeepSeq (deepseq)
4-
import Control.Exception (displayException)
4+
import Control.Exception (Exception (..), displayException)
55
import Control.Monad (void)
66
import qualified Control.Monad.IOSim as IOSim
77
import Data.Bits ((.&.))
88
import qualified Data.ByteString as BS
99
import qualified Data.ByteString.Builder as BS.Builder
1010
import qualified Data.ByteString.Builder.Extra as BS.Builder
1111
import qualified Data.ByteString.Lazy as LBS
12+
import qualified Data.List as List
1213
import qualified Data.Set as Set
1314
import qualified Data.Vector as V
1415
import qualified Data.Vector.Primitive as VP
@@ -26,6 +27,8 @@ import Test.Tasty.QuickCheck hiding ((.&.))
2627
import Data.BloomFilter.Blocked (Salt)
2728
import qualified Data.BloomFilter.Blocked as Bloom
2829
import Database.LSMTree.Internal.BloomFilter
30+
import Database.LSMTree.Internal.CRC32C (FileCorruptedError (..),
31+
FileFormat (..))
2932
import Database.LSMTree.Internal.Paths (SessionSalt (..))
3033
import Database.LSMTree.Internal.Serialise (SerialisedKey,
3134
serialiseKey)
@@ -69,9 +72,18 @@ limitBits b = b .&. 0xffffff
6972
prop_total_deserialisation :: BS.ByteString -> Property
7073
prop_total_deserialisation bs =
7174
case bloomFilterFromBS bs of
72-
Left err -> label (displayException err) $ property True
75+
Left err ->
76+
label (mkLabel err) $ property True
7377
Right bf -> label "parsed successfully" $ property $
7478
bf `deepseq` True
79+
where
80+
mkLabel err = case err of
81+
IOSim.FailureException e
82+
| Just (ErrFileFormatInvalid fsep FormatBloomFilterFile msg) <- fromException e
83+
, let msg' = "Expected salt does not match actual salt"
84+
, msg' `List.isPrefixOf` msg
85+
-> displayException $ ErrFileFormatInvalid fsep FormatBloomFilterFile msg'
86+
_ -> displayException err
7587

7688
-- | Write the bytestring to a file in the mock file system and then use
7789
-- 'bloomFilterFromFile'.
@@ -85,7 +97,7 @@ bloomFilterFromBS bs =
8597
void $ FS.hPutAllStrict hfs h bs
8698
-- deserialise from file
8799
FS.withFile hfs file FS.ReadMode $ \h ->
88-
bloomFilterFromFile hfs h
100+
bloomFilterFromFile hfs testSalt h
89101

90102
-- Length is in bits. A large length would require significant amount of
91103
-- memory, so we make it 'Small'.

test/Test/Database/LSMTree/Internal/Run.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,8 @@ prop_WriteAndOpen fs hbio wb =
219219
paths' = paths { runNumber = RunNumber 17}
220220
hardLinkRunFiles fs hbio reg paths paths'
221221
loaded <- openFromDisk fs hbio (runParamCaching runParams)
222-
(runParamIndex runParams) (simplePath 17)
222+
(runParamIndex runParams) (getSessionSalt testSessionSalt)
223+
(simplePath 17)
223224

224225
Run.size written @=? Run.size loaded
225226
withRef written $ \written' ->

0 commit comments

Comments
 (0)