go.etcd.io/etcd@v3.3.27+incompatible/functional/tester/stresser_runner.go (about) 1 // Copyright 2018 The etcd Authors 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 package tester 16 17 import ( 18 "fmt" 19 "io/ioutil" 20 "os/exec" 21 "syscall" 22 23 "github.com/coreos/etcd/functional/rpcpb" 24 25 "go.uber.org/zap" 26 "golang.org/x/time/rate" 27 ) 28 29 type runnerStresser struct { 30 stype rpcpb.Stresser 31 etcdClientEndpoint string 32 lg *zap.Logger 33 34 cmd *exec.Cmd 35 cmdStr string 36 args []string 37 rl *rate.Limiter 38 reqRate int 39 40 errc chan error 41 donec chan struct{} 42 } 43 44 func newRunnerStresser( 45 stype rpcpb.Stresser, 46 ep string, 47 lg *zap.Logger, 48 cmdStr string, 49 args []string, 50 rl *rate.Limiter, 51 reqRate int, 52 ) *runnerStresser { 53 rl.SetLimit(rl.Limit() - rate.Limit(reqRate)) 54 return &runnerStresser{ 55 stype: stype, 56 etcdClientEndpoint: ep, 57 cmdStr: cmdStr, 58 args: args, 59 rl: rl, 60 reqRate: reqRate, 61 errc: make(chan error, 1), 62 donec: make(chan struct{}), 63 } 64 } 65 66 func (rs *runnerStresser) setupOnce() (err error) { 67 if rs.cmd != nil { 68 return nil 69 } 70 71 rs.cmd = exec.Command(rs.cmdStr, rs.args...) 72 stderr, err := rs.cmd.StderrPipe() 73 if err != nil { 74 return err 75 } 76 77 go func() { 78 defer close(rs.donec) 79 out, err := ioutil.ReadAll(stderr) 80 if err != nil { 81 rs.errc <- err 82 } else { 83 rs.errc <- fmt.Errorf("(%v %v) stderr %v", rs.cmdStr, rs.args, string(out)) 84 } 85 }() 86 87 return rs.cmd.Start() 88 } 89 90 func (rs *runnerStresser) Stress() (err error) { 91 rs.lg.Info( 92 "stress START", 93 zap.String("stress-type", rs.stype.String()), 94 ) 95 if err = rs.setupOnce(); err != nil { 96 return err 97 } 98 return syscall.Kill(rs.cmd.Process.Pid, syscall.SIGCONT) 99 } 100 101 func (rs *runnerStresser) Pause() map[string]int { 102 rs.lg.Info( 103 "stress STOP", 104 zap.String("stress-type", rs.stype.String()), 105 ) 106 syscall.Kill(rs.cmd.Process.Pid, syscall.SIGSTOP) 107 return nil 108 } 109 110 func (rs *runnerStresser) Close() map[string]int { 111 syscall.Kill(rs.cmd.Process.Pid, syscall.SIGINT) 112 rs.cmd.Wait() 113 <-rs.donec 114 rs.rl.SetLimit(rs.rl.Limit() + rate.Limit(rs.reqRate)) 115 return nil 116 } 117 118 func (rs *runnerStresser) ModifiedKeys() int64 { 119 return 1 120 }