github.com/polarismesh/polaris@v1.17.8/store/mysql/fault_detect_config.go (about) 1 /** 2 * Tencent is pleased to support the open source community by making Polaris available. 3 * 4 * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. 5 * 6 * Licensed under the BSD 3-Clause License (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * https://opensource.org/licenses/BSD-3-Clause 11 * 12 * Unless required by applicable law or agreed to in writing, software distributed 13 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 14 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 15 * specific language governing permissions and limitations under the License. 16 */ 17 18 package sqldb 19 20 import ( 21 "database/sql" 22 "fmt" 23 "strings" 24 "time" 25 26 "github.com/polarismesh/polaris/common/model" 27 "github.com/polarismesh/polaris/store" 28 ) 29 30 var _ store.FaultDetectRuleStore = (*faultDetectRuleStore)(nil) 31 32 type faultDetectRuleStore struct { 33 master *BaseDB 34 slave *BaseDB 35 } 36 37 const ( 38 labelCreateFaultDetectRule = "createFaultDetectRule" 39 labelUpdateFaultDetectRule = "updateFaultDetectRule" 40 labelDeleteFaultDetectRule = "deleteFaultDetectRule" 41 ) 42 43 const ( 44 insertFaultDetectSql = `insert into fault_detect_rule( 45 id, name, namespace, revision, description, dst_service, dst_namespace, dst_method, config, ctime, mtime) 46 values(?,?,?,?,?,?,?,?,?, sysdate(),sysdate())` 47 updateFaultDetectSql = `update fault_detect_rule set name = ?, namespace = ?, revision = ?, description = ?, 48 dst_service = ?, dst_namespace = ?, dst_method = ?, config = ?, mtime = sysdate() where id = ?` 49 deleteFaultDetectSql = `update fault_detect_rule set flag = 1, mtime = sysdate() where id = ?` 50 countFaultDetectSql = `select count(*) from fault_detect_rule where flag = 0` 51 queryFaultDetectFullSql = `select id, name, namespace, revision, description, dst_service, 52 dst_namespace, dst_method, config, unix_timestamp(ctime), unix_timestamp(mtime) 53 from fault_detect_rule where flag = 0` 54 queryFaultDetectBriefSql = `select id, name, namespace, revision, description, dst_service, 55 dst_namespace, dst_method, unix_timestamp(ctime), unix_timestamp(mtime) 56 from fault_detect_rule where flag = 0` 57 queryFaultDetectCacheSql = `select id, name, namespace, revision, description, dst_service, 58 dst_namespace, dst_method, config, flag, unix_timestamp(ctime), unix_timestamp(mtime) 59 from fault_detect_rule where mtime > FROM_UNIXTIME(?)` 60 ) 61 62 // CreateFaultDetectRule create fault detect rule 63 func (f *faultDetectRuleStore) CreateFaultDetectRule(fdRule *model.FaultDetectRule) error { 64 err := RetryTransaction(labelCreateFaultDetectRule, func() error { 65 return f.createFaultDetectRule(fdRule) 66 }) 67 return store.Error(err) 68 } 69 70 func (f *faultDetectRuleStore) createFaultDetectRule(fdRule *model.FaultDetectRule) error { 71 return f.master.processWithTransaction(labelCreateFaultDetectRule, func(tx *BaseTx) error { 72 if _, err := tx.Exec(insertFaultDetectSql, fdRule.ID, fdRule.Name, fdRule.Namespace, fdRule.Revision, 73 fdRule.Description, fdRule.DstService, fdRule.DstNamespace, fdRule.DstMethod, fdRule.Rule); err != nil { 74 log.Errorf("[Store][database] fail to %s exec sql, rule(%+v), err: %s", 75 labelCreateFaultDetectRule, fdRule, err.Error()) 76 return err 77 } 78 79 if err := tx.Commit(); err != nil { 80 log.Errorf("[Store][database] fail to %s commit tx, rule(%+v), err: %s", 81 labelCreateFaultDetectRule, fdRule, err.Error()) 82 return err 83 } 84 return nil 85 }) 86 } 87 88 // UpdateFaultDetectRule update fault detect rule 89 func (f *faultDetectRuleStore) UpdateFaultDetectRule(fdRule *model.FaultDetectRule) error { 90 err := RetryTransaction(labelUpdateFaultDetectRule, func() error { 91 return f.updateFaultDetectRule(fdRule) 92 }) 93 return store.Error(err) 94 } 95 96 func (f *faultDetectRuleStore) updateFaultDetectRule(fdRule *model.FaultDetectRule) error { 97 return f.master.processWithTransaction(labelUpdateFaultDetectRule, func(tx *BaseTx) error { 98 if _, err := tx.Exec(updateFaultDetectSql, fdRule.Name, fdRule.Namespace, fdRule.Revision, 99 fdRule.Description, fdRule.DstService, fdRule.DstNamespace, fdRule.DstMethod, fdRule.Rule, fdRule.ID); err != nil { 100 log.Errorf("[Store][database] fail to %s exec sql, rule(%+v), err: %s", 101 labelUpdateFaultDetectRule, fdRule, err.Error()) 102 return err 103 } 104 105 if err := tx.Commit(); err != nil { 106 log.Errorf("[Store][database] fail to %s commit tx, rule(%+v), err: %s", 107 labelUpdateFaultDetectRule, fdRule, err.Error()) 108 return err 109 } 110 return nil 111 }) 112 } 113 114 // DeleteFaultDetectRule delete fault detect rule 115 func (f *faultDetectRuleStore) DeleteFaultDetectRule(id string) error { 116 err := RetryTransaction(labelDeleteFaultDetectRule, func() error { 117 return f.deleteFaultDetectRule(id) 118 }) 119 return store.Error(err) 120 } 121 122 func (f *faultDetectRuleStore) deleteFaultDetectRule(id string) error { 123 return f.master.processWithTransaction(labelDeleteFaultDetectRule, func(tx *BaseTx) error { 124 if _, err := tx.Exec(deleteFaultDetectSql, id); err != nil { 125 log.Errorf("[Store][database] fail to %s exec sql, rule(%s), err: %s", 126 labelDeleteFaultDetectRule, id, err.Error()) 127 return err 128 } 129 130 if err := tx.Commit(); err != nil { 131 log.Errorf("[Store][database] fail to %s commit tx, rule(%s), err: %s", 132 labelDeleteFaultDetectRule, id, err.Error()) 133 return err 134 } 135 return nil 136 }) 137 } 138 139 // HasFaultDetectRule check fault detect rule exists 140 func (f *faultDetectRuleStore) HasFaultDetectRule(id string) (bool, error) { 141 queryParams := map[string]string{"id": id} 142 count, err := f.getFaultDetectRulesCount(queryParams) 143 if nil != err { 144 return false, err 145 } 146 return count > 0, nil 147 } 148 149 // HasFaultDetectRuleByName check fault detect rule exists by name 150 func (f *faultDetectRuleStore) HasFaultDetectRuleByName(name string, namespace string) (bool, error) { 151 queryParams := map[string]string{exactName: name, "namespace": namespace} 152 count, err := f.getFaultDetectRulesCount(queryParams) 153 if nil != err { 154 return false, err 155 } 156 return count > 0, nil 157 } 158 159 // HasFaultDetectRuleByNameExcludeId check fault detect rule exists by name not this id 160 func (f *faultDetectRuleStore) HasFaultDetectRuleByNameExcludeId( 161 name string, namespace string, id string) (bool, error) { 162 queryParams := map[string]string{exactName: name, "namespace": namespace, excludeId: id} 163 count, err := f.getFaultDetectRulesCount(queryParams) 164 if nil != err { 165 return false, err 166 } 167 return count > 0, nil 168 } 169 170 // GetFaultDetectRules get all fault detect rules by query and limit 171 func (f *faultDetectRuleStore) GetFaultDetectRules( 172 filter map[string]string, offset uint32, limit uint32) (uint32, []*model.FaultDetectRule, error) { 173 var out []*model.FaultDetectRule 174 var err error 175 176 bValue, ok := filter[briefSearch] 177 var isBrief = ok && strings.ToLower(bValue) == "true" 178 delete(filter, briefSearch) 179 180 if isBrief { 181 out, err = f.getBriefFaultDetectRules(filter, offset, limit) 182 } else { 183 out, err = f.getFullFaultDetectRules(filter, offset, limit) 184 } 185 if err != nil { 186 return 0, nil, err 187 } 188 num, err := f.getFaultDetectRulesCount(filter) 189 if err != nil { 190 return 0, nil, err 191 } 192 return num, out, nil 193 } 194 195 // GetFaultDetectRulesForCache get increment circuitbreaker rules 196 func (f *faultDetectRuleStore) GetFaultDetectRulesForCache( 197 mtime time.Time, firstUpdate bool) ([]*model.FaultDetectRule, error) { 198 str := queryFaultDetectCacheSql 199 if firstUpdate { 200 str += " and flag != 1" 201 } 202 rows, err := f.slave.Query(str, timeToTimestamp(mtime)) 203 if err != nil { 204 log.Errorf("[Store][database] query fault detect rules with mtime err: %s", err.Error()) 205 return nil, err 206 } 207 fdRules, err := fetchFaultDetectRulesRows(rows) 208 if err != nil { 209 return nil, err 210 } 211 return fdRules, nil 212 } 213 214 func fetchFaultDetectRulesRows(rows *sql.Rows) ([]*model.FaultDetectRule, error) { 215 defer rows.Close() 216 var out []*model.FaultDetectRule 217 for rows.Next() { 218 var fdRule model.FaultDetectRule 219 var flag int 220 var ctime, mtime int64 221 err := rows.Scan(&fdRule.ID, &fdRule.Name, &fdRule.Namespace, &fdRule.Revision, 222 &fdRule.Description, &fdRule.DstService, &fdRule.DstNamespace, 223 &fdRule.DstMethod, &fdRule.Rule, &flag, &ctime, &mtime) 224 if err != nil { 225 log.Errorf("[Store][database] fetch brief fault detect rule scan err: %s", err.Error()) 226 return nil, err 227 } 228 fdRule.CreateTime = time.Unix(ctime, 0) 229 fdRule.ModifyTime = time.Unix(mtime, 0) 230 fdRule.Valid = true 231 if flag == 1 { 232 fdRule.Valid = false 233 } 234 out = append(out, &fdRule) 235 } 236 if err := rows.Err(); err != nil { 237 log.Errorf("[Store][database] fetch brief fault detect rule next err: %s", err.Error()) 238 return nil, err 239 } 240 return out, nil 241 } 242 243 func genFaultDetectRuleSQL(query map[string]string) (string, []interface{}) { 244 str := "" 245 args := make([]interface{}, 0, len(query)) 246 var svcNamespaceQueryValue string 247 var svcQueryValue string 248 for key, value := range query { 249 if len(value) == 0 { 250 continue 251 } 252 if key == svcSpecificQueryKeyService { 253 svcQueryValue = value 254 continue 255 } 256 if key == svcSpecificQueryKeyNamespace { 257 svcNamespaceQueryValue = value 258 continue 259 } 260 storeKey := toUnderscoreName(key) 261 if _, ok := blurQueryKeys[key]; ok { 262 str += fmt.Sprintf(" and %s like ?", storeKey) 263 args = append(args, "%"+value+"%") 264 } else if key == exactName { 265 str += " and name = ?" 266 args = append(args, value) 267 } else if key == excludeId { 268 str += " and id != ?" 269 args = append(args, value) 270 } else { 271 str += fmt.Sprintf(" and %s = ?", storeKey) 272 args = append(args, value) 273 } 274 } 275 if len(svcQueryValue) > 0 { 276 str += " and (dst_service = ? or dst_service = '*')" 277 args = append(args, svcQueryValue) 278 } 279 if len(svcNamespaceQueryValue) > 0 { 280 str += " and (dst_namespace = ? or dst_namespace = '*')" 281 args = append(args, svcNamespaceQueryValue) 282 } 283 return str, args 284 } 285 286 func (f *faultDetectRuleStore) getFaultDetectRulesCount(filter map[string]string) (uint32, error) { 287 queryStr, args := genFaultDetectRuleSQL(filter) 288 str := countFaultDetectSql + queryStr 289 var total uint32 290 err := f.master.QueryRow(str, args...).Scan(&total) 291 switch { 292 case err == sql.ErrNoRows: 293 return 0, nil 294 case err != nil: 295 log.Errorf("[Store][database] get fault detect rule count err: %s", err.Error()) 296 return 0, err 297 default: 298 } 299 return total, nil 300 } 301 302 func (f *faultDetectRuleStore) getBriefFaultDetectRules( 303 filter map[string]string, offset uint32, limit uint32) ([]*model.FaultDetectRule, error) { 304 queryStr, args := genFaultDetectRuleSQL(filter) 305 args = append(args, offset, limit) 306 str := queryFaultDetectBriefSql + queryStr + ` order by mtime desc limit ?, ?` 307 308 rows, err := f.master.Query(str, args...) 309 if err != nil { 310 log.Errorf("[Store][database] query brief fault detect rule rules err: %s", err.Error()) 311 return nil, err 312 } 313 out, err := fetchBriefFaultDetectRules(rows) 314 if err != nil { 315 return nil, err 316 } 317 return out, nil 318 } 319 320 func fetchBriefFaultDetectRules(rows *sql.Rows) ([]*model.FaultDetectRule, error) { 321 defer rows.Close() 322 var out []*model.FaultDetectRule 323 for rows.Next() { 324 var fdRule model.FaultDetectRule 325 var ctime, mtime int64 326 err := rows.Scan(&fdRule.ID, &fdRule.Name, &fdRule.Namespace, &fdRule.Revision, 327 &fdRule.Description, &fdRule.DstService, &fdRule.DstNamespace, 328 &fdRule.DstMethod, &ctime, &mtime) 329 if err != nil { 330 log.Errorf("[Store][database] fetch brief fault detect rule scan err: %s", err.Error()) 331 return nil, err 332 } 333 fdRule.CreateTime = time.Unix(ctime, 0) 334 fdRule.ModifyTime = time.Unix(mtime, 0) 335 out = append(out, &fdRule) 336 } 337 if err := rows.Err(); err != nil { 338 log.Errorf("[Store][database] fetch brief fault detect rule next err: %s", err.Error()) 339 return nil, err 340 } 341 return out, nil 342 } 343 344 func (f *faultDetectRuleStore) getFullFaultDetectRules( 345 filter map[string]string, offset uint32, limit uint32) ([]*model.FaultDetectRule, error) { 346 queryStr, args := genFaultDetectRuleSQL(filter) 347 args = append(args, offset, limit) 348 str := queryFaultDetectFullSql + queryStr + ` order by mtime desc limit ?, ?` 349 350 rows, err := f.master.Query(str, args...) 351 if err != nil { 352 log.Errorf("[Store][database] query brief fault detect rules err: %s", err.Error()) 353 return nil, err 354 } 355 out, err := fetchFullFaultDetectRules(rows) 356 if err != nil { 357 return nil, err 358 } 359 return out, nil 360 } 361 362 func fetchFullFaultDetectRules(rows *sql.Rows) ([]*model.FaultDetectRule, error) { 363 defer rows.Close() 364 var out []*model.FaultDetectRule 365 for rows.Next() { 366 var fdRule model.FaultDetectRule 367 var ctime, mtime int64 368 err := rows.Scan(&fdRule.ID, &fdRule.Name, &fdRule.Namespace, &fdRule.Revision, 369 &fdRule.Description, &fdRule.DstService, &fdRule.DstNamespace, 370 &fdRule.DstMethod, &fdRule.Rule, &ctime, &mtime) 371 if err != nil { 372 log.Errorf("[Store][database] fetch brief fault detect rule scan err: %s", err.Error()) 373 return nil, err 374 } 375 fdRule.CreateTime = time.Unix(ctime, 0) 376 fdRule.ModifyTime = time.Unix(mtime, 0) 377 out = append(out, &fdRule) 378 } 379 if err := rows.Err(); err != nil { 380 log.Errorf("[Store][database] fetch brief fault detect rule next err: %s", err.Error()) 381 return nil, err 382 } 383 return out, nil 384 }