From d50609d4a0971854cbcfb22669596512ce73580f Mon Sep 17 00:00:00 2001 From: Ccheers <1048315650@qq.com> Date: Mon, 19 Aug 2024 10:53:58 +0800 Subject: [PATCH] fix(registry/polaris): fix concurrent map iteration and map write #3361 (#3386) * fix(registry/polaris): fix concurrent map iteration and map write #3361 * fix(test): support go 1.20.x * fix(test): fix test mock concurrent read * fix: fix Metadata use rmd & remove dup space --- contrib/polaris/registry.go | 30 +++++++++++++++++++++++------- contrib/polaris/registry_test.go | 15 +++++++++++++++ 2 files changed, 38 insertions(+), 7 deletions(-) diff --git a/contrib/polaris/registry.go b/contrib/polaris/registry.go index 4d1e4a33747..9a8472c05cd 100644 --- a/contrib/polaris/registry.go +++ b/contrib/polaris/registry.go @@ -115,15 +115,16 @@ func (r *Registry) Register(_ context.Context, instance *registry.ServiceInstanc } // metadata - if instance.Metadata == nil { - instance.Metadata = make(map[string]string) + rmd := mapClone(instance.Metadata) + if rmd == nil { + rmd = make(map[string]string) } - instance.Metadata["merge"] = id - if _, ok := instance.Metadata["weight"]; !ok { - instance.Metadata["weight"] = strconv.Itoa(r.opt.Weight) + rmd["merge"] = id + if _, ok := rmd["weight"]; !ok { + rmd["weight"] = strconv.Itoa(r.opt.Weight) } - weight, _ := strconv.Atoi(instance.Metadata["weight"]) + weight, _ := strconv.Atoi(rmd["weight"]) _, err = r.provider.RegisterInstance( &polaris.InstanceRegisterRequest{ @@ -137,7 +138,7 @@ func (r *Registry) Register(_ context.Context, instance *registry.ServiceInstanc Weight: &weight, Priority: &r.opt.Priority, Version: &instance.Version, - Metadata: instance.Metadata, + Metadata: rmd, Healthy: &r.opt.Healthy, Isolate: &r.opt.Isolate, TTL: &r.opt.TTL, @@ -378,3 +379,18 @@ func instancesToServiceInstances(instances map[string][]model.Instance) []*regis } return serviceInstances } + +// Clone returns a copy of m. This is a shallow clone: +// the new keys and values are set using ordinary assignment. +func mapClone[M ~map[K]V, K comparable, V any](m M) M { + // Preserve nil in case it matters. + if m == nil { + return nil + } + // Make a shallow copy of the map. + m2 := make(M, len(m)) + for k, v := range m { + m2[k] = v + } + return m2 +} diff --git a/contrib/polaris/registry_test.go b/contrib/polaris/registry_test.go index a03f807e497..2a4426ed4ff 100644 --- a/contrib/polaris/registry_test.go +++ b/contrib/polaris/registry_test.go @@ -2,6 +2,7 @@ package polaris import ( "context" + "strconv" "testing" "time" @@ -28,6 +29,9 @@ func TestRegistry(t *testing.T) { WithRegistryTTL(1000), ) + mm := map[string]string{ + "test1": "test1", + } ins := ®istry.ServiceInstance{ ID: "test-ut", Name: "test-ut", @@ -36,8 +40,19 @@ func TestRegistry(t *testing.T) { "grpc://127.0.0.1:8080", "http://127.0.0.1:9090", }, + Metadata: mm, } + go func() { + for i := 0; true; i++ { + str := "test" + strconv.Itoa(i) + _ = mm[str] + if i > 100 { + i = 0 + } + } + }() + err = r.Register(context.Background(), ins) t.Cleanup(func() {