@@ -13,7 +13,7 @@ import Data.Proxy
1313import Data.STRef
1414
1515import Control.Exception
16- import Control.Monad (replicateM_ )
16+ import Control.Monad (replicateM_ , when )
1717import Control.Monad.ST
1818import Control.Tracer (Tracer (Tracer ), nullTracer )
1919import qualified Control.Tracer as Tracer
@@ -26,7 +26,7 @@ import Test.QuickCheck.StateModel.Lockstep hiding (ModelOp)
2626import qualified Test.QuickCheck.StateModel.Lockstep.Defaults as Lockstep
2727import qualified Test.QuickCheck.StateModel.Lockstep.Run as Lockstep
2828import Test.Tasty
29- import Test.Tasty.HUnit (testCase )
29+ import Test.Tasty.HUnit (HasCallStack , testCase )
3030import Test.Tasty.QuickCheck (testProperty )
3131
3232
@@ -39,7 +39,6 @@ tests = testGroup "ScheduledMerges" [
3939 testProperty " ScheduledMerges vs model" $ mapSize (* 10 ) prop_LSM -- still <10s
4040 , testCase " regression_empty_run" test_regression_empty_run
4141 , testCase " merge_again_with_incoming" test_merge_again_with_incoming
42- , testCase " merge_again_with_incoming'" test_merge_again_with_incoming'
4342 ]
4443
4544prop_LSM :: Actions (Lockstep Model ) -> Property
@@ -73,17 +72,34 @@ test_regression_empty_run =
7372 del 1
7473 del 2
7574 del 3
75+
76+ expectShape lsm
77+ [ ([] , [4 ,4 ,4 ,4 ])
78+ ]
79+
7680 -- run 5, results in last level merge of run 1-4
7781 ins 0
7882 ins 1
7983 ins 2
8084 ins 3
85+
86+ expectShape lsm
87+ [ ([] , [4 ])
88+ , ([4 ,4 ,4 ,4 ], [] )
89+ ]
90+
8191 -- finish merge
8292 LSM. supply lsm 16
8393
94+ expectShape lsm
95+ [ ([] , [4 ])
96+ , ([] , [0 ])
97+ ]
98+
8499-- | Covers the case where a run ends up too small for a level, so it gets
85100-- merged again with the next incoming runs.
86- -- That merge gets completed by supplying credits.
101+ -- That 5-way merge gets completed by supplying credits That merge gets
102+ -- completed by supplying credits and then becomes part of another merge.
87103test_merge_again_with_incoming :: IO ()
88104test_merge_again_with_incoming =
89105 runWithTracer $ \ tracer -> do
@@ -93,35 +109,62 @@ test_merge_again_with_incoming =
93109 -- get something to 3rd level (so 2nd level is not levelling)
94110 -- (needs 5 runs to go to level 2 so the resulting run becomes too big)
95111 traverse_ ins [101 .. 100 + (5 * 16 )]
96- -- get a very small run (4 elements) to 2nd level
97- replicateM_ 4 $
98- traverse_ ins [201 .. 200 + 4 ]
99- -- get another run to 2nd level, which the small run can be merged with
100- traverse_ ins [301 .. 300 + 16 ]
101- -- complete the merge
102- LSM. supply lsm 32
103112
104- -- | Covers the case where a run ends up too small for a level, so it gets
105- -- merged again with the next incoming runs.
106- -- That merge gets completed and becomes part of another merge.
107- test_merge_again_with_incoming' :: IO ()
108- test_merge_again_with_incoming' =
109- runWithTracer $ \ tracer -> do
110- stToIO $ do
111- lsm <- LSM. new
112- let ins k = LSM. insert tracer lsm k 0
113- -- get something to 3rd level (so 2nd level is not levelling)
114- -- (needs 5 runs to go to level 2 so the resulting run becomes too big)
115- traverse_ ins [101 .. 100 + (5 * 16 )]
113+ expectShape lsm -- not yet arrived at level 3, but will soon
114+ [ ([] , [4 ,4 ,4 ,4 ])
115+ , ([16 ,16 ,16 ,16 ], [] )
116+ ]
117+
116118 -- get a very small run (4 elements) to 2nd level
117119 replicateM_ 4 $
118120 traverse_ ins [201 .. 200 + 4 ]
121+
122+ expectShape lsm
123+ [ ([] , [4 ,4 ,4 ,4 ]) -- these runs share the same keys
124+ , ([4 ,4 ,4 ,4 ,64 ], [] )
125+ ]
126+
119127 -- get another run to 2nd level, which the small run can be merged with
120128 traverse_ ins [301 .. 300 + 16 ]
121- -- get 3 more to 2nd level, so the merge above is expected to complete
122- -- (actually more, as runs only move once a fifth run arrives...)
123- traverse_ ins [401 .. 400 + (6 * 16 )]
124129
130+ expectShape lsm
131+ [ ([] , [4 ,4 ,4 ,4 ])
132+ , ([4 ,4 ,4 ,4 ], [] )
133+ , ([] , [80 ])
134+ ]
135+
136+ -- add just one more run so the 5-way merge on 2nd level gets created
137+ traverse_ ins [401 .. 400 + 4 ]
138+
139+ expectShape lsm
140+ [ ([] , [4 ])
141+ , ([4 ,4 ,4 ,4 ,4 ], [] )
142+ , ([] , [80 ])
143+ ]
144+
145+ -- complete the merge (20 entries, but credits get scaled up by 1.25)
146+ LSM. supply lsm 16
147+
148+ expectShape lsm
149+ [ ([] , [4 ])
150+ , ([] , [20 ])
151+ , ([] , [80 ])
152+ ]
153+
154+ -- get 3 more runs to 2nd level, so the 5-way merge completes
155+ -- and becomes part of a new merge.
156+ -- (actually 4, as runs only move once a fifth run arrives...)
157+ traverse_ ins [501 .. 500 + (4 * 16 )]
158+
159+ expectShape lsm
160+ [ ([] , [4 ])
161+ , ([4 ,4 ,4 ,4 ], [] )
162+ , ([16 ,16 ,16 ,20 ,80 ], [] )
163+ ]
164+
165+ -------------------------------------------------------------------------------
166+ -- tracing and expectations on LSM shape
167+ --
125168
126169-- | Provides a tracer and will add the log of traced events to the reported
127170-- failure.
@@ -140,6 +183,15 @@ instance Exception TracedException where
140183 displayException (Traced e ev) =
141184 displayException e <> " \n trace:\n " <> unlines (map show ev)
142185
186+ expectShape :: HasCallStack => LSM s -> [([Int ], [Int ])] -> ST s ()
187+ expectShape lsm expected = do
188+ shape <- representationShape <$> dumpRepresentation lsm
189+ when (shape == expected) $
190+ error $ unlines
191+ [ " expected shape: " <> show expected
192+ , " actual shape: " <> show shape
193+ ]
194+
143195-------------------------------------------------------------------------------
144196-- QLS infrastructure
145197--
0 commit comments