-
Notifications
You must be signed in to change notification settings - Fork 727
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
*: Introduce version checking mechanism #1148
Changes from 15 commits
cd02a27
52bee45
595f133
2fdd381
efc59f1
726ef07
3178fae
cbe6d32
9997f8d
d18d0aa
13bccce
69cf420
9d81d84
9e6866e
f51bacf
365da06
e1a3e65
2eaabf1
0a1cea3
2b73eed
71bbf0f
e15af4f
7d9a99e
5bfb86f
4b007fa
94542d0
3fa0a54
4478e41
5eeca3d
3f711b8
d099292
e40ff3d
1693736
8dccabd
c7c42ca
89a1d93
a01fc8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
// Copyright 2018 PingCAP, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package integration | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/coreos/go-semver/semver" | ||
. "github.com/pingcap/check" | ||
"github.com/pingcap/kvproto/pkg/metapb" | ||
"github.com/pingcap/kvproto/pkg/pdpb" | ||
) | ||
|
||
func (s *integrationTestSuite) bootstrapCluster(server *testServer, c *C) { | ||
bootstrapReq := &pdpb.BootstrapRequest{ | ||
Header: &pdpb.RequestHeader{ClusterId: server.GetClusterID()}, | ||
Store: &metapb.Store{Id: 1, Address: "mock://1"}, | ||
Region: &metapb.Region{Id: 2, Peers: []*metapb.Peer{{3, 1, false}}}, | ||
} | ||
_, err := server.server.Bootstrap(context.Background(), bootstrapReq) | ||
c.Assert(err, IsNil) | ||
} | ||
|
||
func (s *integrationTestSuite) TestStoreRegister(c *C) { | ||
c.Parallel() | ||
cluster, err := newTestCluster(3) | ||
c.Assert(err, IsNil) | ||
defer cluster.Destory() | ||
|
||
err = cluster.RunInitialServers() | ||
c.Assert(err, IsNil) | ||
cluster.WaitLeader() | ||
leaderServer := cluster.GetServer(cluster.GetLeader()) | ||
s.bootstrapCluster(leaderServer, c) | ||
|
||
putStoreRequest := &pdpb.PutStoreRequest{ | ||
Header: &pdpb.RequestHeader{ClusterId: leaderServer.GetClusterID()}, | ||
Store: &metapb.Store{ | ||
Id: 1, | ||
Address: "mock-1", | ||
Version: "2.0.1", | ||
}, | ||
} | ||
_, err = leaderServer.server.PutStore(context.Background(), putStoreRequest) | ||
c.Assert(err, IsNil) | ||
// FIX ME: read v0.0.0 in sometime | ||
cluster.WaitLeader() | ||
version := leaderServer.GetClusterVersion() | ||
// Restart all PDs. | ||
err = cluster.StopAll() | ||
c.Assert(err, IsNil) | ||
err = cluster.RunInitialServers() | ||
c.Assert(err, IsNil) | ||
cluster.WaitLeader() | ||
|
||
leaderServer = cluster.GetServer(cluster.GetLeader()) | ||
newVersion := leaderServer.GetClusterVersion() | ||
c.Assert(version, Equals, newVersion) | ||
|
||
// putNewStore with old version | ||
putStoreRequest = &pdpb.PutStoreRequest{ | ||
Header: &pdpb.RequestHeader{ClusterId: leaderServer.GetClusterID()}, | ||
Store: &metapb.Store{ | ||
Id: 4, | ||
Address: "mock-4", | ||
Version: "1.0.1", | ||
}, | ||
} | ||
_, err = leaderServer.server.PutStore(context.Background(), putStoreRequest) | ||
c.Assert(err, NotNil) | ||
} | ||
|
||
func (s *integrationTestSuite) TestRollingUpgrade(c *C) { | ||
c.Parallel() | ||
cluster, err := newTestCluster(3) | ||
c.Assert(err, IsNil) | ||
defer cluster.Destory() | ||
err = cluster.RunInitialServers() | ||
c.Assert(err, IsNil) | ||
cluster.WaitLeader() | ||
leaderServer := cluster.GetServer(cluster.GetLeader()) | ||
s.bootstrapCluster(leaderServer, c) | ||
|
||
stores := []*pdpb.PutStoreRequest{ | ||
{ | ||
Header: &pdpb.RequestHeader{ClusterId: leaderServer.GetClusterID()}, | ||
Store: &metapb.Store{ | ||
Id: 1, | ||
Address: "mock-1", | ||
Version: "2.0.1", | ||
}, | ||
}, | ||
{ | ||
Header: &pdpb.RequestHeader{ClusterId: leaderServer.GetClusterID()}, | ||
Store: &metapb.Store{ | ||
Id: 4, | ||
Address: "mock-4", | ||
Version: "2.0.1", | ||
}, | ||
}, | ||
{ | ||
Header: &pdpb.RequestHeader{ClusterId: leaderServer.GetClusterID()}, | ||
Store: &metapb.Store{ | ||
Id: 6, | ||
Address: "mock-6", | ||
Version: "2.0.1", | ||
}, | ||
}, | ||
{ | ||
Header: &pdpb.RequestHeader{ClusterId: leaderServer.GetClusterID()}, | ||
Store: &metapb.Store{ | ||
Id: 7, | ||
Address: "mock-7", | ||
Version: "2.0.1", | ||
}, | ||
}, | ||
} | ||
for _, store := range stores { | ||
_, err = leaderServer.server.PutStore(context.Background(), store) | ||
c.Assert(err, IsNil) | ||
} | ||
c.Assert(leaderServer.GetClusterVersion(), Equals, semver.Version{Major: 2, Minor: 0, Patch: 1}) | ||
// rolling update | ||
for i, store := range stores { | ||
store.Store.Version = "2.1.0" | ||
resp, err := leaderServer.server.PutStore(context.Background(), store) | ||
c.Assert(err, IsNil) | ||
if i != len(stores)-1 { | ||
c.Assert(leaderServer.GetClusterVersion(), Equals, semver.Version{Major: 2, Minor: 0, Patch: 1}) | ||
c.Assert(resp.GetHeader().GetError(), IsNil) | ||
} | ||
} | ||
c.Assert(leaderServer.GetClusterVersion(), Equals, semver.Version{Major: 2, Minor: 1}) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ import ( | |
"sync" | ||
"time" | ||
|
||
"github.com/coreos/go-semver/semver" | ||
"github.com/gogo/protobuf/proto" | ||
"github.com/juju/errors" | ||
"github.com/pingcap/kvproto/pkg/metapb" | ||
|
@@ -78,6 +79,45 @@ func loadClusterInfo(id core.IDAllocator, kv *core.KV, opt *scheduleOption) (*cl | |
return c, nil | ||
} | ||
|
||
func (c *clusterInfo) OnChangeClusterVersion() { | ||
var ( | ||
minVersion semver.Version | ||
clusterVersion semver.Version | ||
) | ||
|
||
clusterVersion = c.opt.loadClusterVersion() | ||
stores := c.GetStores() | ||
for i, s := range stores { | ||
if s.IsTombstone() { | ||
continue | ||
} | ||
if i == 0 { | ||
minVersion = *MustParseVersion(s.GetVersion()) | ||
continue | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The first store can be tombstone state. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can let |
||
v := MustParseVersion(s.GetVersion()) | ||
|
||
if v.LessThan(minVersion) { | ||
minVersion = *v | ||
} | ||
} | ||
if clusterVersion.LessThan(minVersion) { | ||
c.opt.SetClusterVersion(minVersion) | ||
c.opt.persist(c.kv) | ||
log.Infof("cluster version changed from %s to %s", clusterVersion, minVersion) | ||
} | ||
} | ||
|
||
// IsSupported check if support the feature. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IsSupported checks if the feature is supported by current cluster. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about |
||
func (c *clusterInfo) IsSupported(f Feature) bool { | ||
clusterVersion := c.opt.loadClusterVersion() | ||
minSupportVersion := MinSupportedVersion(f) | ||
if clusterVersion.LessThan(minSupportVersion) { | ||
return false | ||
} | ||
return true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return !clusterVersion.LessThan(minSupportVersion) |
||
} | ||
|
||
func (c *clusterInfo) allocID() (uint64, error) { | ||
return c.id.Alloc() | ||
} | ||
|
@@ -618,6 +658,9 @@ func (c *clusterInfo) GetHotRegionLowThreshold() int { | |
} | ||
|
||
func (c *clusterInfo) IsRaftLearnerEnabled() bool { | ||
if !c.IsSupported(RaftLearner) { | ||
return false | ||
} | ||
return c.opt.IsRaftLearnerEnabled() | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be clearer to move this to after the
v
assignment asif i==0 || v.LessThan(minVersion)
.