github.com/pingcap/failpoint@v0.0.0-20240412033321-fd0796e60f86/terms.go (about)

     1  // Copyright 2019 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Copyright 2016 CoreOS, Inc.
    16  //
    17  // Licensed under the Apache License, Version 2.0 (the "License");
    18  // you may not use this file except in compliance with the License.
    19  // You may obtain a copy of the License at
    20  //
    21  //     http://www.apache.org/licenses/LICENSE-2.0
    22  //
    23  // Unless required by applicable law or agreed to in writing, software
    24  // distributed under the License is distributed on an "AS IS" BASIS,
    25  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    26  // See the License for the specific language governing permissions and
    27  // limitations under the License.
    28  
    29  package failpoint
    30  
    31  import (
    32  	"fmt"
    33  	"math/rand"
    34  	"os"
    35  	"os/exec"
    36  	"strings"
    37  	"sync"
    38  	"time"
    39  )
    40  
    41  func init() {
    42  	rand.Seed(time.Now().Unix())
    43  }
    44  
    45  // terms encodes the state for a failpoint term string (see fail(9) for examples)
    46  // <fp> :: <term> ( "->" <term> )*
    47  type terms struct {
    48  	// chain is a slice of all the terms from desc
    49  	chain []*term
    50  	// desc is the full term given for the failpoint
    51  	desc string
    52  	// mu protects the state of the terms chain
    53  	mu sync.Mutex
    54  }
    55  
    56  // term is an executable unit of the failpoint terms chain
    57  type term struct {
    58  	desc string
    59  
    60  	mods mod
    61  	act  actFunc
    62  	val  interface{}
    63  
    64  	parent *terms
    65  	fp     *Failpoint
    66  }
    67  
    68  type mod interface {
    69  	allow() bool
    70  }
    71  
    72  type modCount struct{ c int }
    73  
    74  func (mc *modCount) allow() bool {
    75  	if mc.c > 0 {
    76  		mc.c--
    77  		return true
    78  	}
    79  	return false
    80  }
    81  
    82  type modProb struct{ p float64 }
    83  
    84  func (mp *modProb) allow() bool { return rand.Float64() <= mp.p }
    85  
    86  type modList struct{ l []mod }
    87  
    88  func (ml *modList) allow() bool {
    89  	for _, m := range ml.l {
    90  		if !m.allow() {
    91  			return false
    92  		}
    93  	}
    94  	return true
    95  }
    96  
    97  func newTerms(desc string, fp *Failpoint) (*terms, error) {
    98  	chain, err := parse(desc, fp)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  	t := &terms{chain: chain, desc: desc}
   103  	for _, c := range chain {
   104  		c.parent = t
   105  	}
   106  	return t, nil
   107  }
   108  
   109  func (t *terms) String() string { return t.desc }
   110  
   111  func (t *terms) eval() (Value, error) {
   112  	t.mu.Lock()
   113  	defer t.mu.Unlock()
   114  	for _, term := range t.chain {
   115  		if term.mods.allow() {
   116  			return term.do()
   117  		}
   118  	}
   119  	return nil, ErrNotAllowed
   120  }
   121  
   122  // split terms from a -> b -> ... into [a, b, ...]
   123  func parse(desc string, fp *Failpoint) (chain []*term, err error) {
   124  	origDesc := desc
   125  	for len(desc) != 0 {
   126  		t := parseTerm(desc, fp)
   127  		if t == nil {
   128  			return nil, fmt.Errorf("failpoint: failed to parse %q past %q", origDesc, desc)
   129  		}
   130  		desc = desc[len(t.desc):]
   131  		chain = append(chain, t)
   132  		if len(desc) >= 2 {
   133  			if !strings.HasPrefix(desc, "->") {
   134  				return nil, fmt.Errorf("failpoint: failed to parse %q past %q, expected \"->\"", origDesc, desc)
   135  			}
   136  			desc = desc[2:]
   137  		}
   138  	}
   139  	return chain, nil
   140  }
   141  
   142  // <term> :: <mod> <act> [ "(" <val> ")" ]
   143  func parseTerm(desc string, fp *Failpoint) *term {
   144  	t := &term{}
   145  	modStr, mods := parseMod(desc)
   146  	t.mods = &modList{mods}
   147  	actStr, act := parseAct(desc[len(modStr):])
   148  	t.act = act
   149  	valStr, val := parseVal(desc[len(modStr)+len(actStr):])
   150  	t.val = val
   151  	t.desc = desc[:len(modStr)+len(actStr)+len(valStr)]
   152  	t.fp = fp
   153  	if len(t.desc) == 0 {
   154  		return nil
   155  	}
   156  	return t
   157  }
   158  
   159  // <mod> :: ((<float>|<int> "%")|(<int> "*" ))*
   160  func parseMod(desc string) (ret string, mods []mod) {
   161  	applyPercent := func(s string, v float64) {
   162  		ret = ret + desc[:len(s)+1]
   163  		mods = append(mods, &modProb{v / 100.0})
   164  		desc = desc[len(s)+1:]
   165  	}
   166  	applyCount := func(s string, v int) {
   167  		ret = ret + desc[:len(s)+1]
   168  		mods = append(mods, &modCount{v})
   169  		desc = desc[len(s)+1:]
   170  	}
   171  	for {
   172  		s, v := parseIntFloat(desc)
   173  		if len(s) == 0 {
   174  			break
   175  		}
   176  		if len(s) == len(desc) {
   177  			return "", nil
   178  		}
   179  		switch v := v.(type) {
   180  		case float64:
   181  			if desc[len(s)] != '%' {
   182  				return "", nil
   183  			}
   184  			applyPercent(s, v)
   185  		case int:
   186  			switch desc[len(s)] {
   187  			case '%':
   188  				applyPercent(s, float64(v))
   189  			case '*':
   190  				applyCount(s, v)
   191  			default:
   192  				return "", nil
   193  			}
   194  		default:
   195  			panic("???")
   196  		}
   197  	}
   198  	return ret, mods
   199  }
   200  
   201  // parseIntFloat parses an int or float from a string and returns the string
   202  // it parsed it from (unlike scanf).
   203  func parseIntFloat(desc string) (string, interface{}) {
   204  	// parse for ints
   205  	i := 0
   206  	for i < len(desc) {
   207  		if desc[i] < '0' || desc[i] > '9' {
   208  			break
   209  		}
   210  		i++
   211  	}
   212  	if i == 0 {
   213  		return "", nil
   214  	}
   215  
   216  	intVal := int(0)
   217  	_, err := fmt.Sscanf(desc[:i], "%d", &intVal)
   218  	if err != nil {
   219  		return "", nil
   220  	}
   221  	if len(desc) == i {
   222  		return desc[:i], intVal
   223  	}
   224  	if desc[i] != '.' {
   225  		return desc[:i], intVal
   226  	}
   227  
   228  	// parse for floats
   229  	i++
   230  	if i == len(desc) {
   231  		return desc[:i], float64(intVal)
   232  	}
   233  
   234  	j := i
   235  	for i < len(desc) {
   236  		if desc[i] < '0' || desc[i] > '9' {
   237  			break
   238  		}
   239  		i++
   240  	}
   241  	if j == i {
   242  		return desc[:i], float64(intVal)
   243  	}
   244  
   245  	f := float64(0)
   246  	if _, err = fmt.Sscanf(desc[:i], "%f", &f); err != nil {
   247  		return "", nil
   248  	}
   249  	return desc[:i], f
   250  }
   251  
   252  // parseAct parses an action
   253  // <act> :: "off" | "return" | "sleep" | "panic" | "break" | "print" | "pause"
   254  func parseAct(desc string) (string, actFunc) {
   255  	for k, v := range actMap {
   256  		if strings.HasPrefix(desc, k) {
   257  			return k, v
   258  		}
   259  	}
   260  	return "", nil
   261  }
   262  
   263  // <val> :: <int> | <string> | <bool> | <nothing>
   264  func parseVal(desc string) (string, interface{}) {
   265  	// return => struct{}
   266  	if len(desc) == 0 {
   267  		return "", struct{}{}
   268  	}
   269  	// malformed
   270  	if len(desc) == 1 || desc[0] != '(' {
   271  		return "", nil
   272  	}
   273  	// return() => struct{}
   274  	if desc[1] == ')' {
   275  		return "()", struct{}{}
   276  	}
   277  	// return("s") => string
   278  	s := ""
   279  	n, err := fmt.Sscanf(desc[1:], "%q", &s)
   280  	if n == 1 && err == nil {
   281  		return desc[:len(s)+4], s
   282  	}
   283  	// return(1) => int
   284  	v := 0
   285  	n, err = fmt.Sscanf(desc[1:], "%d", &v)
   286  	if n == 1 && err == nil {
   287  		return desc[:len(fmt.Sprintf("%d", v))+2], v
   288  	}
   289  	// return(true) => bool
   290  	b := false
   291  	n, err = fmt.Sscanf(desc[1:], "%t", &b)
   292  	if n == 1 && err == nil {
   293  		return desc[:len(fmt.Sprintf("%t", b))+2], b
   294  	}
   295  	// unknown type; malformed input?
   296  	return "", nil
   297  }
   298  
   299  type actFunc func(*term) (interface{}, error)
   300  
   301  var actMap = map[string]actFunc{
   302  	"off":    actOff,
   303  	"return": actReturn,
   304  	"sleep":  actSleep,
   305  	"panic":  actPanic,
   306  	"break":  actBreak,
   307  	"print":  actPrint,
   308  	"pause":  actPause,
   309  }
   310  
   311  func (t *term) do() (interface{}, error) { return t.act(t) }
   312  
   313  func actOff(t *term) (interface{}, error) { return nil, nil }
   314  
   315  func actReturn(t *term) (interface{}, error) { return t.val, nil }
   316  
   317  func actSleep(t *term) (interface{}, error) {
   318  	var dur time.Duration
   319  	switch v := t.val.(type) {
   320  	case int:
   321  		dur = time.Duration(v) * time.Millisecond
   322  	case string:
   323  		vDur, err := time.ParseDuration(v)
   324  		if err != nil {
   325  			return nil, fmt.Errorf("failpoint: could not parse sleep(%v)", v)
   326  		}
   327  		dur = vDur
   328  	default:
   329  		return nil, fmt.Errorf("failpoint: ignoring sleep(%v)", v)
   330  	}
   331  	time.Sleep(dur)
   332  	return nil, nil
   333  }
   334  
   335  func actPause(t *term) (interface{}, error) {
   336  	if t.fp != nil {
   337  		t.fp.Pause()
   338  	}
   339  	return nil, nil
   340  }
   341  
   342  func actPanic(t *term) (interface{}, error) {
   343  	if t.val != nil {
   344  		panic(fmt.Sprintf("failpoint panic: %v", t.val))
   345  	}
   346  	panic("failpoint panic")
   347  }
   348  
   349  func actBreak(t *term) (interface{}, error) {
   350  	p, perr := exec.LookPath(os.Args[0])
   351  	if perr != nil {
   352  		panic(perr)
   353  	}
   354  	cmd := exec.Command("gdb", p, fmt.Sprintf("%d", os.Getpid()))
   355  	cmd.Stdin = os.Stdin
   356  	cmd.Stdout = os.Stdout
   357  	cmd.Stderr = os.Stderr
   358  	if err := cmd.Start(); err != nil {
   359  		panic(err)
   360  	}
   361  
   362  	// wait for gdb prompt
   363  	// XXX: tried doing this by piping stdout here and waiting on "(gdb) "
   364  	// but the the output won't appear since the process is STOPed and
   365  	// can't copy it back to the actual stdout
   366  	time.Sleep(3 * time.Second)
   367  
   368  	// don't zombie gdb
   369  	go cmd.Wait()
   370  	return nil, nil
   371  }
   372  
   373  func actPrint(t *term) (interface{}, error) {
   374  	fmt.Println("failpoint print:", t.val)
   375  	return nil, nil
   376  }