Copilot commented on code in PR #3402:
URL: https://github.com/apache/dubbo-go/pull/3402#discussion_r3407611122


##########
common/url.go:
##########
@@ -820,7 +820,32 @@ func (c *URL) SetParams(m url.Values) {
 
 // ToMap transfer URL to Map
 func (c *URL) ToMap() map[string]string {
-       paramsMap := make(map[string]string)
+       c.paramsLock.RLock()
+       paramCount := len(c.params)
+       c.paramsLock.RUnlock()
+
+       fixedCount := 0
+       if c.Protocol != "" {
+               fixedCount++
+       }
+       if c.Username != "" {
+               fixedCount++
+       }
+       if c.Password != "" {
+               fixedCount++
+       }
+       if c.Location != "" {
+               fixedCount += 2 // host + port
+       }
+       if c.Path != "" {
+               fixedCount++
+       }
+
+       if paramCount == 0 && fixedCount == 0 {
+               return nil
+       }

Review Comment:
   `ToMap()` releases `paramsLock` before the early-return check, so a 
concurrent `SetParam/SetParams` can add params between the unlock and the 
`return nil`, causing `ToMap()` to incorrectly return nil even though params 
exist. Keep the lock held until the emptiness decision is made (fixedCount can 
be computed outside the lock).



##########
common/url.go:
##########
@@ -1019,23 +1038,76 @@ func IsEquals(left *URL, right *URL, excludes 
...string) bool {
                return false
        }
 
-       leftMap := left.ToMap()
-       rightMap := right.ToMap()
-       for _, exclude := range excludes {
-               delete(leftMap, exclude)
-               delete(rightMap, exclude)
+       // Build a small lookup set for excluded keys to avoid repeated linear 
scans
+       // and to avoid materializing two full maps just for comparison.
+       var excludeSet map[string]struct{}
+       if len(excludes) > 0 {
+               excludeSet = make(map[string]struct{}, len(excludes))
+               for _, k := range excludes {
+                       excludeSet[k] = struct{}{}
+               }
        }
 
-       if len(leftMap) != len(rightMap) {
-               return false
+       isExcluded := func(key string) bool {
+               if excludeSet == nil {
+                       return false
+               }
+               _, ok := excludeSet[key]
+               return ok
        }
 
-       for lk, lv := range leftMap {
-               if rv, ok := rightMap[lk]; !ok {
+       // Compare scalar fields directly.
+       if left.Protocol != right.Protocol && !isExcluded(PROTOCOL) {
+               return false
+       }
+       if left.Username != right.Username && !isExcluded("username") {
+               return false
+       }
+       if left.Password != right.Password && !isExcluded("password") {
+               return false
+       }
+       if left.Path != right.Path && !isExcluded("path") {
+               return false
+       }
+       if left.Location != right.Location {
+               if isExcluded("host") && isExcluded("port") {
+                       // Both excluded, skip Location comparison
+               } else if isExcluded("host") || isExcluded("port") {
+                       // Only one side of host:port excluded — fall through 
to param comparison

Review Comment:
   When only one of `host` or `port` is excluded and `left.Location != 
right.Location`, the current code intentionally "falls through" but never 
compares the non-excluded component. That can incorrectly treat URLs as equal 
even though the non-excluded host/port differs.



##########
common/url.go:
##########
@@ -839,24 +864,18 @@ func (c *URL) ToMap() map[string]string {
                paramsMap["password"] = c.Password
        }
        if c.Location != "" {
-               paramsMap["host"] = strings.Split(c.Location, ":")[0]
-               var port string
-               if strings.Contains(c.Location, ":") {
-                       port = strings.Split(c.Location, ":")[1]
+               // Single-pass split avoids repeated string scanning.
+               parts := strings.Split(c.Location, ":")
+               paramsMap["host"] = parts[0]
+               if len(parts) > 1 {
+                       paramsMap["port"] = parts[len(parts)-1]

Review Comment:
   `ToMap()` currently uses `strings.Split(c.Location, ":")` and then takes the 
last element as port. This both allocates and changes behavior vs the previous 
implementation for locations containing multiple ':' (e.g. IPv6 or multiple 
endpoints). If the goal is to preserve existing semantics while reducing 
allocations, parse host/port without allocating and keep port as the segment 
between the first and second ':' (or "0" when missing).



-- 
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]

Reply via email to