github.com/pingcap/chaos@v0.0.0-20190710112158-c86faf4b3719/pkg/check/porcupine/porcupine.go (about) 1 package porcupine 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/anishathalye/porcupine" 8 "github.com/pingcap/chaos/pkg/core" 9 ) 10 11 // Checker is a linearizability checker powered by Porcupine. 12 type Checker struct{} 13 14 // Check checks the history of operations meets liearizability or not with model. 15 // False means the history is not linearizable. 16 func (Checker) Check(m core.Model, ops []core.Operation) (bool, error) { 17 pModel := porcupine.Model{ 18 Init: m.Init, 19 Step: m.Step, 20 Equal: m.Equal, 21 } 22 events, err := ConvertOperationsToEvents(ops) 23 if err != nil { 24 return false, err 25 } 26 log.Printf("begin to verify %d events", len(events)) 27 return porcupine.CheckEvents(pModel, events), nil 28 } 29 30 // Name is the name of porcupine checker 31 func (Checker) Name() string { 32 return "porcupine_checker" 33 } 34 35 // ConvertOperationsToEvents converts core.Operations to porcupine.Event. 36 func ConvertOperationsToEvents(ops []core.Operation) ([]porcupine.Event, error) { 37 if len(ops)%2 != 0 { 38 return nil, fmt.Errorf("history is not complete") 39 } 40 41 procID := map[int64]uint{} 42 id := uint(0) 43 events := make([]porcupine.Event, 0, len(ops)) 44 for _, op := range ops { 45 if op.Action == core.InvokeOperation { 46 event := porcupine.Event{ 47 Kind: porcupine.CallEvent, 48 Id: id, 49 Value: op.Data, 50 } 51 events = append(events, event) 52 procID[op.Proc] = id 53 id++ 54 } else { 55 if op.Data == nil { 56 continue 57 } 58 59 matchID := procID[op.Proc] 60 delete(procID, op.Proc) 61 event := porcupine.Event{ 62 Kind: porcupine.ReturnEvent, 63 Id: matchID, 64 Value: op.Data, 65 } 66 events = append(events, event) 67 } 68 } 69 70 if len(procID) != 0 { 71 return nil, fmt.Errorf("history is not complete") 72 } 73 74 return events, nil 75 }