github.com/pingcap/chaos@v0.0.0-20190710112158-c86faf4b3719/pkg/model/cas_register.go (about)

     1  package model
     2  
     3  import (
     4  	"encoding/json"
     5  
     6  	"github.com/pingcap/chaos/pkg/core"
     7  	"github.com/pingcap/chaos/pkg/history"
     8  )
     9  
    10  // CasOp is an operation.
    11  type CasOp int
    12  
    13  // cas operation
    14  const (
    15  	CasRegisterRead CasOp = iota
    16  	CasRegisterWrite
    17  	CasRegisterCAS
    18  )
    19  
    20  // CasRegisterRequest is the request that is issued to a cas register.
    21  type CasRegisterRequest struct {
    22  	Op   CasOp
    23  	Arg1 int // used for write, or for CAS from argument
    24  	Arg2 int // used for CAS to argument
    25  }
    26  
    27  // CasRegisterResponse is the response returned by a cas register.
    28  type CasRegisterResponse struct {
    29  	Ok      bool // used for CAS
    30  	Exists  bool // used for read
    31  	Value   int  // used for read
    32  	Unknown bool // used when operation times out
    33  }
    34  
    35  var _ core.UnknownResponse = (*CasRegisterResponse)(nil)
    36  
    37  // IsUnknown implements UnknownResponse interface
    38  func (r CasRegisterResponse) IsUnknown() bool {
    39  	return r.Unknown
    40  }
    41  
    42  type casRegister struct {
    43  	perparedState *int
    44  }
    45  
    46  func (c *casRegister) Prepare(state interface{}) {
    47  	s := state.(int)
    48  	c.perparedState = &s
    49  }
    50  
    51  func (c *casRegister) Init() interface{} {
    52  	if c.perparedState != nil {
    53  		return *c.perparedState
    54  	}
    55  	return -1
    56  }
    57  
    58  func (*casRegister) Step(state interface{}, input interface{}, output interface{}) (bool, interface{}) {
    59  	st := state.(int)
    60  	inp := input.(CasRegisterRequest)
    61  	out := output.(CasRegisterResponse)
    62  	if inp.Op == CasRegisterRead {
    63  		// read
    64  		ok := (out.Exists == false && st == -1) || (out.Exists == true && st == out.Value) || out.Unknown
    65  		return ok, state
    66  	} else if inp.Op == CasRegisterWrite {
    67  		// write
    68  		return true, inp.Arg1
    69  	}
    70  
    71  	// cas
    72  	ok := (inp.Arg1 == st && out.Ok) || (inp.Arg1 != st && !out.Ok) || out.Unknown
    73  	result := st
    74  	if inp.Arg1 == st {
    75  		result = inp.Arg2
    76  	}
    77  	return ok, result
    78  }
    79  
    80  func (*casRegister) Equal(state1, state2 interface{}) bool {
    81  	st1 := state1.(int)
    82  	st2 := state2.(int)
    83  	return st1 == st2
    84  }
    85  
    86  func (*casRegister) Name() string {
    87  	return "cas_register"
    88  }
    89  
    90  // CasRegisterModel returns a cas register model
    91  func CasRegisterModel() core.Model {
    92  	return &casRegister{}
    93  }
    94  
    95  type casRegisterParser struct {
    96  }
    97  
    98  func (p casRegisterParser) OnRequest(data json.RawMessage) (interface{}, error) {
    99  	r := CasRegisterRequest{}
   100  	err := json.Unmarshal(data, &r)
   101  	return r, err
   102  }
   103  
   104  func (p casRegisterParser) OnResponse(data json.RawMessage) (interface{}, error) {
   105  	r := CasRegisterResponse{}
   106  	err := json.Unmarshal(data, &r)
   107  	if r.Unknown {
   108  		return nil, err
   109  	}
   110  	return r, nil
   111  }
   112  
   113  func (p casRegisterParser) OnNoopResponse() interface{} {
   114  	return CasRegisterResponse{Unknown: true}
   115  }
   116  
   117  func (p casRegisterParser) OnState(data json.RawMessage) (interface{}, error) {
   118  	var state int
   119  	err := json.Unmarshal(data, &state)
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	return state, nil
   124  }
   125  
   126  // CasRegisterParser parses CasRegister history.
   127  func CasRegisterParser() history.RecordParser {
   128  	return casRegisterParser{}
   129  }