Aetherance commented on code in PR #3305: URL: https://github.com/apache/dubbo-go/pull/3305#discussion_r3367092366
########## cluster/router/tag/cache.go: ########## @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package tag + +import ( + "strings" +) + +import ( + "github.com/RoaringBitmap/roaring" +) + +import ( + "dubbo.apache.org/dubbo-go/v3/cluster/router" + "dubbo.apache.org/dubbo-go/v3/common" + "dubbo.apache.org/dubbo-go/v3/common/constant" + "dubbo.apache.org/dubbo-go/v3/global" + "dubbo.apache.org/dubbo-go/v3/protocol/base" +) + +func (p *PriorityRouter) Name() string { + return "tag" +} + +func (p *PriorityRouter) ShouldPool() bool { + return true +} + +// Pool builds bitmap indices for tag, address, and port keys. +// Key space uses "\x00" as separator. +// Other Poolable routers should use different prefixes to avoid conflicts. +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, constant.PoolKeyAll, i) + tag := url.GetParam(constant.Tagkey, "") + upsertBM(pool, constant.PoolKeyTagPrefix+tag, i) + addr := url.Location + if addr != "" { + upsertBM(pool, constant.PoolKeyAddrPrefix+addr, i) + if idx := strings.LastIndex(addr, ":"); idx > 0 { + upsertBM(pool, constant.PoolKeyPortPrefix+addr[idx+1:], i) + } + } + } + return pool, nil +} + +func (p *PriorityRouter) SetCache(cache router.Cache) { + if cache != nil { + p.cache.Store(cache) + } +} + +func (p *PriorityRouter) routeWithPool(invokers []base.Invoker, pool router.AddrPool, url *common.URL, invocation base.Invocation) []base.Invoker { + if len(invokers) == 0 { + return invokers + } + 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[constant.PoolKeyTagPrefix+tag]; bm != nil && !bm.IsEmpty() { + return bm + } + if requestIsForce(url, invocation) { + return nil + } + } + return pool[constant.PoolKeyTagPrefix] +} + +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 + } + } + + if len(match) != 0 { + return nil // not bitmap-cached; fall back to requestTag + } Review Comment: 缓存 ParamMatch 会引入过于高的复杂度 已在注释和 pr 描述中明确 ParamMatch 对应字段不为空直接fallback到无缓存路径 -- 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]
