Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

server: remove extra region clone when handle region heartbeat #1195

Merged
merged 13 commits into from
Sep 6, 2018
6 changes: 3 additions & 3 deletions server/api/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ func (s *testAdminSuite) TestDropRegion(c *C) {
// Update region's epoch to (100, 100).
region := cluster.GetRegionInfoByKey([]byte("foo"))
region.RegionEpoch.ConfVer, region.RegionEpoch.Version = 100, 100
err := cluster.HandleRegionHeartbeat(region)
err := cluster.HandleRegionHeartbeat(region.Clone())
c.Assert(err, IsNil)

// Region epoch cannot decrease.
region.RegionEpoch.ConfVer, region.RegionEpoch.Version = 50, 50
err = cluster.HandleRegionHeartbeat(region)
err = cluster.HandleRegionHeartbeat(region.Clone())
c.Assert(err, NotNil)

// After drop region from cache, lower version is accepted.
Expand All @@ -65,7 +65,7 @@ func (s *testAdminSuite) TestDropRegion(c *C) {
c.Assert(err, IsNil)
c.Assert(res.StatusCode, Equals, http.StatusOK)
res.Body.Close()
err = cluster.HandleRegionHeartbeat(region)
err = cluster.HandleRegionHeartbeat(region.Clone())
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove the Clone method?

c.Assert(err, IsNil)

region = cluster.GetRegionInfoByKey([]byte("foo"))
Expand Down
2 changes: 1 addition & 1 deletion server/api/operator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func mustPutStore(c *C, svr *server.Server, id uint64, state metapb.StoreState,

func mustRegionHeartbeat(c *C, svr *server.Server, region *core.RegionInfo) {
cluster := svr.GetRaftCluster()
err := cluster.HandleRegionHeartbeat(region)
err := cluster.HandleRegionHeartbeat(region.Clone())
c.Assert(err, IsNil)
}

Expand Down
1 change: 0 additions & 1 deletion server/cluster_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,6 @@ func (c *clusterInfo) updateStoreStatusLocked(id uint64) {

// handleRegionHeartbeat updates the region information.
func (c *clusterInfo) handleRegionHeartbeat(region *core.RegionInfo) error {
region = region.Clone()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The region is used after calling this function. Are you sure that it is safe to not clone? See: https://github.com/pingcap/pd/blob/9b0763fb0474c657c1abbef8238871f3d1284817/server/cluster_worker.go#L28-L41

Copy link
Contributor Author

@nolouch nolouch Aug 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, all function only read it. More reassuring, I clone the region which has operator now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not make sense to clone the region. Cloning the region reads the region too.

I'm not so sure that the region is inmutable. I think you can propose another PR to change all fields of core.RegionInfo to unexported fields and add read only methods to access them. After that we can be sure that the RegionInfo is inmutable and discard the Clone method of it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

got it.

c.RLock()
origin := c.core.Regions.GetRegion(region.GetId())
isWriteUpdate, writeItem := c.core.CheckWriteStatus(region)
Expand Down
30 changes: 15 additions & 15 deletions server/cluster_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,12 +353,12 @@ func (s *testClusterInfoSuite) TestRegionHeartbeat(c *C) {

for i, region := range regions {
// region does not exist.
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])
checkRegionsKV(c, cluster.kv, regions[:i+1])

// region is the same, not updated.
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])
checkRegionsKV(c, cluster.kv, regions[:i+1])

Expand All @@ -368,7 +368,7 @@ func (s *testClusterInfoSuite) TestRegionHeartbeat(c *C) {
region.RegionEpoch = &metapb.RegionEpoch{
Version: epoch.GetVersion() + 1,
}
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])
checkRegionsKV(c, cluster.kv, regions[:i+1])

Expand All @@ -386,7 +386,7 @@ func (s *testClusterInfoSuite) TestRegionHeartbeat(c *C) {
Version: epoch.GetVersion() + 1,
ConfVer: epoch.GetConfVer() + 1,
}
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])
checkRegionsKV(c, cluster.kv, regions[:i+1])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicated?


Expand All @@ -406,33 +406,33 @@ func (s *testClusterInfoSuite) TestRegionHeartbeat(c *C) {
DownSeconds: 42,
},
}
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])

// Add a pending peer.
region.PendingPeers = []*metapb.Peer{region.Peers[rand.Intn(len(region.Peers))]}
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])

// Clear down peers.
region.DownPeers = nil
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])

// Clear pending peers.
region.PendingPeers = nil
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])

// Remove peers.
origin := region.Clone()
region.Peers = region.Peers[:1]
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])
checkRegionsKV(c, cluster.kv, regions[:i+1])
// Add peers.
region.Peers = origin.Peers
c.Assert(cluster.handleRegionHeartbeat(region), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region.Clone()), IsNil)
checkRegions(c, cluster.core.Regions, regions[:i+1])
checkRegionsKV(c, cluster.kv, regions[:i+1])
}
Expand Down Expand Up @@ -538,29 +538,29 @@ func (s *testClusterInfoSuite) TestHeartbeatSplit(c *C) {

// 1: [nil, nil)
region1 := core.NewRegionInfo(&metapb.Region{Id: 1, RegionEpoch: &metapb.RegionEpoch{Version: 1, ConfVer: 1}}, nil)
c.Assert(cluster.handleRegionHeartbeat(region1), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region1.Clone()), IsNil)
checkRegion(c, cluster.searchRegion([]byte("foo")), region1)

// split 1 to 2: [nil, m) 1: [m, nil), sync 2 first.
region1.StartKey, region1.RegionEpoch.Version = []byte("m"), 2
region2 := core.NewRegionInfo(&metapb.Region{Id: 2, EndKey: []byte("m"), RegionEpoch: &metapb.RegionEpoch{Version: 1, ConfVer: 1}}, nil)
c.Assert(cluster.handleRegionHeartbeat(region2), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region2.Clone()), IsNil)
checkRegion(c, cluster.searchRegion([]byte("a")), region2)
// [m, nil) is missing before r1's heartbeat.
c.Assert(cluster.searchRegion([]byte("z")), IsNil)

c.Assert(cluster.handleRegionHeartbeat(region1), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region1.Clone()), IsNil)
checkRegion(c, cluster.searchRegion([]byte("z")), region1)

// split 1 to 3: [m, q) 1: [q, nil), sync 1 first.
region1.StartKey, region1.RegionEpoch.Version = []byte("q"), 3
region3 := core.NewRegionInfo(&metapb.Region{Id: 3, StartKey: []byte("m"), EndKey: []byte("q"), RegionEpoch: &metapb.RegionEpoch{Version: 1, ConfVer: 1}}, nil)
c.Assert(cluster.handleRegionHeartbeat(region1), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region1.Clone()), IsNil)
checkRegion(c, cluster.searchRegion([]byte("z")), region1)
checkRegion(c, cluster.searchRegion([]byte("a")), region2)
// [m, q) is missing before r3's heartbeat.
c.Assert(cluster.searchRegion([]byte("n")), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region3), IsNil)
c.Assert(cluster.handleRegionHeartbeat(region3.Clone()), IsNil)
checkRegion(c, cluster.searchRegion([]byte("n")), region3)
}

Expand Down