Skip to content

Commit 5a5cad1

Browse files
authored
*: Fix data race between getting labels and setting labels in config (#45563) (#45567)
close #45561
1 parent ff34755 commit 5a5cad1

File tree

2 files changed

+50
-5
lines changed

2 files changed

+50
-5
lines changed

server/http_handler.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,12 +2207,15 @@ func (h labelHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
22072207

22082208
if len(labels) > 0 {
22092209
cfg := *config.GetGlobalConfig()
2210-
if cfg.Labels == nil {
2211-
cfg.Labels = make(map[string]string, len(labels))
2212-
}
2213-
for k, v := range labels {
2214-
cfg.Labels[k] = v
2210+
// Be careful of data race. The key & value of cfg.Labels must not be changed.
2211+
if cfg.Labels != nil {
2212+
for k, v := range cfg.Labels {
2213+
if _, found := labels[k]; !found {
2214+
labels[k] = v
2215+
}
2216+
}
22152217
}
2218+
cfg.Labels = labels
22162219
config.StoreGlobalConfig(&cfg)
22172220
logutil.BgLogger().Info("update server labels", zap.Any("labels", cfg.Labels))
22182221
}

server/http_handler_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"encoding/json"
2525
"fmt"
2626
"io"
27+
"math/rand"
2728
"net"
2829
"net/http"
2930
"net/http/httptest"
@@ -1197,3 +1198,44 @@ func TestSetLabels(t *testing.T) {
11971198
// reset the global variable
11981199
config.GetGlobalConfig().Labels = map[string]string{}
11991200
}
1201+
1202+
func TestSetLabelsConcurrentWithGetLabel(t *testing.T) {
1203+
ts := createBasicHTTPHandlerTestSuite()
1204+
1205+
ts.startServer(t)
1206+
defer ts.stopServer(t)
1207+
1208+
testUpdateLabels := func() {
1209+
labels := map[string]string{}
1210+
labels["zone"] = fmt.Sprintf("z-%v", rand.Intn(100000))
1211+
buffer := bytes.NewBuffer([]byte{})
1212+
require.Nil(t, json.NewEncoder(buffer).Encode(labels))
1213+
resp, err := ts.postStatus("/labels", "application/json", buffer)
1214+
require.NoError(t, err)
1215+
require.NotNil(t, resp)
1216+
defer func() {
1217+
require.NoError(t, resp.Body.Close())
1218+
}()
1219+
require.Equal(t, http.StatusOK, resp.StatusCode)
1220+
newLabels := config.GetGlobalConfig().Labels
1221+
require.Equal(t, newLabels, labels)
1222+
}
1223+
done := make(chan struct{})
1224+
go func() {
1225+
for {
1226+
select {
1227+
case <-done:
1228+
return
1229+
default:
1230+
config.GetGlobalConfig().GetTiKVConfig()
1231+
}
1232+
}
1233+
}()
1234+
for i := 0; i < 100; i++ {
1235+
testUpdateLabels()
1236+
}
1237+
close(done)
1238+
1239+
// reset the global variable
1240+
config.GetGlobalConfig().Labels = map[string]string{}
1241+
}

0 commit comments

Comments
 (0)