diff --git a/remoting/codec.go b/remoting/codec.go index 91126ebf24..e273a3d718 100644 --- a/remoting/codec.go +++ b/remoting/codec.go @@ -19,6 +19,7 @@ package remoting import ( "bytes" + "sync" ) // Codec is the interface that wrap EncodeRequest、 EncodeResponse and Decode method @@ -34,12 +35,19 @@ type DecodeResult struct { Result any } -var codec = make(map[string]Codec, 2) +var ( + codecMu sync.RWMutex + codec = make(map[string]Codec, 2) +) func RegistryCodec(protocol string, codecTmp Codec) { + codecMu.Lock() + defer codecMu.Unlock() codec[protocol] = codecTmp } func GetCodec(protocol string) Codec { + codecMu.RLock() + defer codecMu.RUnlock() return codec[protocol] } diff --git a/remoting/codec_test.go b/remoting/codec_test.go index ced9c6ca20..0fa14cb063 100644 --- a/remoting/codec_test.go +++ b/remoting/codec_test.go @@ -19,6 +19,7 @@ package remoting import ( "bytes" + "sync" "testing" ) @@ -101,3 +102,28 @@ func TestCodecInterface(t *testing.T) { assert.NotNil(t, result) assert.Equal(t, 9, length) } + +func TestConcurrentCodecAccess(t *testing.T) { + const goroutines = 100 + var wg sync.WaitGroup + wg.Add(goroutines * 2) + + // Concurrent writers + for i := 0; i < goroutines; i++ { + go func(i int) { + defer wg.Done() + RegistryCodec("concurrent-"+string(rune('a'+i%26)), &mockCodec{}) + }(i) + } + + // Concurrent readers + for i := 0; i < goroutines; i++ { + go func(i int) { + defer wg.Done() + GetCodec("concurrent-" + string(rune('a'+i%26))) + }(i) + } + + wg.Wait() + // If we reach here without a panic, the concurrent access is safe. +}