@@ -37,6 +37,7 @@ import (
3737 "github.com/tikv/pd/pkg/mock/mockid"
3838 sc "github.com/tikv/pd/pkg/schedule/config"
3939 "github.com/tikv/pd/pkg/schedule/operator"
40+ "github.com/tikv/pd/pkg/schedule/schedulers"
4041 "github.com/tikv/pd/pkg/storage"
4142 "github.com/tikv/pd/pkg/syncer"
4243 "github.com/tikv/pd/pkg/tso"
@@ -47,6 +48,7 @@ import (
4748 "github.com/tikv/pd/server/cluster"
4849 "github.com/tikv/pd/server/config"
4950 "github.com/tikv/pd/tests"
51+ "github.com/tikv/pd/tests/server/api"
5052 "google.golang.org/grpc/codes"
5153 "google.golang.org/grpc/status"
5254)
@@ -1275,6 +1277,119 @@ func TestStaleTermHeartbeat(t *testing.T) {
12751277 re .NoError (err )
12761278}
12771279
1280+ func TestTransferLeaderForScheduler (t * testing.T ) {
1281+ re := require .New (t )
1282+ ctx , cancel := context .WithCancel (context .Background ())
1283+ defer cancel ()
1284+ re .NoError (failpoint .Enable ("github.com/tikv/pd/pkg/schedule/changeCoordinatorTicker" , `return(true)` ))
1285+ tc , err := tests .NewTestCluster (ctx , 2 )
1286+ defer tc .Destroy ()
1287+ re .NoError (err )
1288+ err = tc .RunInitialServers ()
1289+ re .NoError (err )
1290+ tc .WaitLeader ()
1291+ // start
1292+ leaderServer := tc .GetServer (tc .GetLeader ())
1293+ re .NoError (leaderServer .BootstrapCluster ())
1294+ rc := leaderServer .GetServer ().GetRaftCluster ()
1295+ re .NotNil (rc )
1296+
1297+ storesNum := 2
1298+ grpcPDClient := testutil .MustNewGrpcClient (re , leaderServer .GetAddr ())
1299+ for i := 1 ; i <= storesNum ; i ++ {
1300+ store := & metapb.Store {
1301+ Id : uint64 (i ),
1302+ Address : "127.0.0.1:" + strconv .Itoa (i ),
1303+ }
1304+ resp , err := putStore (grpcPDClient , leaderServer .GetClusterID (), store )
1305+ re .NoError (err )
1306+ re .Equal (pdpb .ErrorType_OK , resp .GetHeader ().GetError ().GetType ())
1307+ }
1308+ // region heartbeat
1309+ id := leaderServer .GetAllocator ()
1310+ putRegionWithLeader (re , rc , id , 1 )
1311+
1312+ time .Sleep (time .Second )
1313+ re .True (leaderServer .GetRaftCluster ().IsPrepared ())
1314+ // Add evict leader scheduler
1315+ api .MustAddScheduler (re , leaderServer .GetAddr (), schedulers .EvictLeaderName , map [string ]interface {}{
1316+ "store_id" : 1 ,
1317+ })
1318+ api .MustAddScheduler (re , leaderServer .GetAddr (), schedulers .EvictLeaderName , map [string ]interface {}{
1319+ "store_id" : 2 ,
1320+ })
1321+ // Check scheduler updated.
1322+ schedulersController := rc .GetCoordinator ().GetSchedulersController ()
1323+ re .Len (schedulersController .GetSchedulerNames (), 6 )
1324+ checkEvictLeaderSchedulerExist (re , schedulersController , true )
1325+ checkEvictLeaderStoreIDs (re , schedulersController , []uint64 {1 , 2 })
1326+
1327+ // transfer PD leader to another PD
1328+ tc .ResignLeader ()
1329+ rc .Stop ()
1330+ tc .WaitLeader ()
1331+ leaderServer = tc .GetServer (tc .GetLeader ())
1332+ rc1 := leaderServer .GetServer ().GetRaftCluster ()
1333+ rc1 .Start (leaderServer .GetServer ())
1334+ re .NoError (err )
1335+ re .NotNil (rc1 )
1336+ // region heartbeat
1337+ id = leaderServer .GetAllocator ()
1338+ putRegionWithLeader (re , rc1 , id , 1 )
1339+ time .Sleep (time .Second )
1340+ re .True (leaderServer .GetRaftCluster ().IsPrepared ())
1341+ // Check scheduler updated.
1342+ schedulersController = rc1 .GetCoordinator ().GetSchedulersController ()
1343+ re .Len (schedulersController .GetSchedulerNames (), 6 )
1344+ checkEvictLeaderSchedulerExist (re , schedulersController , true )
1345+ checkEvictLeaderStoreIDs (re , schedulersController , []uint64 {1 , 2 })
1346+
1347+ // transfer PD leader back to the previous PD
1348+ tc .ResignLeader ()
1349+ rc1 .Stop ()
1350+ tc .WaitLeader ()
1351+ leaderServer = tc .GetServer (tc .GetLeader ())
1352+ rc = leaderServer .GetServer ().GetRaftCluster ()
1353+ rc .Start (leaderServer .GetServer ())
1354+ re .NotNil (rc )
1355+ // region heartbeat
1356+ id = leaderServer .GetAllocator ()
1357+ putRegionWithLeader (re , rc , id , 1 )
1358+ time .Sleep (time .Second )
1359+ re .True (leaderServer .GetRaftCluster ().IsPrepared ())
1360+ // Check scheduler updated
1361+ schedulersController = rc .GetCoordinator ().GetSchedulersController ()
1362+ re .Len (schedulersController .GetSchedulerNames (), 6 )
1363+ checkEvictLeaderSchedulerExist (re , schedulersController , true )
1364+ checkEvictLeaderStoreIDs (re , schedulersController , []uint64 {1 , 2 })
1365+
1366+ re .NoError (failpoint .Disable ("github.com/tikv/pd/pkg/schedule/changeCoordinatorTicker" ))
1367+ }
1368+
1369+ func checkEvictLeaderSchedulerExist (re * require.Assertions , sc * schedulers.Controller , exist bool ) {
1370+ testutil .Eventually (re , func () bool {
1371+ if ! exist {
1372+ return sc .GetScheduler (schedulers .EvictLeaderName ) == nil
1373+ }
1374+ return sc .GetScheduler (schedulers .EvictLeaderName ) != nil
1375+ })
1376+ }
1377+
1378+ func checkEvictLeaderStoreIDs (re * require.Assertions , sc * schedulers.Controller , expected []uint64 ) {
1379+ handler , ok := sc .GetSchedulerHandlers ()[schedulers .EvictLeaderName ]
1380+ re .True (ok )
1381+ h , ok := handler .(interface {
1382+ EvictStoreIDs () []uint64
1383+ })
1384+ re .True (ok )
1385+ var evictStoreIDs []uint64
1386+ testutil .Eventually (re , func () bool {
1387+ evictStoreIDs = h .EvictStoreIDs ()
1388+ return len (evictStoreIDs ) == len (expected )
1389+ })
1390+ re .ElementsMatch (evictStoreIDs , expected )
1391+ }
1392+
12781393func putRegionWithLeader (re * require.Assertions , rc * cluster.RaftCluster , id id.Allocator , storeID uint64 ) {
12791394 for i := 0 ; i < 3 ; i ++ {
12801395 regionID , err := id .Alloc ()
0 commit comments