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  }