-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Persist write buffer when creating a snapshot #478
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks promising!
I think this works for writing out the write buffer. It would be good to add a test that exercises writeWriteBuffer
directly. Maybe we could test that the WriteBufferWriter
and RunBuilder
produce the same keyops and blob files?
Is there any testing infrastructure that would allow me to easily set up the required inputs? |
Do you have any initial feelings regarding the amount of duplication? |
^ contains some definitions for generating data for runs, which is equivalent to data for write buffers. It's just sorted key/value data without duplicate keys lsm-tree/test/Test/Database/LSMTree/Internal/Run.hs Lines 179 to 212 in d11c709
^ this test could give you an idea of how to use the run data. |
Oops, yes, I meant to write about that but I forgot. I think it's okay to have the duplication for now, as long as we
|
Fair! I still think the generalisation of the run infrastructure to permit empty filters and indices might be worthwhile, especially with SPJ's recent "specialise with value" extension. |
True, though we wouldn't be able to take advantage of that on older GHCs... unless that stuff is backported |
We could do something a bit unhinged and encode the flag using instances of a type class. That way it's easily backwards compatible. |
Added the test
|
The assertion at the specified line of the code asserts that keys should be longer than 8 bytes. The |
8e1f2bf
to
6a7eee5
Compare
I've added an implementation for |
eb55cf0
to
b472261
Compare
@jorisdral This is ready for review. |
f5ad722
to
c7d5451
Compare
This is ready for review but not for merge. There appear to be some non-deterministic test failures. |
Here's my assessment of the CI failures, for reference when I continue work on LSM next week: # REPRODUCED with GHC 9.8.2
#
# propLockstep_RealImpl_MockFS_IOSim: FAIL (0.69s)
# *** Failed! Falsified (after 1 test and 24 shrinks):
# do action $ New (PrettyProxy @((Key,Value,Blob))) (TableConfig {confMergePolicy = MergePolicyLazyLevelling, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries (NumEntries 1), confBloomFilterAlloc = AllocFixed 10, confFencePointerIndex = CompactIndex, confDiskCachePolicy = DiskCacheNone, confMergeSchedule = Incremental})
# pure ()
# FailureEvaluation RefNeverReleased RefId 4653
# Allocation site: CallStack (from HasCallStack):
# newRefWithTracker, called at src-control/Control/RefCount.hs:226:7 in lsm-tree-0.1.0.0-inplace-control:Control.RefCount
# newRef, called at src/Database/LSMTree/Internal/WriteBufferBlobs.hs:140:5 in lsm-tree-0.1.0.0-inplace:Database.LSMTree.Internal.WriteBufferBlobs
# Use --quickcheck-replay="(SMGen 3745502568310153392 9447962285702497153,91)" to reproduce.
cabal run lsm-tree-test -- -p '/propLockstep_RealImpl_MockFS_IOSim/' --quickcheck-replay="(SMGen 3745502568310153392 9447962285702497153,91)"
# REPRODUCED with GHC 9.8.2
#
# propLockstep_RealImpl_RealFS_IO: FAIL (11.33s)
# *** Failed! Assertion failed (after 1 test and 158 shrinks):
# do var1 <- action $ New (PrettyProxy @((Key,Value,Blob))) (TableConfig {confMergePolicy = MergePolicyLazyLevelling, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries (NumEntries 2), confBloomFilterAlloc = AllocFixed 10, confFencePointerIndex = CompactIndex, confDiskCachePolicy = DiskCacheNone, confMergeSchedule = Incremental})
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [121,62,225,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [0]))))] (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# action $ CreateSnapshot (SnapshotLabel "Key Value Blob") "snap1" (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# var6 <- action $ OpenSnapshot (SnapshotLabel "Key Value Blob") "snap1"
# var10 <- action $ Duplicate (unsafeMkGVar var6 (OpFromRight `OpComp` OpId))
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [0,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [1]))))] (unsafeMkGVar var10 (OpFromRight `OpComp` OpId))
# var15 <- action $ NewCursor (Just (Key (KeyForIndexCompact {getKeyForIndexCompact = [121,62,224,96,53,92,252,220,175,239,140,57,8,65,169,5,100,247,111,202,35,151,202,139,199,203,174,214,40,157,156,189,98,28,59,226,206,234,147,114,163,92,201,7,143,220,140,176,239,130,40,54,57,93,139,13,136,97,182,85,161,139,223,24,216,231,106,90,66,136,24,105,62,156]}))) (unsafeMkGVar var10 (OpFromRight `OpComp` OpId))
# var23 <- action $ ReadCursor 59 (unsafeMkGVar var15 (OpFromRight `OpComp` OpId))
# action $ RetrieveBlobs (unsafeMkGVar var23 (OpQueryResults `OpComp` OpFromRight `OpComp` OpId))
# pure ()
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList []))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,0,0,0), successActions = ["New"], failActions = [], numActionsPerTable = fromList [(0,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList []})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 1,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["ReadCursor","NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RetrieveBlobs","ReadCursor","NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# System under test returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])})])) (Right [WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])}])
# but model returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])) (MEither (Right (MVector [MBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])))
# Use --quickcheck-replay="(SMGen 6681553406898521959 16697549380326312555,88)" to reproduce.
cabal run lsm-tree-test -- -p '/propLockstep_RealImpl_RealFS_IO/' --quickcheck-replay="(SMGen 6681553406898521959 16697549380326312555,88)"
# REPRODUCED with GHC 9.8.2
#
# propLockstep_RealImpl_RealFS_IO: FAIL (73.11s)
# *** Failed! Assertion failed (after 1 test and 285 shrinks):
# do var27 <- action $ New (PrettyProxy @((Key,Value,Blob))) (TableConfig {confMergePolicy = MergePolicyLazyLevelling, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries (NumEntries 2), confBloomFilterAlloc = AllocFixed 10, confFencePointerIndex = CompactIndex, confDiskCachePolicy = DiskCacheNone, confMergeSchedule = Incremental})
# var37 <- action $ Duplicate (unsafeMkGVar var27 (OpFromRight `OpComp` OpId))
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [72,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [0]))))] (unsafeMkGVar var37 (OpFromRight `OpComp` OpId))
# action $ CreateSnapshot (SnapshotLabel "Key Value Blob") "snap3" (unsafeMkGVar var37 (OpFromRight `OpComp` OpId))
# var59 <- action $ OpenSnapshot (SnapshotLabel "Key Value Blob") "snap3"
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [0,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [1]))))] (unsafeMkGVar var59 (OpFromRight `OpComp` OpId))
# var63 <- action $ RangeLookup (FromToExcluding (Key (KeyForIndexCompact {getKeyForIndexCompact = [71,146,85,251,201,63,13,171,108,104,235,95,72,169,31,247,251,180,104,35,142,30,40,142,208,251,88,106,217,209,67,69,8,54,185,129,193,219,230,17,30,138,26,139]})) (Key (KeyForIndexCompact {getKeyForIndexCompact = [224,160,131,208,135,90,169,220,1,9,97,98,40,28,141,128,196,117,26,157,178,207,140,15,244,111,77,4,244,27,67,169,231,191,131,248,144,5,185,46,19,6,84,160,63,255,190,249,47,109,124,98,204,187,249,98,174,182,56,126,219,98,247,211,6,56,196,196,37,200,90,195,244,206,206,146,53,111,225,29,22,70,150,191,106,130,227,204,110,36,187,39,138,10,59,67,51,177,186,184,98,108,33,87,5,68,147,155]}))) (unsafeMkGVar var59 (OpFromRight `OpComp` OpId))
# action $ RetrieveBlobs (unsafeMkGVar var63 (OpQueryResults `OpComp` OpFromRight `OpComp` OpId))
# pure ()
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList []))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,0,0,0), successActions = ["New"], failActions = [], numActionsPerTable = fromList [(0,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList []})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 0,fromList []))], cursors = fromList [], nextID = 2, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,0,0,0), successActions = ["Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0)], dupTableActionLog = fromList []})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 1,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Updates","Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0)], dupTableActionLog = fromList [(0,[1])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 2,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList [("snap3",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap3"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["CreateSnapshot","Updates","Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0)], dupTableActionLog = fromList [(0,[1])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 2,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap3",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap3"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["OpenSnapshot","CreateSnapshot","Updates","Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,1),(2,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0),(2,2)], dupTableActionLog = fromList [(0,[1])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 2,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap3",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap3"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["Updates","OpenSnapshot","CreateSnapshot","Updates","Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,1),(2,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0),(2,2)], dupTableActionLog = fromList [(0,[1]),(2,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 2,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap3",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap3"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RangeLookup","Updates","OpenSnapshot","CreateSnapshot","Updates","Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,1),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0),(2,2)], dupTableActionLog = fromList [(0,[1]),(2,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList [])),(1,(UpdateCounter 2,fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap3",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("H\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap3"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RetrieveBlobs","RangeLookup","Updates","OpenSnapshot","CreateSnapshot","Updates","Duplicate","New"], failActions = [], numActionsPerTable = fromList [(0,0),(1,1),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,0),(2,2)], dupTableActionLog = fromList [(0,[1]),(2,[2])]})
# System under test returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])})])) (Right [WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])}])
# but model returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])) (MEither (Right (MVector [MBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])))
# Use --quickcheck-replay="(SMGen 856599901754634088 14991145271356155781,87)" to reproduce.
cabal run lsm-tree-test -- -p '/propLockstep_RealImpl_RealFS_IO/' --quickcheck-replay="(SMGen 856599901754634088 14991145271356155781,87)"
# REPRODUCED with GHC 9.8.2
#
# propLockstep_RealImpl_RealFS_IO: FAIL (11.40s)
# *** Failed! Assertion failed (after 1 test and 158 shrinks):
# do var1 <- action $ New (PrettyProxy @((Key,Value,Blob))) (TableConfig {confMergePolicy = MergePolicyLazyLevelling, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries (NumEntries 2), confBloomFilterAlloc = AllocFixed 10, confFencePointerIndex = CompactIndex, confDiskCachePolicy = DiskCacheNone, confMergeSchedule = Incremental})
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [121,62,225,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [0]))))] (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# action $ CreateSnapshot (SnapshotLabel "Key Value Blob") "snap1" (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# var6 <- action $ OpenSnapshot (SnapshotLabel "Key Value Blob") "snap1"
# var10 <- action $ Duplicate (unsafeMkGVar var6 (OpFromRight `OpComp` OpId))
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [0,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [1]))))] (unsafeMkGVar var10 (OpFromRight `OpComp` OpId))
# var15 <- action $ NewCursor (Just (Key (KeyForIndexCompact {getKeyForIndexCompact = [121,62,224,96,53,92,252,220,175,239,140,57,8,65,169,5,100,247,111,202,35,151,202,139,199,203,174,214,40,157,156,189,98,28,59,226,206,234,147,114,163,92,201,7,143,220,140,176,239,130,40,54,57,93,139,13,136,97,182,85,161,139,223,24,216,231,106,90,66,136,24,105,62,156]}))) (unsafeMkGVar var10 (OpFromRight `OpComp` OpId))
# var23 <- action $ ReadCursor 59 (unsafeMkGVar var15 (OpFromRight `OpComp` OpId))
# action $ RetrieveBlobs (unsafeMkGVar var23 (OpQueryResults `OpComp` OpFromRight `OpComp` OpId))
# pure ()
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList []))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,0,0,0), successActions = ["New"], failActions = [], numActionsPerTable = fromList [(0,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList []})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 1,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["ReadCursor","NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RetrieveBlobs","ReadCursor","NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# System under test returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])})])) (Right [WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])}])
# but model returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])) (MEither (Right (MVector [MBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])))
# Use --quickcheck-replay="(SMGen 6681553406898521959 16697549380326312555,88)" to reproduce.
cabal run lsm-tree-test -- -p '/propLockstep_RealImpl_RealFS_IO/' --quickcheck-replay="(SMGen 8643971879424937837 17377864027749461975,88)"
# REPRODUCED with GHC 9.8.2
#
# propLockstep_RealImpl_RealFS_IO: FAIL (11.73s)
# *** Failed! Assertion failed (after 1 test and 158 shrinks):
# do var1 <- action $ New (PrettyProxy @((Key,Value,Blob))) (TableConfig {confMergePolicy = MergePolicyLazyLevelling, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries (NumEntries 2), confBloomFilterAlloc = AllocFixed 10, confFencePointerIndex = CompactIndex, confDiskCachePolicy = DiskCacheNone, confMergeSchedule = Incremental})
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [121,62,225,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [0]))))] (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# action $ CreateSnapshot (SnapshotLabel "Key Value Blob") "snap1" (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# var6 <- action $ OpenSnapshot (SnapshotLabel "Key Value Blob") "snap1"
# var10 <- action $ Duplicate (unsafeMkGVar var6 (OpFromRight `OpComp` OpId))
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [0,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [1]))))] (unsafeMkGVar var10 (OpFromRight `OpComp` OpId))
# var15 <- action $ NewCursor (Just (Key (KeyForIndexCompact {getKeyForIndexCompact = [121,62,224,96,53,92,252,220,175,239,140,57,8,65,169,5,100,247,111,202,35,151,202,139,199,203,174,214,40,157,156,189,98,28,59,226,206,234,147,114,163,92,201,7,143,220,140,176,239,130,40,54,57,93,139,13,136,97,182,85,161,139,223,24,216,231,106,90,66,136,24,105,62,156]}))) (unsafeMkGVar var10 (OpFromRight `OpComp` OpId))
# var23 <- action $ ReadCursor 59 (unsafeMkGVar var15 (OpFromRight `OpComp` OpId))
# action $ RetrieveBlobs (unsafeMkGVar var23 (OpQueryResults `OpComp` OpFromRight `OpComp` OpId))
# pure ()
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList []))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,0,0,0), successActions = ["New"], failActions = [], numActionsPerTable = fromList [(0,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList []})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 1,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["ReadCursor","NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [(3,<<Cursor Key Value Blob>>)], nextID = 4, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("y>\225\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RetrieveBlobs","ReadCursor","NewCursor","Updates","Duplicate","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0),(2,2)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2])]})
# System under test returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])})])) (Right [WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])}])
# but model returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])) (MEither (Right (MVector [MBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])))
# Use --quickcheck-replay="(SMGen 6681553406898521959 16697549380326312555,88)" to reproduce.
cabal run lsm-tree-test -- -p '/propLockstep_RealImpl_RealFS_IO/' --quickcheck-replay="(SMGen 6681553406898521959 16697549380326312555,88)"
# REPRODUCED with GHC 9.8.2
#
# propLockstep_RealImpl_MockFS_IO: FAIL (41.87s)
# *** Failed! Assertion failed (after 1 test and 280 shrinks):
# do var1 <- action $ New (PrettyProxy @((Key,Value,Blob))) (TableConfig {confMergePolicy = MergePolicyLazyLevelling, confSizeRatio = Four, confWriteBufferAlloc = AllocNumEntries (NumEntries 2), confBloomFilterAlloc = AllocFixed 10, confFencePointerIndex = CompactIndex, confDiskCachePolicy = DiskCacheNone, confMergeSchedule = Incremental})
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [6,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [0]))))] (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# action $ CreateSnapshot (SnapshotLabel "Key Value Blob") "snap1" (unsafeMkGVar var1 (OpFromRight `OpComp` OpId))
# var17 <- action $ OpenSnapshot (SnapshotLabel "Key Value Blob") "snap1"
# action $ Updates [(Key (KeyForIndexCompact {getKeyForIndexCompact = [0,0,0,0,0,0,0,0]}),Insert (Value (SerialisedValue [])) (Just (Blob (SerialisedBlob [1]))))] (unsafeMkGVar var17 (OpFromRight `OpComp` OpId))
# var21 <- action $ Duplicate (unsafeMkGVar var17 (OpFromRight `OpComp` OpId))
# var22 <- action $ RangeLookup (FromToExcluding (Key (KeyForIndexCompact {getKeyForIndexCompact = [5,227,86,48,98,173,194,45,23,220,116,97,188,153,32,140,117,157,159,43,45,43,242,245,16,140,191,188,124,233,23,63,85,237,202,154,113,142,157,208,240,248,83,145,199,253,69,169,190,187,24,25,88,33,108,25,14,244,56,122,151,94,143,32,204,202,158,250,245,50,80,115,134,68,28]})) (Key (KeyForIndexCompact {getKeyForIndexCompact = [174,85,235,200,159,46,48,93,200,144,34,95,64,87,157,140,51,172,50,35,76,160,1,194,109,98,172,31,8,59,34,148,207,129,98,149,32,134,185,35,132,60,207,237,165,138,29,101,62,91,129,215,181,104,17,219,145,130,143,127,115,72,8,115,106,126,242,253,61,105,138,85,18,230,76,94,231,165,227,235,163,181,174,79,74,188,81,84,34,20,222,198,143,93,228,179,247,197,158,94,151,120,215,234,36,34,3,154]}))) (unsafeMkGVar var21 (OpFromRight `OpComp` OpId))
# action $ RetrieveBlobs (unsafeMkGVar var22 (OpQueryResults `OpComp` OpFromRight `OpComp` OpId))
# pure ()
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 0,fromList []))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,0,0,0), successActions = ["New"], failActions = [], numActionsPerTable = fromList [(0,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList []})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 1,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList []}) (Stats {snapshotted = fromList [], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 1, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 0,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,1,0,0), successActions = ["OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1)], dupTableActionLog = fromList [(0,[0])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 2, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["Updates","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1)], dupTableActionLog = fromList [(0,[0]),(1,[1])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["Duplicate","Updates","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,1),(2,0)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[1])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RangeLookup","Duplicate","Updates","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,1),(2,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2,1])]})
# State: ModelState (Model {tables = fromList [(0,(UpdateCounter 2,fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(1,(UpdateCounter 1,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])),(2,(UpdateCounter 0,fromList [("\NUL\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\SOH"),("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")]))], cursors = fromList [], nextID = 3, snapshots = fromList [("snap1",Snapshot TableConfig (SnapshotLabel "Key Value Blob") fromList [("\ACK\NUL\NUL\NUL\NUL\NUL\NUL\NUL","",Just "\NUL")])]}) (Stats {snapshotted = fromList ["snap1"], numLookupsResults = (0,0,0), numUpdates = (0,2,0,0), successActions = ["RetrieveBlobs","RangeLookup","Duplicate","Updates","OpenSnapshot","CreateSnapshot","Updates","New"], failActions = [], numActionsPerTable = fromList [(0,1),(1,1),(2,1)], closedTableSizes = fromList [], parentTable = fromList [(0,0),(1,1),(2,1)], dupTableActionLog = fromList [(0,[0]),(1,[2,1])]})
# System under test returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])})])) (Right [WrapBlob {unwrapBlob = Blob (SerialisedBlob [1])}])
# but model returned: OEither (Right (OVector [OBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])) (MEither (Right (MVector [MBlob (WrapBlob {unwrapBlob = Blob (SerialisedBlob [0])})])))
# Use --quickcheck-replay="(SMGen 7870052982708161788 8378283829282625597,88)" to reproduce.
cabal run lsm-tree-test -- -p '$0=="lsm-tree.Test.Database.LSMTree.StateMachine.propLockstep_RealImpl_MockFS_IO"' --quickcheck-replay="(SMGen 7870052982708161788 8378283829282625597,88)"
# CANNOT REPRODUCE
cabal run lsm-tree-test -- -p '/prop_example/' --quickcheck-replay="(SMGen 5733627160528804339 16188990791829584463,0)"
# CANNOT REPRODUCE (the original error is a timeout with GHC 8.10.7)
cabal run lsm-tree-test -- -p '$0=="lsm-tree.Test.Database.LSMTree.StateMachine.propLockstep_RealImpl_MockFS_IO"' |
19be2a2
to
d68478f
Compare
This is ready for review |
We don't have any guidelines, it's rather free form. I like the style that @dcoutts uses, for example in https://github.com/IntersectMBO/lsm-tree/pull/417/commits, because it creates kind of a story with a flow. Each commit generally changes some smallish thing and the message describes the goal, and if the changes are non-trivial, the messages describes the why and how. Subsequent commits then build on top of previous commit, which advances the story. IMO the smaller the commit with a clearly defined goal, the easier it is to review. Contrast that with less structure, for example just one larger commit, then it's less straightforward where to start, and in which order to review different parts of the diff, and to know which details are important and which aren't. In general, it's easier to sign off on a small diff that tackles only a single thing (or a few things). I can't speak for the review experience of my own PRs because I am not the one reviewing them, but I typically spend time rewriting the commit history to also craft a bit of a story. I don't really have rules for myself on how granular to make commits, but as a baseline I make sure that each commit can build and pass tests individually. |
@jorisdral There's two remaining open discussions:
Do you have any strong feelings either way on whether or not these should be implemented before merging? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like almost everything is resolved. I have two commits to include in this PR, however, if that's okay with you @wenkokke ?
8ca3798
to
35be751
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM! Let's squash/rewrite the history a bit, and then we can merge
This is required for properly modelling the model's response to disk faults in `createSnapshot`. The current implementation for `createSnapshot` in the real system can invalidate blob references even if creating the snapshot failed, so the model will invalidate blob references as well. This change might become obsolete once #478 is merged.
e0398ef
to
71f541a
Compare
chore: run pre-commit
This commit fixes the error in the open function for WriteBufferBlobs, but also contains a significant amount of refactoring based on feedback on the PR.
Co-authored-by: Joris Dral <[email protected]>
71f541a
to
1efe0e0
Compare
This is required for properly modelling the model's response to disk faults in `createSnapshot`. The current implementation for `createSnapshot` in the real system can invalidate blob references even if creating the snapshot failed, so the model will invalidate blob references as well. This change might become obsolete once #478 is merged.
This is a WIP PR that serialises the write buffer when creating a snapshot.
I'd love some feedback :)