Aetherance commented on code in PR #3305:
URL: https://github.com/apache/dubbo-go/pull/3305#discussion_r3293056458
##########
cluster/router/tag/router.go:
##########
@@ -157,3 +172,269 @@ func parseRoute(routeContent string)
(*global.RouterConfig, error) {
}
return routerConfig, nil
}
+
+func (p *PriorityRouter) Name() string {
+ return "tag"
+}
+
+func (p *PriorityRouter) ShouldPool() bool {
+ return true
+}
+
+func (p *PriorityRouter) Pool(invokers []base.Invoker) (router.AddrPool,
router.AddrMetadata) {
+ pool := make(router.AddrPool)
+ for i, invoker := range invokers {
+ url := invoker.GetURL()
+ upsertBM(pool, "*", i)
+ tag := url.GetParam(constant.Tagkey, "")
+ upsertBM(pool, "tag\x00"+tag, i)
+ addr := url.Location
+ if addr != "" {
+ upsertBM(pool, "addr\x00"+addr, i)
+ if idx := strings.LastIndex(addr, ":"); idx > 0 {
+ upsertBM(pool, "port\x00"+addr[idx+1:], i)
+ }
+ }
+ for _, key := range []string{"version", "group"} {
+ if v := url.GetParam(key, ""); v != "" {
+ upsertBM(pool, "param\x00"+key+"\x00"+v, i)
+ } else {
+ upsertBM(pool, "param\x00"+key+"\x00\x00", i)
+ }
+ }
+ }
+ return pool, nil
+}
+
+func (p *PriorityRouter) SetCache(cache router.Cache) {
+ p.cache = cache
+}
+
+func (p *PriorityRouter) routeWithPool(invokers []base.Invoker, pool
router.AddrPool, url *common.URL, invocation base.Invocation) []base.Invoker {
+ tag := invocation.GetAttachmentWithDefaultValue(constant.Tagkey,
url.GetParam(constant.Tagkey, ""))
+
+ application := invokers[0].GetURL().GetParam(constant.ApplicationKey,
"")
+ key := strings.Join([]string{application,
constant.TagRouterRuleSuffix}, "")
+ value, ok := p.routerConfigs.Load(key)
+ if !ok {
+ return collectInvokers(invokers, p.staticTagMatchBM(pool, tag,
url, invocation))
+ }
+ routerCfg := value.(global.RouterConfig)
+ enabled := routerCfg.Enabled == nil || *routerCfg.Enabled
+ valid := (routerCfg.Valid != nil && *routerCfg.Valid) ||
(routerCfg.Valid == nil && len(routerCfg.Tags) > 0)
+ if !enabled || !valid {
+ return collectInvokers(invokers, p.staticTagMatchBM(pool, tag,
url, invocation))
+ }
+ if tag == "" {
+ return collectInvokers(invokers, p.emptyTagMatchBM(pool,
routerCfg))
+ }
+ bm := p.requestTagMatchBM(pool, url, invocation, routerCfg, tag)
+ if bm == nil {
+ return requestTag(invokers, url, invocation, routerCfg, tag)
+ }
+ return collectInvokers(invokers, bm)
+}
+
+func (p *PriorityRouter) staticTagMatchBM(pool router.AddrPool, tag string,
url *common.URL, invocation base.Invocation) *roaring.Bitmap {
+ if tag != "" {
+ if bm := pool["tag\x00"+tag]; bm != nil && !bm.IsEmpty() {
+ return bm
+ }
+ if requestIsForce(url, invocation) {
+ return nil
+ }
+ }
+ return pool["tag\x00"]
+}
+
+func (p *PriorityRouter) requestTagMatchBM(pool router.AddrPool, url
*common.URL, invocation base.Invocation,
+ cfg global.RouterConfig, tag string) *roaring.Bitmap {
+ var (
+ addresses []string
+ match []*common.ParamMatch
+ )
+ for _, tagCfg := range cfg.Tags {
+ if tagCfg.Name == tag {
+ addresses = tagCfg.Addresses
+ match = tagCfg.Match
+ break
+ }
+ }
+
+ var resultBM *roaring.Bitmap
+ if len(match) != 0 {
+ resultBM = p.matchBM(pool, match)
+ } else if len(addresses) != 0 {
+ resultBM = p.addressesBM(pool, addresses)
+ } else {
+ resultBM = pool["tag\x00"+tag]
+ }
+
+ if (cfg.Force != nil && *cfg.Force) || requestIsForce(url, invocation) {
+ return resultBM
+ }
+ if resultBM != nil && !resultBM.IsEmpty() {
+ return resultBM
+ }
+
+ emptyBM := pool["tag\x00"]
+ if emptyBM == nil {
+ return nil
+ }
+ if len(addresses) == 0 {
+ return emptyBM
+ }
+ addrBM := p.addressesBM(pool, addresses)
+ if addrBM != nil && !addrBM.IsEmpty() {
+ allBM := pool["*"]
+ if allBM != nil {
+ result := allBM.Clone()
+ result.AndNot(addrBM)
+ return result
+ }
+ }
+ return pool["*"]
+}
+
+func (p *PriorityRouter) emptyTagMatchBM(pool router.AddrPool, cfg
global.RouterConfig) *roaring.Bitmap {
+ bm := pool["tag\x00"]
+ if bm == nil || bm.IsEmpty() {
+ return bm
+ }
+ for _, tagCfg := range cfg.Tags {
+ if len(tagCfg.Addresses) == 0 {
+ continue
+ }
+ addrBM := p.addressesBM(pool, tagCfg.Addresses)
+ if addrBM != nil && !addrBM.IsEmpty() && bm != nil {
+ result := bm.Clone()
+ result.AndNot(addrBM)
+ bm = result
+ }
+ }
+ return bm
+}
+
+func (p *PriorityRouter) addressesBM(pool router.AddrPool, addrs []string)
*roaring.Bitmap {
+ bm := roaring.NewBitmap()
+ for _, addr := range addrs {
+ if ab := pool["addr\x00"+addr]; ab != nil {
+ bm.Or(ab)
+ }
+ if idx := strings.LastIndex(addr, ":"); idx > 0 && addr[:idx]
== constant.AnyHostValue {
+ if pb := pool["port\x00"+addr[idx+1:]]; pb != nil {
+ bm.Or(pb)
+ }
+ }
+ }
+ return bm
+}
+
+func (p *PriorityRouter) matchBM(pool router.AddrPool, matches
[]*common.ParamMatch) *roaring.Bitmap {
+ var result *roaring.Bitmap
+ for _, m := range matches {
+ bm := p.paramMatchBM(pool, m)
+ if bm == nil {
+ return nil
+ }
+ if result == nil {
+ result = bm.Clone()
+ } else {
+ result.And(bm)
+ }
+ if result.IsEmpty() {
+ return result
+ }
+ }
+ return result
+}
+
+func (p *PriorityRouter) paramMatchBM(pool router.AddrPool, pm
*common.ParamMatch) *roaring.Bitmap {
+ prefix := "param\x00" + pm.Key + "\x00"
+ switch {
+ case pm.Value.Exact != "":
+ return pool[prefix+pm.Value.Exact]
+ case pm.Value.Wildcard != "":
+ if pm.Value.Wildcard == constant.AnyValue {
+ return pool["*"]
+ }
+ return pool[prefix+pm.Value.Wildcard]
+ case pm.Value.Prefix != "":
+ return scanPrefixBM(pool, prefix, pm.Value.Prefix)
+ case pm.Value.Regex != "":
+ return scanRegexBM(pool, prefix, pm.Value.Regex)
+ case pm.Value.Empty != "":
+ return pool[prefix+"\x00"]
+ case pm.Value.Noempty != "":
+ emptyBM := pool[prefix+"\x00"]
+ allBM := pool["*"]
+ if allBM == nil {
+ return roaring.NewBitmap()
+ }
+ if emptyBM != nil {
+ result := allBM.Clone()
+ result.AndNot(emptyBM)
+ return result
+ }
+ return allBM
+ }
+ return roaring.NewBitmap()
+}
+
+func collectInvokers(invokers []base.Invoker, bm *roaring.Bitmap)
[]base.Invoker {
+ if bm == nil || bm.IsEmpty() {
+ return []base.Invoker{}
+ }
+ result := make([]base.Invoker, 0, bm.GetCardinality())
+ for _, idx := range bm.ToArray() {
+ if int(idx) < len(invokers) {
+ result = append(result, invokers[int(idx)])
+ }
+ }
+ return result
+}
+
+func upsertBM(pool router.AddrPool, key string, idx int) {
+ if _, ok := pool[key]; !ok {
+ pool[key] = roaring.NewBitmap()
+ }
+ pool[key].Add(uint32(idx))
+}
+
+func scanPrefixBM(pool router.AddrPool, prefix string, value string)
*roaring.Bitmap {
+ bm := roaring.NewBitmap()
+ for key, entry := range pool {
+ if !strings.HasPrefix(key, prefix) {
+ continue
+ }
+ if strings.HasSuffix(key, "\x00") {
+ continue
+ }
+ val := key[len(prefix):]
+ if strings.HasPrefix(val, value) {
+ bm.Or(entry)
+ }
+ }
+ return bm
+}
+
+func scanRegexBM(pool router.AddrPool, prefix string, pattern string)
*roaring.Bitmap {
+ re, err := regexp.Compile(pattern)
+ if err != nil {
+ return roaring.NewBitmap()
+ }
+ bm := roaring.NewBitmap()
+ for key, entry := range pool {
+ if !strings.HasPrefix(key, prefix) {
+ continue
Review Comment:
match 字段的 Key 可以是任意字段名,全量 bitmap 索引成本过高,已移除。非空时 fallback 到 requestTag 遍历。
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]