github.com/polarismesh/polaris@v1.17.8/cache/service/ratelimit_bucket.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 service
    19  
    20  import (
    21  	"crypto/sha1"
    22  	"encoding/hex"
    23  	"sort"
    24  	"sync"
    25  
    26  	"go.uber.org/zap"
    27  
    28  	types "github.com/polarismesh/polaris/cache/api"
    29  	"github.com/polarismesh/polaris/common/model"
    30  	"github.com/polarismesh/polaris/common/utils"
    31  )
    32  
    33  func newRateLimitRuleBucket() *rateLimitRuleBucket {
    34  	return &rateLimitRuleBucket{
    35  		ids:   utils.NewSyncMap[string, *model.RateLimit](),
    36  		rules: utils.NewSyncMap[string, *subRateLimitRuleBucket](),
    37  	}
    38  }
    39  
    40  type rateLimitRuleBucket struct {
    41  	ids   *utils.SyncMap[string, *model.RateLimit]
    42  	rules *utils.SyncMap[string, *subRateLimitRuleBucket]
    43  }
    44  
    45  func (r *rateLimitRuleBucket) foreach(proc types.RateLimitIterProc) {
    46  	r.rules.Range(func(key string, val *subRateLimitRuleBucket) bool {
    47  		val.foreach(proc)
    48  		return true
    49  	})
    50  }
    51  
    52  func (r *rateLimitRuleBucket) count() int {
    53  	count := 0
    54  	r.rules.Range(func(key string, val *subRateLimitRuleBucket) bool {
    55  		count += val.count()
    56  		return true
    57  	})
    58  	return count
    59  }
    60  
    61  func (r *rateLimitRuleBucket) saveRule(rule *model.RateLimit) {
    62  	r.cleanOldSvcRule(rule)
    63  
    64  	r.ids.Store(rule.ID, rule)
    65  	key := buildServiceKey(rule.Proto.GetNamespace().GetValue(), rule.Proto.GetService().GetValue())
    66  
    67  	if _, ok := r.rules.Load(key); !ok {
    68  		r.rules.Store(key, &subRateLimitRuleBucket{
    69  			rules: map[string]*model.RateLimit{},
    70  		})
    71  	}
    72  
    73  	b, _ := r.rules.Load(key)
    74  	b.saveRule(rule)
    75  }
    76  
    77  // cleanOldSvcRule 清理规则之前绑定的服务数据信息
    78  func (r *rateLimitRuleBucket) cleanOldSvcRule(rule *model.RateLimit) {
    79  	oldRule, ok := r.ids.Load(rule.ID)
    80  	if !ok {
    81  		return
    82  	}
    83  	// 清理原来老记录的绑定数据信息
    84  	key := buildServiceKey(oldRule.Proto.GetNamespace().GetValue(), oldRule.Proto.GetService().GetValue())
    85  	bucket, ok := r.rules.Load(key)
    86  	if !ok {
    87  		return
    88  	}
    89  	// 删除服务绑定的限流规则信息
    90  	bucket.delRule(rule)
    91  	if bucket.count() == 0 {
    92  		r.rules.Delete(key)
    93  	}
    94  }
    95  
    96  func (r *rateLimitRuleBucket) delRule(rule *model.RateLimit) {
    97  	r.cleanOldSvcRule(rule)
    98  	r.ids.Delete(rule.ID)
    99  
   100  	key := buildServiceKey(rule.Proto.GetNamespace().GetValue(), rule.Proto.GetService().GetValue())
   101  	if _, ok := r.rules.Load(key); !ok {
   102  		return
   103  	}
   104  
   105  	b, _ := r.rules.Load(key)
   106  	b.delRule(rule)
   107  	if b.count() == 0 {
   108  		r.rules.Delete(key)
   109  	}
   110  }
   111  
   112  func (r *rateLimitRuleBucket) getRuleByID(id string) *model.RateLimit {
   113  	ret, _ := r.ids.Load(id)
   114  	return ret
   115  }
   116  
   117  func (r *rateLimitRuleBucket) getRules(serviceKey model.ServiceKey) ([]*model.RateLimit, string) {
   118  	key := buildServiceKey(serviceKey.Namespace, serviceKey.Name)
   119  	if _, ok := r.rules.Load(key); !ok {
   120  		return nil, ""
   121  	}
   122  
   123  	b, _ := r.rules.Load(key)
   124  	return b.toSlice(), b.revision
   125  }
   126  
   127  func (r *rateLimitRuleBucket) reloadRevision(serviceKey model.ServiceKey) {
   128  	key := buildServiceKey(serviceKey.Namespace, serviceKey.Name)
   129  	v, ok := r.rules.Load(key)
   130  	if !ok {
   131  		return
   132  	}
   133  	v.reloadRevision()
   134  }
   135  
   136  type subRateLimitRuleBucket struct {
   137  	lock     sync.RWMutex
   138  	revision string
   139  	rules    map[string]*model.RateLimit
   140  }
   141  
   142  func (r *subRateLimitRuleBucket) saveRule(rule *model.RateLimit) {
   143  	r.lock.Lock()
   144  	defer r.lock.Unlock()
   145  
   146  	r.rules[rule.ID] = rule
   147  }
   148  
   149  func (r *subRateLimitRuleBucket) delRule(rule *model.RateLimit) {
   150  	r.lock.Lock()
   151  	defer r.lock.Unlock()
   152  
   153  	delete(r.rules, rule.ID)
   154  }
   155  
   156  func (r *subRateLimitRuleBucket) foreach(proc types.RateLimitIterProc) {
   157  	r.lock.RLock()
   158  	defer r.lock.RUnlock()
   159  
   160  	for _, v := range r.rules {
   161  		proc(v)
   162  	}
   163  }
   164  
   165  func (r *subRateLimitRuleBucket) toSlice() []*model.RateLimit {
   166  	r.lock.RLock()
   167  	defer r.lock.RUnlock()
   168  
   169  	ret := make([]*model.RateLimit, 0, len(r.rules))
   170  	for i := range r.rules {
   171  		ret = append(ret, r.rules[i])
   172  	}
   173  	return ret
   174  }
   175  
   176  func (r *subRateLimitRuleBucket) count() int {
   177  	r.lock.RLock()
   178  	defer r.lock.RUnlock()
   179  
   180  	return len(r.rules)
   181  }
   182  
   183  func (r *subRateLimitRuleBucket) reloadRevision() {
   184  	r.lock.Lock()
   185  	defer r.lock.Unlock()
   186  
   187  	revisions := make([]string, 0, len(r.rules))
   188  	for i := range r.rules {
   189  		revisions = append(revisions, r.rules[i].Revision)
   190  	}
   191  
   192  	sort.Strings(revisions)
   193  	h := sha1.New()
   194  	for i := range revisions {
   195  		if _, err := h.Write([]byte(revisions[i])); err != nil {
   196  			log.Error("[Cache][RateLimit] rebuild ratelimit rule revision", zap.Error(err))
   197  			return
   198  		}
   199  	}
   200  
   201  	r.revision = hex.EncodeToString(h.Sum(nil))
   202  }