github.com/polarismesh/polaris@v1.17.8/cache/service/router_rule_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  	"fmt"
    22  	"sync"
    23  
    24  	apitraffic "github.com/polarismesh/specification/source/go/api/v1/traffic_manage"
    25  
    26  	types "github.com/polarismesh/polaris/cache/api"
    27  	"github.com/polarismesh/polaris/common/model"
    28  )
    29  
    30  type (
    31  	routingLevel int16
    32  	boundType    int16
    33  
    34  	serviceInfo interface {
    35  		GetNamespace() string
    36  		GetService() string
    37  	}
    38  )
    39  
    40  const (
    41  	_ routingLevel = iota
    42  	level1RoutingV2
    43  	level2RoutingV2
    44  	level3RoutingV2
    45  
    46  	_ boundType = iota
    47  	inBound
    48  	outBound
    49  )
    50  
    51  func newRouteRuleBucket() *routeRuleBucket {
    52  	return &routeRuleBucket{
    53  		rules:       make(map[string]*model.ExtendRouterConfig),
    54  		level1Rules: map[string]map[string]struct{}{},
    55  		level2Rules: map[boundType]map[string]map[string]struct{}{
    56  			inBound:  {},
    57  			outBound: {},
    58  		},
    59  		level3Rules: map[boundType]map[string]struct{}{
    60  			inBound:  {},
    61  			outBound: {},
    62  		},
    63  		v1rules:      map[string][]*model.ExtendRouterConfig{},
    64  		v1rulesToOld: map[string]string{},
    65  	}
    66  }
    67  
    68  // ServiceWithCircuitBreakerRules 与服务关系绑定的熔断规则
    69  type ServiceWithRouterRules struct {
    70  	mutex    sync.RWMutex
    71  	Service  model.ServiceKey
    72  	v2Rules  map[string]*model.ExtendRouterConfig
    73  	v1Rules  *apitraffic.Routing
    74  	Revision string
    75  }
    76  
    77  func NewServiceWithRouterRules(svcKey model.ServiceKey) *ServiceWithRouterRules {
    78  	return &ServiceWithRouterRules{
    79  		Service: svcKey,
    80  		v2Rules: make(map[string]*model.ExtendRouterConfig),
    81  	}
    82  }
    83  
    84  func (s *ServiceWithRouterRules) AddRouterRule(rule *model.ExtendRouterConfig) {
    85  	s.mutex.Lock()
    86  	defer s.mutex.Unlock()
    87  	s.v2Rules[rule.ID] = rule
    88  }
    89  
    90  func (s *ServiceWithRouterRules) DelRouterRule(id string) {
    91  	s.mutex.Lock()
    92  	defer s.mutex.Unlock()
    93  	delete(s.v2Rules, id)
    94  }
    95  
    96  func (s *ServiceWithRouterRules) IterateRouterRules(callback func(*model.ExtendRouterConfig)) {
    97  	s.mutex.RLock()
    98  	defer s.mutex.RUnlock()
    99  	for _, rule := range s.v2Rules {
   100  		callback(rule)
   101  	}
   102  }
   103  
   104  func (s *ServiceWithRouterRules) CountRouterRules() int {
   105  	s.mutex.RLock()
   106  	defer s.mutex.RUnlock()
   107  	return len(s.v2Rules)
   108  }
   109  
   110  func (s *ServiceWithRouterRules) Clear() {
   111  	s.mutex.Lock()
   112  	defer s.mutex.Unlock()
   113  	s.v2Rules = make(map[string]*model.ExtendRouterConfig)
   114  	s.Revision = ""
   115  }
   116  
   117  // routeRuleBucket v2 路由规则缓存 bucket
   118  type routeRuleBucket struct {
   119  	lock sync.RWMutex
   120  	// rules id => routing rule
   121  	rules map[string]*model.ExtendRouterConfig
   122  	// level1Rules service(name)+namespace => 路由规则ID列表,只针对某个具体的服务有效
   123  	level1Rules map[string]map[string]struct{}
   124  	// level2Rules service(*) + namespace =>  路由规则ID列表, 针对某个命名空间下所有服务都生效的路由规则
   125  	level2Rules map[boundType]map[string]map[string]struct{}
   126  	// level3Rules service(*) + namespace(*) =>  路由规则ID列表, 针对所有命名空间下的所有服务都生效的规则
   127  	level3Rules map[boundType]map[string]struct{}
   128  	// v1rules service-id => []*model.ExtendRouterConfig v1 版本的规则自动转为 v2 版本的规则,用于 v2 接口的数据查看
   129  	v1rules map[string][]*model.ExtendRouterConfig
   130  
   131  	// fetched service cache
   132  	// key1: namespace, key2: service
   133  	routerRules map[string]map[string]*ServiceWithRouterRules
   134  	// key1: namespace
   135  	nsWildcardRules map[string]*ServiceWithRouterRules
   136  	// all rules are wildcard specific
   137  	allWildcardRules *ServiceWithRouterRules
   138  
   139  	// v1rulesToOld 转为 v2 规则id 对应的原本的 v1 规则id 信息
   140  	v1rulesToOld map[string]string
   141  }
   142  
   143  func (b *routeRuleBucket) getV2(id string) *model.ExtendRouterConfig {
   144  	b.lock.RLock()
   145  	defer b.lock.RUnlock()
   146  
   147  	return b.rules[id]
   148  }
   149  
   150  func (b *routeRuleBucket) saveV2(conf *model.ExtendRouterConfig) {
   151  	b.lock.Lock()
   152  	defer b.lock.Unlock()
   153  
   154  	b.rules[conf.ID] = conf
   155  	handler := func(bt boundType, item serviceInfo) {
   156  		// level1 级别 cache 处理
   157  		if item.GetService() != model.MatchAll && item.GetNamespace() != model.MatchAll {
   158  			key := buildServiceKey(item.GetNamespace(), item.GetService())
   159  			if _, ok := b.level1Rules[key]; !ok {
   160  				b.level1Rules[key] = map[string]struct{}{}
   161  			}
   162  
   163  			b.level1Rules[key][conf.ID] = struct{}{}
   164  			return
   165  		}
   166  		// level2 级别 cache 处理
   167  		if item.GetService() == model.MatchAll && item.GetNamespace() != model.MatchAll {
   168  			if _, ok := b.level2Rules[bt][item.GetNamespace()]; !ok {
   169  				b.level2Rules[bt][item.GetNamespace()] = map[string]struct{}{}
   170  			}
   171  			b.level2Rules[bt][item.GetNamespace()][conf.ID] = struct{}{}
   172  			return
   173  		}
   174  		// level3 级别 cache 处理
   175  		if item.GetService() == model.MatchAll && item.GetNamespace() == model.MatchAll {
   176  			b.level3Rules[bt][conf.ID] = struct{}{}
   177  			return
   178  		}
   179  	}
   180  
   181  	if conf.GetRoutingPolicy() == apitraffic.RoutingPolicy_RulePolicy {
   182  		subRules := conf.RuleRouting.Rules
   183  		for i := range subRules {
   184  			sources := subRules[i].Sources
   185  			for i := range sources {
   186  				item := sources[i]
   187  				handler(outBound, item)
   188  			}
   189  
   190  			destinations := subRules[i].Destinations
   191  			for i := range destinations {
   192  				item := destinations[i]
   193  				handler(inBound, item)
   194  			}
   195  		}
   196  	}
   197  }
   198  
   199  // saveV1 保存 v1 级别的路由规则
   200  func (b *routeRuleBucket) saveV1(v1rule *model.RoutingConfig, v2rules []*model.ExtendRouterConfig) {
   201  	b.lock.Lock()
   202  	defer b.lock.Unlock()
   203  
   204  	b.v1rules[v1rule.ID] = v2rules
   205  
   206  	for i := range v2rules {
   207  		item := v2rules[i]
   208  		b.v1rulesToOld[item.ID] = v1rule.ID
   209  	}
   210  }
   211  
   212  func (b *routeRuleBucket) convertV2Size() uint32 {
   213  	b.lock.RLock()
   214  	defer b.lock.RUnlock()
   215  
   216  	return uint32(len(b.v1rulesToOld))
   217  }
   218  
   219  func (b *routeRuleBucket) deleteV2(id string) {
   220  	b.lock.Lock()
   221  	defer b.lock.Unlock()
   222  
   223  	rule := b.rules[id]
   224  	delete(b.rules, id)
   225  
   226  	if rule == nil {
   227  		return
   228  	}
   229  
   230  	if rule.GetRoutingPolicy() != apitraffic.RoutingPolicy_RulePolicy {
   231  		return
   232  	}
   233  
   234  	subRules := rule.RuleRouting.Rules
   235  	for i := range subRules {
   236  		for j := range subRules[i].GetSources() {
   237  			source := subRules[i].GetSources()[j]
   238  			service := source.GetService()
   239  			namespace := source.GetNamespace()
   240  
   241  			if service == model.MatchAll && namespace == model.MatchAll {
   242  				delete(b.level3Rules[outBound], id)
   243  				delete(b.level3Rules[inBound], id)
   244  			}
   245  
   246  			if service == model.MatchAll && namespace != model.MatchAll {
   247  				delete(b.level2Rules[outBound][namespace], id)
   248  				delete(b.level2Rules[inBound][namespace], id)
   249  			}
   250  
   251  			if service != model.MatchAll && namespace != model.MatchAll {
   252  				key := buildServiceKey(namespace, service)
   253  				delete(b.level1Rules[key], id)
   254  			}
   255  		}
   256  	}
   257  }
   258  
   259  // deleteV1 删除 v1 的路由规则
   260  func (b *routeRuleBucket) deleteV1(serviceId string) {
   261  	b.lock.Lock()
   262  	defer b.lock.Unlock()
   263  
   264  	items, ok := b.v1rules[serviceId]
   265  	if !ok {
   266  		delete(b.v1rules, serviceId)
   267  		return
   268  	}
   269  
   270  	for i := range items {
   271  		delete(b.v1rulesToOld, items[i].ID)
   272  	}
   273  	delete(b.v1rules, serviceId)
   274  }
   275  
   276  // size Number of routing-v2 cache rules
   277  func (b *routeRuleBucket) size() int {
   278  	b.lock.RLock()
   279  	defer b.lock.RUnlock()
   280  
   281  	cnt := len(b.rules)
   282  	for k := range b.v1rules {
   283  		cnt += len(b.v1rules[k])
   284  	}
   285  
   286  	return cnt
   287  }
   288  
   289  // listEnableRules Inquire the routing rules of the V2 version through the service name,
   290  // and perform some filtering according to the Predicate
   291  func (b *routeRuleBucket) listEnableRules(service, namespace string) map[routingLevel][]*model.ExtendRouterConfig {
   292  	ret := make(map[routingLevel][]*model.ExtendRouterConfig)
   293  	tmpRecord := map[string]struct{}{}
   294  
   295  	b.lock.RLock()
   296  	defer b.lock.RUnlock()
   297  
   298  	predicate := func(item *model.ExtendRouterConfig) bool {
   299  		return item.Enable
   300  	}
   301  
   302  	// Query Level1 V2 version routing rules
   303  	key := buildServiceKey(namespace, service)
   304  	ids := b.level1Rules[key]
   305  	level1 := make([]*model.ExtendRouterConfig, 0, 4)
   306  	for i := range ids {
   307  		if v, ok := b.rules[i]; ok && predicate(v) {
   308  			level1 = append(level1, v)
   309  			tmpRecord[v.ID] = struct{}{}
   310  		}
   311  	}
   312  	ret[level1RoutingV2] = level1
   313  
   314  	handler := func(ids map[string]struct{}, bt boundType) []*model.ExtendRouterConfig {
   315  		ret := make([]*model.ExtendRouterConfig, 0, 4)
   316  
   317  		for k := range ids {
   318  			v := b.rules[k]
   319  			if v == nil {
   320  				continue
   321  			}
   322  			if _, ok := tmpRecord[v.ID]; ok {
   323  				continue
   324  			}
   325  			if !predicate(v) {
   326  				continue
   327  			}
   328  			ret = append(ret, v)
   329  			tmpRecord[v.ID] = struct{}{}
   330  		}
   331  
   332  		return ret
   333  	}
   334  
   335  	// Query Level 2 level routing-v2 rules
   336  	level2 := make([]*model.ExtendRouterConfig, 0, 4)
   337  	level2 = append(level2, handler(b.level2Rules[outBound][namespace], outBound)...)
   338  	level2 = append(level2, handler(b.level2Rules[inBound][namespace], inBound)...)
   339  	ret[level2RoutingV2] = level2
   340  
   341  	// Query Level3 level routing-v2 rules
   342  	level3 := make([]*model.ExtendRouterConfig, 0, 4)
   343  	level3 = append(level3, handler(b.level3Rules[outBound], outBound)...)
   344  	level3 = append(level3, handler(b.level3Rules[inBound], inBound)...)
   345  	ret[level3RoutingV2] = level3
   346  	return ret
   347  }
   348  
   349  // foreach Traversing all routing rules
   350  func (b *routeRuleBucket) foreach(proc types.RouterRuleIterProc) {
   351  	b.lock.RLock()
   352  	defer b.lock.RUnlock()
   353  
   354  	for k, v := range b.rules {
   355  		proc(k, v)
   356  	}
   357  
   358  	for _, rules := range b.v1rules {
   359  		for i := range rules {
   360  			proc(rules[i].ID, rules[i])
   361  		}
   362  	}
   363  }
   364  
   365  func buildServiceKey(namespace, service string) string {
   366  	return fmt.Sprintf("%s@@%s", namespace, service)
   367  }