-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTwophase4_pbt.lean
More file actions
77 lines (61 loc) · 2.33 KB
/
Copy pathTwophase4_pbt.lean
File metadata and controls
77 lines (61 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
/-
Property-based testing of the two-phase commit protocol with Plausible.
Copyright (c) 2025 Igor Konnov
Released under MIT license as described in the file LICENSE.
Authors: Igor Konnov, 2025
-/
import Plausible
import Twophase.System
open Plausible
set_option maxRecDepth 1000000
-- An instance of three resource managers.
inductive RM
| RM1
| RM2
| RM3
| RM4
deriving Repr, DecidableEq, Hashable, Inhabited
-- define a generator for RM
instance RM.shrinkable: Shrinkable RM where
shrink := fun (_: RM) => []
def genRm: Gen RM := (Gen.elements [ RM.RM1, RM.RM2, RM.RM3, RM.RM4 ] (by decide))
instance : SampleableExt RM :=
SampleableExt.mkSelfContained genRm
#sample RM
-- define a generator for Action RM
instance Action.shrinkable: Shrinkable (@Action RM) where
shrink := fun (_: @Action RM) => []
def genAction: Gen (@Action RM) :=
Gen.oneOf #[
Gen.elements [ Action.TMCommit, Action.TMAbort] (by decide),
(do return (Action.TMRcvPrepared (← genRm))),
(do return (Action.RMPrepare (← genRm))),
(do return (Action.RMChooseToAbort (← genRm))),
(do return (Action.RMRcvCommitMsg (← genRm))),
(do return (Action.RMRcvAbortMsg (← genRm)))
]
(by decide)
instance : SampleableExt (@Action RM) :=
SampleableExt.mkSelfContained genAction
#sample @Action RM
def genSchedule: Gen (List (@Action RM)) :=
Gen.listOf genAction
-- given a concrete schedule, inductively apply the schedule and check the invariant
def applySchedule (s: ProtocolState RM) (schedule: List (@Action RM))
(inv: ProtocolState RM → Bool): ProtocolState RM :=
schedule.foldl (fun s a => if inv s then (next s a).getD s else s) s
-- apply a schedule to the initial state
def checkInvariant (schedule: List (@Action RM)) (inv: ProtocolState RM → Bool): Bool :=
let init_s := init [ RM.RM1, RM.RM2, RM.RM3, RM.RM4 ]
let last_s := applySchedule init_s schedule inv
inv last_s
-- consistentInv
example schedule:
let inv := fun (s: ProtocolState RM) =>
let existsAborted :=
∅ ≠ (Finset.filter (fun rm => s.rmState.get? rm = RMState.Aborted) s.all)
let existsCommitted :=
∅ ≠ (Finset.filter (fun rm => s.rmState.get? rm = RMState.Committed) s.all)
¬existsAborted ∨ ¬existsCommitted
checkInvariant schedule inv
:= by plausible (config := { numInst := 3000, maxSize := 100 })