Repository: pingcap/pd (go)

Issue:
Store cannot become tombstone when max-replicas=1
Please answer these questions before submitting your issue. Thanks!

1. What did you do?
- run a cluster with max-replicas=1
- use `pd-ctl store delete 1` to take down a store

2. What did you expect to see?
regions moves away and store becomes tombstone

3. What did you see instead?
No operator created. Store keeps offline state.

4. What version of PD are you using (`pd-server -V`)?
master


Pull request description:
checker: fix offline when only having one replica
### What problem does this PR solve? <!--add the issue link with summary if it exists-->
Closes #1923.

### What is changed and how it works?
This PR fixes it by checking if the max replica is 1 before transferring the leader.

### Check List <!--REMOVE the items that are not applicable-->

Tests <!-- At least one of them must be included. -->

 - Unit test

Patch:
diff --git a/server/schedule/checker/replica_checker.go b/server/schedule/checker/replica_checker.go
index 647aa18bc..abc98c876 100644
--- a/server/schedule/checker/replica_checker.go
+++ b/server/schedule/checker/replica_checker.go
@@ -26,7 +26,10 @@ import (
 	"go.uber.org/zap"
 )
 
-const replicaCheckerName = "replica-checker"
+const (
+	replicaCheckerName = "replica-checker"
+	minReplicaCount    = 1
+)
 
 const (
 	offlineStatus = "offline"
@@ -277,7 +280,7 @@ func (r *ReplicaChecker) fixPeer(region *core.RegionInfo, peer *metapb.Peer, sta
 
 	replace := fmt.Sprintf("replace-%s-replica", status)
 	var op *operator.Operator
-	if status == offlineStatus {
+	if status == offlineStatus && r.cluster.GetMaxReplicas() > minReplicaCount {
 		op, err = operator.CreateOfflinePeerOperator(replace, r.cluster, region, operator.OpReplica, peer.GetStoreId(), newPeer)
 	} else {
 		op, err = operator.CreateMovePeerOperator(replace, r.cluster, region, operator.OpReplica, peer.GetStoreId(), newPeer)


Test patch:
diff --git a/server/schedule/checker/replica_checker_test.go b/server/schedule/checker/replica_checker_test.go
index afeb31e65..59ec16630 100644
--- a/server/schedule/checker/replica_checker_test.go
+++ b/server/schedule/checker/replica_checker_test.go
@@ -128,3 +128,18 @@ func (s *testReplicaCheckerSuite) TestReplaceOfflinePeer(c *C) {
 	c.Assert(op.Step(2).(operator.PromoteLearner).ToStore, Equals, uint64(4))
 	c.Assert(op.Step(3).(operator.RemovePeer).FromStore, Equals, uint64(1))
 }
+
+func (s *testReplicaCheckerSuite) TestOfflineWithOneReplica(c *C) {
+	s.cluster.MaxReplicas = 1
+	peers := []*metapb.Peer{
+		{
+			Id:      4,
+			StoreId: 1,
+		},
+	}
+	r := core.NewRegionInfo(&metapb.Region{Id: 2, Peers: peers}, peers[0])
+	s.cluster.PutRegion(r)
+	op := s.rc.Check(r)
+	c.Assert(op, NotNil)
+	c.Assert(op.Desc(), Equals, "replace-offline-replica")
+}