Skip to content

Commit a1ea04c

Browse files
authored
*: Implement /upgrade/start and upgrade/finish APIs (pingcap#47000)
close pingcap#47172
1 parent 9fdf362 commit a1ea04c

15 files changed

+581
-97
lines changed

ddl/mock.go

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -143,43 +143,48 @@ func NewMockStateSyncer() syncer.StateSyncer {
143143
return &MockStateSyncer{}
144144
}
145145

146+
// clusterState mocks cluster state.
147+
// We move it from MockStateSyncer to here. Because we want to make it unaffected by ddl close.
148+
var clusterState *atomicutil.Pointer[syncer.StateInfo]
149+
146150
// MockStateSyncer is a mock state syncer, it is exported for testing.
147151
type MockStateSyncer struct {
148-
clusterState *atomicutil.Pointer[syncer.StateInfo]
149-
globalVerCh chan clientv3.WatchResponse
150-
mockSession chan struct{}
152+
globalVerCh chan clientv3.WatchResponse
153+
mockSession chan struct{}
151154
}
152155

153156
// Init implements StateSyncer.Init interface.
154157
func (s *MockStateSyncer) Init(context.Context) error {
155158
s.globalVerCh = make(chan clientv3.WatchResponse, 1)
156159
s.mockSession = make(chan struct{}, 1)
157160
state := syncer.NewStateInfo(syncer.StateNormalRunning)
158-
s.clusterState = atomicutil.NewPointer(state)
161+
if clusterState == nil {
162+
clusterState = atomicutil.NewPointer(state)
163+
}
159164
return nil
160165
}
161166

162167
// UpdateGlobalState implements StateSyncer.UpdateGlobalState interface.
163168
func (s *MockStateSyncer) UpdateGlobalState(_ context.Context, stateInfo *syncer.StateInfo) error {
164169
failpoint.Inject("mockUpgradingState", func(val failpoint.Value) {
165170
if val.(bool) {
166-
s.clusterState.Store(stateInfo)
171+
clusterState.Store(stateInfo)
167172
failpoint.Return(nil)
168173
}
169174
})
170175
s.globalVerCh <- clientv3.WatchResponse{}
171-
s.clusterState.Store(stateInfo)
176+
clusterState.Store(stateInfo)
172177
return nil
173178
}
174179

175180
// GetGlobalState implements StateSyncer.GetGlobalState interface.
176-
func (s *MockStateSyncer) GetGlobalState(context.Context) (*syncer.StateInfo, error) {
177-
return s.clusterState.Load(), nil
181+
func (*MockStateSyncer) GetGlobalState(context.Context) (*syncer.StateInfo, error) {
182+
return clusterState.Load(), nil
178183
}
179184

180185
// IsUpgradingState implements StateSyncer.IsUpgradingState interface.
181-
func (s *MockStateSyncer) IsUpgradingState() bool {
182-
return s.clusterState.Load().State == syncer.StateUpgrading
186+
func (*MockStateSyncer) IsUpgradingState() bool {
187+
return clusterState.Load().State == syncer.StateUpgrading
183188
}
184189

185190
// WatchChan implements StateSyncer.WatchChan interface.

docs/tidb_http_api.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,6 @@ timezone.*
564564
# reset the size of the ballast object (2GB in this example)
565565
curl -v -X POST -d "2147483648" http://{TiDBIP}:10080/debug/ballast-object-sz
566566
```
567-
568567
569568
1. Set deadlock history table capacity
570569
@@ -591,3 +590,14 @@ timezone.*
591590
```shell
592591
curl -X POST -d "transaction_summary_capacity={number}" http://{TiDBIP}:10080/settings
593592
```
593+
594+
1. Send upgrade operations to the cluster. The operations here include `start` and `finish`.
595+
596+
```shell
597+
curl -X POST http://{TiDBIP}:10080/upgrade/{op}
598+
```
599+
600+
```shell
601+
$curl -X POST http://127.0.0.1:10080/upgrade/start
602+
"success!"
603+
```

server/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ go_library(
2222
"stat.go",
2323
"statistics_handler.go",
2424
"tokenlimiter.go",
25+
"upgrade_handler.go",
2526
"util.go",
2627
],
2728
importpath = "github.com/pingcap/tidb/server",

server/handler/BUILD.bazel

Whitespace-only changes.

server/handler/tests/BUILD.bazel

Whitespace-only changes.

server/http_handler_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1243,3 +1243,88 @@ func TestSetLabelsConcurrentWithGetLabel(t *testing.T) {
12431243
conf.Labels = map[string]string{}
12441244
})
12451245
}
1246+
1247+
func TestUpgrade(t *testing.T) {
1248+
ts := createBasicHTTPHandlerTestSuite()
1249+
ts.startServer(t)
1250+
defer ts.stopServer(t)
1251+
1252+
resp, err := ts.fetchStatus("/upgrade/start")
1253+
require.NoError(t, err)
1254+
require.Equal(t, http.StatusBadRequest, resp.StatusCode)
1255+
require.NoError(t, resp.Body.Close())
1256+
1257+
require.NoError(t, err)
1258+
require.NotNil(t, resp)
1259+
// test upgrade start
1260+
resp, err = ts.postStatus("/upgrade/start", "application/x-www-form-urlencoded", nil)
1261+
require.NoError(t, err)
1262+
require.Equal(t, http.StatusOK, resp.StatusCode)
1263+
b, err := httputil.DumpResponse(resp, true)
1264+
require.NoError(t, err)
1265+
require.Greater(t, len(b), 0)
1266+
body, err := io.ReadAll(resp.Body)
1267+
require.NoError(t, err)
1268+
require.NoError(t, resp.Body.Close())
1269+
require.Equal(t, "\"success!\"", string(body))
1270+
// check the result
1271+
se, err := session.CreateSession(ts.store)
1272+
require.NoError(t, err)
1273+
isUpgrading, err := session.IsUpgradingClusterState(se)
1274+
require.NoError(t, err)
1275+
require.True(t, isUpgrading)
1276+
1277+
// Do start upgrade again.
1278+
resp, err = ts.postStatus("/upgrade/start", "application/x-www-form-urlencoded", nil)
1279+
require.NoError(t, err)
1280+
require.Equal(t, http.StatusOK, resp.StatusCode)
1281+
b, err = httputil.DumpResponse(resp, true)
1282+
require.NoError(t, err)
1283+
require.Greater(t, len(b), 0)
1284+
body, err = io.ReadAll(resp.Body)
1285+
require.NoError(t, err)
1286+
require.NoError(t, resp.Body.Close())
1287+
require.Equal(t, "\"It's a duplicated operation and the cluster is already in upgrading state.\"", string(body))
1288+
// check the result
1289+
se, err = session.CreateSession(ts.store)
1290+
require.NoError(t, err)
1291+
isUpgrading, err = session.IsUpgradingClusterState(se)
1292+
require.NoError(t, err)
1293+
require.True(t, isUpgrading)
1294+
1295+
// test upgrade finish
1296+
resp, err = ts.postStatus("/upgrade/finish", "application/x-www-form-urlencoded", nil)
1297+
require.NoError(t, err)
1298+
require.Equal(t, http.StatusOK, resp.StatusCode)
1299+
b, err = httputil.DumpResponse(resp, true)
1300+
require.NoError(t, err)
1301+
require.Greater(t, len(b), 0)
1302+
body, err = io.ReadAll(resp.Body)
1303+
require.NoError(t, err)
1304+
require.NoError(t, resp.Body.Close())
1305+
require.Equal(t, "\"success!\"", string(body))
1306+
// check the result
1307+
se, err = session.CreateSession(ts.store)
1308+
require.NoError(t, err)
1309+
isUpgrading, err = session.IsUpgradingClusterState(se)
1310+
require.NoError(t, err)
1311+
require.False(t, isUpgrading)
1312+
1313+
// Do finish upgrade again.
1314+
resp, err = ts.postStatus("/upgrade/finish", "application/x-www-form-urlencoded", nil)
1315+
require.NoError(t, err)
1316+
require.Equal(t, http.StatusOK, resp.StatusCode)
1317+
b, err = httputil.DumpResponse(resp, true)
1318+
require.NoError(t, err)
1319+
require.Greater(t, len(b), 0)
1320+
body, err = io.ReadAll(resp.Body)
1321+
require.NoError(t, err)
1322+
require.NoError(t, resp.Body.Close())
1323+
require.Equal(t, "\"It's a duplicated operation and the cluster is already in normal state.\"", string(body))
1324+
// check the result
1325+
se, err = session.CreateSession(ts.store)
1326+
require.NoError(t, err)
1327+
isUpgrading, err = session.IsUpgradingClusterState(se)
1328+
require.NoError(t, err)
1329+
require.False(t, isUpgrading)
1330+
}

server/http_status.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,9 @@ func (s *Server) startHTTPServer() {
239239
// HTTP path for get table tiflash replica info.
240240
router.Handle("/tiflash/replica-deprecated", flashReplicaHandler{tikvHandlerTool})
241241

242+
// HTTP path for upgrade operations.
243+
router.Handle("/upgrade/{op}", NewClusterUpgradeHandler(tikvHandlerTool.Store.(kv.Storage))).Name("upgrade operations")
244+
242245
if s.cfg.Store == "tikv" {
243246
// HTTP path for tikv.
244247
router.Handle("/tables/{db}/{table}/regions", tableHandler{tikvHandlerTool, opTableRegions})

0 commit comments

Comments
 (0)