github.com/polarismesh/polaris@v1.17.8/store/boltdb/faultdetector.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 "strings" 23 "time" 24 25 bolt "go.etcd.io/bbolt" 26 27 "github.com/polarismesh/polaris/common/model" 28 "github.com/polarismesh/polaris/store" 29 ) 30 31 type faultDetectStore struct { 32 handler BoltHandler 33 } 34 35 const ( 36 // rule 相关信息以及映射 37 tblFaultDetectRule string = "faultdetect_rule" 38 ) 39 40 func initFaultDetectRule(cb *model.FaultDetectRule) { 41 cb.Valid = true 42 cb.CreateTime = time.Now() 43 cb.ModifyTime = time.Now() 44 } 45 46 // cleanCircuitBreaker 彻底清理熔断规则 47 func (c *faultDetectStore) cleanFaultDetectRule(id string) error { 48 if err := c.handler.DeleteValues(tblFaultDetectRule, []string{id}); err != nil { 49 log.Errorf("[Store][fault-detect] clean invalid fault-detect rule(%s) err: %s", 50 id, err.Error()) 51 return store.Error(err) 52 } 53 54 return nil 55 } 56 57 // CreateFaultDetectRule create fault detect rule 58 func (c *faultDetectStore) CreateFaultDetectRule(fdRule *model.FaultDetectRule) error { 59 dbOp := c.handler 60 61 initFaultDetectRule(fdRule) 62 if err := c.cleanFaultDetectRule(fdRule.ID); err != nil { 63 log.Errorf("[Store][fault-detect] clean fault-detect rule(%s) err: %s", 64 fdRule.ID, err.Error()) 65 return store.Error(err) 66 } 67 if err := dbOp.SaveValue(tblFaultDetectRule, fdRule.ID, fdRule); err != nil { 68 log.Errorf("[Store][fault-detect] create fault-detect(%s, %s) err: %s", 69 fdRule.ID, fdRule.Name, err.Error()) 70 return store.Error(err) 71 } 72 73 return nil 74 } 75 76 // UpdateFaultDetectRule update fault detect rule 77 func (c *faultDetectStore) UpdateFaultDetectRule(fdRule *model.FaultDetectRule) error { 78 dbOp := c.handler 79 fdRule.Valid = true 80 fdRule.ModifyTime = time.Now() 81 82 if err := dbOp.SaveValue(tblFaultDetectRule, fdRule.ID, fdRule); err != nil { 83 log.Errorf("[Store][fault-detect] update rule(%s) exec err: %s", fdRule.ID, err.Error()) 84 return store.Error(err) 85 } 86 87 return nil 88 } 89 90 // DeleteFaultDetectRule delete fault detect rule 91 func (c *faultDetectStore) DeleteFaultDetectRule(id string) error { 92 handler := c.handler 93 return handler.Execute(true, func(tx *bolt.Tx) error { 94 95 properties := make(map[string]interface{}) 96 properties[CommonFieldValid] = false 97 properties[CommonFieldModifyTime] = time.Now() 98 99 if err := updateValue(tx, tblFaultDetectRule, id, properties); err != nil { 100 log.Errorf("[Store][fault-detect] delete rule(%s) err: %s", id, err.Error()) 101 return err 102 } 103 104 return nil 105 }) 106 } 107 108 func (c *faultDetectStore) getFaultDetectRuleWithID(id string) (*model.FaultDetectRule, error) { 109 if id == "" { 110 return nil, ErrBadParam 111 } 112 113 handler := c.handler 114 result, err := handler.LoadValues(tblFaultDetectRule, []string{id}, &model.FaultDetectRule{}) 115 116 if err != nil { 117 log.Errorf("[Store][fault-detect] get rule fail : %s", err.Error()) 118 return nil, err 119 } 120 121 if len(result) > 1 { 122 return nil, ErrMultipleResult 123 } 124 125 if len(result) == 0 { 126 return nil, nil 127 } 128 129 cbRule := result[id].(*model.FaultDetectRule) 130 if cbRule.Valid { 131 return cbRule, nil 132 } 133 134 return nil, nil 135 } 136 137 // HasFaultDetectRule check fault detect rule exists 138 func (c *faultDetectStore) HasFaultDetectRule(id string) (bool, error) { 139 cbRule, err := c.getFaultDetectRuleWithID(id) 140 if nil != err { 141 return false, err 142 } 143 return cbRule != nil, nil 144 } 145 146 // HasFaultDetectRuleByName check fault detect rule exists by name 147 func (c *faultDetectStore) HasFaultDetectRuleByName(name string, namespace string) (bool, error) { 148 filter := map[string]string{ 149 exactName: name, 150 "namespace": namespace, 151 } 152 total, _, err := c.GetFaultDetectRules(filter, 0, 10) 153 if nil != err { 154 return false, err 155 } 156 return total > 0, nil 157 } 158 159 // HasFaultDetectRuleByNameExcludeId check fault detect rule exists by name not this id 160 func (c *faultDetectStore) HasFaultDetectRuleByNameExcludeId(name string, namespace string, id string) (bool, error) { 161 filter := map[string]string{ 162 exactName: name, 163 "namespace": namespace, 164 excludeId: id, 165 } 166 total, _, err := c.GetFaultDetectRules(filter, 0, 10) 167 if nil != err { 168 return false, err 169 } 170 return total > 0, nil 171 } 172 173 const ( 174 fdFieldDstService = "DstService" 175 fdFieldDstNamespace = "DstNamespace" 176 fdFieldDstMethod = "DstMethod" 177 ) 178 179 var ( 180 fdSearchFields = []string{ 181 CommonFieldID, CommonFieldName, CommonFieldNamespace, CommonFieldDescription, fdFieldDstService, 182 fdFieldDstNamespace, fdFieldDstMethod, CommonFieldEnable, CommonFieldValid, 183 } 184 fdBlurSearchFields = map[string]bool{ 185 CommonFieldName: true, 186 CommonFieldDescription: true, 187 fdFieldDstService: true, 188 fdFieldDstNamespace: true, 189 fdFieldDstMethod: true, 190 } 191 ) 192 193 // GetFaultDetectRules get all circuitbreaker rules by query and limit 194 func (c *faultDetectStore) GetFaultDetectRules( 195 filter map[string]string, offset uint32, limit uint32) (uint32, []*model.FaultDetectRule, error) { 196 svc, hasSvc := filter[svcSpecificQueryKeyService] 197 delete(filter, svcSpecificQueryKeyService) 198 svcNs, hasSvcNs := filter[svcSpecificQueryKeyNamespace] 199 delete(filter, svcSpecificQueryKeyNamespace) 200 exactNameValue, hasExactName := filter[exactName] 201 delete(filter, exactName) 202 excludeIdValue, hasExcludeId := filter[excludeId] 203 delete(filter, excludeId) 204 delete(filter, "brief") 205 result, err := c.handler.LoadValuesByFilter(tblFaultDetectRule, fdSearchFields, &model.FaultDetectRule{}, 206 func(m map[string]interface{}) bool { 207 validVal, ok := m[CommonFieldValid] 208 if ok && !validVal.(bool) { 209 return false 210 } 211 if hasSvc && hasSvcNs { 212 dstServiceValue := m[fdFieldDstService] 213 dstNamespaceValue := m[fdFieldDstNamespace] 214 if !(dstServiceValue == svc && dstNamespaceValue == svcNs) { 215 return false 216 } 217 } 218 if hasExactName { 219 if exactNameValue != m[CommonFieldName] { 220 return false 221 } 222 } 223 if hasExcludeId { 224 if excludeIdValue == m[CBFieldNameID] { 225 return false 226 } 227 } 228 if len(filter) == 0 { 229 return true 230 } 231 var matched = true 232 for fieldKey, fieldValue := range m { 233 lowerKey := strings.ToLower(fieldKey) 234 filterValue, ok := filter[lowerKey] 235 if !ok { 236 continue 237 } 238 _, isBlur := fdBlurSearchFields[fieldKey] 239 if isBlur { 240 if !strings.Contains(fieldValue.(string), filterValue) { 241 matched = false 242 break 243 } 244 } else { 245 if filterValue != fieldValue.(string) { 246 matched = false 247 break 248 } 249 } 250 } 251 return matched 252 }) 253 if nil != err { 254 return 0, nil, err 255 } 256 out := make([]*model.FaultDetectRule, 0, len(result)) 257 for _, value := range result { 258 out = append(out, value.(*model.FaultDetectRule)) 259 } 260 return uint32(len(out)), sublistFaultDetectRules(out, offset, limit), nil 261 } 262 263 func sublistFaultDetectRules(cbRules []*model.FaultDetectRule, offset, limit uint32) []*model.FaultDetectRule { 264 beginIndex := offset 265 endIndex := beginIndex + limit 266 totalCount := uint32(len(cbRules)) 267 // handle invalid offset, limit 268 if totalCount == 0 { 269 return cbRules 270 } 271 if beginIndex >= endIndex { 272 return cbRules 273 } 274 if beginIndex >= totalCount { 275 return cbRules 276 } 277 if endIndex > totalCount { 278 endIndex = totalCount 279 } 280 281 sort.Slice(cbRules, func(i, j int) bool { 282 // sort by modify time 283 if cbRules[i].ModifyTime.After(cbRules[j].ModifyTime) { 284 return true 285 } else if cbRules[i].ModifyTime.Before(cbRules[j].ModifyTime) { 286 return false 287 } else { 288 return strings.Compare(cbRules[i].ID, cbRules[j].ID) < 0 289 } 290 }) 291 292 return cbRules[beginIndex:endIndex] 293 } 294 295 // GetFaultDetectRulesForCache get increment circuitbreaker rules 296 func (c *faultDetectStore) GetFaultDetectRulesForCache( 297 mtime time.Time, firstUpdate bool) ([]*model.FaultDetectRule, error) { 298 handler := c.handler 299 300 if firstUpdate { 301 mtime = time.Time{} 302 } 303 304 results, err := handler.LoadValuesByFilter( 305 tblFaultDetectRule, []string{CommonFieldModifyTime}, &model.FaultDetectRule{}, 306 func(m map[string]interface{}) bool { 307 mt := m[CommonFieldModifyTime].(time.Time) 308 isAfter := !mt.Before(mtime) 309 return isAfter 310 }) 311 312 if err != nil { 313 return nil, err 314 } 315 316 if len(results) == 0 { 317 return []*model.FaultDetectRule{}, nil 318 } 319 320 out := make([]*model.FaultDetectRule, 0, len(results)) 321 for _, value := range results { 322 out = append(out, value.(*model.FaultDetectRule)) 323 } 324 325 return out, nil 326 }