github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/function/ctl/cmd_label.go (about)

     1  // Copyright 2021 - 2023 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 ctl
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"regexp"
    21  	"strconv"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/matrixorigin/matrixone/pkg/clusterservice"
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    28  	querypb "github.com/matrixorigin/matrixone/pkg/pb/query"
    29  	"github.com/matrixorigin/matrixone/pkg/pb/timestamp"
    30  	"github.com/matrixorigin/matrixone/pkg/vm/process"
    31  )
    32  
    33  type cnLabel struct {
    34  	uuid   string
    35  	key    string
    36  	values []string
    37  }
    38  
    39  type cnWorkState struct {
    40  	uuid  string
    41  	state int
    42  }
    43  
    44  type parser interface {
    45  	parseLabel() cnLabel
    46  	parseWorkState() cnWorkState
    47  }
    48  
    49  type singleValue struct {
    50  	s   string
    51  	reg *regexp.Regexp
    52  }
    53  
    54  func newSingleValue(s string, reg *regexp.Regexp) *singleValue {
    55  	return &singleValue{
    56  		s:   s,
    57  		reg: reg,
    58  	}
    59  }
    60  
    61  func (s *singleValue) parseLabel() cnLabel {
    62  	items := s.reg.FindStringSubmatch(s.s)
    63  	var c cnLabel
    64  	c.uuid = items[1]
    65  	c.key = items[2]
    66  	c.values = []string{items[3]}
    67  	return c
    68  }
    69  
    70  func (s *singleValue) parseWorkState() cnWorkState {
    71  	items := s.reg.FindStringSubmatch(s.s)
    72  	var c cnWorkState
    73  	c.uuid = items[1]
    74  	c.state, _ = strconv.Atoi(items[2])
    75  	return c
    76  }
    77  
    78  type multiValues struct {
    79  	s   string
    80  	reg *regexp.Regexp
    81  }
    82  
    83  func newMultiValue(s string, reg *regexp.Regexp) *multiValues {
    84  	return &multiValues{
    85  		s:   s,
    86  		reg: reg,
    87  	}
    88  }
    89  
    90  func (m *multiValues) parseLabel() cnLabel {
    91  	items := m.reg.FindStringSubmatch(m.s)
    92  	var c cnLabel
    93  	c.uuid = items[1]
    94  	c.key = items[2]
    95  	c.values = strings.Split(items[3], ",")
    96  	return c
    97  }
    98  
    99  // not implemented.
   100  func (m *multiValues) parseWorkState() cnWorkState {
   101  	return cnWorkState{}
   102  }
   103  
   104  const (
   105  	singlePattern      = `^([a-zA-Z0-9\-_]+):([a-zA-Z0-9_]+):([a-zA-Z0-9_]+)$`
   106  	multiplePattern    = `^([a-zA-Z0-9\-_]+):([a-zA-Z0-9_]+):\[([a-zA-Z0-9_]+(,[a-zA-Z0-9_]+)*)\]$`
   107  	singlePatternState = `^([a-zA-Z0-9\-_]+):([0-9]+)$`
   108  )
   109  
   110  var (
   111  	singlePatternReg      = regexp.MustCompile(singlePattern)
   112  	multiPatternReg       = regexp.MustCompile(multiplePattern)
   113  	singleStatePatternReg = regexp.MustCompile(singlePatternState)
   114  )
   115  
   116  func identifyParser(param string) parser {
   117  	if matched := singlePatternReg.MatchString(param); matched {
   118  		return newSingleValue(param, singlePatternReg)
   119  	}
   120  	if matched := multiPatternReg.MatchString(param); matched {
   121  		return newMultiValue(param, multiPatternReg)
   122  	}
   123  	return nil
   124  }
   125  
   126  func identifyStateParser(param string) parser {
   127  	if matched := singleStatePatternReg.MatchString(param); matched {
   128  		return newSingleValue(param, singleStatePatternReg)
   129  	}
   130  	return nil
   131  }
   132  
   133  // parseParameter parses the parameter which contains CN uuid and its label
   134  // information. Its format can be: (1) cn:key:value (2) cn:key:[v1,v2,v3]
   135  func parseCNLabel(param string) (cnLabel, error) {
   136  	p := identifyParser(param)
   137  	if p == nil {
   138  		return cnLabel{}, moerr.NewInternalErrorNoCtx("format is: cn:key:value or cn:key:[v1,v2,...]")
   139  	}
   140  	return p.parseLabel(), nil
   141  }
   142  
   143  func handleSetLabel(proc *process.Process,
   144  	service serviceType,
   145  	parameter string,
   146  	sender requestSender) (Result, error) {
   147  	cluster := clusterservice.GetMOCluster()
   148  	c, err := parseCNLabel(parameter)
   149  	if err != nil {
   150  		return Result{}, err
   151  	}
   152  	kvs := make(map[string][]string, 1)
   153  	kvs[c.key] = c.values
   154  	if err := cluster.DebugUpdateCNLabel(c.uuid, kvs); err != nil {
   155  		return Result{}, err
   156  	}
   157  	return Result{
   158  		Method: LabelMethod,
   159  		Data:   "OK",
   160  	}, nil
   161  }
   162  
   163  func parseCNWorkState(param string) (cnWorkState, error) {
   164  	p := identifyStateParser(param)
   165  	if p == nil {
   166  		return cnWorkState{}, moerr.NewInternalErrorNoCtx("format is: cn:key:value or cn:key:[v1,v2,...]")
   167  	}
   168  	return p.parseWorkState(), nil
   169  }
   170  
   171  func handleSetWorkState(proc *process.Process,
   172  	service serviceType,
   173  	parameter string,
   174  	sender requestSender) (Result, error) {
   175  	cluster := clusterservice.GetMOCluster()
   176  	c, err := parseCNWorkState(parameter)
   177  	if err != nil {
   178  		return Result{}, err
   179  	}
   180  	if err := cluster.DebugUpdateCNWorkState(c.uuid, c.state); err != nil {
   181  		return Result{}, err
   182  	}
   183  	return Result{
   184  		Method: LabelMethod,
   185  		Data:   "OK",
   186  	}, nil
   187  }
   188  
   189  func handleSyncCommit(
   190  	proc *process.Process,
   191  	service serviceType,
   192  	parameter string,
   193  	sender requestSender) (Result, error) {
   194  	qt := proc.QueryClient
   195  	mc := clusterservice.GetMOCluster()
   196  	var addrs []string
   197  	mc.GetCNService(
   198  		clusterservice.NewSelector(),
   199  		func(c metadata.CNService) bool {
   200  			addrs = append(addrs, c.QueryAddress)
   201  			return true
   202  		})
   203  	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
   204  	defer cancel()
   205  	maxCommitTS := timestamp.Timestamp{}
   206  	for _, addr := range addrs {
   207  		req := qt.NewRequest(querypb.CmdMethod_GetCommit)
   208  		resp, err := qt.SendMessage(ctx, addr, req)
   209  		if err != nil {
   210  			return Result{}, err
   211  		}
   212  		if maxCommitTS.Less(resp.GetCommit.CurrentCommitTS) {
   213  			maxCommitTS = resp.GetCommit.CurrentCommitTS
   214  		}
   215  		qt.Release(resp)
   216  	}
   217  
   218  	for _, addr := range addrs {
   219  		req := qt.NewRequest(querypb.CmdMethod_SyncCommit)
   220  		req.SycnCommit = &querypb.SyncCommitRequest{LatestCommitTS: maxCommitTS}
   221  		resp, err := qt.SendMessage(ctx, addr, req)
   222  		if err != nil {
   223  			return Result{}, err
   224  		}
   225  		qt.Release(resp)
   226  	}
   227  
   228  	return Result{
   229  		Method: SyncCommitMethod,
   230  		Data: fmt.Sprintf("sync %d cn services's commit ts to %s",
   231  			len(addrs),
   232  			maxCommitTS.DebugString()),
   233  	}, nil
   234  }