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 }