|
| 1 | +-------------------------- MODULE MasterDoubledTest ---------------------------- |
| 2 | +EXTENDS storage, TLC |
| 3 | + |
| 4 | +(***************************************************************************) |
| 5 | +(* Cluster: two replica sets, two storages each. *) |
| 6 | +(* We'll force rs1 to send a bucket to rs2, lose replication, and failover.*) |
| 7 | +(***************************************************************************) |
| 8 | + |
| 9 | +CONSTANTS |
| 10 | + b1, b2, b3, b4 |
| 11 | + |
| 12 | +StoragesC == {"s1", "s2", "s3", "s4"} |
| 13 | +ReplicaSetsC == {"rs1", "rs2"} |
| 14 | +BucketIdsC == {b1, b2, b3, b4} |
| 15 | +StorageAssignmentsC == |
| 16 | + [rs1 |-> {"s1", "s2"}, |
| 17 | + rs2 |-> {"s3", "s4"}] |
| 18 | +BucketAssignmentsC == |
| 19 | + [rs1 |-> {b1, b2}, |
| 20 | + rs2 |-> {b3, b4}] |
| 21 | +MasterAssignmentsC == |
| 22 | + [rs1 |-> {"s1"}, |
| 23 | + rs2 |-> {"s3"}] |
| 24 | + |
| 25 | +(***************************************************************************) |
| 26 | +(* Variables and initialization *) |
| 27 | +(***************************************************************************) |
| 28 | + |
| 29 | +VARIABLE phase |
| 30 | + |
| 31 | +TestInit == |
| 32 | + /\ Init |
| 33 | + /\ phase = 1 |
| 34 | + |
| 35 | +(***************************************************************************) |
| 36 | +(* Phase-driven Next *) |
| 37 | +(***************************************************************************) |
| 38 | + |
| 39 | +TestNext == |
| 40 | + \/ /\ phase = 1 |
| 41 | + /\ ~( |
| 42 | + storages["s1"].buckets[b1].status = "SENT" |
| 43 | + /\ storages["s3"].buckets[b1].status = "ACTIVE" |
| 44 | + ) |
| 45 | + /\ \E i \in {"s1"}, j \in {"s3"}, b \in {b1} : |
| 46 | + \/ StorageStateApply(i, BucketSendStart(StorageState(i), b, j)) |
| 47 | + \/ /\ Len(StorageState(j).networkReceive[i]) > 0 |
| 48 | + /\ \/ StorageStateApply(j, BucketRecvStart(StorageState(j), i)) |
| 49 | + \/ StorageStateApply(j, BucketRecvFinish(StorageState(j), i)) |
| 50 | + \/ /\ Len(StorageState(i).networkReceive[j]) > 0 |
| 51 | + /\ StorageStateApply(i, BucketSendFinish(StorageState(i), j)) |
| 52 | + /\ UNCHANGED <<storageToReplicaset, phase>> |
| 53 | + |
| 54 | + \/ /\ phase = 1 |
| 55 | + /\ storages["s1"].buckets[b1].status = "SENT" |
| 56 | + /\ storages["s3"].buckets[b1].status = "ACTIVE" |
| 57 | + /\ UNCHANGED <<network, storages, storageToReplicaset>> |
| 58 | + /\ phase' = 3 |
| 59 | + |
| 60 | + \/ /\ phase = 3 |
| 61 | + /\ \E i \in {"s2"} : |
| 62 | + /\ StorageStateApply(i, BecomeMaster(StorageState(i))) |
| 63 | + /\ PrintT("Phase 3: failover, s2 becomes master") |
| 64 | + /\ phase' = 4 |
| 65 | + |
| 66 | + \/ /\ phase = 4 |
| 67 | + /\ UNCHANGED <<network, storages, storageToReplicaset, phase>> |
| 68 | + /\ PrintT("Phase 4: check for double ACTIVE") |
| 69 | + |
| 70 | +(***************************************************************************) |
| 71 | +(* Spec *) |
| 72 | +(***************************************************************************) |
| 73 | + |
| 74 | +Spec == |
| 75 | + TestInit /\ [][TestNext]_<<network, storages, storageToReplicaset, phase>> |
| 76 | + |
| 77 | +(***************************************************************************) |
| 78 | +(* STATE INVARIANTS *) |
| 79 | +(***************************************************************************) |
| 80 | + |
| 81 | +NoActiveSimultaneousInv == |
| 82 | + \* No bucket can be ACTIVE in storages belonging to different ReplicaSets |
| 83 | + \A b \in BucketIds : |
| 84 | + \A rs1, rs2 \in ReplicaSets : |
| 85 | + rs1 # rs2 => |
| 86 | + ~(\E s1, s2 \in Storages : |
| 87 | + storageToReplicaset[s1] = rs1 /\ |
| 88 | + storageToReplicaset[s2] = rs2 /\ |
| 89 | + storages[s1].status = "master" /\ |
| 90 | + storages[s2].status = "master" /\ |
| 91 | + storages[s1].buckets[b].status = "ACTIVE" /\ |
| 92 | + storages[s2].buckets[b].status = "ACTIVE") |
| 93 | +=============================================================================== |
0 commit comments