github.com/polarismesh/polaris@v1.17.8/store/boltdb/circuitbreaker_rule.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 boltdb 19 20 import ( 21 "sort" 22 "strconv" 23 "strings" 24 "time" 25 26 bolt "go.etcd.io/bbolt" 27 28 "github.com/polarismesh/polaris/common/model" 29 "github.com/polarismesh/polaris/store" 30 ) 31 32 const ( 33 // rule 相关信息以及映射 34 tblCircuitBreakerRule string = "circuitbreaker_rule_v2" 35 ) 36 37 const ( 38 CbFieldLevel = "Level" 39 CbFieldSrcService = "SrcService" 40 CbFieldSrcNamespace = "SrcNamespace" 41 CbFieldDstService = "DstService" 42 CbFieldDstNamespace = "DstNamespace" 43 CbFieldDstMethod = "DstMethod" 44 CbFieldRule = "Rule" 45 ) 46 47 const ( 48 // rule 相关信息以及映射 49 tblCircuitBreaker string = "circuitbreaker_rule" 50 51 // relation 相关信息以及映射信息 52 tblCircuitBreakerRelation string = "circuitbreaker_rule_relation" 53 VersionForMaster string = "master" 54 CBFieldNameValid string = "Valid" 55 CBFieldNameVersion string = "Version" 56 CBFieldNameID string = "ID" 57 CBFieldNameModifyTime string = "ModifyTime" 58 59 CBRFieldNameServiceID string = "ServiceID" 60 CBRFieldNameRuleID string = "RuleID" 61 CBRFieldNameRuleVersion string = "RuleVersion" 62 63 CBRelationFieldServiceID string = "ServiceID" 64 CBRelationFieldRuleID string = "RuleID" 65 CBRelationFieldRuleVersion string = "RuleVersion" 66 CBRelationFieldValid string = "Valid" 67 CBRelationFieldCreateTime string = "CreateTime" 68 CBRelationFieldModifyTime string = "ModifyTime" 69 ) 70 71 type circuitBreakerStore struct { 72 handler BoltHandler 73 } 74 75 func initCircuitBreakerRule(cb *model.CircuitBreakerRule) { 76 cb.Valid = true 77 cb.CreateTime = time.Now() 78 cb.ModifyTime = time.Now() 79 } 80 81 // cleanCircuitBreaker 彻底清理熔断规则 82 func (c *circuitBreakerStore) cleanCircuitBreakerRule(id string) error { 83 if err := c.handler.DeleteValues(tblCircuitBreakerRule, []string{id}); err != nil { 84 log.Errorf("[Store][circuitBreaker] clean invalid circuit-breaker rule(%s) err: %s", 85 id, err.Error()) 86 return store.Error(err) 87 } 88 89 return nil 90 } 91 92 // CreateCircuitBreakerRule create general circuitbreaker rule 93 func (c *circuitBreakerStore) CreateCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 94 dbOp := c.handler 95 96 initCircuitBreakerRule(cbRule) 97 if err := c.cleanCircuitBreakerRule(cbRule.ID); err != nil { 98 log.Errorf("[Store][circuitBreaker] clean circuit breaker rule(%s) err: %s", 99 cbRule.ID, err.Error()) 100 return store.Error(err) 101 } 102 if err := dbOp.SaveValue(tblCircuitBreakerRule, cbRule.ID, cbRule); err != nil { 103 log.Errorf("[Store][circuitBreaker] create circuit breaker(%s, %s) err: %s", 104 cbRule.ID, cbRule.Name, err.Error()) 105 return store.Error(err) 106 } 107 108 return nil 109 } 110 111 // UpdateCircuitBreakerRule update general circuitbreaker rule 112 func (c *circuitBreakerStore) UpdateCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 113 dbOp := c.handler 114 properties := map[string]interface{}{ 115 CommonFieldName: cbRule.Name, 116 CommonFieldNamespace: cbRule.Namespace, 117 CommonFieldRevision: cbRule.Revision, 118 CommonFieldDescription: cbRule.Description, 119 CommonFieldModifyTime: time.Now(), 120 CbFieldLevel: cbRule.Level, 121 CbFieldSrcService: cbRule.SrcService, 122 CbFieldSrcNamespace: cbRule.SrcNamespace, 123 CbFieldDstService: cbRule.DstService, 124 CbFieldDstNamespace: cbRule.DstNamespace, 125 CbFieldDstMethod: cbRule.DstMethod, 126 CbFieldRule: cbRule.Rule, 127 } 128 if err := dbOp.UpdateValue(tblCircuitBreakerRule, cbRule.ID, properties); err != nil { 129 log.Errorf("[Store][CircuitBreaker] update rule(%s) exec err: %s", cbRule.ID, err.Error()) 130 return store.Error(err) 131 } 132 return nil 133 } 134 135 // DeleteCircuitBreakerRule delete general circuitbreaker rule 136 func (c *circuitBreakerStore) DeleteCircuitBreakerRule(id string) error { 137 handler := c.handler 138 return handler.Execute(true, func(tx *bolt.Tx) error { 139 140 properties := make(map[string]interface{}) 141 properties[CommonFieldValid] = false 142 properties[CommonFieldModifyTime] = time.Now() 143 144 if err := updateValue(tx, tblCircuitBreakerRule, id, properties); err != nil { 145 log.Errorf("[Store][CircuitBreaker] delete rule(%s) err: %s", id, err.Error()) 146 return err 147 } 148 149 return nil 150 }) 151 } 152 153 // getCircuitBreakerRuleWithID 根据规则ID拉取熔断规则 154 func (c *circuitBreakerStore) getCircuitBreakerRuleWithID(id string) (*model.CircuitBreakerRule, error) { 155 if id == "" { 156 return nil, ErrBadParam 157 } 158 159 handler := c.handler 160 result, err := handler.LoadValues(tblCircuitBreakerRule, []string{id}, &model.CircuitBreakerRule{}) 161 162 if err != nil { 163 log.Errorf("[Store][boltdb] get rate limit fail : %s", err.Error()) 164 return nil, err 165 } 166 167 if len(result) > 1 { 168 return nil, ErrMultipleResult 169 } 170 171 if len(result) == 0 { 172 return nil, nil 173 } 174 175 cbRule := result[id].(*model.CircuitBreakerRule) 176 if cbRule.Valid { 177 return cbRule, nil 178 } 179 180 return nil, nil 181 } 182 183 // HasCircuitBreakerRule check circuitbreaker rule exists 184 func (c *circuitBreakerStore) HasCircuitBreakerRule(id string) (bool, error) { 185 cbRule, err := c.getCircuitBreakerRuleWithID(id) 186 if nil != err { 187 return false, err 188 } 189 return cbRule != nil, nil 190 } 191 192 // HasCircuitBreakerRuleByName check circuitbreaker rule exists for name 193 func (c *circuitBreakerStore) HasCircuitBreakerRuleByName(name string, namespace string) (bool, error) { 194 filter := map[string]string{ 195 exactName: name, 196 "namespace": namespace, 197 } 198 total, _, err := c.GetCircuitBreakerRules(filter, 0, 10) 199 if nil != err { 200 return false, err 201 } 202 return total > 0, nil 203 } 204 205 // HasCircuitBreakerRuleByNameExcludeId check circuitbreaker rule exists for name not this id 206 func (c *circuitBreakerStore) HasCircuitBreakerRuleByNameExcludeId( 207 name string, namespace string, id string) (bool, error) { 208 filter := map[string]string{ 209 exactName: name, 210 "namespace": namespace, 211 excludeId: id, 212 } 213 total, _, err := c.GetCircuitBreakerRules(filter, 0, 10) 214 if nil != err { 215 return false, err 216 } 217 return total > 0, nil 218 } 219 220 var ( 221 cbSearchFields = []string{CommonFieldID, CommonFieldName, CommonFieldNamespace, CommonFieldDescription, 222 CbFieldLevel, CbFieldSrcService, CbFieldSrcNamespace, CbFieldDstService, CbFieldDstNamespace, 223 CbFieldDstMethod, CommonFieldEnable, CommonFieldValid, 224 } 225 cbBlurSearchFields = map[string]bool{ 226 CommonFieldName: true, 227 CommonFieldDescription: true, 228 CbFieldSrcService: true, 229 CbFieldDstService: true, 230 CbFieldDstMethod: true, 231 } 232 ) 233 234 // GetCircuitBreakerRules get all circuitbreaker rules by query and limit 235 func (c *circuitBreakerStore) GetCircuitBreakerRules( 236 filter map[string]string, offset uint32, limit uint32) (uint32, []*model.CircuitBreakerRule, error) { 237 svc, hasSvc := filter[svcSpecificQueryKeyService] 238 delete(filter, svcSpecificQueryKeyService) 239 svcNs, hasSvcNs := filter[svcSpecificQueryKeyNamespace] 240 delete(filter, svcSpecificQueryKeyNamespace) 241 exactNameValue, hasExactName := filter[exactName] 242 delete(filter, exactName) 243 excludeIdValue, hasExcludeId := filter[excludeId] 244 delete(filter, excludeId) 245 delete(filter, "brief") 246 lowerFilter := make(map[string]string, len(filter)) 247 for k, v := range filter { 248 lowerFilter[strings.ToLower(k)] = v 249 } 250 result, err := c.handler.LoadValuesByFilter(tblCircuitBreakerRule, cbSearchFields, &model.CircuitBreakerRule{}, 251 func(m map[string]interface{}) bool { 252 validVal, ok := m[CommonFieldValid] 253 if ok && !validVal.(bool) { 254 return false 255 } 256 if hasSvc && hasSvcNs { 257 srcSvcValue := m[CbFieldSrcService] 258 srcNsValue := m[CbFieldSrcNamespace] 259 dstSvcValue := m[CbFieldDstService] 260 dstNsValue := m[CbFieldDstNamespace] 261 if !((srcSvcValue == svc && srcNsValue == svcNs) || (dstSvcValue == svc && dstNsValue == svcNs)) { 262 return false 263 } 264 } 265 if hasExactName { 266 if exactNameValue != m[CommonFieldName] { 267 return false 268 } 269 } 270 if hasExcludeId { 271 if excludeIdValue == m[CBFieldNameID] { 272 return false 273 } 274 } 275 if len(lowerFilter) == 0 { 276 return true 277 } 278 var matched = true 279 for fieldKey, fieldValue := range m { 280 lowerKey := strings.ToLower(fieldKey) 281 filterValue, ok := lowerFilter[lowerKey] 282 if !ok { 283 continue 284 } 285 _, isBlur := cbBlurSearchFields[fieldKey] 286 if isBlur { 287 if !strings.Contains(fieldValue.(string), filterValue) { 288 matched = false 289 break 290 } 291 } else if fieldKey == CommonFieldEnable { 292 filterEnable, _ := strconv.ParseBool(filterValue) 293 if filterEnable != fieldValue.(bool) { 294 matched = false 295 break 296 } 297 } else if fieldKey == CbFieldLevel { 298 levels := strings.Split(filterValue, ",") 299 var inLevel = false 300 for _, level := range levels { 301 levelInt, _ := strconv.Atoi(level) 302 if int64(levelInt) == fieldValue.(int64) { 303 inLevel = true 304 break 305 } 306 } 307 if !inLevel { 308 matched = false 309 break 310 } 311 } else { 312 if filterValue != fieldValue.(string) { 313 matched = false 314 break 315 } 316 } 317 } 318 return matched 319 }) 320 if nil != err { 321 return 0, nil, err 322 } 323 out := make([]*model.CircuitBreakerRule, 0, len(result)) 324 for _, value := range result { 325 out = append(out, value.(*model.CircuitBreakerRule)) 326 } 327 return uint32(len(out)), sublistCircuitBreakerRules(out, offset, limit), nil 328 } 329 330 func sublistCircuitBreakerRules(cbRules []*model.CircuitBreakerRule, offset, limit uint32) []*model.CircuitBreakerRule { 331 beginIndex := offset 332 endIndex := beginIndex + limit 333 totalCount := uint32(len(cbRules)) 334 // handle invalid offset, limit 335 if totalCount == 0 { 336 return cbRules 337 } 338 if beginIndex >= endIndex { 339 return cbRules 340 } 341 if beginIndex >= totalCount { 342 return cbRules 343 } 344 if endIndex > totalCount { 345 endIndex = totalCount 346 } 347 348 sort.Slice(cbRules, func(i, j int) bool { 349 // sort by modify time 350 if cbRules[i].ModifyTime.After(cbRules[j].ModifyTime) { 351 return true 352 } else if cbRules[i].ModifyTime.Before(cbRules[j].ModifyTime) { 353 return false 354 } else { 355 return strings.Compare(cbRules[i].ID, cbRules[j].ID) < 0 356 } 357 }) 358 359 return cbRules[beginIndex:endIndex] 360 } 361 362 // GetCircuitBreakerRulesForCache get increment circuitbreaker rules 363 func (c *circuitBreakerStore) GetCircuitBreakerRulesForCache( 364 mtime time.Time, firstUpdate bool) ([]*model.CircuitBreakerRule, error) { 365 handler := c.handler 366 367 if firstUpdate { 368 mtime = time.Time{} 369 } 370 371 results, err := handler.LoadValuesByFilter( 372 tblCircuitBreakerRule, []string{CommonFieldModifyTime}, &model.CircuitBreakerRule{}, 373 func(m map[string]interface{}) bool { 374 mt := m[CommonFieldModifyTime].(time.Time) 375 isAfter := !mt.Before(mtime) 376 return isAfter 377 }) 378 379 if err != nil { 380 return nil, err 381 } 382 383 if len(results) == 0 { 384 return []*model.CircuitBreakerRule{}, nil 385 } 386 387 out := make([]*model.CircuitBreakerRule, 0, len(results)) 388 for _, value := range results { 389 out = append(out, value.(*model.CircuitBreakerRule)) 390 } 391 392 return out, nil 393 } 394 395 // EnableCircuitBreakerRule enable specific circuitbreaker rule 396 func (c *circuitBreakerStore) EnableCircuitBreakerRule(cbRule *model.CircuitBreakerRule) error { 397 handler := c.handler 398 return handler.Execute(true, func(tx *bolt.Tx) error { 399 properties := make(map[string]interface{}) 400 properties[CommonFieldEnable] = cbRule.Enable 401 properties[CommonFieldRevision] = cbRule.Revision 402 properties[CommonFieldModifyTime] = time.Now() 403 if cbRule.Enable { 404 properties[CommonFieldEnableTime] = time.Now() 405 } else { 406 properties[CommonFieldEnableTime] = time.Unix(0, 0) 407 } 408 // create ratelimit_config 409 if err := updateValue(tx, tblCircuitBreakerRule, cbRule.ID, properties); err != nil { 410 log.Errorf("[Store][RateLimit] update circuitbreaker rule(%s) err: %s", 411 cbRule.ID, err.Error()) 412 return err 413 } 414 return nil 415 }) 416 }