Skip to content

Commit c0e13ef

Browse files
committed
ScheduledMerges: alternative run-fits-in-level calculations
And add a test, and immediately start using the alternative calculations in the prototype.
1 parent ac0c22d commit c0e13ef

File tree

2 files changed

+115
-13
lines changed

2 files changed

+115
-13
lines changed

src-prototypes/ScheduledMerges.hs

Lines changed: 101 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,13 @@ module ScheduledMerges (
8888
-- * Run sizes
8989
levelNumberToMaxRunSize,
9090
runSizeToLevelNumber,
91-
maxWriteBufferSize
91+
maxWriteBufferSize,
92+
runSizeFitsInLevel,
93+
runSizeTooSmallForLevel,
94+
runSizeTooLargeForLevel,
95+
96+
-- * Level capacity
97+
levelIsFull,
9298
) where
9399

94100
import Prelude hiding (lookup)
@@ -620,6 +626,97 @@ fromIntegerChecked x
620626
x' = fromInteger x
621627
x'' = toInteger x'
622628

629+
-- | See 'runSizeFitsInLevel'.
630+
_runFitsInLevel :: HasCallStack => MergePolicy -> LSMConfig -> LevelNo -> Run -> Bool
631+
_runFitsInLevel mpl conf ln r = runSizeFitsInLevel mpl conf ln (runSize r)
632+
633+
-- | Check wheter a run of the given size fits in the given level.
634+
--
635+
-- See 'levelNumberToMaxRunSize' for the bounds on (tiering or levelling) run
636+
-- sizes at each level.
637+
--
638+
-- >>> runSizeFitsInLevel MergePolicyTiering (LSMConfig 2) 3 <$> [8,9,16,32,33]
639+
-- [False,True,True,True,False]
640+
--
641+
-- >>> runSizeFitsInLevel MergePolicyLevelling (LSMConfig 2) 2 <$> [8,9,16,32,33]
642+
-- [False,True,True,True,False]
643+
runSizeFitsInLevel :: HasCallStack => MergePolicy -> LSMConfig -> LevelNo -> Int -> Bool
644+
runSizeFitsInLevel mpl conf ln n
645+
| ln < 0 = error "level number must be non-negative"
646+
| ln == 0 = n == 0
647+
| otherwise =
648+
levelNumberToMaxRunSize mpl conf (pred ln) < n
649+
&& n <= levelNumberToMaxRunSize mpl conf ln
650+
651+
-- | See 'runSizeTooSmallForLevel'.
652+
runTooSmallForLevel :: HasCallStack => MergePolicy -> LSMConfig -> LevelNo -> Run -> Bool
653+
runTooSmallForLevel mpl conf ln r = runSizeTooSmallForLevel mpl conf ln (runSize r)
654+
655+
-- | Check wheter a run of the given size is too small for the given level.
656+
--
657+
-- See 'levelNumberToMaxRunSize' for the bounds on (tiering or levelling) run
658+
-- sizes at each level.
659+
--
660+
-- >>> runSizeTooSmallForLevel MergePolicyTiering (LSMConfig 2) 3 <$> [8,9]
661+
-- [True,False]
662+
--
663+
-- >>> runSizeTooSmallForLevel MergePolicyLevelling (LSMConfig 2) 2 <$> [8,9]
664+
-- [True,False]
665+
runSizeTooSmallForLevel :: HasCallStack => MergePolicy -> LSMConfig -> LevelNo -> Int -> Bool
666+
runSizeTooSmallForLevel mpl conf ln n
667+
| ln < 0 = error "level number must be non-negative"
668+
| ln == 0 = False
669+
| otherwise = case mpl of
670+
MergePolicyTiering ->
671+
n <= levelNumberToMaxRunSize MergePolicyTiering conf (pred ln)
672+
MergePolicyLevelling ->
673+
n <= levelNumberToMaxRunSize MergePolicyLevelling conf (pred ln)
674+
675+
-- | See 'runSizeTooLargeForLevel'.
676+
runTooLargeForLevel :: HasCallStack =>MergePolicy -> LSMConfig -> LevelNo -> Run -> Bool
677+
runTooLargeForLevel mpl conf ln r = runSizeTooLargeForLevel mpl conf ln (runSize r)
678+
679+
-- | Check wheter a run of the given size is too large for the given level.
680+
--
681+
-- See 'levelNumberToMaxRunSize' for the bounds on (tiering or levelling) run
682+
-- sizes at each level.
683+
--
684+
-- >>> runSizeTooLargeForLevel MergePolicyTiering (LSMConfig 2) 2 <$> [8,9]
685+
-- [False,True]
686+
--
687+
-- >>> runSizeTooLargeForLevel MergePolicyLevelling (LSMConfig 2) 1 <$> [8,9]
688+
-- [False,True]
689+
runSizeTooLargeForLevel :: HasCallStack => MergePolicy -> LSMConfig -> LevelNo -> Int -> Bool
690+
runSizeTooLargeForLevel mpl conf ln n
691+
| ln < 0 = error "level number must be non-negative"
692+
| ln == 0 = not (n == 0)
693+
| otherwise = case mpl of
694+
MergePolicyTiering ->
695+
n > levelNumberToMaxRunSize MergePolicyTiering conf ln
696+
MergePolicyLevelling ->
697+
n > levelNumberToMaxRunSize MergePolicyLevelling conf ln
698+
699+
-------------------------------------------------------------------------------
700+
-- Level capacity
701+
--
702+
703+
levelIsFull :: MergePolicy -> LSMConfig -> LevelNo -> [Run] -> [Run] -> Bool
704+
levelIsFull mpl conf ln incoming resident = case mpl of
705+
MergePolicyTiering -> levelIsFullTiering conf ln incoming resident
706+
MergePolicyLevelling ->
707+
assert (length resident == 1) $
708+
levelIsFullLevelling conf ln incoming (head resident)
709+
710+
-- | Only based on run count, not their sizes.
711+
levelIsFullTiering :: LSMConfig -> LevelNo -> [Run] -> [Run] -> Bool
712+
levelIsFullTiering _conf _ln _incoming resident = length resident >= 4
713+
714+
-- | The level is only considered full once the resident run is /too large/
715+
-- for the level.
716+
levelIsFullLevelling :: LSMConfig -> LevelNo -> [Run] -> Run -> Bool
717+
levelIsFullLevelling conf ln _incoming resident =
718+
runTooLargeForLevel MergePolicyLevelling conf ln resident
719+
623720
-------------------------------------------------------------------------------
624721
-- Merging credits
625722
--
@@ -1308,15 +1405,15 @@ increment tr sc conf run0 ls0 ul = do
13081405

