Skip to content

Commit 7a24768

Browse files
committed
also generate structurally empty trees
1 parent 1cec2a1 commit 7a24768

File tree

1 file changed

+40
-24
lines changed

1 file changed

+40
-24
lines changed

src-extras/Database/LSMTree/Extras/MergingTreeData.hs

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -133,29 +133,38 @@ data PreExistingRunData k v b =
133133
| PreExistingMergingRunData (MergingRunData MR.LevelMergeType k v b)
134134
deriving stock (Show, Eq)
135135

136+
mergingTreeIsStructurallyEmpty :: MergingTreeData k v b -> Bool
137+
mergingTreeIsStructurallyEmpty = \case
138+
CompletedTreeMergeData _ -> False -- could be, but we match MT
139+
OngoingTreeMergeData _ -> False
140+
PendingLevelMergeData ps t -> null ps && null t
141+
PendingUnionMergeData ts -> null ts
142+
136143
-- | See @treeInvariant@ in prototype.
137144
mergingTreeDataInvariant :: MergingTreeData k v b -> Either String ()
138-
mergingTreeDataInvariant = \case
139-
CompletedTreeMergeData _rd ->
140-
Right ()
141-
OngoingTreeMergeData mr ->
142-
mergingRunDataInvariant mr
143-
PendingLevelMergeData prs t -> do
144-
assertI "pending level merges have at least one input" $
145-
length prs + length t > 0
146-
for_ prs $ \case
147-
PreExistingRunData _r -> Right ()
148-
PreExistingMergingRunData mr -> mergingRunDataInvariant mr
149-
for_ (drop 1 (reverse prs)) $ \case
150-
PreExistingRunData _r -> Right ()
151-
PreExistingMergingRunData mr ->
152-
assertI "only the last pre-existing run can be a last level merge" $
153-
mergingRunDataMergeType mr == MR.MergeMidLevel
154-
for_ t mergingTreeDataInvariant
155-
PendingUnionMergeData ts -> do
156-
assertI "pending union merges are non-trivial (at least two inputs)" $
157-
length ts >= 2
158-
for_ ts mergingTreeDataInvariant
145+
mergingTreeDataInvariant mtd
146+
| mergingTreeIsStructurallyEmpty mtd = Right ()
147+
| otherwise = case mtd of
148+
CompletedTreeMergeData _rd ->
149+
Right ()
150+
OngoingTreeMergeData mr ->
151+
mergingRunDataInvariant mr
152+
PendingLevelMergeData prs t -> do
153+
assertI "pending level merges have at least one input" $
154+
length prs + length t > 0
155+
for_ prs $ \case
156+
PreExistingRunData _r -> Right ()
157+
PreExistingMergingRunData mr -> mergingRunDataInvariant mr
158+
for_ (drop 1 (reverse prs)) $ \case
159+
PreExistingRunData _r -> Right ()
160+
PreExistingMergingRunData mr ->
161+
assertI "only the last pre-existing run can be a last level merge" $
162+
mergingRunDataMergeType mr == MR.MergeMidLevel
163+
for_ t mergingTreeDataInvariant
164+
PendingUnionMergeData ts -> do
165+
assertI "pending union merges are non-trivial (at least two inputs)" $
166+
length ts >= 2
167+
for_ ts mergingTreeDataInvariant
159168
where
160169
assertI msg False = Left msg
161170
assertI _ True = Right ()
@@ -241,9 +250,16 @@ instance ( Ord k, Arbitrary k, Arbitrary v, Arbitrary b
241250

242251
genMergingTreeData ::
243252
Ord k => Gen k -> Gen v -> Gen b -> Gen (MergingTreeData k v b)
244-
genMergingTreeData genKey genVal genBlob = QC.sized $ \s -> do
245-
treeSize <- QC.chooseInt (1, 1 + (s `div` 4)) -- up to 26
246-
genMergingTreeDataOfSize genKey genVal genBlob treeSize
253+
genMergingTreeData genKey genVal genBlob =
254+
QC.frequency
255+
-- Only at the root, we can have pending merges with no children, see
256+
-- 'MR.newPendingLevelMerge' and 'MR.newPendingUnionMerge'.
257+
[ ( 1, pure $ PendingLevelMergeData [] Nothing)
258+
, ( 1, pure $ PendingUnionMergeData [])
259+
, (50, QC.sized $ \s -> do
260+
treeSize <- QC.chooseInt (1, 1 + (s `div` 4)) -- up to 26
261+
genMergingTreeDataOfSize genKey genVal genBlob treeSize)
262+
]
247263

248264
-- | Minimal returned size will be 1. Doesn't generate structurally empty trees!
249265
--

0 commit comments

Comments
 (0)