Skip to content

Commit 3bf11e4

Browse files
committed
chore: resolve merge conflicts with apache#3370, keeping DeepCopy for concurrency safety and integrating new Tag field
Signed-off-by: jieguo-coder <1193249232@qq.com>
2 parents d3f571d + a7b6ee6 commit 3bf11e4

14 files changed

Lines changed: 931 additions & 160 deletions

common/url.go

Lines changed: 158 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -395,17 +395,36 @@ func isMatchCategory(category1 string, category2 string) bool {
395395
}
396396

397397
func (c *URL) String() string {
398-
c.paramsLock.Lock()
399-
defer c.paramsLock.Unlock()
398+
c.paramsLock.RLock()
399+
defer c.paramsLock.RUnlock()
400+
401+
encodedParams := c.params.Encode()
400402
var buf strings.Builder
401-
if len(c.Username) == 0 && len(c.Password) == 0 {
402-
buf.WriteString(fmt.Sprintf("%s://%s:%s%s", c.Protocol, c.Ip, c.Port, c.Path))
403-
} else {
404-
buf.WriteString(fmt.Sprintf("%s://%s:%s@%s:%s%s", c.Protocol, c.Username, c.Password, c.Ip, c.Port, c.Path))
403+
404+
size := len(c.Protocol) + len("://") + len(c.Ip) + len(":") + len(c.Port) + len(c.Path)
405+
if len(c.Username) != 0 || len(c.Password) != 0 {
406+
size += len(c.Username) + len(":") + len(c.Password) + len("@")
407+
}
408+
if encodedParams != "" {
409+
size += len("?") + len(encodedParams)
410+
}
411+
412+
buf.Grow(size)
413+
buf.WriteString(c.Protocol)
414+
buf.WriteString("://")
415+
if len(c.Username) != 0 || len(c.Password) != 0 {
416+
buf.WriteString(c.Username)
417+
buf.WriteString(":")
418+
buf.WriteString(c.Password)
419+
buf.WriteString("@")
405420
}
406-
if encoded := c.params.Encode(); encoded != "" {
421+
buf.WriteString(c.Ip)
422+
buf.WriteString(":")
423+
buf.WriteString(c.Port)
424+
buf.WriteString(c.Path)
425+
if encodedParams != "" {
407426
buf.WriteByte('?')
408-
buf.WriteString(encoded)
427+
buf.WriteString(encodedParams)
409428
}
410429
return buf.String()
411430
}
@@ -678,23 +697,34 @@ func (c *URL) GetParams() url.Values {
678697
return c.CopyParams()
679698
}
680699

681-
// CopyParams returns a deep copy of params.
682-
func (c *URL) CopyParams() url.Values {
683-
c.paramsLock.RLock()
684-
defer c.paramsLock.RUnlock()
685-
686-
if c.params == nil {
700+
func copyURLValues(src url.Values) url.Values {
701+
if src == nil {
687702
return nil
688703
}
689704

690-
params := make(url.Values, len(c.params))
691-
for k, vs := range c.params {
705+
dst := make(url.Values, len(src))
706+
for k, vs := range src {
692707
copied := make([]string, len(vs))
693708
copy(copied, vs)
694-
params[k] = copied
709+
dst[k] = copied
695710
}
696711

697-
return params
712+
return dst
713+
}
714+
715+
func valuesHasNonDefaultParam(values url.Values, key string) bool {
716+
if len(values) == 0 {
717+
return false
718+
}
719+
return values.Get(key) != ""
720+
}
721+
722+
// CopyParams returns a deep copy of params.
723+
func (c *URL) CopyParams() url.Values {
724+
c.paramsLock.RLock()
725+
defer c.paramsLock.RUnlock()
726+
727+
return copyURLValues(c.params)
698728
}
699729

700730
// GetParamAndDecoded gets values and decode
@@ -880,41 +910,53 @@ func (c *URL) ToMap() map[string]string {
880910
func (c *URL) MergeURL(anotherUrl *URL) *URL {
881911
// After Clone, it is a new URL that there is no thread safe issue.
882912
mergedURL := c.Clone()
883-
params := mergedURL.GetParams()
884-
// iterator the anotherUrl if c not have the key ,merge in
885-
// anotherUrl usually will not changed. so change RangeParams to GetParams to avoid the string value copy.// Group get group
886-
for key, value := range anotherUrl.GetParams() {
887-
if _, ok := mergedURL.GetNonDefaultParam(key); !ok {
888-
if len(value) > 0 {
889-
params[key] = make([]string, len(value))
890-
copy(params[key], value)
913+
params := mergedURL.params
914+
if params == nil {
915+
params = url.Values{}
916+
mergedURL.params = params
917+
}
918+
baseTimestamp := params.Get(constant.TimestampKey)
919+
baseHasTimestamp := baseTimestamp != ""
920+
921+
func() {
922+
anotherUrl.paramsLock.RLock()
923+
defer anotherUrl.paramsLock.RUnlock()
924+
925+
// Merge params from anotherUrl under one read lock.
926+
for key, value := range anotherUrl.params {
927+
if !valuesHasNonDefaultParam(params, key) {
928+
if len(value) > 0 {
929+
params[key] = make([]string, len(value))
930+
copy(params[key], value)
931+
}
891932
}
892933
}
893-
}
894-
895-
// remote timestamp
896-
if v, ok := c.GetNonDefaultParam(constant.TimestampKey); !ok {
897-
params[constant.RemoteTimestampKey] = []string{v}
898-
params[constant.TimestampKey] = []string{anotherUrl.GetParam(constant.TimestampKey, "")}
899-
}
900934

901-
// finally execute methodConfigMergeFcn
902-
mergedURL.Methods = make([]string, len(anotherUrl.Methods))
903-
for i, method := range anotherUrl.Methods {
904-
for _, paramKey := range []string{constant.LoadbalanceKey, constant.ClusterKey, constant.RetriesKey, constant.TimeoutKey} {
905-
if v := anotherUrl.GetParam(paramKey, ""); len(v) > 0 {
906-
params[paramKey] = []string{v}
907-
}
935+
// remote timestamp
936+
if !baseHasTimestamp {
937+
params[constant.RemoteTimestampKey] = []string{baseTimestamp}
938+
params[constant.TimestampKey] = []string{anotherUrl.params.Get(constant.TimestampKey)}
939+
}
908940

909-
methodsKey := "methods." + method + "." + paramKey
910-
// if len(mergedURL.GetParam(methodsKey, "")) == 0 {
911-
if v := anotherUrl.GetParam(methodsKey, ""); len(v) > 0 {
912-
params[methodsKey] = []string{v}
941+
// finally execute methodConfigMergeFcn
942+
mergedURL.Methods = make([]string, len(anotherUrl.Methods))
943+
for i, method := range anotherUrl.Methods {
944+
for _, paramKey := range []string{constant.LoadbalanceKey, constant.ClusterKey, constant.RetriesKey, constant.TimeoutKey} {
945+
if v := anotherUrl.params.Get(paramKey); len(v) > 0 {
946+
params[paramKey] = []string{v}
947+
}
948+
949+
methodsKey := "methods." + method + "." + paramKey
950+
// if len(mergedURL.GetParam(methodsKey, "")) == 0 {
951+
if v := anotherUrl.params.Get(methodsKey); len(v) > 0 {
952+
params[methodsKey] = []string{v}
953+
}
954+
// }
955+
mergedURL.Methods[i] = method
913956
}
914-
// }
915-
mergedURL.Methods[i] = method
916957
}
917-
}
958+
}()
959+
918960
// merge attributes
919961
anotherUrl.RangeAttributes(func(attrK string, attrV any) bool {
920962
if _, ok := mergedURL.GetAttribute(attrK); !ok {
@@ -931,7 +973,27 @@ func (c *URL) MergeURL(anotherUrl *URL) *URL {
931973
// excludeParams: the set of parameters to exclude from the cloned URL
932974
// reserveParams: the set of parameters to retain in the cloned URL
933975
func (c *URL) CloneWithFilter(excludeParams *gxset.HashSet, reserveParams []string) *URL {
934-
newURL := &URL{
976+
newURL := c.newURLForClone()
977+
newURL.params = c.copyFilteredParams(newURL.params, excludeParams, reserveParams)
978+
979+
// Copy attributes
980+
c.RangeAttributes(
981+
func(key string, value any) bool {
982+
newURL.SetAttribute(key, value)
983+
return true
984+
},
985+
)
986+
987+
// Copy SubURL if it exists
988+
if c.SubURL != nil {
989+
newURL.SubURL = c.SubURL.Clone()
990+
}
991+
992+
return newURL
993+
}
994+
995+
func (c *URL) newURLForClone() *URL {
996+
return &URL{
935997
Protocol: c.Protocol,
936998
Location: c.Location,
937999
Ip: c.Ip,
@@ -945,37 +1007,60 @@ func (c *URL) CloneWithFilter(excludeParams *gxset.HashSet, reserveParams []stri
9451007
attributes: make(map[string]any),
9461008
params: url.Values{},
9471009
}
1010+
}
9481011

949-
// Copy and filter params based on excludeParams or reserveParams
950-
c.RangeParams(
951-
func(key, value string) bool {
952-
// If the param is in excludeParams or not in reserveParams, skip it
953-
if excludeParams != nil && excludeParams.Contains(key) {
954-
return true
955-
}
956-
if len(reserveParams) > 0 && !slices.Contains(reserveParams, key) {
957-
return true
1012+
func (c *URL) copyFilteredParams(params url.Values, excludeParams *gxset.HashSet, reserveParams []string) url.Values {
1013+
c.paramsLock.RLock()
1014+
defer c.paramsLock.RUnlock()
1015+
1016+
if excludeParams == nil && len(reserveParams) == 0 {
1017+
if len(c.params) > 8 {
1018+
copiedParams := copyURLValues(c.params)
1019+
if copiedParams != nil {
1020+
return copiedParams
9581021
}
959-
// Set the param if it passes the filter
960-
newURL.SetParam(key, value)
961-
return true
962-
},
963-
)
1022+
}
1023+
for key, values := range c.params {
1024+
copied := make([]string, len(values))
1025+
copy(copied, values)
1026+
params[key] = copied
1027+
}
1028+
return params
1029+
}
9641030

965-
// Copy attributes
966-
c.RangeAttributes(
967-
func(key string, value any) bool {
968-
newURL.SetAttribute(key, value)
969-
return true
970-
},
971-
)
1031+
if capacity := paramsCapacityForClone(len(c.params), excludeParams, reserveParams); capacity > 8 {
1032+
params = make(url.Values, capacity)
1033+
}
9721034

973-
// Copy SubURL if it exists
974-
if c.SubURL != nil {
975-
newURL.SubURL = c.SubURL.Clone()
1035+
for key, values := range c.params {
1036+
if shouldCopyParam(key, excludeParams, reserveParams) {
1037+
copied := make([]string, len(values))
1038+
copy(copied, values)
1039+
params[key] = copied
1040+
}
9761041
}
9771042

978-
return newURL
1043+
return params
1044+
}
1045+
1046+
func paramsCapacityForClone(paramsLen int, excludeParams *gxset.HashSet, reserveParams []string) int {
1047+
if len(reserveParams) > 0 && len(reserveParams) < paramsLen {
1048+
paramsLen = len(reserveParams)
1049+
}
1050+
if excludeParams != nil {
1051+
paramsLen -= excludeParams.Size()
1052+
}
1053+
if paramsLen < 0 {
1054+
return 0
1055+
}
1056+
return paramsLen
1057+
}
1058+
1059+
func shouldCopyParam(key string, excludeParams *gxset.HashSet, reserveParams []string) bool {
1060+
if excludeParams != nil && excludeParams.Contains(key) {
1061+
return false
1062+
}
1063+
return len(reserveParams) == 0 || slices.Contains(reserveParams, key)
9791064
}
9801065

9811066
// Clone will copy the URL

0 commit comments

Comments
 (0)