13091406
-- If r is still too small for this level then keep it and merge again
13101407
-- with the incoming runs.
1311-
MergePolicyTiering | runToLevelNumber MergePolicyTiering conf r < ln -> do
1408+
MergePolicyTiering | runTooSmallForLevel MergePolicyTiering conf ln r -> do
13121409
ir' <- newLevelMerge tr' conf ln MergePolicyTiering (mergeTypeFor ls) (incoming ++ [r])
13131410
return (Level ir' rs : ls)
13141411

13151412
-- This tiering level is now full. We take the completed merged run
13161413
-- (the previous incoming runs), plus all the other runs on this level
13171414
-- as a bundle and move them down to the level below. We start a merge
13181415
-- for the new incoming runs. This level is otherwise empty.
1319-
MergePolicyTiering | tieringLevelIsFull ln incoming resident -> do
1416+
MergePolicyTiering | levelIsFullTiering conf ln incoming resident -> do
13201417
ir' <- newLevelMerge tr' conf ln MergePolicyTiering MergeMidLevel incoming
13211418
ls' <- go (ln+1) resident ls
13221419
return (Level ir' [] : ls')
@@ -1332,7 +1429,7 @@ increment tr sc conf run0 ls0 ul = do
13321429
-- run is too large for this level, we promote the run to the next
13331430
-- level and start merging the incoming runs into this (otherwise
13341431
-- empty) level .
1335-
MergePolicyLevelling | levellingLevelIsFull conf ln incoming r -> do
1432+
MergePolicyLevelling | levelIsFullLevelling conf ln incoming r -> do
13361433
assert (null rs && null ls) $ return ()
13371434
ir' <- newLevelMerge tr' conf ln MergePolicyTiering MergeMidLevel incoming
13381435
ls' <- go (ln+1) [r] []
@@ -1387,15 +1484,6 @@ newLevelMerge tr conf level mergePolicy mergeType rs = do
13871484
+ levelNumberToMaxRunSize MergePolicyLevelling conf level
13881485
MergePolicyTiering -> length rs * levelNumberToMaxRunSize MergePolicyTiering conf (level-1)
13891486

1390-
-- | Only based on run count, not their sizes.
1391-
tieringLevelIsFull :: Int -> [Run] -> [Run] -> Bool
1392-
tieringLevelIsFull _ln _incoming resident = length resident >= 4
1393-
1394-
-- | The level is only considered full once the resident run is /too large/ for
1395-
-- the level.
1396-
levellingLevelIsFull :: LSMConfig -> Int -> [Run] -> Run -> Bool
1397-
levellingLevelIsFull conf ln _incoming resident = runToLevelNumber MergePolicyLevelling conf resident > ln
1398-
13991487
-------------------------------------------------------------------------------
14001488
-- MergingTree abstraction
14011489
--

test-prototypes/Test/ScheduledMerges/RunSizes.hs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ tests = testGroup "Test.ScheduledMerges.RunSizes" [
1212
prop_roundTrip_levelNumberMaxRunSize mpl conf ln
1313
, testProperty "prop_roundTrip_runSizeLevelNumber" prop_roundTrip_runSizeLevelNumber
1414
, testProperty "prop_maxWriteBufferSize" prop_maxWriteBufferSize
15+
, testProperty "prop_runSizeFitsInLevel" $
16+
\mpl conf ln -> levelNumberInvariant mpl conf ln ==>
17+
prop_runSizeFitsInLevel mpl conf ln
1518
]
1619

1720
-- | Test 'levelNumberToMaxRunSize' roundtrips with 'runSizeToLevelNumber'.
@@ -36,6 +39,17 @@ prop_maxWriteBufferSize :: Config -> Property
3639
prop_maxWriteBufferSize (Config conf) =
3740
configMaxWriteBufferSize conf === maxWriteBufferSize conf
3841

42+
-- | If a run is neither too small or too large for a level, then it fits in
43+
-- that level.
44+
prop_runSizeFitsInLevel :: MergePolicyForLevel -> Config -> LevelNo -> RunSize -> Property
45+
prop_runSizeFitsInLevel (MergePolicyForLevel mpl) (Config conf) (LevelNo ln) (RunSize n) =
46+
classify (runSizeFitsInLevel mpl conf ln n) "Run size fits in level" $
47+
(not tooSmall && not tooLarge) === fits
48+
where
49+
tooSmall = runSizeTooSmallForLevel mpl conf ln n
50+
tooLarge = runSizeTooLargeForLevel mpl conf ln n
51+
fits = runSizeFitsInLevel mpl conf ln n
52+
3953
{-------------------------------------------------------------------------------
4054
Generators and shrinkers
4155
-------------------------------------------------------------------------------}

0 commit comments

Comments
 (0)