github.com/matrixorigin/matrixone@v0.7.0/pkg/vm/engine/tae/tasks/worker/worker.go (about)

     1  // Copyright 2021 Matrix Origin
     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 ops
    16  
    17  import (
    18  	"fmt"
    19  	"sync/atomic"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    22  	"github.com/matrixorigin/matrixone/pkg/logutil"
    23  	"github.com/matrixorigin/matrixone/pkg/vm/engine/tae/common"
    24  	iops "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks/ops/base"
    25  	iw "github.com/matrixorigin/matrixone/pkg/vm/engine/tae/tasks/worker/base"
    26  )
    27  
    28  type Cmd = uint8
    29  
    30  const (
    31  	QUIT Cmd = iota
    32  )
    33  
    34  const (
    35  	CREATED int32 = iota
    36  	RUNNING
    37  	StoppingReceiver
    38  	StoppingCMD
    39  	STOPPED
    40  )
    41  
    42  const (
    43  	QueueSize = 10000
    44  )
    45  
    46  var (
    47  	_ iw.IOpWorker = (*OpWorker)(nil)
    48  )
    49  
    50  type OpExecFunc func(op iops.IOp)
    51  
    52  type Stats struct {
    53  	Processed atomic.Uint64
    54  	Successed atomic.Uint64
    55  	Failed    atomic.Uint64
    56  	AvgTime   atomic.Int64
    57  }
    58  
    59  func (s *Stats) AddProcessed() {
    60  	s.Processed.Add(1)
    61  }
    62  
    63  func (s *Stats) AddSuccessed() {
    64  	s.Successed.Add(1)
    65  }
    66  
    67  func (s *Stats) AddFailed() {
    68  	s.Failed.Add(1)
    69  }
    70  
    71  func (s *Stats) RecordTime(t int64) {
    72  	procced := s.Processed.Load()
    73  	avg := s.AvgTime.Load()
    74  	//TODO: avgTime is wrong
    75  	s.AvgTime.Store((avg*int64(procced-1) + t) / int64(procced))
    76  }
    77  
    78  func (s *Stats) String() string {
    79  	r := fmt.Sprintf("Total: %d, Succ: %d, Fail: %d, AvgTime: %dus",
    80  		s.Processed.Load(),
    81  		s.Failed.Load(),
    82  		s.AvgTime.Load(),
    83  		s.AvgTime.Load())
    84  	return r
    85  }
    86  
    87  type OpWorker struct {
    88  	Name       string
    89  	OpC        chan iops.IOp
    90  	CmdC       chan Cmd
    91  	State      atomic.Int32
    92  	Pending    atomic.Int64
    93  	ClosedCh   chan struct{}
    94  	Stats      Stats
    95  	ExecFunc   OpExecFunc
    96  	CancelFunc OpExecFunc
    97  }
    98  
    99  func NewOpWorker(name string, args ...int) *OpWorker {
   100  	var l int
   101  	if len(args) == 0 {
   102  		l = QueueSize
   103  	} else {
   104  		l = args[0]
   105  		if l < 0 {
   106  			logutil.Warnf("Create OpWorker with negtive queue size %d", l)
   107  			l = QueueSize
   108  		}
   109  	}
   110  	if name == "" {
   111  		name = fmt.Sprintf("[worker-%d]", common.NextGlobalSeqNum())
   112  	}
   113  	worker := &OpWorker{
   114  		Name:     name,
   115  		OpC:      make(chan iops.IOp, l),
   116  		CmdC:     make(chan Cmd, l),
   117  		ClosedCh: make(chan struct{}),
   118  	}
   119  	worker.State.Store(CREATED)
   120  	worker.ExecFunc = worker.onOp
   121  	worker.CancelFunc = worker.opCancelOp
   122  	return worker
   123  }
   124  
   125  func (w *OpWorker) Start() {
   126  	logutil.Debugf("%s Started", w.Name)
   127  	if w.State.Load() != CREATED {
   128  		panic(fmt.Sprintf("logic error: %v", w.State.Load()))
   129  	}
   130  	w.State.Store(RUNNING)
   131  	go func() {
   132  		for {
   133  			state := w.State.Load()
   134  			if state == STOPPED {
   135  				break
   136  			}
   137  			select {
   138  			case op := <-w.OpC:
   139  				w.ExecFunc(op)
   140  				// if state == RUNNING {
   141  				// 	w.ExecFunc(op)
   142  				// } else {
   143  				// 	w.CancelFunc(op)
   144  				// }
   145  				w.Pending.Add(-1)
   146  			case cmd := <-w.CmdC:
   147  				w.onCmd(cmd)
   148  			}
   149  		}
   150  	}()
   151  }
   152  
   153  func (w *OpWorker) Stop() {
   154  	w.StopReceiver()
   155  	w.WaitStop()
   156  	logutil.Debugf("%s Stopped", w.Name)
   157  }
   158  
   159  func (w *OpWorker) StopReceiver() {
   160  	state := w.State.Load()
   161  	if state >= StoppingReceiver {
   162  		return
   163  	}
   164  	w.State.CompareAndSwap(state, StoppingReceiver)
   165  }
   166  
   167  func (w *OpWorker) WaitStop() {
   168  	state := w.State.Load()
   169  	if state <= RUNNING {
   170  		panic("logic error")
   171  	}
   172  	if state == STOPPED {
   173  		return
   174  	}
   175  	if w.State.CompareAndSwap(StoppingReceiver, StoppingCMD) {
   176  		pending := w.Pending.Load()
   177  		for {
   178  			if pending == 0 {
   179  				break
   180  			}
   181  			pending = w.Pending.Load()
   182  		}
   183  		w.CmdC <- QUIT
   184  	}
   185  	<-w.ClosedCh
   186  }
   187  
   188  func (w *OpWorker) SendOp(op iops.IOp) bool {
   189  	state := w.State.Load()
   190  	if state != RUNNING {
   191  		return false
   192  	}
   193  	w.Pending.Add(1)
   194  	if w.State.Load() != RUNNING {
   195  		w.Pending.Add(-1)
   196  		return false
   197  	}
   198  	w.OpC <- op
   199  	return true
   200  }
   201  
   202  func (w *OpWorker) opCancelOp(op iops.IOp) {
   203  	op.SetError(moerr.NewInternalErrorNoCtx("op cancelled"))
   204  }
   205  
   206  func (w *OpWorker) onOp(op iops.IOp) {
   207  	err := op.OnExec()
   208  	w.Stats.AddProcessed()
   209  	if err != nil {
   210  		w.Stats.AddFailed()
   211  	} else {
   212  		w.Stats.AddSuccessed()
   213  	}
   214  	op.SetError(err)
   215  	w.Stats.RecordTime(op.GetExecutTime())
   216  }
   217  
   218  func (w *OpWorker) onCmd(cmd Cmd) {
   219  	switch cmd {
   220  	case QUIT:
   221  		// log.Infof("Quit OpWorker")
   222  		close(w.CmdC)
   223  		close(w.OpC)
   224  		if !w.State.CompareAndSwap(StoppingCMD, STOPPED) {
   225  			panic("logic error")
   226  		}
   227  		w.ClosedCh <- struct{}{}
   228  	default:
   229  		panic(fmt.Sprintf("Unsupported cmd %d", cmd))
   230  	}
   231  }
   232  
   233  func (w *OpWorker) StatsString() string {
   234  	s := fmt.Sprintf("| Stats | %s | w | %s", w.Stats.String(), w.Name)
   235  	return s
   236  }