|
4 | 4 | module Test.Database.LSMTree.Class ( |
5 | 5 | tests |
6 | 6 | ) where |
7 | | -import Control.Exception (SomeException, try) |
| 7 | +import Control.Exception (SomeException, assert, try) |
| 8 | +import Control.Monad (forM, when) |
8 | 9 | import Control.Monad.ST.Strict (runST) |
9 | 10 | import Control.Monad.Trans.State |
10 | 11 | import qualified Data.ByteString as BS |
@@ -108,7 +109,7 @@ tests = testGroup "Test.Database.LSMTree.Class" |
108 | 109 | , testProperty' "snapshot-nochanges" $ prop_snapshotNoChanges tbl |
109 | 110 | , testProperty' "snapshot-nochanges2" $ prop_snapshotNoChanges2 tbl |
110 | 111 | , testProperty' "lookup-mupsert" $ prop_lookupUpdate tbl |
111 | | - , testProperty' "merge" $ prop_union tbl |
| 112 | + , testProperty' "union" $ prop_union tbl |
112 | 113 | ] |
113 | 114 |
|
114 | 115 | testProperty' :: forall a. Testable a => TestName -> a -> Bool -> TestTree |
@@ -600,44 +601,69 @@ prop_lookupUpdate h ups k v1 mb1 v2 = ioProperty $ do |
600 | 601 | prop_union :: forall h. |
601 | 602 | IsTable h |
602 | 603 | => Proxy h -> [(Key, Update Value Blob)] -> [(Key, Update Value Blob)] |
603 | | - -> [Key] -> Property |
604 | | -prop_union h ups1 ups2 (V.fromList -> testKeys) = ioProperty $ do |
| 604 | + -> [Key] |
| 605 | + -> Positive (Small Int) -- ^ Number of batches for supplying union credits |
| 606 | + -> Property |
| 607 | +prop_union h ups1 ups2 |
| 608 | + (V.fromList -> testKeys) |
| 609 | + (Positive (Small nSupplyBatches)) |
| 610 | + = ioProperty $ do |
605 | 611 | withSessionAndTableNew h ups1 $ \s tbl1 -> do |
606 | 612 | withTableNew s (testTableConfig h) $ \tbl2 -> do |
607 | 613 | updates tbl2 $ V.fromList ups2 |
608 | 614 |
|
609 | 615 | -- union them. |
610 | 616 | withTableUnion tbl1 tbl2 $ \tbl3 -> do |
| 617 | + propBegin <- compareLookups s tbl1 tbl2 tbl3 |
| 618 | + |
| 619 | + -- Supply union credits in @nSupplyBatches@ batches |
| 620 | + props <- forM (reverse [1 .. nSupplyBatches]) $ \i -> do |
| 621 | + -- Try to keep the batch sizes roughly the same size |
| 622 | + UnionDebt debt <- remainingUnionDebt tbl3 |
| 623 | + _ <- supplyUnionCredits tbl3 (UnionCredits (debt `div` i)) |
| 624 | + |
| 625 | + -- In case @i == 0@, then @debt `div` i == debt@, so the last supply |
| 626 | + -- should have finished the union. |
| 627 | + when (i == 1) $ do |
| 628 | + finalDebt <- remainingUnionDebt tbl3 |
| 629 | + assert (finalDebt == UnionDebt 0) $ pure () |
611 | 630 |
|
612 | | - -- results in parts and the union table |
613 | | - res1 <- lookupsWithBlobs tbl1 s testKeys |
614 | | - res2 <- lookupsWithBlobs tbl2 s testKeys |
615 | | - res3 <- lookupsWithBlobs tbl3 s testKeys |
616 | | - |
617 | | - let unionResult :: |
618 | | - LookupResult Value Blob |
619 | | - -> LookupResult Value Blob |
620 | | - -> LookupResult Value Blob |
621 | | - |
622 | | - unionResult r@NotFound NotFound = r |
623 | | - unionResult NotFound r@(Found _) = r |
624 | | - unionResult NotFound r@(FoundWithBlob _ _) = r |
625 | | - |
626 | | - unionResult r@(Found _) NotFound |
627 | | - = r |
628 | | - unionResult (Found v1) (Found v2) |
629 | | - = Found (resolve v1 v2) |
630 | | - unionResult (Found v1) (FoundWithBlob v2 _) |
631 | | - = Found (resolve v1 v2) |
632 | | - |
633 | | - unionResult r@(FoundWithBlob _ _) NotFound |
634 | | - = r |
635 | | - unionResult (FoundWithBlob v1 b1) (Found v2) |
636 | | - = FoundWithBlob (resolve v1 v2) b1 |
637 | | - unionResult (FoundWithBlob v1 b1) (FoundWithBlob v2 _b2) |
638 | | - = FoundWithBlob (resolve v1 v2) b1 |
639 | | - |
640 | | - return $ V.zipWith unionResult res1 res2 == res3 |
| 631 | + -- Check that the lookup results are still the same after each batch |
| 632 | + -- of union credits. |
| 633 | + compareLookups s tbl1 tbl2 tbl3 |
| 634 | + |
| 635 | + pure (propBegin .&&. conjoin props) |
| 636 | + where |
| 637 | + compareLookups s tbl1 tbl2 tbl3 = do |
| 638 | + -- results in parts and the union table |
| 639 | + res1 <- lookupsWithBlobs tbl1 s testKeys |
| 640 | + res2 <- lookupsWithBlobs tbl2 s testKeys |
| 641 | + res3 <- lookupsWithBlobs tbl3 s testKeys |
| 642 | + |
| 643 | + let unionResult :: |
| 644 | + LookupResult Value Blob |
| 645 | + -> LookupResult Value Blob |
| 646 | + -> LookupResult Value Blob |
| 647 | + |
| 648 | + unionResult r@NotFound NotFound = r |
| 649 | + unionResult NotFound r@(Found _) = r |
| 650 | + unionResult NotFound r@(FoundWithBlob _ _) = r |
| 651 | + |
| 652 | + unionResult r@(Found _) NotFound |
| 653 | + = r |
| 654 | + unionResult (Found v1) (Found v2) |
| 655 | + = Found (resolve v1 v2) |
| 656 | + unionResult (Found v1) (FoundWithBlob v2 _) |
| 657 | + = Found (resolve v1 v2) |
| 658 | + |
| 659 | + unionResult r@(FoundWithBlob _ _) NotFound |
| 660 | + = r |
| 661 | + unionResult (FoundWithBlob v1 b1) (Found v2) |
| 662 | + = FoundWithBlob (resolve v1 v2) b1 |
| 663 | + unionResult (FoundWithBlob v1 b1) (FoundWithBlob v2 _b2) |
| 664 | + = FoundWithBlob (resolve v1 v2) b1 |
| 665 | + |
| 666 | + return $ V.zipWith unionResult res1 res2 === res3 |
641 | 667 |
|
642 | 668 | ------------------------------------------------------------------------------- |
643 | 669 | -- implement classic QC tests for snapshots |
|
0 commit comments