зеркало из https://github.com/github/vitess-gh.git
Now using proto3's Shard record.
This commit is contained in:
Родитель
a88afc2cd4
Коммит
f1b1c1ea18
|
@ -43,13 +43,13 @@ func TestAPI(t *testing.T) {
|
|||
|
||||
// Populate topo.
|
||||
ts.CreateKeyspace(ctx, "ks1", &pb.Keyspace{ShardingColumnName: "shardcol"})
|
||||
ts.CreateShard(ctx, "ks1", "-80", &topo.Shard{
|
||||
ts.CreateShard(ctx, "ks1", "-80", &pb.Shard{
|
||||
Cells: cells,
|
||||
KeyRange: key.KeyRange{Start: "", End: "\x80"},
|
||||
KeyRange: &pb.KeyRange{Start: nil, End: []byte{0x80}},
|
||||
})
|
||||
ts.CreateShard(ctx, "ks1", "80-", &topo.Shard{
|
||||
ts.CreateShard(ctx, "ks1", "80-", &pb.Shard{
|
||||
Cells: cells,
|
||||
KeyRange: key.KeyRange{Start: "\x80", End: ""},
|
||||
KeyRange: &pb.KeyRange{Start: []byte{0x80}, End: nil},
|
||||
})
|
||||
|
||||
topo.CreateTablet(ctx, ts, &topo.Tablet{
|
||||
|
@ -106,12 +106,8 @@ func TestAPI(t *testing.T) {
|
|||
// Shards
|
||||
{"GET", "shards/ks1/", `["-80","80-"]`},
|
||||
{"GET", "shards/ks1/-80", `{
|
||||
"MasterAlias": {"Cell":"","Uid":0},
|
||||
"KeyRange": {"Start":"","End":"80"},
|
||||
"ServedTypesMap": null,
|
||||
"SourceShards": null,
|
||||
"Cells": ["cell1", "cell2"],
|
||||
"TabletControlMap": null
|
||||
"key_range": {"end":"gA=="},
|
||||
"cells": ["cell1", "cell2"]
|
||||
}`},
|
||||
{"POST", "shards/ks1/-80?action=TestShardAction", `{
|
||||
"Name": "TestShardAction",
|
||||
|
|
|
@ -292,7 +292,7 @@ type Shard struct {
|
|||
ShardName string
|
||||
|
||||
// Shard is the topo value of this shard
|
||||
Shard *topo.Shard
|
||||
Shard *pb.Shard
|
||||
}
|
||||
|
||||
// Reset is part of the VersionedObject interface
|
||||
|
|
|
@ -226,13 +226,13 @@ func TestShardNamesCache(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("CreateKeyspace failed: %v", err)
|
||||
}
|
||||
if err := ts.CreateShard(ctx, "ks1", "s1", &topo.Shard{
|
||||
if err := ts.CreateShard(ctx, "ks1", "s1", &pb.Shard{
|
||||
Cells: []string{"cell1", "cell2"},
|
||||
}); err != nil {
|
||||
t.Fatalf("CreateShard failed: %v", err)
|
||||
}
|
||||
if err := ts.CreateShard(ctx, "ks1", "s2", &topo.Shard{
|
||||
MasterAlias: topo.TabletAlias{
|
||||
if err := ts.CreateShard(ctx, "ks1", "s2", &pb.Shard{
|
||||
MasterAlias: &pb.TabletAlias{
|
||||
Cell: "cell1",
|
||||
Uid: 12,
|
||||
},
|
||||
|
@ -257,13 +257,13 @@ func TestShardCache(t *testing.T) {
|
|||
}); err != nil {
|
||||
t.Fatalf("CreateKeyspace failed: %v", err)
|
||||
}
|
||||
if err := ts.CreateShard(ctx, "ks1", "s1", &topo.Shard{
|
||||
if err := ts.CreateShard(ctx, "ks1", "s1", &pb.Shard{
|
||||
Cells: []string{"cell1", "cell2"},
|
||||
}); err != nil {
|
||||
t.Fatalf("CreateShard failed: %v", err)
|
||||
}
|
||||
if err := ts.CreateShard(ctx, "ks1", "s2", &topo.Shard{
|
||||
MasterAlias: topo.TabletAlias{
|
||||
if err := ts.CreateShard(ctx, "ks1", "s2", &pb.Shard{
|
||||
MasterAlias: &pb.TabletAlias{
|
||||
Cell: "cell1",
|
||||
Uid: 12,
|
||||
},
|
||||
|
@ -276,17 +276,18 @@ func TestShardCache(t *testing.T) {
|
|||
expectedS := Shard{
|
||||
KeyspaceName: "ks1",
|
||||
ShardName: "s1",
|
||||
Shard: &topo.Shard{
|
||||
Shard: &pb.Shard{
|
||||
Cells: []string{"cell1", "cell2"},
|
||||
},
|
||||
}
|
||||
testVersionedObjectCacheMap(t, sc, "ks1/s1", &s, &expectedS)
|
||||
|
||||
s = Shard{}
|
||||
expectedS = Shard{
|
||||
KeyspaceName: "ks1",
|
||||
ShardName: "s2",
|
||||
Shard: &topo.Shard{
|
||||
MasterAlias: topo.TabletAlias{
|
||||
Shard: &pb.Shard{
|
||||
MasterAlias: &pb.TabletAlias{
|
||||
Cell: "cell1",
|
||||
Uid: 12,
|
||||
},
|
||||
|
|
|
@ -119,7 +119,7 @@ Binlog player state: {{.State}}</br>
|
|||
{{range .Controllers}}
|
||||
<tr>
|
||||
<td>{{.Index}}</td>
|
||||
<td>{{.SourceShard.AsHTML}}</td>
|
||||
<td>{{.SourceShardAsHTML}}</td>
|
||||
<td>{{.State}}
|
||||
{{if eq .State "Running"}}
|
||||
{{if .SourceTablet.IsZero}}
|
||||
|
|
|
@ -78,7 +78,7 @@ func TestHandlePathKeyspace(t *testing.T) {
|
|||
input := path.Join(explorerRoot, "global", keyspaceDirPath("test_keyspace"))
|
||||
cells := []string{"cell1", "cell2", "cell3"}
|
||||
keyspace := &pb.Keyspace{}
|
||||
shard := &topo.Shard{}
|
||||
shard := &pb.Shard{}
|
||||
want := jscfg.ToJSON(keyspace)
|
||||
|
||||
ctx := context.Background()
|
||||
|
@ -115,7 +115,7 @@ func TestHandlePathShard(t *testing.T) {
|
|||
input := path.Join(explorerRoot, "global", shardDirPath("test_keyspace", "-80"))
|
||||
cells := []string{"cell1", "cell2", "cell3"}
|
||||
keyspace := &pb.Keyspace{}
|
||||
shard := &topo.Shard{}
|
||||
shard := &pb.Shard{}
|
||||
want := jscfg.ToJSON(shard)
|
||||
|
||||
ctx := context.Background()
|
||||
|
|
|
@ -13,10 +13,12 @@ import (
|
|||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"github.com/youtube/vitess/go/vt/topo/events"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// CreateShard implements topo.Server.
|
||||
func (s *Server) CreateShard(ctx context.Context, keyspace, shard string, value *topo.Shard) error {
|
||||
func (s *Server) CreateShard(ctx context.Context, keyspace, shard string, value *pb.Shard) error {
|
||||
data := jscfg.ToJSON(value)
|
||||
global := s.getGlobal()
|
||||
|
||||
|
@ -78,7 +80,7 @@ func (s *Server) GetShard(ctx context.Context, keyspace, shard string) (*topo.Sh
|
|||
return nil, ErrBadResponse
|
||||
}
|
||||
|
||||
value := &topo.Shard{}
|
||||
value := &pb.Shard{}
|
||||
if err := json.Unmarshal([]byte(resp.Node.Value), value); err != nil {
|
||||
return nil, fmt.Errorf("bad shard data (%v): %q", err, resp.Node.Value)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,8 @@ import (
|
|||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
//
|
||||
|
@ -156,22 +158,75 @@ func ParseKeyRangeParts(start, end string) (KeyRange, error) {
|
|||
return KeyRange{Start: s, End: e}, nil
|
||||
}
|
||||
|
||||
// Parse a start and end hex values and build a proto KeyRange
|
||||
func ParseKeyRangeParts3(start, end string) (*pb.KeyRange, error) {
|
||||
s, err := hex.DecodeString(start)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e, err := hex.DecodeString(end)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &pb.KeyRange{Start: s, End: e}, nil
|
||||
}
|
||||
|
||||
// Returns true if the KeyRange does not cover the entire space.
|
||||
func (kr KeyRange) IsPartial() bool {
|
||||
return !(kr.Start == MinKey && kr.End == MaxKey)
|
||||
}
|
||||
|
||||
// KeyRangesIntersect returns true if some Keyspace values exist in both ranges.
|
||||
//
|
||||
// Returns true if the KeyRange does not cover the entire space.
|
||||
func KeyRangeIsPartial(kr *pb.KeyRange) bool {
|
||||
return !(len(kr.Start) == 0 && len(kr.End) == 0)
|
||||
}
|
||||
|
||||
// Returns true if both key ranges cover the same area
|
||||
func KeyRangeEqual(left, right *pb.KeyRange) bool {
|
||||
return string(left.Start) == string(right.Start) &&
|
||||
string(left.End) == string(right.End)
|
||||
}
|
||||
|
||||
// Returns true if both key ranges have the same start
|
||||
func KeyRangeStartEqual(left, right *pb.KeyRange) bool {
|
||||
if left == nil {
|
||||
return right == nil || len(right.Start) == 0
|
||||
}
|
||||
if right == nil {
|
||||
return len(left.Start) == 0
|
||||
}
|
||||
return string(left.Start) == string(right.Start)
|
||||
}
|
||||
|
||||
// Returns true if both key ranges have the same end
|
||||
func KeyRangeEndEqual(left, right *pb.KeyRange) bool {
|
||||
if left == nil {
|
||||
return right == nil || len(right.End) == 0
|
||||
}
|
||||
if right == nil {
|
||||
return len(left.End) == 0
|
||||
}
|
||||
return string(left.End) == string(right.End)
|
||||
}
|
||||
|
||||
// For more info on the following functions, see:
|
||||
// See: http://stackoverflow.com/questions/4879315/what-is-a-tidy-algorithm-to-find-overlapping-intervals
|
||||
// two segments defined as (a,b) and (c,d) (with a<b and c<d):
|
||||
// intersects = (b > c) && (a < d)
|
||||
// overlap = min(b, d) - max(c, a)
|
||||
|
||||
// KeyRangesIntersect returns true if some Keyspace values exist in both ranges.
|
||||
func KeyRangesIntersect(first, second KeyRange) bool {
|
||||
return (first.End == MaxKey || second.Start < first.End) &&
|
||||
(second.End == MaxKey || first.Start < second.End)
|
||||
}
|
||||
|
||||
// KeyRangesIntersect3 returns true if some Keyspace values exist in both ranges.
|
||||
func KeyRangesIntersect3(first, second *pb.KeyRange) bool {
|
||||
return (len(first.End) == 0 || string(second.Start) < string(first.End)) &&
|
||||
(len(second.End) == 0 || string(first.Start) < string(second.End))
|
||||
}
|
||||
|
||||
// KeyRangesOverlap returns the overlap between two KeyRanges.
|
||||
// They need to overlap, otherwise an error is returned.
|
||||
func KeyRangesOverlap(first, second KeyRange) (KeyRange, error) {
|
||||
|
@ -195,6 +250,29 @@ func KeyRangesOverlap(first, second KeyRange) (KeyRange, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
// KeyRangesOverlap3 returns the overlap between two KeyRanges.
|
||||
// They need to overlap, otherwise an error is returned.
|
||||
func KeyRangesOverlap3(first, second *pb.KeyRange) (*pb.KeyRange, error) {
|
||||
if !KeyRangesIntersect3(first, second) {
|
||||
return nil, fmt.Errorf("KeyRanges %v and %v don't overlap", first, second)
|
||||
}
|
||||
// compute max(c,a) and min(b,d)
|
||||
// start with (a,b)
|
||||
result := &(*first)
|
||||
// if c > a, then use c
|
||||
if string(second.Start) > string(first.Start) {
|
||||
result.Start = second.Start
|
||||
}
|
||||
// if b is maxed out, or
|
||||
// (d is not maxed out and d < b)
|
||||
// ^ valid test as neither b nor d are max
|
||||
// then use d
|
||||
if len(first.End) == 0 || (len(second.End) != 0 && string(second.End) < string(first.End)) {
|
||||
result.End = second.End
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
//
|
||||
// KeyspaceIdArray definitions
|
||||
//
|
||||
|
|
|
@ -48,6 +48,9 @@ func KeyRangeToProto(k KeyRange) *pb.KeyRange {
|
|||
|
||||
// ProtoToKeyRange translates a proto KeyRange, or panics
|
||||
func ProtoToKeyRange(k *pb.KeyRange) KeyRange {
|
||||
if k == nil {
|
||||
return KeyRange{}
|
||||
}
|
||||
return KeyRange{
|
||||
Start: KeyspaceId(k.Start),
|
||||
End: KeyspaceId(k.End),
|
||||
|
|
|
@ -205,8 +205,12 @@ func (m *Tablet) GetHealthMap() map[string]string {
|
|||
|
||||
// A Shard contains data about a subset of the data whithin a keyspace.
|
||||
type Shard struct {
|
||||
// There can be only at most one master, but there may be none. (0)
|
||||
// master_alias is the tablet alias of the master for the shard.
|
||||
// If it is unset, then there is no master in this shard yet.
|
||||
MasterAlias *TabletAlias `protobuf:"bytes,1,opt,name=master_alias" json:"master_alias,omitempty"`
|
||||
// key_range is the KeyRange for this shard. It can be unset if:
|
||||
// - we are not using range-based sharding in this shard.
|
||||
// - the shard covers the entire keyrange.
|
||||
// This must match the shard name based on our other conventions, but
|
||||
// helpful to have it decomposed here.
|
||||
KeyRange *KeyRange `protobuf:"bytes,2,opt,name=key_range" json:"key_range,omitempty"`
|
||||
|
@ -260,7 +264,7 @@ func (m *Shard) GetTabletControls() []*Shard_TabletControl {
|
|||
return nil
|
||||
}
|
||||
|
||||
// ShardServedType is an entry in the served_types
|
||||
// ServedType is an entry in the served_types
|
||||
type Shard_ServedType struct {
|
||||
TabletType TabletType `protobuf:"varint,1,opt,name=tablet_type,enum=topodata.TabletType" json:"tablet_type,omitempty"`
|
||||
Cells []string `protobuf:"bytes,2,rep,name=cells" json:"cells,omitempty"`
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
"github.com/youtube/vitess/go/vt/topo/test/faketopo"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
|
||||
// import the gRPC client implementation for tablet manager
|
||||
_ "github.com/youtube/vitess/go/vt/tabletmanager/grpctmclient"
|
||||
)
|
||||
|
@ -282,8 +284,8 @@ func (topoServer *fakeTopo) GetShardNames(ctx context.Context, keyspace string)
|
|||
}
|
||||
|
||||
func (topoServer *fakeTopo) GetShard(ctx context.Context, keyspace string, shard string) (*topo.ShardInfo, error) {
|
||||
value := &topo.Shard{
|
||||
MasterAlias: topo.TabletAlias{
|
||||
value := &pb.Shard{
|
||||
MasterAlias: &pb.TabletAlias{
|
||||
Cell: "test_cell",
|
||||
Uid: 0,
|
||||
},
|
||||
|
|
|
@ -54,7 +54,7 @@ func (exec *TabletExecutor) Open(ctx context.Context, keyspace string) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("unable to get shard info, keyspace: %s, shard: %s, error: %v", keyspace, shardName, err)
|
||||
}
|
||||
tabletInfo, err := exec.topoServer.GetTablet(ctx, shardInfo.MasterAlias)
|
||||
tabletInfo, err := exec.topoServer.GetTablet(ctx, topo.ProtoToTabletAlias(shardInfo.MasterAlias))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to get master tablet info, keyspace: %s, shard: %s, error: %v", keyspace, shardName, err)
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
package actionnode
|
||||
|
||||
import (
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -39,12 +40,12 @@ type ApplySchemaShardArgs struct {
|
|||
// SetShardServedTypesArgs is the payload for SetShardServedTypes
|
||||
type SetShardServedTypesArgs struct {
|
||||
Cells []string
|
||||
ServedType topo.TabletType
|
||||
ServedType pb.TabletType
|
||||
}
|
||||
|
||||
// MigrateServedTypesArgs is the payload for MigrateServedTypes
|
||||
type MigrateServedTypesArgs struct {
|
||||
ServedType topo.TabletType
|
||||
ServedType pb.TabletType
|
||||
}
|
||||
|
||||
// keyspace action node structures
|
||||
|
@ -114,7 +115,7 @@ func ApplySchemaShard(masterTabletAlias topo.TabletAlias, change string, simple
|
|||
}
|
||||
|
||||
// SetShardServedTypes returns an ActionNode
|
||||
func SetShardServedTypes(cells []string, servedType topo.TabletType) *ActionNode {
|
||||
func SetShardServedTypes(cells []string, servedType pb.TabletType) *ActionNode {
|
||||
return (&ActionNode{
|
||||
Action: ShardActionSetServedTypes,
|
||||
Args: &SetShardServedTypesArgs{
|
||||
|
@ -125,7 +126,7 @@ func SetShardServedTypes(cells []string, servedType topo.TabletType) *ActionNode
|
|||
}
|
||||
|
||||
// MigrateServedTypes returns an ActionNode
|
||||
func MigrateServedTypes(servedType topo.TabletType) *ActionNode {
|
||||
func MigrateServedTypes(servedType pb.TabletType) *ActionNode {
|
||||
return (&ActionNode{
|
||||
Action: ShardActionMigrateServedTypes,
|
||||
Args: &MigrateServedTypesArgs{
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"github.com/youtube/vitess/go/vt/topo"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/query"
|
||||
pbt "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -153,7 +154,7 @@ func (agent *ActionAgent) changeCallback(ctx context.Context, oldTablet, newTabl
|
|||
// Read the shard to get SourceShards / TabletControlMap if
|
||||
// we're going to use it.
|
||||
var shardInfo *topo.ShardInfo
|
||||
var tabletControl *topo.TabletControl
|
||||
var tabletControl *pbt.Shard_TabletControl
|
||||
var blacklistedTables []string
|
||||
var err error
|
||||
if allowQuery {
|
||||
|
@ -164,7 +165,7 @@ func (agent *ActionAgent) changeCallback(ctx context.Context, oldTablet, newTabl
|
|||
if newTablet.Type == topo.TYPE_MASTER {
|
||||
allowQuery = len(shardInfo.SourceShards) == 0
|
||||
}
|
||||
if tc, ok := shardInfo.TabletControlMap[newTablet.Type]; ok {
|
||||
if tc := shardInfo.GetTabletControl(topo.TabletTypeToProto(newTablet.Type)); tc != nil {
|
||||
if topo.InCellList(newTablet.Alias.Cell, tc.Cells) {
|
||||
if tc.DisableQueryService {
|
||||
allowQuery = false
|
||||
|
|
|
@ -45,6 +45,8 @@ import (
|
|||
"github.com/youtube/vitess/go/vt/tabletserver"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"github.com/youtube/vitess/go/vt/topotools"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -88,7 +90,7 @@ type ActionAgent struct {
|
|||
// to update the fields, nothing else.
|
||||
mutex sync.Mutex
|
||||
_tablet *topo.TabletInfo
|
||||
_tabletControl *topo.TabletControl
|
||||
_tabletControl *pb.Shard_TabletControl
|
||||
_waitingForMysql bool
|
||||
|
||||
// if the agent is healthy, this is nil. Otherwise it contains
|
||||
|
@ -317,7 +319,7 @@ func (agent *ActionAgent) DisableQueryService() bool {
|
|||
return disable
|
||||
}
|
||||
|
||||
func (agent *ActionAgent) setTabletControl(tc *topo.TabletControl) {
|
||||
func (agent *ActionAgent) setTabletControl(tc *pb.Shard_TabletControl) {
|
||||
agent.mutex.Lock()
|
||||
agent._tabletControl = tc
|
||||
agent.mutex.Unlock()
|
||||
|
|
|
@ -9,6 +9,7 @@ package tabletmanager
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"math/rand" // not crypto-safe is OK here
|
||||
"sort"
|
||||
"strings"
|
||||
|
@ -44,11 +45,11 @@ type BinlogPlayerController struct {
|
|||
// Information about us (set at construction, immutable).
|
||||
cell string
|
||||
keyspaceIDType pb.KeyspaceIdType
|
||||
keyRange key.KeyRange
|
||||
keyRange *pb.KeyRange
|
||||
dbName string
|
||||
|
||||
// Information about the source (set at construction, immutable).
|
||||
sourceShard topo.SourceShard
|
||||
sourceShard *pb.Shard_SourceShard
|
||||
|
||||
// BinlogPlayerStats has the stats for the players we're going to use
|
||||
// (pointer is set at construction, immutable, values are thread-safe).
|
||||
|
@ -75,7 +76,7 @@ type BinlogPlayerController struct {
|
|||
lastError error
|
||||
}
|
||||
|
||||
func newBinlogPlayerController(ts topo.Server, dbConfig *sqldb.ConnParams, mysqld mysqlctl.MysqlDaemon, cell string, keyspaceIDType pb.KeyspaceIdType, keyRange key.KeyRange, sourceShard topo.SourceShard, dbName string) *BinlogPlayerController {
|
||||
func newBinlogPlayerController(ts topo.Server, dbConfig *sqldb.ConnParams, mysqld mysqlctl.MysqlDaemon, cell string, keyspaceIDType pb.KeyspaceIdType, keyRange *pb.KeyRange, sourceShard *pb.Shard_SourceShard, dbName string) *BinlogPlayerController {
|
||||
blc := &BinlogPlayerController{
|
||||
ts: ts,
|
||||
dbConfig: dbConfig,
|
||||
|
@ -91,7 +92,7 @@ func newBinlogPlayerController(ts topo.Server, dbConfig *sqldb.ConnParams, mysql
|
|||
}
|
||||
|
||||
func (bpc *BinlogPlayerController) String() string {
|
||||
return "BinlogPlayerController(" + bpc.sourceShard.String() + ")"
|
||||
return "BinlogPlayerController(" + topo.SourceShardString(bpc.sourceShard) + ")"
|
||||
}
|
||||
|
||||
// Start will start the player in the background and run forever.
|
||||
|
@ -282,12 +283,12 @@ func (bpc *BinlogPlayerController) Iteration() (err error) {
|
|||
}
|
||||
// the data we have to replicate is the intersection of the
|
||||
// source keyrange and our keyrange
|
||||
overlap, err := key.KeyRangesOverlap(bpc.sourceShard.KeyRange, bpc.keyRange)
|
||||
overlap, err := key.KeyRangesOverlap3(bpc.sourceShard.KeyRange, bpc.keyRange)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Source shard %v doesn't overlap destination shard %v", bpc.sourceShard.KeyRange, bpc.keyRange)
|
||||
}
|
||||
|
||||
player := binlogplayer.NewBinlogPlayerKeyRange(vtClient, endPoint, bpc.keyspaceIDType, overlap, startPosition, bpc.stopPosition, bpc.binlogPlayerStats)
|
||||
player := binlogplayer.NewBinlogPlayerKeyRange(vtClient, endPoint, bpc.keyspaceIDType, key.ProtoToKeyRange(overlap), startPosition, bpc.stopPosition, bpc.binlogPlayerStats)
|
||||
return player.ApplyBinlogEvents(bpc.ctx)
|
||||
}
|
||||
|
||||
|
@ -384,7 +385,7 @@ func (blm *BinlogPlayerMap) size() int64 {
|
|||
}
|
||||
|
||||
// addPlayer adds a new player to the map. It assumes we have the lock.
|
||||
func (blm *BinlogPlayerMap) addPlayer(ctx context.Context, cell string, keyspaceIDType pb.KeyspaceIdType, keyRange key.KeyRange, sourceShard topo.SourceShard, dbName string) {
|
||||
func (blm *BinlogPlayerMap) addPlayer(ctx context.Context, cell string, keyspaceIDType pb.KeyspaceIdType, keyRange *pb.KeyRange, sourceShard *pb.Shard_SourceShard, dbName string) {
|
||||
bpc, ok := blm.players[sourceShard.Uid]
|
||||
if ok {
|
||||
log.Infof("Already playing logs for %v", sourceShard)
|
||||
|
@ -446,7 +447,7 @@ func (blm *BinlogPlayerMap) RefreshMap(ctx context.Context, tablet *topo.Tablet,
|
|||
|
||||
// for each source, add it if not there, and delete from toRemove
|
||||
for _, sourceShard := range shardInfo.SourceShards {
|
||||
blm.addPlayer(ctx, tablet.Alias.Cell, keyspaceInfo.ShardingColumnType, tablet.KeyRange, sourceShard, tablet.DbName())
|
||||
blm.addPlayer(ctx, tablet.Alias.Cell, keyspaceInfo.ShardingColumnType, key.KeyRangeToProto(tablet.KeyRange), sourceShard, tablet.DbName())
|
||||
delete(toRemove, sourceShard.Uid)
|
||||
}
|
||||
hasPlayers := len(shardInfo.SourceShards) > 0
|
||||
|
@ -571,7 +572,7 @@ func (blm *BinlogPlayerMap) RunUntil(ctx context.Context, blpPositionList *blpro
|
|||
type BinlogPlayerControllerStatus struct {
|
||||
// configuration values
|
||||
Index uint32
|
||||
SourceShard topo.SourceShard
|
||||
SourceShard *pb.Shard_SourceShard
|
||||
StopPosition myproto.ReplicationPosition
|
||||
|
||||
// stats and current values
|
||||
|
@ -584,6 +585,11 @@ type BinlogPlayerControllerStatus struct {
|
|||
LastError string
|
||||
}
|
||||
|
||||
// SourceShardAsHTML returns the SourceShard as HTML
|
||||
func (bpcs *BinlogPlayerControllerStatus) SourceShardAsHTML() template.HTML {
|
||||
return topo.SourceShardAsHTML(bpcs.SourceShard)
|
||||
}
|
||||
|
||||
// BinlogPlayerControllerStatusList is the list of statuses.
|
||||
type BinlogPlayerControllerStatusList []*BinlogPlayerControllerStatus
|
||||
|
||||
|
|
|
@ -295,8 +295,9 @@ func TestTabletControl(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
si.TabletControlMap = map[topo.TabletType]*topo.TabletControl{
|
||||
targetTabletType: &topo.TabletControl{
|
||||
si.TabletControls = []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: topo.TabletTypeToProto(targetTabletType),
|
||||
DisableQueryService: true,
|
||||
},
|
||||
}
|
||||
|
|
|
@ -97,7 +97,7 @@ func (agent *ActionAgent) InitTablet(port, gRPCPort int) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("InitTablet cannot GetOrCreateShard shard: %v", err)
|
||||
}
|
||||
if si.MasterAlias == agent.TabletAlias {
|
||||
if si.MasterAlias != nil && *si.MasterAlias == *topo.TabletAliasToProto(agent.TabletAlias) {
|
||||
// we are the current master for this shard (probably
|
||||
// means the master tablet process was just restarted),
|
||||
// so InitTablet as master.
|
||||
|
|
|
@ -137,7 +137,7 @@ func TestInitTablet(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
si.MasterAlias = tabletAlias
|
||||
si.MasterAlias = topo.TabletAliasToProto(tabletAlias)
|
||||
if err := topo.UpdateShard(ctx, ts, si); err != nil {
|
||||
t.Fatalf("UpdateShard failed: %v", err)
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ func (agent *ActionAgent) TabletExternallyReparented(ctx context.Context, extern
|
|||
log.Warningf("fastTabletExternallyReparented: failed to read global shard record for %v/%v: %v", tablet.Keyspace, tablet.Shard, err)
|
||||
return err
|
||||
}
|
||||
if si.MasterAlias == tablet.Alias {
|
||||
if si.MasterAlias != nil && *si.MasterAlias == *topo.TabletAliasToProto(tablet.Alias) {
|
||||
// We may get called on the current master even when nothing has changed.
|
||||
// If the global shard record is already updated, it means we successfully
|
||||
// finished a previous reparent to this tablet.
|
||||
|
@ -69,9 +69,12 @@ func (agent *ActionAgent) TabletExternallyReparented(ctx context.Context, extern
|
|||
|
||||
// Create a reusable Reparent event with available info.
|
||||
ev := &events.Reparent{
|
||||
ShardInfo: *si,
|
||||
NewMaster: *tablet.Tablet,
|
||||
OldMaster: topo.Tablet{Alias: si.MasterAlias, Type: topo.TYPE_MASTER},
|
||||
ShardInfo: *si,
|
||||
NewMaster: *tablet.Tablet,
|
||||
OldMaster: topo.Tablet{
|
||||
Alias: topo.ProtoToTabletAlias(si.MasterAlias),
|
||||
Type: topo.TYPE_MASTER,
|
||||
},
|
||||
ExternalID: externalID,
|
||||
}
|
||||
defer func() {
|
||||
|
@ -168,12 +171,12 @@ func (agent *ActionAgent) finalizeTabletExternallyReparented(ctx context.Context
|
|||
}
|
||||
}()
|
||||
|
||||
if !oldMasterAlias.IsZero() {
|
||||
if !topo.TabletAliasIsZero(oldMasterAlias) {
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
// Force the old master to spare.
|
||||
var oldMasterTablet *topo.Tablet
|
||||
err := topo.UpdateTabletFields(ctx, agent.TopoServer, oldMasterAlias,
|
||||
err := topo.UpdateTabletFields(ctx, agent.TopoServer, topo.ProtoToTabletAlias(oldMasterAlias),
|
||||
func(tablet *topo.Tablet) error {
|
||||
tablet.Type = topo.TYPE_SPARE
|
||||
oldMasterTablet = tablet
|
||||
|
@ -217,8 +220,8 @@ func (agent *ActionAgent) finalizeTabletExternallyReparented(ctx context.Context
|
|||
// write it back. Now we use an update loop pattern to do that instead.
|
||||
event.DispatchUpdate(ev, "updating global shard record")
|
||||
log.Infof("finalizeTabletExternallyReparented: updating global shard record")
|
||||
si, err = topo.UpdateShardFields(ctx, agent.TopoServer, tablet.Keyspace, tablet.Shard, func(shard *topo.Shard) error {
|
||||
shard.MasterAlias = tablet.Alias
|
||||
si, err = topo.UpdateShardFields(ctx, agent.TopoServer, tablet.Keyspace, tablet.Shard, func(shard *pb.Shard) error {
|
||||
shard.MasterAlias = topo.TabletAliasToProto(tablet.Alias)
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -228,7 +231,7 @@ func (agent *ActionAgent) finalizeTabletExternallyReparented(ctx context.Context
|
|||
// We already took care of updating the serving graph for the old and new masters.
|
||||
// All that's left now is in case of a cross-cell reparent, we need to update the
|
||||
// master cell setting in the SrvShard records of all cells.
|
||||
if oldMasterAlias.Cell != tablet.Alias.Cell {
|
||||
if oldMasterAlias == nil || oldMasterAlias.Cell != tablet.Alias.Cell {
|
||||
event.DispatchUpdate(ev, "rebuilding shard serving graph")
|
||||
log.Infof("finalizeTabletExternallyReparented: updating SrvShard in all cells for cross-cell reparent")
|
||||
if err := topotools.UpdateAllSrvShards(ctx, agent.TopoServer, si); err != nil {
|
||||
|
|
|
@ -55,7 +55,10 @@ func (agent *ActionAgent) RestoreFromBackup(ctx context.Context) error {
|
|||
if err != nil {
|
||||
return fmt.Errorf("Cannot read shard: %v", err)
|
||||
}
|
||||
ti, err := agent.TopoServer.GetTablet(ctx, si.MasterAlias)
|
||||
if si.MasterAlias == nil {
|
||||
return fmt.Errorf("Shard %v/%v has no master", tablet.Keyspace, tablet.Shard)
|
||||
}
|
||||
ti, err := agent.TopoServer.GetTablet(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot read master tablet %v: %v", si.MasterAlias, err)
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ func createSetup(ctx context.Context, t *testing.T) (topo.Server, topo.Server) {
|
|||
if err := fromTS.CreateKeyspace(ctx, "test_keyspace", &pb.Keyspace{}); err != nil {
|
||||
t.Fatalf("cannot create keyspace: %v", err)
|
||||
}
|
||||
if err := fromTS.CreateShard(ctx, "test_keyspace", "0", &topo.Shard{Cells: []string{"test_cell"}}); err != nil {
|
||||
if err := fromTS.CreateShard(ctx, "test_keyspace", "0", &pb.Shard{Cells: []string{"test_cell"}}); err != nil {
|
||||
t.Fatalf("cannot create shard: %v", err)
|
||||
}
|
||||
if err := topo.CreateTablet(ctx, fromTS, &topo.Tablet{
|
||||
|
|
|
@ -226,7 +226,7 @@ func (tee *Tee) DeleteKeyspaceShards(ctx context.Context, keyspace string) error
|
|||
//
|
||||
|
||||
// CreateShard is part of the topo.Server interface
|
||||
func (tee *Tee) CreateShard(ctx context.Context, keyspace, shard string, value *topo.Shard) error {
|
||||
func (tee *Tee) CreateShard(ctx context.Context, keyspace, shard string, value *pb.Shard) error {
|
||||
err := tee.primary.CreateShard(ctx, keyspace, shard, value)
|
||||
if err != nil && err != topo.ErrNodeExists {
|
||||
return err
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
|
@ -25,6 +26,9 @@ func TabletAliasToProto(t TabletAlias) *pb.TabletAlias {
|
|||
|
||||
// ProtoToTabletAlias turns a proto to a TabletAlias
|
||||
func ProtoToTabletAlias(t *pb.TabletAlias) TabletAlias {
|
||||
if t == nil {
|
||||
return TabletAlias{}
|
||||
}
|
||||
return TabletAlias{
|
||||
Cell: t.Cell,
|
||||
Uid: t.Uid,
|
||||
|
|
|
@ -106,7 +106,7 @@ type Server interface {
|
|||
// yet. The contents of the shard will be a new Shard{} object,
|
||||
// with KeyRange populated by the result of ValidateShardName().
|
||||
// Can return ErrNodeExists if it already exists.
|
||||
CreateShard(ctx context.Context, keyspace, shard string, value *Shard) error
|
||||
CreateShard(ctx context.Context, keyspace, shard string, value *pb.Shard) error
|
||||
|
||||
// UpdateShard updates the shard information
|
||||
// pointed at by si.keyspace / si.shard to the *si value.
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package topo
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"reflect"
|
||||
|
@ -19,6 +20,8 @@ import (
|
|||
"github.com/youtube/vitess/go/trace"
|
||||
"github.com/youtube/vitess/go/vt/concurrency"
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// Functions for dealing with shard representations in topology.
|
||||
|
@ -84,42 +87,18 @@ func ParseKeyspaceShardString(param string) (string, string, error) {
|
|||
return keySpaceShard[0], keySpaceShard[1], nil
|
||||
}
|
||||
|
||||
// SourceShard represents a data source for filtered replication
|
||||
// across shards. When this is used in a destination shard, the master
|
||||
// of that shard will run filtered replication.
|
||||
type SourceShard struct {
|
||||
// Uid is the unique ID for this SourceShard object.
|
||||
// It is for instance used as a unique index in blp_checkpoint
|
||||
// when storing the position. It should be unique whithin a
|
||||
// destination Shard, but not globally unique.
|
||||
Uid uint32
|
||||
|
||||
// the source keyspace
|
||||
Keyspace string
|
||||
|
||||
// the source shard
|
||||
Shard string
|
||||
|
||||
// The source shard keyrange
|
||||
// If partial, len(Tables) has to be zero
|
||||
KeyRange key.KeyRange
|
||||
|
||||
// The source table list to replicate
|
||||
// If non-empty, KeyRange must not be partial (must be KeyRange{})
|
||||
Tables []string
|
||||
}
|
||||
|
||||
// String returns a printable view of a SourceShard.
|
||||
func (source *SourceShard) String() string {
|
||||
// SourceShardString returns a printable view of a SourceShard.
|
||||
func SourceShardString(source *pb.Shard_SourceShard) string {
|
||||
return fmt.Sprintf("SourceShard(%v,%v/%v)", source.Uid, source.Keyspace, source.Shard)
|
||||
}
|
||||
|
||||
// AsHTML returns a HTML version of the object.
|
||||
func (source *SourceShard) AsHTML() template.HTML {
|
||||
// SourceShardAsHTML returns a HTML version of the object.
|
||||
func SourceShardAsHTML(source *pb.Shard_SourceShard) template.HTML {
|
||||
result := fmt.Sprintf("<b>Uid</b>: %v</br>\n<b>Source</b>: %v/%v</br>\n", source.Uid, source.Keyspace, source.Shard)
|
||||
if source.KeyRange.IsPartial() {
|
||||
if key.KeyRangeIsPartial(source.KeyRange) {
|
||||
result += fmt.Sprintf("<b>KeyRange</b>: %v-%v</br>\n",
|
||||
source.KeyRange.Start.Hex(), source.KeyRange.End.Hex())
|
||||
hex.EncodeToString(source.KeyRange.Start),
|
||||
hex.EncodeToString(source.KeyRange.End))
|
||||
}
|
||||
if len(source.Tables) > 0 {
|
||||
result += fmt.Sprintf("<b>Tables</b>: %v</br>\n",
|
||||
|
@ -128,59 +107,6 @@ func (source *SourceShard) AsHTML() template.HTML {
|
|||
return template.HTML(result)
|
||||
}
|
||||
|
||||
// TabletControl describes the parameters used by the vttablet processes
|
||||
// to know what specific configurations they should be using.
|
||||
type TabletControl struct {
|
||||
// How to match the tablets
|
||||
Cells []string // nil means all cells
|
||||
|
||||
// What specific action to take
|
||||
DisableQueryService bool
|
||||
BlacklistedTables []string // only used if DisableQueryService==false
|
||||
}
|
||||
|
||||
// ShardServedType describes the cells where the given shard is serving.
|
||||
type ShardServedType struct {
|
||||
Cells []string // nil means all cells
|
||||
}
|
||||
|
||||
// Shard is a pure data struct for information stored in topology server. This
|
||||
// node is used to present a controlled view of the shard, unaware of
|
||||
// every management action. It also contains configuration data for a
|
||||
// shard.
|
||||
type Shard struct {
|
||||
// There can be only at most one master, but there may be none. (0)
|
||||
MasterAlias TabletAlias
|
||||
|
||||
// This must match the shard name based on our other conventions, but
|
||||
// helpful to have it decomposed here.
|
||||
KeyRange key.KeyRange
|
||||
|
||||
// ServedTypesMap is a map of all the tablet types this shard
|
||||
// will serve, to the cells that serve this type. This is
|
||||
// usually used with overlapping shards during data shuffles
|
||||
// like shard splitting. Note the master record will always
|
||||
// list all the cells.
|
||||
ServedTypesMap map[TabletType]*ShardServedType
|
||||
|
||||
// SourceShards is the list of shards we're replicating from,
|
||||
// using filtered replication.
|
||||
SourceShards []SourceShard
|
||||
|
||||
// Cells is the list of cells that have tablets for this shard.
|
||||
// It is populated at InitTablet time when a tablet is added
|
||||
// in a cell that is not in the list yet.
|
||||
Cells []string
|
||||
|
||||
// TabletControlMap is a map of TabletControl to apply specific
|
||||
// configurations to tablets by type.
|
||||
TabletControlMap map[TabletType]*TabletControl
|
||||
}
|
||||
|
||||
func newShard() *Shard {
|
||||
return &Shard{}
|
||||
}
|
||||
|
||||
// IsShardUsingRangeBasedSharding returns true if the shard name
|
||||
// implies it is using range based sharding.
|
||||
func IsShardUsingRangeBasedSharding(shard string) bool {
|
||||
|
@ -189,45 +115,35 @@ func IsShardUsingRangeBasedSharding(shard string) bool {
|
|||
|
||||
// ValidateShardName takes a shard name and sanitizes it, and also returns
|
||||
// the KeyRange.
|
||||
func ValidateShardName(shard string) (string, key.KeyRange, error) {
|
||||
func ValidateShardName(shard string) (string, *pb.KeyRange, error) {
|
||||
if !IsShardUsingRangeBasedSharding(shard) {
|
||||
return shard, key.KeyRange{}, nil
|
||||
return shard, nil, nil
|
||||
}
|
||||
|
||||
parts := strings.Split(shard, "-")
|
||||
if len(parts) != 2 {
|
||||
return "", key.KeyRange{}, fmt.Errorf("invalid shardId, can only contain one '-': %v", shard)
|
||||
return "", nil, fmt.Errorf("invalid shardId, can only contain one '-': %v", shard)
|
||||
}
|
||||
|
||||
keyRange, err := key.ParseKeyRangeParts(parts[0], parts[1])
|
||||
keyRange, err := key.ParseKeyRangeParts3(parts[0], parts[1])
|
||||
if err != nil {
|
||||
return "", key.KeyRange{}, err
|
||||
return "", nil, err
|
||||
}
|
||||
|
||||
if keyRange.End != key.MaxKey && keyRange.Start >= keyRange.End {
|
||||
return "", key.KeyRange{}, fmt.Errorf("out of order keys: %v is not strictly smaller than %v", keyRange.Start.Hex(), keyRange.End.Hex())
|
||||
if len(keyRange.End) > 0 && string(keyRange.Start) >= string(keyRange.End) {
|
||||
return "", nil, fmt.Errorf("out of order keys: %v is not strictly smaller than %v", hex.EncodeToString(keyRange.Start), hex.EncodeToString(keyRange.End))
|
||||
}
|
||||
|
||||
return strings.ToLower(shard), keyRange, nil
|
||||
}
|
||||
|
||||
// HasCell returns true if the cell is listed in the Cells for the shard.
|
||||
func (shard *Shard) HasCell(cell string) bool {
|
||||
for _, c := range shard.Cells {
|
||||
if c == cell {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// ShardInfo is a meta struct that contains metadata to give the data
|
||||
// more context and convenience. This is the main way we interact with a shard.
|
||||
type ShardInfo struct {
|
||||
keyspace string
|
||||
shardName string
|
||||
version int64
|
||||
*Shard
|
||||
*pb.Shard
|
||||
}
|
||||
|
||||
// Keyspace returns the keyspace a shard belongs to
|
||||
|
@ -248,7 +164,7 @@ func (si *ShardInfo) Version() int64 {
|
|||
// NewShardInfo returns a ShardInfo basing on shard with the
|
||||
// keyspace / shard. This function should be only used by Server
|
||||
// implementations.
|
||||
func NewShardInfo(keyspace, shard string, value *Shard, version int64) *ShardInfo {
|
||||
func NewShardInfo(keyspace, shard string, value *pb.Shard, version int64) *ShardInfo {
|
||||
return &ShardInfo{
|
||||
keyspace: keyspace,
|
||||
shardName: shard,
|
||||
|
@ -257,6 +173,16 @@ func NewShardInfo(keyspace, shard string, value *Shard, version int64) *ShardInf
|
|||
}
|
||||
}
|
||||
|
||||
// HasCell returns true if the cell is listed in the Cells for the shard.
|
||||
func (si *ShardInfo) HasCell(cell string) bool {
|
||||
for _, c := range si.Cells {
|
||||
if c == cell {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetShard is a high level function to read shard data.
|
||||
// It generates trace spans.
|
||||
func GetShard(ctx context.Context, ts Server, keyspace, shard string) (*ShardInfo, error) {
|
||||
|
@ -293,7 +219,7 @@ func UpdateShard(ctx context.Context, ts Server, si *ShardInfo) error {
|
|||
// update function on it, and then write it back. If the write fails due to
|
||||
// a version mismatch, it will re-read the record and retry the update.
|
||||
// If the update succeeds, it returns the updated ShardInfo.
|
||||
func UpdateShardFields(ctx context.Context, ts Server, keyspace, shard string, update func(*Shard) error) (*ShardInfo, error) {
|
||||
func UpdateShardFields(ctx context.Context, ts Server, keyspace, shard string, update func(*pb.Shard) error) (*ShardInfo, error) {
|
||||
for {
|
||||
si, err := GetShard(ctx, ts, keyspace, shard)
|
||||
if err != nil {
|
||||
|
@ -320,13 +246,13 @@ func CreateShard(ctx context.Context, ts Server, keyspace, shard string) error {
|
|||
|
||||
// start the shard with all serving types. If it overlaps with
|
||||
// other shards for some serving types, remove them.
|
||||
s := &Shard{
|
||||
servedTypes := map[pb.TabletType]bool{
|
||||
pb.TabletType_MASTER: true,
|
||||
pb.TabletType_REPLICA: true,
|
||||
pb.TabletType_RDONLY: true,
|
||||
}
|
||||
s := &pb.Shard{
|
||||
KeyRange: keyRange,
|
||||
ServedTypesMap: map[TabletType]*ShardServedType{
|
||||
TYPE_MASTER: &ShardServedType{},
|
||||
TYPE_REPLICA: &ShardServedType{},
|
||||
TYPE_RDONLY: &ShardServedType{},
|
||||
},
|
||||
}
|
||||
|
||||
if IsShardUsingRangeBasedSharding(name) {
|
||||
|
@ -337,20 +263,34 @@ func CreateShard(ctx context.Context, ts Server, keyspace, shard string) error {
|
|||
return err
|
||||
}
|
||||
for _, si := range sis {
|
||||
if key.KeyRangesIntersect(si.KeyRange, keyRange) {
|
||||
for t := range si.ServedTypesMap {
|
||||
delete(s.ServedTypesMap, t)
|
||||
if si.KeyRange == nil || key.KeyRangesIntersect3(si.KeyRange, keyRange) {
|
||||
for _, st := range si.ServedTypes {
|
||||
delete(servedTypes, st.TabletType)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(s.ServedTypesMap) == 0 {
|
||||
s.ServedTypesMap = nil
|
||||
}
|
||||
}
|
||||
|
||||
for st, _ := range servedTypes {
|
||||
s.ServedTypes = append(s.ServedTypes, &pb.Shard_ServedType{
|
||||
TabletType: st,
|
||||
})
|
||||
}
|
||||
|
||||
return ts.CreateShard(ctx, keyspace, name, s)
|
||||
}
|
||||
|
||||
// GetTabletControl returns the Shard_TabletControl for the given tablet type,
|
||||
// or nil if it is not in the map.
|
||||
func (si *ShardInfo) GetTabletControl(tabletType pb.TabletType) *pb.Shard_TabletControl {
|
||||
for _, tc := range si.TabletControls {
|
||||
if tc.TabletType == tabletType {
|
||||
return tc
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateSourceBlacklistedTables will add or remove the listed tables
|
||||
// in the shard record's TabletControl structures. Note we don't
|
||||
// support a lot of the corner cases:
|
||||
|
@ -358,17 +298,11 @@ func CreateShard(ctx context.Context, ts Server, keyspace, shard string) error {
|
|||
// table list that the provided one, we error out.
|
||||
// - we don't support DisableQueryService at the same time as BlacklistedTables,
|
||||
// because it's not used in the same context (vertical vs horizontal sharding)
|
||||
func (si *ShardInfo) UpdateSourceBlacklistedTables(tabletType TabletType, cells []string, remove bool, tables []string) error {
|
||||
if si.TabletControlMap == nil {
|
||||
si.TabletControlMap = make(map[TabletType]*TabletControl)
|
||||
}
|
||||
tc, ok := si.TabletControlMap[tabletType]
|
||||
if !ok {
|
||||
func (si *ShardInfo) UpdateSourceBlacklistedTables(tabletType pb.TabletType, cells []string, remove bool, tables []string) error {
|
||||
tc := si.GetTabletControl(tabletType)
|
||||
if tc == nil {
|
||||
// handle the case where the TabletControl object is new
|
||||
if remove {
|
||||
if len(si.TabletControlMap) == 0 {
|
||||
si.TabletControlMap = nil
|
||||
}
|
||||
// we try to remove from something that doesn't exist,
|
||||
// log, but we're done.
|
||||
log.Warningf("Trying to remove TabletControl.BlacklistedTables for missing type %v in shard %v/%v", tabletType, si.keyspace, si.shardName)
|
||||
|
@ -376,11 +310,12 @@ func (si *ShardInfo) UpdateSourceBlacklistedTables(tabletType TabletType, cells
|
|||
}
|
||||
|
||||
// trying to add more constraints with no existing record
|
||||
si.TabletControlMap[tabletType] = &TabletControl{
|
||||
si.TabletControls = append(si.TabletControls, &pb.Shard_TabletControl{
|
||||
TabletType: tabletType,
|
||||
Cells: cells,
|
||||
DisableQueryService: false,
|
||||
BlacklistedTables: tables,
|
||||
}
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -407,23 +342,18 @@ func (si *ShardInfo) UpdateSourceBlacklistedTables(tabletType TabletType, cells
|
|||
// of the corner cases:
|
||||
// - we don't support DisableQueryService at the same time as BlacklistedTables,
|
||||
// because it's not used in the same context (vertical vs horizontal sharding)
|
||||
func (si *ShardInfo) UpdateDisableQueryService(tabletType TabletType, cells []string, disableQueryService bool) error {
|
||||
if si.TabletControlMap == nil {
|
||||
si.TabletControlMap = make(map[TabletType]*TabletControl)
|
||||
}
|
||||
tc, ok := si.TabletControlMap[tabletType]
|
||||
if !ok {
|
||||
func (si *ShardInfo) UpdateDisableQueryService(tabletType pb.TabletType, cells []string, disableQueryService bool) error {
|
||||
tc := si.GetTabletControl(tabletType)
|
||||
if tc == nil {
|
||||
// handle the case where the TabletControl object is new
|
||||
if disableQueryService {
|
||||
si.TabletControlMap[tabletType] = &TabletControl{
|
||||
si.TabletControls = append(si.TabletControls, &pb.Shard_TabletControl{
|
||||
TabletType: tabletType,
|
||||
Cells: cells,
|
||||
DisableQueryService: true,
|
||||
BlacklistedTables: nil,
|
||||
}
|
||||
})
|
||||
} else {
|
||||
if len(si.TabletControlMap) == 0 {
|
||||
si.TabletControlMap = nil
|
||||
}
|
||||
log.Warningf("Trying to remove TabletControl.DisableQueryService for missing type: %v", tabletType)
|
||||
}
|
||||
return nil
|
||||
|
@ -446,45 +376,58 @@ func (si *ShardInfo) UpdateDisableQueryService(tabletType TabletType, cells []st
|
|||
return nil
|
||||
}
|
||||
|
||||
func (si *ShardInfo) removeCellsFromTabletControl(tc *TabletControl, tabletType TabletType, cells []string) {
|
||||
func (si *ShardInfo) removeCellsFromTabletControl(tc *pb.Shard_TabletControl, tabletType pb.TabletType, cells []string) {
|
||||
result, emptyList := removeCells(tc.Cells, cells, si.Cells)
|
||||
if emptyList {
|
||||
// we don't have any cell left, we need to clear this record
|
||||
delete(si.TabletControlMap, tabletType)
|
||||
if len(si.TabletControlMap) == 0 {
|
||||
si.TabletControlMap = nil
|
||||
var tabletControls []*pb.Shard_TabletControl
|
||||
for _, tc := range si.TabletControls {
|
||||
if tc.TabletType != tabletType {
|
||||
tabletControls = append(tabletControls, tc)
|
||||
}
|
||||
}
|
||||
si.TabletControls = tabletControls
|
||||
} else {
|
||||
tc.Cells = result
|
||||
}
|
||||
}
|
||||
|
||||
// GetServedType returns the Shard_ServedType for a TabletType, or nil
|
||||
func (si *ShardInfo) GetServedType(tabletType pb.TabletType) *pb.Shard_ServedType {
|
||||
for _, st := range si.ServedTypes {
|
||||
if st.TabletType == tabletType {
|
||||
return st
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetServedTypesPerCell returns the list of types this shard is serving
|
||||
// in the provided cell.
|
||||
func (si *ShardInfo) GetServedTypesPerCell(cell string) []TabletType {
|
||||
result := make([]TabletType, 0, len(si.ServedTypesMap))
|
||||
for tt, sst := range si.ServedTypesMap {
|
||||
if InCellList(cell, sst.Cells) {
|
||||
result = append(result, tt)
|
||||
result := make([]TabletType, 0, len(si.ServedTypes))
|
||||
for _, st := range si.ServedTypes {
|
||||
if InCellList(cell, st.Cells) {
|
||||
result = append(result, ProtoToTabletType(st.TabletType))
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// CheckServedTypesMigration makes sure the provided migration is possible
|
||||
func (si *ShardInfo) CheckServedTypesMigration(tabletType TabletType, cells []string, remove bool) error {
|
||||
func (si *ShardInfo) CheckServedTypesMigration(tabletType pb.TabletType, cells []string, remove bool) error {
|
||||
// master is a special case with a few extra checks
|
||||
if tabletType == TYPE_MASTER {
|
||||
if tabletType == pb.TabletType_MASTER {
|
||||
if len(cells) > 0 {
|
||||
return fmt.Errorf("cannot migrate only some cells for master in shard %v/%v", si.keyspace, si.shardName)
|
||||
}
|
||||
if remove && len(si.ServedTypesMap) > 1 {
|
||||
if remove && len(si.ServedTypes) > 1 {
|
||||
return fmt.Errorf("cannot migrate master away from %v/%v until everything else is migrated", si.keyspace, si.shardName)
|
||||
}
|
||||
}
|
||||
|
||||
// we can't remove a type we don't have
|
||||
if _, ok := si.ServedTypesMap[tabletType]; !ok && remove {
|
||||
if si.GetServedType(tabletType) == nil && remove {
|
||||
return fmt.Errorf("supplied type %v cannot be migrated out of %#v", tabletType, si)
|
||||
}
|
||||
|
||||
|
@ -493,27 +436,22 @@ func (si *ShardInfo) CheckServedTypesMigration(tabletType TabletType, cells []st
|
|||
|
||||
// UpdateServedTypesMap handles ServedTypesMap. It can add or remove
|
||||
// records, cells, ...
|
||||
func (si *ShardInfo) UpdateServedTypesMap(tabletType TabletType, cells []string, remove bool) error {
|
||||
func (si *ShardInfo) UpdateServedTypesMap(tabletType pb.TabletType, cells []string, remove bool) error {
|
||||
// check parameters to be sure
|
||||
if err := si.CheckServedTypesMigration(tabletType, cells, remove); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if si.ServedTypesMap == nil {
|
||||
si.ServedTypesMap = make(map[TabletType]*ShardServedType)
|
||||
}
|
||||
sst, ok := si.ServedTypesMap[tabletType]
|
||||
if !ok {
|
||||
sst := si.GetServedType(tabletType)
|
||||
if sst == nil {
|
||||
// the record doesn't exist
|
||||
if remove {
|
||||
if len(si.ServedTypesMap) == 0 {
|
||||
si.ServedTypesMap = nil
|
||||
}
|
||||
log.Warningf("Trying to remove ShardServedType for missing type %v in shard %v/%v", tabletType, si.keyspace, si.shardName)
|
||||
} else {
|
||||
si.ServedTypesMap[tabletType] = &ShardServedType{
|
||||
Cells: cells,
|
||||
}
|
||||
si.ServedTypes = append(si.ServedTypes, &pb.Shard_ServedType{
|
||||
TabletType: tabletType,
|
||||
Cells: cells,
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -522,10 +460,13 @@ func (si *ShardInfo) UpdateServedTypesMap(tabletType TabletType, cells []string,
|
|||
result, emptyList := removeCells(sst.Cells, cells, si.Cells)
|
||||
if emptyList {
|
||||
// we don't have any cell left, we need to clear this record
|
||||
delete(si.ServedTypesMap, tabletType)
|
||||
if len(si.ServedTypesMap) == 0 {
|
||||
si.ServedTypesMap = nil
|
||||
var servedTypes []*pb.Shard_ServedType
|
||||
for _, st := range si.ServedTypes {
|
||||
if st.TabletType != tabletType {
|
||||
servedTypes = append(servedTypes, st)
|
||||
}
|
||||
}
|
||||
si.ServedTypes = servedTypes
|
||||
} else {
|
||||
sst.Cells = result
|
||||
}
|
||||
|
@ -587,9 +528,9 @@ func FindAllTabletAliasesInShardByCell(ctx context.Context, ts Server, keyspace,
|
|||
}
|
||||
|
||||
resultAsMap := make(map[TabletAlias]bool)
|
||||
if !si.MasterAlias.IsZero() {
|
||||
if si.MasterAlias != nil && !TabletAliasIsZero(si.MasterAlias) {
|
||||
if InCellList(si.MasterAlias.Cell, cells) {
|
||||
resultAsMap[si.MasterAlias] = true
|
||||
resultAsMap[ProtoToTabletAlias(si.MasterAlias)] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ package topo
|
|||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// This file tests the shard related object functionnalities.
|
||||
|
@ -83,13 +85,14 @@ func TestParseKeyspaceShardString(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpdateSourceBlacklistedTables(t *testing.T) {
|
||||
si := NewShardInfo("ks", "sh", &Shard{
|
||||
si := NewShardInfo("ks", "sh", &pb.Shard{
|
||||
Cells: []string{"first", "second", "third"},
|
||||
}, 1)
|
||||
|
||||
// add one cell
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"first"}, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"first"}, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first"},
|
||||
BlacklistedTables: []string{"t1", "t2"},
|
||||
},
|
||||
|
@ -98,25 +101,26 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) {
|
|||
}
|
||||
|
||||
// remove that cell, going back
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"first"}, true, nil); err != nil || si.TabletControlMap != nil {
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"first"}, true, nil); err != nil || len(si.TabletControls) != 0 {
|
||||
t.Fatalf("going back should have remove the record: %v", si)
|
||||
}
|
||||
|
||||
// re-add a cell, then another with different table list to
|
||||
// make sure it fails
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"first"}, false, []string{"t1", "t2"}); err != nil {
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"first"}, false, []string{"t1", "t2"}); err != nil {
|
||||
t.Fatalf("one cell add failed: %v", si)
|
||||
}
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"second"}, false, []string{"t2", "t3"}); err == nil || err.Error() != "trying to use two different sets of blacklisted tables for shard ks/sh: [t1 t2] and [t2 t3]" {
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"second"}, false, []string{"t2", "t3"}); err == nil || err.Error() != "trying to use two different sets of blacklisted tables for shard ks/sh: [t1 t2] and [t2 t3]" {
|
||||
t.Fatalf("different table list should fail: %v", err)
|
||||
}
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, []string{"first"}, true); err == nil || err.Error() != "cannot safely alter DisableQueryService as BlacklistedTables is set" {
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, []string{"first"}, true); err == nil || err.Error() != "cannot safely alter DisableQueryService as BlacklistedTables is set" {
|
||||
t.Fatalf("UpdateDisableQueryService should fail: %v", err)
|
||||
}
|
||||
|
||||
// add another cell, see the list grow
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"second"}, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"second"}, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "second"},
|
||||
BlacklistedTables: []string{"t1", "t2"},
|
||||
},
|
||||
|
@ -125,8 +129,9 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) {
|
|||
}
|
||||
|
||||
// add all cells, see the list grow to all
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, nil, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, nil, false, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: nil,
|
||||
BlacklistedTables: []string{"t1", "t2"},
|
||||
},
|
||||
|
@ -135,8 +140,9 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) {
|
|||
}
|
||||
|
||||
// remove one cell from the full list
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"second"}, true, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"second"}, true, []string{"t1", "t2"}); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "third"},
|
||||
BlacklistedTables: []string{"t1", "t2"},
|
||||
},
|
||||
|
@ -146,13 +152,14 @@ func TestUpdateSourceBlacklistedTables(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpdateDisableQueryService(t *testing.T) {
|
||||
si := NewShardInfo("ks", "sh", &Shard{
|
||||
si := NewShardInfo("ks", "sh", &pb.Shard{
|
||||
Cells: []string{"first", "second", "third"},
|
||||
}, 1)
|
||||
|
||||
// add one cell
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, []string{"first"}, true); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, []string{"first"}, true); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first"},
|
||||
DisableQueryService: true,
|
||||
},
|
||||
|
@ -161,22 +168,23 @@ func TestUpdateDisableQueryService(t *testing.T) {
|
|||
}
|
||||
|
||||
// remove that cell, going back
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, []string{"first"}, false); err != nil || si.TabletControlMap != nil {
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, []string{"first"}, false); err != nil || len(si.TabletControls) != 0 {
|
||||
t.Fatalf("going back should have remove the record: %v %v", err, si)
|
||||
}
|
||||
|
||||
// re-add a cell, then another with a table list to
|
||||
// make sure it fails
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, []string{"first"}, true); err != nil {
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, []string{"first"}, true); err != nil {
|
||||
t.Fatalf("one cell add failed: %v", si)
|
||||
}
|
||||
if err := si.UpdateSourceBlacklistedTables(TYPE_RDONLY, []string{"second"}, false, []string{"t1", "t1"}); err == nil || err.Error() != "cannot safely alter BlacklistedTables as DisableQueryService is set for shard ks/sh" {
|
||||
if err := si.UpdateSourceBlacklistedTables(pb.TabletType_RDONLY, []string{"second"}, false, []string{"t1", "t1"}); err == nil || err.Error() != "cannot safely alter BlacklistedTables as DisableQueryService is set for shard ks/sh" {
|
||||
t.Fatalf("UpdateSourceBlacklistedTables should fail: %v", err)
|
||||
}
|
||||
|
||||
// add another cell, see the list grow
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "second"},
|
||||
DisableQueryService: true,
|
||||
},
|
||||
|
@ -185,8 +193,9 @@ func TestUpdateDisableQueryService(t *testing.T) {
|
|||
}
|
||||
|
||||
// add all cells, see the list grow to all
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, nil, true); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, nil, true); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: nil,
|
||||
DisableQueryService: true,
|
||||
},
|
||||
|
@ -195,8 +204,9 @@ func TestUpdateDisableQueryService(t *testing.T) {
|
|||
}
|
||||
|
||||
// remove one cell from the full list
|
||||
if err := si.UpdateDisableQueryService(TYPE_RDONLY, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.TabletControlMap, map[TabletType]*TabletControl{
|
||||
TYPE_RDONLY: &TabletControl{
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_RDONLY, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "third"},
|
||||
DisableQueryService: true,
|
||||
},
|
||||
|
@ -206,103 +216,116 @@ func TestUpdateDisableQueryService(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestUpdateServedTypesMap(t *testing.T) {
|
||||
si := NewShardInfo("ks", "sh", &Shard{
|
||||
si := NewShardInfo("ks", "sh", &pb.Shard{
|
||||
Cells: []string{"first", "second", "third"},
|
||||
}, 1)
|
||||
|
||||
// add all cells for rdonly
|
||||
if err := si.UpdateServedTypesMap(TYPE_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: nil,
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: nil,
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("rdonly all cells add failed: %v", err)
|
||||
}
|
||||
|
||||
// add some cells for replica
|
||||
if err := si.UpdateServedTypesMap(TYPE_REPLICA, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: nil,
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_REPLICA, []string{"second"}, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: nil,
|
||||
},
|
||||
TYPE_REPLICA: &ShardServedType{
|
||||
Cells: []string{"second"},
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
Cells: []string{"second"},
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("replica some cells add failed: %v", err)
|
||||
}
|
||||
|
||||
// remove some cells for rdonly
|
||||
if err := si.UpdateServedTypesMap(TYPE_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: []string{"first", "third"},
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_RDONLY, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "third"},
|
||||
},
|
||||
TYPE_REPLICA: &ShardServedType{
|
||||
Cells: []string{"second"},
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
Cells: []string{"second"},
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("remove some cells for rdonly failed: %v", err)
|
||||
}
|
||||
|
||||
// remove last cell for replica
|
||||
if err := si.UpdateServedTypesMap(TYPE_REPLICA, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: []string{"first", "third"},
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_REPLICA, []string{"second"}, true); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "third"},
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("remove last cell for replica failed: %v", err)
|
||||
}
|
||||
|
||||
// migrate all
|
||||
if err := si.UpdateServedTypesMap(TYPE_REPLICA, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: []string{"first", "third"},
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_REPLICA, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: []string{"first", "third"},
|
||||
},
|
||||
TYPE_REPLICA: &ShardServedType{
|
||||
Cells: nil,
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
Cells: nil,
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("migrate replica failed: %v", err)
|
||||
}
|
||||
if err := si.UpdateServedTypesMap(TYPE_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: nil,
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_RDONLY, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: nil,
|
||||
},
|
||||
TYPE_REPLICA: &ShardServedType{
|
||||
Cells: nil,
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
Cells: nil,
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("migrate rdonly failed: %v", err)
|
||||
}
|
||||
if err := si.UpdateServedTypesMap(TYPE_MASTER, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypesMap, map[TabletType]*ShardServedType{
|
||||
TYPE_RDONLY: &ShardServedType{
|
||||
Cells: nil,
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_MASTER, nil, false); err != nil || !reflect.DeepEqual(si.ServedTypes, []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
Cells: nil,
|
||||
},
|
||||
TYPE_REPLICA: &ShardServedType{
|
||||
Cells: nil,
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
Cells: nil,
|
||||
},
|
||||
TYPE_MASTER: &ShardServedType{
|
||||
Cells: nil,
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_MASTER,
|
||||
Cells: nil,
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("migrate master failed: %v", err)
|
||||
}
|
||||
|
||||
// try to migrate master away, see it fail
|
||||
if err := si.UpdateServedTypesMap(TYPE_MASTER, nil, true); err == nil || err.Error() != "cannot migrate master away from ks/sh until everything else is migrated" {
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_MASTER, nil, true); err == nil || err.Error() != "cannot migrate master away from ks/sh until everything else is migrated" {
|
||||
t.Fatalf("migrate master away unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// remove all, see the map get emptied
|
||||
if err := si.UpdateServedTypesMap(TYPE_RDONLY, nil, true); err != nil {
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_RDONLY, nil, true); err != nil {
|
||||
t.Fatalf("remove master failed: %v", err)
|
||||
}
|
||||
if err := si.UpdateServedTypesMap(TYPE_REPLICA, nil, true); err != nil {
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_REPLICA, nil, true); err != nil {
|
||||
t.Fatalf("remove master failed: %v", err)
|
||||
}
|
||||
if err := si.UpdateServedTypesMap(TYPE_MASTER, nil, true); err != nil {
|
||||
if err := si.UpdateServedTypesMap(pb.TabletType_MASTER, nil, true); err != nil {
|
||||
t.Fatalf("remove master failed: %v", err)
|
||||
}
|
||||
if si.ServedTypesMap != nil {
|
||||
if len(si.ServedTypes) != 0 {
|
||||
t.Fatalf("expected empty map after removing all")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,22 @@ func (ta TabletAlias) IsZero() bool {
|
|||
return ta.Cell == "" && ta.Uid == 0
|
||||
}
|
||||
|
||||
// TabletAliasIsZero returns true iff cell and uid are empty
|
||||
func TabletAliasIsZero(ta *pb.TabletAlias) bool {
|
||||
return ta == nil || (ta.Cell == "" && ta.Uid == 0)
|
||||
}
|
||||
|
||||
// TabletAliasEqual returns true if two TabletAlias match
|
||||
func TabletAliasEqual(left, right *pb.TabletAlias) bool {
|
||||
if left == nil {
|
||||
return right == nil
|
||||
}
|
||||
if right == nil {
|
||||
return false
|
||||
}
|
||||
return *left == *right
|
||||
}
|
||||
|
||||
// String formats a TabletAlias
|
||||
func (ta TabletAlias) String() string {
|
||||
return fmtAlias(ta.Cell, ta.Uid)
|
||||
|
@ -450,9 +466,13 @@ func (ti *TabletInfo) Version() int64 {
|
|||
// Complete validates and normalizes the tablet. If the shard name
|
||||
// contains a '-' it is going to try to infer the keyrange from it.
|
||||
func (tablet *Tablet) Complete() error {
|
||||
var err error
|
||||
tablet.Shard, tablet.KeyRange, err = ValidateShardName(tablet.Shard)
|
||||
return err
|
||||
shard, kr, err := ValidateShardName(tablet.Shard)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tablet.Shard = shard
|
||||
tablet.KeyRange = key.ProtoToKeyRange(kr)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsHealthEqual compares the tablet's health with the passed one, and
|
||||
|
|
|
@ -70,7 +70,7 @@ func (ft FakeTopo) DeleteKeyspaceShards(ctx context.Context, keyspace string) er
|
|||
}
|
||||
|
||||
// CreateShard implements topo.Server.
|
||||
func (ft FakeTopo) CreateShard(ctx context.Context, keyspace, shard string, value *topo.Shard) error {
|
||||
func (ft FakeTopo) CreateShard(ctx context.Context, keyspace, shard string, value *pb.Shard) error {
|
||||
return errNotImplemented
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,13 @@ import (
|
|||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
func shardEqual(left, right *topo.Shard) (bool, error) {
|
||||
func shardEqual(left, right *pb.Shard) (bool, error) {
|
||||
lj, err := json.Marshal(left)
|
||||
if err != nil {
|
||||
return false, err
|
||||
|
@ -64,32 +65,41 @@ func CheckShard(ctx context.Context, t *testing.T, ts topo.Server) {
|
|||
if err != nil {
|
||||
t.Errorf("GetShard: %v", err)
|
||||
}
|
||||
if want := newKeyRange("b0-c0"); shardInfo.KeyRange != want {
|
||||
if want := newKeyRange3("b0-c0"); !key.KeyRangeEqual(shardInfo.KeyRange, want) {
|
||||
t.Errorf("shardInfo.KeyRange: want %v, got %v", want, shardInfo.KeyRange)
|
||||
}
|
||||
master := topo.TabletAlias{Cell: "ny", Uid: 1}
|
||||
master := &pb.TabletAlias{Cell: "ny", Uid: 1}
|
||||
shardInfo.MasterAlias = master
|
||||
shardInfo.KeyRange = newKeyRange("b0-c0")
|
||||
shardInfo.ServedTypesMap = map[topo.TabletType]*topo.ShardServedType{
|
||||
topo.TYPE_MASTER: &topo.ShardServedType{},
|
||||
topo.TYPE_REPLICA: &topo.ShardServedType{Cells: []string{"c1"}},
|
||||
topo.TYPE_RDONLY: &topo.ShardServedType{},
|
||||
shardInfo.KeyRange = newKeyRange3("b0-c0")
|
||||
shardInfo.ServedTypes = []*pb.Shard_ServedType{
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_MASTER,
|
||||
},
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
Cells: []string{"c1"},
|
||||
},
|
||||
&pb.Shard_ServedType{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
},
|
||||
}
|
||||
shardInfo.SourceShards = []topo.SourceShard{
|
||||
topo.SourceShard{
|
||||
shardInfo.SourceShards = []*pb.Shard_SourceShard{
|
||||
&pb.Shard_SourceShard{
|
||||
Uid: 1,
|
||||
Keyspace: "source_ks",
|
||||
Shard: "b8-c0",
|
||||
KeyRange: newKeyRange("b8-c0"),
|
||||
KeyRange: newKeyRange3("b8-c0"),
|
||||
Tables: []string{"table1", "table2"},
|
||||
},
|
||||
}
|
||||
shardInfo.TabletControlMap = map[topo.TabletType]*topo.TabletControl{
|
||||
topo.TYPE_MASTER: &topo.TabletControl{
|
||||
shardInfo.TabletControls = []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_MASTER,
|
||||
Cells: []string{"c1", "c2"},
|
||||
BlacklistedTables: []string{"black1", "black2"},
|
||||
},
|
||||
topo.TYPE_REPLICA: &topo.TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
DisableQueryService: true,
|
||||
},
|
||||
}
|
||||
|
@ -97,8 +107,8 @@ func CheckShard(ctx context.Context, t *testing.T, ts topo.Server) {
|
|||
t.Errorf("UpdateShard: %v", err)
|
||||
}
|
||||
|
||||
other := topo.TabletAlias{Cell: "ny", Uid: 82873}
|
||||
_, err = topo.UpdateShardFields(ctx, ts, "test_keyspace", "b0-c0", func(shard *topo.Shard) error {
|
||||
other := &pb.TabletAlias{Cell: "ny", Uid: 82873}
|
||||
_, err = topo.UpdateShardFields(ctx, ts, "test_keyspace", "b0-c0", func(shard *pb.Shard) error {
|
||||
shard.MasterAlias = other
|
||||
return nil
|
||||
})
|
||||
|
@ -109,10 +119,10 @@ func CheckShard(ctx context.Context, t *testing.T, ts topo.Server) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard: %v", err)
|
||||
}
|
||||
if si.MasterAlias != other {
|
||||
if *si.MasterAlias != *other {
|
||||
t.Fatalf("shard.MasterAlias = %v, want %v", si.MasterAlias, other)
|
||||
}
|
||||
_, err = topo.UpdateShardFields(ctx, ts, "test_keyspace", "b0-c0", func(shard *topo.Shard) error {
|
||||
_, err = topo.UpdateShardFields(ctx, ts, "test_keyspace", "b0-c0", func(shard *pb.Shard) error {
|
||||
shard.MasterAlias = master
|
||||
return nil
|
||||
})
|
||||
|
|
|
@ -10,9 +10,19 @@ import (
|
|||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
func newKeyRange(value string) key.KeyRange {
|
||||
_, result, err := topo.ValidateShardName(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return key.ProtoToKeyRange(result)
|
||||
}
|
||||
|
||||
func newKeyRange3(value string) *pb.KeyRange {
|
||||
_, result, err := topo.ValidateShardName(value)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
|
@ -32,6 +32,6 @@ type MigrateServedTypes struct {
|
|||
Keyspace topo.KeyspaceInfo
|
||||
SourceShards []*topo.ShardInfo
|
||||
DestinationShards []*topo.ShardInfo
|
||||
ServedType topo.TabletType
|
||||
ServedType pb.TabletType
|
||||
Reverse bool
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"github.com/youtube/vitess/go/trace"
|
||||
"github.com/youtube/vitess/go/vt/concurrency"
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/logutil"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"golang.org/x/net/context"
|
||||
|
@ -404,9 +405,11 @@ func UpdateTabletEndpoints(ctx context.Context, ts topo.Server, tablet *topo.Tab
|
|||
// and writes it to the given cell.
|
||||
func UpdateSrvShard(ctx context.Context, ts topo.Server, cell string, si *topo.ShardInfo) error {
|
||||
srvShard := &topo.SrvShard{
|
||||
Name: si.ShardName(),
|
||||
KeyRange: si.KeyRange,
|
||||
MasterCell: si.MasterAlias.Cell,
|
||||
Name: si.ShardName(),
|
||||
KeyRange: key.ProtoToKeyRange(si.KeyRange),
|
||||
}
|
||||
if si.MasterAlias != nil {
|
||||
srvShard.MasterCell = si.MasterAlias.Cell
|
||||
}
|
||||
return ts.UpdateSrvShard(ctx, cell, si.Keyspace(), si.ShardName(), srvShard)
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ func TestCreateShardCustomSharding(t *testing.T) {
|
|||
if si, err := ts.GetShard(ctx, keyspace, shard0); err != nil {
|
||||
t.Fatalf("GetShard(shard0) failed: %v", err)
|
||||
} else {
|
||||
if len(si.ServedTypesMap) != 3 {
|
||||
if len(si.ServedTypes) != 3 {
|
||||
t.Fatalf("shard0 should have all 3 served types")
|
||||
}
|
||||
}
|
||||
|
@ -82,7 +82,7 @@ func TestCreateShardCustomSharding(t *testing.T) {
|
|||
if si, err := ts.GetShard(ctx, keyspace, shard1); err != nil {
|
||||
t.Fatalf("GetShard(shard1) failed: %v", err)
|
||||
} else {
|
||||
if len(si.ServedTypesMap) != 3 {
|
||||
if len(si.ServedTypes) != 3 {
|
||||
t.Fatalf("shard1 should have all 3 served types")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -120,12 +120,12 @@ func findOverlappingShards(shardMap map[string]*topo.ShardInfo) ([]*OverlappingS
|
|||
// we should not have holes on either side
|
||||
hasHoles := false
|
||||
for i := 0; i < len(left)-1; i++ {
|
||||
if left[i].KeyRange.End != left[i+1].KeyRange.Start {
|
||||
if string(left[i].KeyRange.End) != string(left[i+1].KeyRange.Start) {
|
||||
hasHoles = true
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(right)-1; i++ {
|
||||
if right[i].KeyRange.End != right[i+1].KeyRange.Start {
|
||||
if string(right[i].KeyRange.End) != string(right[i+1].KeyRange.Start) {
|
||||
hasHoles = true
|
||||
}
|
||||
}
|
||||
|
@ -134,10 +134,10 @@ func findOverlappingShards(shardMap map[string]*topo.ShardInfo) ([]*OverlappingS
|
|||
}
|
||||
|
||||
// the two sides should match
|
||||
if left[0].KeyRange.Start != right[0].KeyRange.Start {
|
||||
if !key.KeyRangeStartEqual(left[0].KeyRange, right[0].KeyRange) {
|
||||
continue
|
||||
}
|
||||
if left[len(left)-1].KeyRange.End != right[len(right)-1].KeyRange.End {
|
||||
if !key.KeyRangeEndEqual(left[len(left)-1].KeyRange, right[len(right)-1].KeyRange) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -157,7 +157,7 @@ func findOverlappingShards(shardMap map[string]*topo.ShardInfo) ([]*OverlappingS
|
|||
func findIntersectingShard(shardMap map[string]*topo.ShardInfo, sourceArray []*topo.ShardInfo) *topo.ShardInfo {
|
||||
for name, si := range shardMap {
|
||||
for _, sourceShardInfo := range sourceArray {
|
||||
if key.KeyRangesIntersect(si.KeyRange, sourceShardInfo.KeyRange) {
|
||||
if si.KeyRange == nil || sourceShardInfo.KeyRange == nil || key.KeyRangesIntersect3(si.KeyRange, sourceShardInfo.KeyRange) {
|
||||
delete(shardMap, name)
|
||||
return si
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ func findIntersectingShard(shardMap map[string]*topo.ShardInfo, sourceArray []*t
|
|||
// in the destination array
|
||||
func intersect(si *topo.ShardInfo, allShards []*topo.ShardInfo) bool {
|
||||
for _, shard := range allShards {
|
||||
if key.KeyRangesIntersect(si.KeyRange, shard.KeyRange) {
|
||||
if key.KeyRangesIntersect3(si.KeyRange, shard.KeyRange) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ func (sil shardInfoList) Len() int {
|
|||
|
||||
// Less is part of sort.Interface
|
||||
func (sil shardInfoList) Less(i, j int) bool {
|
||||
return sil[i].KeyRange.Start < sil[j].KeyRange.Start
|
||||
return string(sil[i].KeyRange.Start) < string(sil[j].KeyRange.Start)
|
||||
}
|
||||
|
||||
// Swap is part of sort.Interface
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package topotools
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"testing"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// helper methods for tests to be shorter
|
||||
|
||||
func hki(hexValue string) key.KeyspaceId {
|
||||
k, err := key.HexKeyspaceId(hexValue).Unhex()
|
||||
func hki(hexValue string) []byte {
|
||||
k, err := hex.DecodeString(hexValue)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -19,9 +21,9 @@ func hki(hexValue string) key.KeyspaceId {
|
|||
|
||||
func si(start, end string) *topo.ShardInfo {
|
||||
s := hki(start)
|
||||
e := hki((end))
|
||||
return topo.NewShardInfo("keyspace", s.String()+"-"+e.String(), &topo.Shard{
|
||||
KeyRange: key.KeyRange{
|
||||
e := hki(end)
|
||||
return topo.NewShardInfo("keyspace", start+"-"+end, &pb.Shard{
|
||||
KeyRange: &pb.KeyRange{
|
||||
Start: s,
|
||||
End: e,
|
||||
},
|
||||
|
|
|
@ -99,7 +99,6 @@ import (
|
|||
"github.com/youtube/vitess/go/jscfg"
|
||||
"github.com/youtube/vitess/go/netutil"
|
||||
hk "github.com/youtube/vitess/go/vt/hook"
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/logutil"
|
||||
myproto "github.com/youtube/vitess/go/vt/mysqlctl/proto"
|
||||
"github.com/youtube/vitess/go/vt/tabletmanager/actionnode"
|
||||
|
@ -586,6 +585,19 @@ func parseTabletType3(param string) (pb.TabletType, error) {
|
|||
return pb.TabletType(value), nil
|
||||
}
|
||||
|
||||
// parseServingTabletType3 parses the tablet type into the enum,
|
||||
// and makes sure the enum is of serving type (MASTER, REPLICA, RDONLY/BATCH)
|
||||
func parseServingTabletType3(param string) (pb.TabletType, error) {
|
||||
servedType, err := parseTabletType3(param)
|
||||
if err != nil {
|
||||
return pb.TabletType_UNKNOWN, err
|
||||
}
|
||||
if !topo.IsInServingGraph(topo.ProtoToTabletType(servedType)) {
|
||||
return pb.TabletType_UNKNOWN, fmt.Errorf("served_type has to be in the serving graph, not %v", param)
|
||||
}
|
||||
return servedType, nil
|
||||
}
|
||||
|
||||
func commandInitTablet(ctx context.Context, wr *wrangler.Wrangler, subFlags *flag.FlagSet, args []string) error {
|
||||
var (
|
||||
dbNameOverride = subFlags.String("db-name-override", "", "Overrides the name of the database that the vttablet uses")
|
||||
|
@ -1173,7 +1185,8 @@ func commandSetShardServedTypes(ctx context.Context, wr *wrangler.Wrangler, subF
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servedType, err := parseTabletType(subFlags.Arg(1), []topo.TabletType{topo.TYPE_MASTER, topo.TYPE_REPLICA, topo.TYPE_RDONLY})
|
||||
|
||||
servedType, err := parseServingTabletType3(subFlags.Arg(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1200,7 +1213,7 @@ func commandSetShardTabletControl(ctx context.Context, wr *wrangler.Wrangler, su
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tabletType, err := parseTabletType(subFlags.Arg(1), []topo.TabletType{topo.TYPE_MASTER, topo.TYPE_REPLICA, topo.TYPE_RDONLY})
|
||||
tabletType, err := parseServingTabletType3(subFlags.Arg(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1260,7 +1273,7 @@ func commandSourceShardAdd(ctx context.Context, wr *wrangler.Wrangler, subFlags
|
|||
if *tablesStr != "" {
|
||||
tables = strings.Split(*tablesStr, ",")
|
||||
}
|
||||
var kr key.KeyRange
|
||||
var kr *pb.KeyRange
|
||||
if *keyRange != "" {
|
||||
if _, kr, err = topo.ValidateShardName(*keyRange); err != nil {
|
||||
return err
|
||||
|
@ -1393,13 +1406,10 @@ func commandCreateKeyspace(ctx context.Context, wr *wrangler.Wrangler, subFlags
|
|||
}
|
||||
if len(servedFrom) > 0 {
|
||||
for name, value := range servedFrom {
|
||||
tt, err := parseTabletType3(name)
|
||||
tt, err := parseServingTabletType3(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !topo.IsInServingGraph(topo.ProtoToTabletType(tt)) {
|
||||
return fmt.Errorf("The served_from flag specifies a database (tablet) type that is not in the serving graph. The invalid value is: %v", tt)
|
||||
}
|
||||
ki.ServedFroms = append(ki.ServedFroms, &pb.Keyspace_ServedFrom{
|
||||
TabletType: tt,
|
||||
Keyspace: value,
|
||||
|
@ -1561,11 +1571,11 @@ func commandMigrateServedTypes(ctx context.Context, wr *wrangler.Wrangler, subFl
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
servedType, err := parseTabletType(subFlags.Arg(1), []topo.TabletType{topo.TYPE_MASTER, topo.TYPE_REPLICA, topo.TYPE_RDONLY})
|
||||
servedType, err := parseServingTabletType3(subFlags.Arg(1))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if servedType == topo.TYPE_MASTER && *skipReFreshState {
|
||||
if servedType == pb.TabletType_MASTER && *skipReFreshState {
|
||||
return fmt.Errorf("The skip-refresh-state flag can only be specified for non-master migrations.")
|
||||
}
|
||||
var cells []string
|
||||
|
|
|
@ -37,14 +37,14 @@ func resolveDestinationShardMaster(ctx context.Context, keyspace, shard string,
|
|||
return ti, fmt.Errorf("unable to resolve destination shard %v/%v", keyspace, shard)
|
||||
}
|
||||
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return ti, fmt.Errorf("no master in destination shard %v/%v", keyspace, shard)
|
||||
}
|
||||
|
||||
wr.Logger().Infof("Found target master alias %v in shard %v/%v", si.MasterAlias, keyspace, shard)
|
||||
|
||||
shortCtx, cancel = context.WithTimeout(ctx, *remoteActionsTimeout)
|
||||
ti, err = topo.GetTablet(shortCtx, wr.TopoServer(), si.MasterAlias)
|
||||
ti, err = topo.GetTablet(shortCtx, wr.TopoServer(), topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
cancel()
|
||||
if err != nil {
|
||||
return ti, fmt.Errorf("unable to get master tablet from alias %v in shard %v/%v",
|
||||
|
|
|
@ -6,6 +6,7 @@ package worker
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -19,6 +20,8 @@ import (
|
|||
myproto "github.com/youtube/vitess/go/vt/mysqlctl/proto"
|
||||
"github.com/youtube/vitess/go/vt/tabletserver/tabletconn"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// QueryResultReader will stream rows towards the output channel.
|
||||
|
@ -89,8 +92,8 @@ func orderedColumns(tableDefinition *myproto.TableDefinition) []string {
|
|||
|
||||
// uint64FromKeyspaceId returns a 64 bits hex number as a string
|
||||
// (in the form of 0x0123456789abcdef) from the provided keyspaceId
|
||||
func uint64FromKeyspaceId(keyspaceId key.KeyspaceId) string {
|
||||
hex := string(keyspaceId.Hex())
|
||||
func uint64FromKeyspaceId(keyspaceId []byte) string {
|
||||
hex := hex.EncodeToString(keyspaceId)
|
||||
return "0x" + hex + strings.Repeat("0", 16-len(hex))
|
||||
}
|
||||
|
||||
|
@ -107,41 +110,43 @@ func TableScan(ctx context.Context, log logutil.Logger, ts topo.Server, tabletAl
|
|||
// rows from a table that match the supplied KeyRange, ordered by
|
||||
// Primary Key. The returned columns are ordered with the Primary Key
|
||||
// columns in front.
|
||||
func TableScanByKeyRange(ctx context.Context, log logutil.Logger, ts topo.Server, tabletAlias topo.TabletAlias, tableDefinition *myproto.TableDefinition, keyRange key.KeyRange, keyspaceIdType key.KeyspaceIdType) (*QueryResultReader, error) {
|
||||
func TableScanByKeyRange(ctx context.Context, log logutil.Logger, ts topo.Server, tabletAlias topo.TabletAlias, tableDefinition *myproto.TableDefinition, keyRange *pb.KeyRange, keyspaceIdType key.KeyspaceIdType) (*QueryResultReader, error) {
|
||||
where := ""
|
||||
switch keyspaceIdType {
|
||||
case key.KIT_UINT64:
|
||||
if keyRange.Start != key.MinKey {
|
||||
if keyRange.End != key.MaxKey {
|
||||
// have start & end
|
||||
where = fmt.Sprintf("WHERE keyspace_id >= %v AND keyspace_id < %v ", uint64FromKeyspaceId(keyRange.Start), uint64FromKeyspaceId(keyRange.End))
|
||||
if keyRange != nil {
|
||||
switch keyspaceIdType {
|
||||
case key.KIT_UINT64:
|
||||
if len(keyRange.Start) > 0 {
|
||||
if len(keyRange.End) > 0 {
|
||||
// have start & end
|
||||
where = fmt.Sprintf("WHERE keyspace_id >= %v AND keyspace_id < %v ", uint64FromKeyspaceId(keyRange.Start), uint64FromKeyspaceId(keyRange.End))
|
||||
} else {
|
||||
// have start only
|
||||
where = fmt.Sprintf("WHERE keyspace_id >= %v ", uint64FromKeyspaceId(keyRange.Start))
|
||||
}
|
||||
} else {
|
||||
// have start only
|
||||
where = fmt.Sprintf("WHERE keyspace_id >= %v ", uint64FromKeyspaceId(keyRange.Start))
|
||||
if len(keyRange.End) > 0 {
|
||||
// have end only
|
||||
where = fmt.Sprintf("WHERE keyspace_id < %v ", uint64FromKeyspaceId(keyRange.End))
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if keyRange.End != key.MaxKey {
|
||||
// have end only
|
||||
where = fmt.Sprintf("WHERE keyspace_id < %v ", uint64FromKeyspaceId(keyRange.End))
|
||||
}
|
||||
}
|
||||
case key.KIT_BYTES:
|
||||
if keyRange.Start != key.MinKey {
|
||||
if keyRange.End != key.MaxKey {
|
||||
// have start & end
|
||||
where = fmt.Sprintf("WHERE HEX(keyspace_id) >= '%v' AND HEX(keyspace_id) < '%v' ", keyRange.Start.Hex(), keyRange.End.Hex())
|
||||
case key.KIT_BYTES:
|
||||
if len(keyRange.Start) > 0 {
|
||||
if len(keyRange.End) > 0 {
|
||||
// have start & end
|
||||
where = fmt.Sprintf("WHERE HEX(keyspace_id) >= '%v' AND HEX(keyspace_id) < '%v' ", hex.EncodeToString(keyRange.Start), hex.EncodeToString(keyRange.End))
|
||||
} else {
|
||||
// have start only
|
||||
where = fmt.Sprintf("WHERE HEX(keyspace_id) >= '%v' ", hex.EncodeToString(keyRange.Start))
|
||||
}
|
||||
} else {
|
||||
// have start only
|
||||
where = fmt.Sprintf("WHERE HEX(keyspace_id) >= '%v' ", keyRange.Start.Hex())
|
||||
}
|
||||
} else {
|
||||
if keyRange.End != key.MaxKey {
|
||||
// have end only
|
||||
where = fmt.Sprintf("WHERE HEX(keyspace_id) < '%v' ", keyRange.End.Hex())
|
||||
if len(keyRange.End) > 0 {
|
||||
// have end only
|
||||
where = fmt.Sprintf("WHERE HEX(keyspace_id) < '%v' ", hex.EncodeToString(keyRange.End))
|
||||
}
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported KeyspaceIdType: %v", keyspaceIdType)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported KeyspaceIdType: %v", keyspaceIdType)
|
||||
}
|
||||
|
||||
sql := fmt.Sprintf("SELECT %v FROM %v %vORDER BY %v", strings.Join(orderedColumns(tableDefinition), ", "), tableDefinition.Name, where, strings.Join(tableDefinition.PrimaryKeyColumns, ", "))
|
||||
|
|
|
@ -5,12 +5,12 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
mproto "github.com/youtube/vitess/go/mysql/proto"
|
||||
"github.com/youtube/vitess/go/sqltypes"
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
myproto "github.com/youtube/vitess/go/vt/mysqlctl/proto"
|
||||
)
|
||||
|
||||
|
@ -32,9 +32,9 @@ func TestUint64FromKeyspaceId(t *testing.T) {
|
|||
"1234cafe": "0x1234cafe00000000",
|
||||
}
|
||||
for input, want := range table {
|
||||
keyspaceID, err := key.HexKeyspaceId(input).Unhex()
|
||||
keyspaceID, err := hex.DecodeString(input)
|
||||
if err != nil {
|
||||
t.Errorf("Unhex error: %v", err)
|
||||
t.Errorf("hex.DecodeString error: %v", err)
|
||||
continue
|
||||
}
|
||||
if got := uint64FromKeyspaceId(keyspaceID); got != want {
|
||||
|
|
|
@ -29,7 +29,7 @@ func NewRowSplitter(shardInfos []*topo.ShardInfo, typ key.KeyspaceIdType, valueI
|
|||
KeyRanges: make([]key.KeyRange, len(shardInfos)),
|
||||
}
|
||||
for i, si := range shardInfos {
|
||||
result.KeyRanges[i] = si.KeyRange
|
||||
result.KeyRanges[i] = key.ProtoToKeyRange(si.KeyRange)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package worker
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
@ -12,10 +13,12 @@ import (
|
|||
"github.com/youtube/vitess/go/sqltypes"
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
func hki(hexValue string) key.KeyspaceId {
|
||||
k, err := key.HexKeyspaceId(hexValue).Unhex()
|
||||
func hki(hexValue string) []byte {
|
||||
k, err := hex.DecodeString(hexValue)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -25,8 +28,8 @@ func hki(hexValue string) key.KeyspaceId {
|
|||
func si(start, end string) *topo.ShardInfo {
|
||||
s := hki(start)
|
||||
e := hki(end)
|
||||
return topo.NewShardInfo("keyspace", s.String()+"-"+e.String(), &topo.Shard{
|
||||
KeyRange: key.KeyRange{
|
||||
return topo.NewShardInfo("keyspace", start+"-"+end, &pb.Shard{
|
||||
KeyRange: &pb.KeyRange{
|
||||
Start: s,
|
||||
End: e,
|
||||
},
|
||||
|
@ -76,10 +79,12 @@ func TestRowSplitterUint64(t *testing.T) {
|
|||
}
|
||||
|
||||
func siBytes(start, end string) *topo.ShardInfo {
|
||||
return topo.NewShardInfo("keyspace", start+"-"+end, &topo.Shard{
|
||||
KeyRange: key.KeyRange{
|
||||
Start: key.KeyspaceId(start),
|
||||
End: key.KeyspaceId(end),
|
||||
s := hex.EncodeToString([]byte(start))
|
||||
e := hex.EncodeToString([]byte(end))
|
||||
return topo.NewShardInfo("keyspace", s+"-"+e, &pb.Shard{
|
||||
KeyRange: &pb.KeyRange{
|
||||
Start: []byte(start),
|
||||
End: []byte(end),
|
||||
},
|
||||
}, 0)
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ import (
|
|||
"github.com/youtube/vitess/go/vt/topotools"
|
||||
"github.com/youtube/vitess/go/vt/worker/events"
|
||||
"github.com/youtube/vitess/go/vt/wrangler"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// SplitCloneWorker will clone the data within a keyspace from a
|
||||
|
@ -237,7 +239,7 @@ func (scw *SplitCloneWorker) init(ctx context.Context) error {
|
|||
|
||||
// one side should have served types, the other one none,
|
||||
// figure out wich is which, then double check them all
|
||||
if len(os.Left[0].ServedTypesMap) > 0 {
|
||||
if len(os.Left[0].ServedTypes) > 0 {
|
||||
scw.sourceShards = os.Left
|
||||
scw.destinationShards = os.Right
|
||||
} else {
|
||||
|
@ -246,16 +248,16 @@ func (scw *SplitCloneWorker) init(ctx context.Context) error {
|
|||
}
|
||||
|
||||
// validate all serving types
|
||||
servingTypes := []topo.TabletType{topo.TYPE_MASTER, topo.TYPE_REPLICA, topo.TYPE_RDONLY}
|
||||
servingTypes := []pb.TabletType{pb.TabletType_MASTER, pb.TabletType_REPLICA, pb.TabletType_RDONLY}
|
||||
for _, st := range servingTypes {
|
||||
for _, si := range scw.sourceShards {
|
||||
if _, ok := si.ServedTypesMap[st]; !ok {
|
||||
if si.GetServedType(st) == nil {
|
||||
return fmt.Errorf("source shard %v/%v is not serving type %v", si.Keyspace(), si.ShardName(), st)
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, si := range scw.destinationShards {
|
||||
if len(si.ServedTypesMap) > 0 {
|
||||
if len(si.ServedTypes) > 0 {
|
||||
return fmt.Errorf("destination shard %v/%v is serving some types", si.Keyspace(), si.ShardName())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ func (sdw *SplitDiffWorker) init(ctx context.Context) error {
|
|||
if len(sdw.shardInfo.SourceShards) == 0 {
|
||||
return fmt.Errorf("shard %v/%v has no source shard", sdw.keyspace, sdw.shard)
|
||||
}
|
||||
if sdw.shardInfo.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(sdw.shardInfo.MasterAlias) {
|
||||
return fmt.Errorf("shard %v/%v has no master", sdw.keyspace, sdw.shard)
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ func (sdw *SplitDiffWorker) findTargets(ctx context.Context) error {
|
|||
func (sdw *SplitDiffWorker) synchronizeReplication(ctx context.Context) error {
|
||||
sdw.SetState(WorkerStateSyncReplication)
|
||||
|
||||
masterInfo, err := sdw.wr.TopoServer().GetTablet(ctx, sdw.shardInfo.MasterAlias)
|
||||
masterInfo, err := sdw.wr.TopoServer().GetTablet(ctx, topo.ProtoToTabletAlias(sdw.shardInfo.MasterAlias))
|
||||
if err != nil {
|
||||
return fmt.Errorf("synchronizeReplication: cannot get Tablet record for master %v: %v", sdw.shardInfo.MasterAlias, err)
|
||||
}
|
||||
|
@ -390,7 +390,7 @@ func (sdw *SplitDiffWorker) diff(ctx context.Context) error {
|
|||
return
|
||||
}
|
||||
|
||||
overlap, err := key.KeyRangesOverlap(sdw.shardInfo.KeyRange, sdw.shardInfo.SourceShards[0].KeyRange)
|
||||
overlap, err := key.KeyRangesOverlap3(sdw.shardInfo.KeyRange, sdw.shardInfo.SourceShards[0].KeyRange)
|
||||
if err != nil {
|
||||
newErr := fmt.Errorf("Source shard doesn't overlap with destination????: %v", err)
|
||||
rec.RecordError(newErr)
|
||||
|
@ -406,7 +406,7 @@ func (sdw *SplitDiffWorker) diff(ctx context.Context) error {
|
|||
}
|
||||
defer sourceQueryResultReader.Close()
|
||||
|
||||
destinationQueryResultReader, err := TableScanByKeyRange(ctx, sdw.wr.Logger(), sdw.wr.TopoServer(), sdw.destinationAlias, tableDefinition, key.KeyRange{}, key.ProtoToKeyspaceIdType(sdw.keyspaceInfo.ShardingColumnType))
|
||||
destinationQueryResultReader, err := TableScanByKeyRange(ctx, sdw.wr.Logger(), sdw.wr.TopoServer(), sdw.destinationAlias, tableDefinition, nil, key.ProtoToKeyspaceIdType(sdw.keyspaceInfo.ShardingColumnType))
|
||||
if err != nil {
|
||||
newErr := fmt.Errorf("TableScanByKeyRange(destination) failed: %v", err)
|
||||
rec.RecordError(newErr)
|
||||
|
|
|
@ -173,7 +173,7 @@ func (vsdw *VerticalSplitDiffWorker) init(ctx context.Context) error {
|
|||
if len(vsdw.shardInfo.SourceShards[0].Tables) == 0 {
|
||||
return fmt.Errorf("shard %v/%v has no tables in source shard[0]", vsdw.keyspace, vsdw.shard)
|
||||
}
|
||||
if vsdw.shardInfo.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(vsdw.shardInfo.MasterAlias) {
|
||||
return fmt.Errorf("shard %v/%v has no master", vsdw.keyspace, vsdw.shard)
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ func (vsdw *VerticalSplitDiffWorker) findTargets(ctx context.Context) error {
|
|||
func (vsdw *VerticalSplitDiffWorker) synchronizeReplication(ctx context.Context) error {
|
||||
vsdw.SetState(WorkerStateSyncReplication)
|
||||
|
||||
masterInfo, err := vsdw.wr.TopoServer().GetTablet(ctx, vsdw.shardInfo.MasterAlias)
|
||||
masterInfo, err := vsdw.wr.TopoServer().GetTablet(ctx, topo.ProtoToTabletAlias(vsdw.shardInfo.MasterAlias))
|
||||
if err != nil {
|
||||
return fmt.Errorf("synchronizeReplication: cannot get Tablet record for master %v: %v", vsdw.shardInfo.MasterAlias, err)
|
||||
}
|
||||
|
|
|
@ -78,8 +78,8 @@ func (wr *Wrangler) setKeyspaceShardingInfo(ctx context.Context, keyspace, shard
|
|||
|
||||
// MigrateServedTypes is used during horizontal splits to migrate a
|
||||
// served type from a list of shards to another.
|
||||
func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard string, cells []string, servedType topo.TabletType, reverse, skipReFreshState bool, filteredReplicationWaitTime time.Duration) error {
|
||||
if servedType == topo.TYPE_MASTER {
|
||||
func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard string, cells []string, servedType pb.TabletType, reverse, skipReFreshState bool, filteredReplicationWaitTime time.Duration) error {
|
||||
if servedType == pb.TabletType_MASTER {
|
||||
// we cannot migrate a master back, since when master migration
|
||||
// is done, the source shards are dead
|
||||
if reverse {
|
||||
|
@ -176,7 +176,7 @@ func (wr *Wrangler) MigrateServedTypes(ctx context.Context, keyspace, shard stri
|
|||
// - we're not migrating a master
|
||||
// - we don't have any errors
|
||||
// - we're not told to skip the refresh
|
||||
if servedType != topo.TYPE_MASTER && !rec.HasErrors() && !skipReFreshState {
|
||||
if servedType != pb.TabletType_MASTER && !rec.HasErrors() && !skipReFreshState {
|
||||
var refreshShards []*topo.ShardInfo
|
||||
if reverse {
|
||||
// For a backwards migration, we just disabled query service on the destination shards
|
||||
|
@ -217,7 +217,7 @@ func (wr *Wrangler) getMastersPosition(ctx context.Context, shards []*topo.Shard
|
|||
go func(si *topo.ShardInfo) {
|
||||
defer wg.Done()
|
||||
wr.Logger().Infof("Gathering master position for %v", si.MasterAlias)
|
||||
ti, err := wr.ts.GetTablet(ctx, si.MasterAlias)
|
||||
ti, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
rec.RecordError(err)
|
||||
return
|
||||
|
@ -261,7 +261,7 @@ func (wr *Wrangler) waitForFilteredReplication(ctx context.Context, sourcePositi
|
|||
|
||||
// and wait for it
|
||||
wr.Logger().Infof("Waiting for %v to catch up", si.MasterAlias)
|
||||
tablet, err := wr.ts.GetTablet(ctx, si.MasterAlias)
|
||||
tablet, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
rec.RecordError(err)
|
||||
return
|
||||
|
@ -288,7 +288,7 @@ func (wr *Wrangler) refreshMasters(ctx context.Context, shards []*topo.ShardInfo
|
|||
go func(si *topo.ShardInfo) {
|
||||
defer wg.Done()
|
||||
wr.Logger().Infof("RefreshState master %v", si.MasterAlias)
|
||||
ti, err := wr.ts.GetTablet(ctx, si.MasterAlias)
|
||||
ti, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
rec.RecordError(err)
|
||||
return
|
||||
|
@ -306,7 +306,7 @@ func (wr *Wrangler) refreshMasters(ctx context.Context, shards []*topo.ShardInfo
|
|||
}
|
||||
|
||||
// migrateServedTypes operates with all concerned shards locked.
|
||||
func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sourceShards, destinationShards []*topo.ShardInfo, cells []string, servedType topo.TabletType, reverse bool, filteredReplicationWaitTime time.Duration) (err error) {
|
||||
func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sourceShards, destinationShards []*topo.ShardInfo, cells []string, servedType pb.TabletType, reverse bool, filteredReplicationWaitTime time.Duration) (err error) {
|
||||
|
||||
// re-read all the shards so we are up to date
|
||||
wr.Logger().Infof("Re-reading all shards")
|
||||
|
@ -340,10 +340,10 @@ func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sou
|
|||
// - gather all replication points
|
||||
// - wait for filtered replication to catch up before we continue
|
||||
// - disable filtered replication after the fact
|
||||
if servedType == topo.TYPE_MASTER {
|
||||
if servedType == pb.TabletType_MASTER {
|
||||
event.DispatchUpdate(ev, "disabling query service on all source masters")
|
||||
for _, si := range sourceShards {
|
||||
if err := si.UpdateDisableQueryService(topo.TYPE_MASTER, nil, true); err != nil {
|
||||
if err := si.UpdateDisableQueryService(pb.TabletType_MASTER, nil, true); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := topo.UpdateShard(ctx, wr.ts, si); err != nil {
|
||||
|
@ -378,7 +378,7 @@ func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sou
|
|||
if err := si.UpdateServedTypesMap(servedType, cells, !reverse); err != nil {
|
||||
return err
|
||||
}
|
||||
if tc, ok := si.TabletControlMap[servedType]; reverse && ok && tc.DisableQueryService {
|
||||
if tc := si.GetTabletControl(servedType); reverse && tc != nil && tc.DisableQueryService {
|
||||
// this is a backward migration, where the
|
||||
// source tablets were disabled previously, so
|
||||
// we need to refresh them
|
||||
|
@ -387,7 +387,7 @@ func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sou
|
|||
}
|
||||
needToRefreshSourceTablets = true
|
||||
}
|
||||
if !reverse && servedType != topo.TYPE_MASTER {
|
||||
if !reverse && servedType != pb.TabletType_MASTER {
|
||||
// this is a forward migration, we need to disable
|
||||
// query service on the source shards.
|
||||
// (this was already done for masters earlier)
|
||||
|
@ -403,7 +403,7 @@ func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sou
|
|||
if err := si.UpdateServedTypesMap(servedType, cells, reverse); err != nil {
|
||||
return err
|
||||
}
|
||||
if tc, ok := si.TabletControlMap[servedType]; !reverse && ok && tc.DisableQueryService {
|
||||
if tc := si.GetTabletControl(servedType); !reverse && tc != nil && tc.DisableQueryService {
|
||||
// This is a forwards migration, and the destination query service was already in a disabled state.
|
||||
// We need to enable and force a refresh, otherwise it's possible that both the source and destination
|
||||
// will have query service disabled at the same time, and queries would have nowhere to go.
|
||||
|
@ -412,7 +412,7 @@ func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sou
|
|||
}
|
||||
needToRefreshDestinationTablets = true
|
||||
}
|
||||
if reverse && servedType != topo.TYPE_MASTER {
|
||||
if reverse && servedType != pb.TabletType_MASTER {
|
||||
// this is a backwards migration, we need to disable
|
||||
// query service on the destination shards.
|
||||
// (we're not allowed to reverse a master migration)
|
||||
|
@ -451,7 +451,7 @@ func (wr *Wrangler) migrateServedTypes(ctx context.Context, keyspace string, sou
|
|||
// And tell the new shards masters they can now be read-write.
|
||||
// Invoking a remote action will also make the tablet stop filtered
|
||||
// replication.
|
||||
if servedType == topo.TYPE_MASTER {
|
||||
if servedType == pb.TabletType_MASTER {
|
||||
event.DispatchUpdate(ev, "setting destination masters read-write")
|
||||
if err := wr.refreshMasters(ctx, destinationShards); err != nil {
|
||||
return err
|
||||
|
@ -594,7 +594,7 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp
|
|||
|
||||
// Save the source shard (its blacklisted tables field has changed)
|
||||
event.DispatchUpdate(ev, "updating source shard")
|
||||
if err := sourceShard.UpdateSourceBlacklistedTables(topo.ProtoToTabletType(servedType), cells, reverse, tables); err != nil {
|
||||
if err := sourceShard.UpdateSourceBlacklistedTables(servedType, cells, reverse, tables); err != nil {
|
||||
return fmt.Errorf("UpdateSourceBlacklistedTables(%v/%v) failed: %v", sourceShard.Keyspace(), sourceShard.ShardName(), err)
|
||||
}
|
||||
if err := topo.UpdateShard(ctx, wr.ts, sourceShard); err != nil {
|
||||
|
@ -604,7 +604,7 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp
|
|||
// Now refresh the source servers so they reload their
|
||||
// blacklisted table list
|
||||
event.DispatchUpdate(ev, "refreshing sources tablets state so they update their blacklisted tables")
|
||||
if err := wr.RefreshTablesByShard(ctx, sourceShard, topo.ProtoToTabletType(servedType), cells); err != nil {
|
||||
if err := wr.RefreshTablesByShard(ctx, sourceShard, servedType, cells); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -623,18 +623,18 @@ func (wr *Wrangler) replicaMigrateServedFrom(ctx context.Context, ki *topo.Keysp
|
|||
// replication and starts accepting writes
|
||||
func (wr *Wrangler) masterMigrateServedFrom(ctx context.Context, ki *topo.KeyspaceInfo, sourceShard *topo.ShardInfo, destinationShard *topo.ShardInfo, tables []string, ev *events.MigrateServedFrom, filteredReplicationWaitTime time.Duration) error {
|
||||
// Read the data we need
|
||||
sourceMasterTabletInfo, err := wr.ts.GetTablet(ctx, sourceShard.MasterAlias)
|
||||
sourceMasterTabletInfo, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(sourceShard.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destinationMasterTabletInfo, err := wr.ts.GetTablet(ctx, destinationShard.MasterAlias)
|
||||
destinationMasterTabletInfo, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(destinationShard.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update source shard (more blacklisted tables)
|
||||
event.DispatchUpdate(ev, "updating source shard")
|
||||
if err := sourceShard.UpdateSourceBlacklistedTables(topo.TYPE_MASTER, nil, false, tables); err != nil {
|
||||
if err := sourceShard.UpdateSourceBlacklistedTables(pb.TabletType_MASTER, nil, false, tables); err != nil {
|
||||
return fmt.Errorf("UpdateSourceBlacklistedTables(%v/%v) failed: %v", sourceShard.Keyspace(), sourceShard.ShardName(), err)
|
||||
}
|
||||
if err := topo.UpdateShard(ctx, wr.ts, sourceShard); err != nil {
|
||||
|
@ -713,7 +713,7 @@ func (wr *Wrangler) setKeyspaceServedFrom(ctx context.Context, keyspace string,
|
|||
// RefreshTablesByShard calls RefreshState on all the tables of a
|
||||
// given type in a shard. It would work for the master, but the
|
||||
// discovery wouldn't be very efficient.
|
||||
func (wr *Wrangler) RefreshTablesByShard(ctx context.Context, si *topo.ShardInfo, tabletType topo.TabletType, cells []string) error {
|
||||
func (wr *Wrangler) RefreshTablesByShard(ctx context.Context, si *topo.ShardInfo, tabletType pb.TabletType, cells []string) error {
|
||||
wr.Logger().Infof("RefreshTablesByShard called on shard %v/%v", si.Keyspace(), si.ShardName())
|
||||
tabletMap, err := topo.GetTabletMapForShardByCell(ctx, wr.ts, si.Keyspace(), si.ShardName(), cells)
|
||||
switch err {
|
||||
|
@ -728,7 +728,7 @@ func (wr *Wrangler) RefreshTablesByShard(ctx context.Context, si *topo.ShardInfo
|
|||
// ignore errors in this phase
|
||||
wg := sync.WaitGroup{}
|
||||
for _, ti := range tabletMap {
|
||||
if ti.Type != tabletType {
|
||||
if ti.Type != topo.ProtoToTabletType(tabletType) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -49,11 +49,11 @@ func (wr *Wrangler) ValidatePermissionsShard(ctx context.Context, keyspace, shar
|
|||
}
|
||||
|
||||
// get permissions from the master, or error
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return fmt.Errorf("No master in shard %v/%v", keyspace, shard)
|
||||
}
|
||||
log.Infof("Gathering permissions for master %v", si.MasterAlias)
|
||||
masterPermissions, err := wr.GetPermissions(ctx, si.MasterAlias)
|
||||
masterPermissions, err := wr.GetPermissions(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -69,11 +69,11 @@ func (wr *Wrangler) ValidatePermissionsShard(ctx context.Context, keyspace, shar
|
|||
er := concurrency.AllErrorRecorder{}
|
||||
wg := sync.WaitGroup{}
|
||||
for _, alias := range aliases {
|
||||
if alias == si.MasterAlias {
|
||||
if alias == topo.ProtoToTabletAlias(si.MasterAlias) {
|
||||
continue
|
||||
}
|
||||
wg.Add(1)
|
||||
go wr.diffPermissions(ctx, masterPermissions, si.MasterAlias, alias, &wg, &er)
|
||||
go wr.diffPermissions(ctx, masterPermissions, topo.ProtoToTabletAlias(si.MasterAlias), alias, &wg, &er)
|
||||
}
|
||||
wg.Wait()
|
||||
if er.HasErrors() {
|
||||
|
@ -105,12 +105,12 @@ func (wr *Wrangler) ValidatePermissionsKeyspace(ctx context.Context, keyspace st
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return fmt.Errorf("No master in shard %v/%v", keyspace, shards[0])
|
||||
}
|
||||
referenceAlias := si.MasterAlias
|
||||
referenceAlias := topo.ProtoToTabletAlias(si.MasterAlias)
|
||||
log.Infof("Gathering permissions for reference master %v", referenceAlias)
|
||||
referencePermissions, err := wr.GetPermissions(ctx, si.MasterAlias)
|
||||
referencePermissions, err := wr.GetPermissions(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -126,7 +126,7 @@ func (wr *Wrangler) ValidatePermissionsKeyspace(ctx context.Context, keyspace st
|
|||
}
|
||||
|
||||
for _, alias := range aliases {
|
||||
if alias == si.MasterAlias {
|
||||
if alias == topo.ProtoToTabletAlias(si.MasterAlias) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -146,7 +146,7 @@ func (wr *Wrangler) rebuildKeyspace(ctx context.Context, keyspace string, cells
|
|||
}
|
||||
srvKeyspace.Partitions[tabletType].ShardReferences = append(srvKeyspace.Partitions[tabletType].ShardReferences, topo.ShardReference{
|
||||
Name: si.ShardName(),
|
||||
KeyRange: si.KeyRange,
|
||||
KeyRange: key.ProtoToKeyRange(si.KeyRange),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,11 +124,11 @@ func (wr *Wrangler) ReparentTablet(ctx context.Context, tabletAlias topo.TabletA
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if shardInfo.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(shardInfo.MasterAlias) {
|
||||
return fmt.Errorf("no master tablet for shard %v/%v", ti.Keyspace, ti.Shard)
|
||||
}
|
||||
|
||||
masterTi, err := wr.ts.GetTablet(ctx, shardInfo.MasterAlias)
|
||||
masterTi, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(shardInfo.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ func (wr *Wrangler) ReparentTablet(ctx context.Context, tabletAlias topo.TabletA
|
|||
}
|
||||
|
||||
// and do the remote command
|
||||
return wr.TabletManagerClient().SetMaster(ctx, ti, shardInfo.MasterAlias, 0, false)
|
||||
return wr.TabletManagerClient().SetMaster(ctx, ti, topo.ProtoToTabletAlias(shardInfo.MasterAlias), 0, false)
|
||||
}
|
||||
|
||||
// InitShardMaster will make the provided tablet the master for the shard.
|
||||
|
@ -191,7 +191,7 @@ func (wr *Wrangler) initShardMasterLocked(ctx context.Context, ev *events.Repare
|
|||
|
||||
// Check the master is the only master is the shard, or -force was used.
|
||||
_, masterTabletMap := topotools.SortedTabletMap(tabletMap)
|
||||
if shardInfo.MasterAlias != masterElectTabletAlias {
|
||||
if topo.ProtoToTabletAlias(shardInfo.MasterAlias) != masterElectTabletAlias {
|
||||
if !force {
|
||||
return fmt.Errorf("master-elect tablet %v is not the shard master, use -force to proceed anyway", masterElectTabletAlias)
|
||||
}
|
||||
|
@ -285,8 +285,8 @@ func (wr *Wrangler) initShardMasterLocked(ctx context.Context, ev *events.Repare
|
|||
wgSlaves.Wait()
|
||||
return fmt.Errorf("failed to PopulateReparentJournal on master: %v", masterErr)
|
||||
}
|
||||
if shardInfo.MasterAlias != masterElectTabletAlias {
|
||||
shardInfo.MasterAlias = masterElectTabletAlias
|
||||
if topo.ProtoToTabletAlias(shardInfo.MasterAlias) != masterElectTabletAlias {
|
||||
shardInfo.MasterAlias = topo.TabletAliasToProto(masterElectTabletAlias)
|
||||
if err := topo.UpdateShard(ctx, wr.ts, shardInfo); err != nil {
|
||||
wgSlaves.Wait()
|
||||
return fmt.Errorf("failed to update shard master record: %v", err)
|
||||
|
@ -353,10 +353,10 @@ func (wr *Wrangler) plannedReparentShardLocked(ctx context.Context, ev *events.R
|
|||
return fmt.Errorf("master-elect tablet %v is not in the shard", masterElectTabletAlias)
|
||||
}
|
||||
ev.NewMaster = *masterElectTabletInfo.Tablet
|
||||
if shardInfo.MasterAlias == masterElectTabletAlias {
|
||||
if topo.ProtoToTabletAlias(shardInfo.MasterAlias) == masterElectTabletAlias {
|
||||
return fmt.Errorf("master-elect tablet %v is already the master", masterElectTabletAlias)
|
||||
}
|
||||
oldMasterTabletInfo, ok := tabletMap[shardInfo.MasterAlias]
|
||||
oldMasterTabletInfo, ok := tabletMap[topo.ProtoToTabletAlias(shardInfo.MasterAlias)]
|
||||
if !ok {
|
||||
return fmt.Errorf("old master tablet %v is not in the shard", shardInfo.MasterAlias)
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ func (wr *Wrangler) plannedReparentShardLocked(ctx context.Context, ev *events.R
|
|||
return fmt.Errorf("failed to PopulateReparentJournal on master: %v", masterErr)
|
||||
}
|
||||
wr.logger.Infof("updating shard record with new master %v", masterElectTabletAlias)
|
||||
shardInfo.MasterAlias = masterElectTabletAlias
|
||||
shardInfo.MasterAlias = topo.TabletAliasToProto(masterElectTabletAlias)
|
||||
if err := topo.UpdateShard(ctx, wr.ts, shardInfo); err != nil {
|
||||
wgSlaves.Wait()
|
||||
return fmt.Errorf("failed to update shard master record: %v", err)
|
||||
|
@ -485,19 +485,19 @@ func (wr *Wrangler) emergencyReparentShardLocked(ctx context.Context, ev *events
|
|||
return fmt.Errorf("master-elect tablet %v is not in the shard", masterElectTabletAlias)
|
||||
}
|
||||
ev.NewMaster = *masterElectTabletInfo.Tablet
|
||||
if shardInfo.MasterAlias == masterElectTabletAlias {
|
||||
if topo.ProtoToTabletAlias(shardInfo.MasterAlias) == masterElectTabletAlias {
|
||||
return fmt.Errorf("master-elect tablet %v is already the master", masterElectTabletAlias)
|
||||
}
|
||||
|
||||
// Deal with the old master: try to remote-scrap it, if it's
|
||||
// truely dead we force-scrap it. Remove it from our map in any case.
|
||||
if !shardInfo.MasterAlias.IsZero() {
|
||||
if !topo.TabletAliasIsZero(shardInfo.MasterAlias) {
|
||||
scrapOldMaster := true
|
||||
oldMasterTabletInfo, ok := tabletMap[shardInfo.MasterAlias]
|
||||
oldMasterTabletInfo, ok := tabletMap[topo.ProtoToTabletAlias(shardInfo.MasterAlias)]
|
||||
if ok {
|
||||
delete(tabletMap, shardInfo.MasterAlias)
|
||||
delete(tabletMap, topo.ProtoToTabletAlias(shardInfo.MasterAlias))
|
||||
} else {
|
||||
oldMasterTabletInfo, err = wr.ts.GetTablet(ctx, shardInfo.MasterAlias)
|
||||
oldMasterTabletInfo, err = wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(shardInfo.MasterAlias))
|
||||
if err != nil {
|
||||
wr.logger.Warningf("cannot read old master tablet %v, won't touch it: %v", shardInfo.MasterAlias, err)
|
||||
scrapOldMaster = false
|
||||
|
@ -514,7 +514,7 @@ func (wr *Wrangler) emergencyReparentShardLocked(ctx context.Context, ev *events
|
|||
if err := wr.tmc.Scrap(ctx, oldMasterTabletInfo); err != nil {
|
||||
wr.logger.Warningf("remote scrapping failed master failed, will force the scrap: %v", err)
|
||||
|
||||
if err := topotools.Scrap(ctx, wr.ts, shardInfo.MasterAlias, true); err != nil {
|
||||
if err := topotools.Scrap(ctx, wr.ts, topo.ProtoToTabletAlias(shardInfo.MasterAlias), true); err != nil {
|
||||
wr.logger.Warningf("old master topo scrapping failed, continuing anyway: %v", err)
|
||||
}
|
||||
}
|
||||
|
@ -611,7 +611,7 @@ func (wr *Wrangler) emergencyReparentShardLocked(ctx context.Context, ev *events
|
|||
return fmt.Errorf("failed to PopulateReparentJournal on master: %v", masterErr)
|
||||
}
|
||||
wr.logger.Infof("updating shard record with new master %v", masterElectTabletAlias)
|
||||
shardInfo.MasterAlias = masterElectTabletAlias
|
||||
shardInfo.MasterAlias = topo.TabletAliasToProto(masterElectTabletAlias)
|
||||
if err := topo.UpdateShard(ctx, wr.ts, shardInfo); err != nil {
|
||||
wgSlaves.Wait()
|
||||
return fmt.Errorf("failed to update shard master record: %v", err)
|
||||
|
|
|
@ -66,11 +66,11 @@ func (wr *Wrangler) ValidateSchemaShard(ctx context.Context, keyspace, shard str
|
|||
}
|
||||
|
||||
// get schema from the master, or error
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return fmt.Errorf("No master in shard %v/%v", keyspace, shard)
|
||||
}
|
||||
log.Infof("Gathering schema for master %v", si.MasterAlias)
|
||||
masterSchema, err := wr.GetSchema(ctx, si.MasterAlias, nil, excludeTables, includeViews)
|
||||
masterSchema, err := wr.GetSchema(ctx, topo.ProtoToTabletAlias(si.MasterAlias), nil, excludeTables, includeViews)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -86,12 +86,12 @@ func (wr *Wrangler) ValidateSchemaShard(ctx context.Context, keyspace, shard str
|
|||
er := concurrency.AllErrorRecorder{}
|
||||
wg := sync.WaitGroup{}
|
||||
for _, alias := range aliases {
|
||||
if alias == si.MasterAlias {
|
||||
if alias == topo.ProtoToTabletAlias(si.MasterAlias) {
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go wr.diffSchema(ctx, masterSchema, si.MasterAlias, alias, excludeTables, includeViews, &wg, &er)
|
||||
go wr.diffSchema(ctx, masterSchema, topo.ProtoToTabletAlias(si.MasterAlias), alias, excludeTables, includeViews, &wg, &er)
|
||||
}
|
||||
wg.Wait()
|
||||
if er.HasErrors() {
|
||||
|
@ -123,10 +123,10 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string,
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return fmt.Errorf("No master in shard %v/%v", keyspace, shards[0])
|
||||
}
|
||||
referenceAlias := si.MasterAlias
|
||||
referenceAlias := topo.ProtoToTabletAlias(si.MasterAlias)
|
||||
log.Infof("Gathering schema for reference master %v", referenceAlias)
|
||||
referenceSchema, err := wr.GetSchema(ctx, referenceAlias, nil, excludeTables, includeViews)
|
||||
if err != nil {
|
||||
|
@ -144,7 +144,7 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string,
|
|||
}
|
||||
|
||||
for _, alias := range aliases {
|
||||
if alias == si.MasterAlias {
|
||||
if alias == topo.ProtoToTabletAlias(si.MasterAlias) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ func (wr *Wrangler) ValidateSchemaKeyspace(ctx context.Context, keyspace string,
|
|||
continue
|
||||
}
|
||||
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
er.RecordError(fmt.Errorf("No master in shard %v/%v", keyspace, shard))
|
||||
continue
|
||||
}
|
||||
|
@ -223,12 +223,12 @@ func (wr *Wrangler) ApplySchemaShard(ctx context.Context, keyspace, shard, chang
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
preflight, err := wr.PreflightSchema(ctx, shardInfo.MasterAlias, change)
|
||||
preflight, err := wr.PreflightSchema(ctx, topo.ProtoToTabletAlias(shardInfo.MasterAlias), change)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return wr.lockAndApplySchemaShard(ctx, shardInfo, preflight, keyspace, shard, shardInfo.MasterAlias, change, newParentTabletAlias, simple, force, waitSlaveTimeout)
|
||||
return wr.lockAndApplySchemaShard(ctx, shardInfo, preflight, keyspace, shard, topo.ProtoToTabletAlias(shardInfo.MasterAlias), change, newParentTabletAlias, simple, force, waitSlaveTimeout)
|
||||
}
|
||||
|
||||
func (wr *Wrangler) lockAndApplySchemaShard(ctx context.Context, shardInfo *topo.ShardInfo, preflight *myproto.SchemaChangeResult, keyspace, shard string, masterTabletAlias topo.TabletAlias, change string, newParentTabletAlias topo.TabletAlias, simple, force bool, waitSlaveTimeout time.Duration) (*myproto.SchemaChangeResult, error) {
|
||||
|
@ -375,7 +375,7 @@ func (wr *Wrangler) applySchemaShardComplex(ctx context.Context, statusArray []*
|
|||
// if newParentTabletAlias is passed in, use that as the new master
|
||||
if !newParentTabletAlias.IsZero() {
|
||||
log.Infof("Reparenting with new master set to %v", newParentTabletAlias)
|
||||
oldMasterAlias := shardInfo.MasterAlias
|
||||
oldMasterAlias := topo.ProtoToTabletAlias(shardInfo.MasterAlias)
|
||||
|
||||
// Create reusable Reparent event with available info
|
||||
ev := &events.Reparent{}
|
||||
|
@ -425,7 +425,7 @@ func (wr *Wrangler) CopySchemaShardFromShard(ctx context.Context, tables, exclud
|
|||
return err
|
||||
}
|
||||
|
||||
return wr.CopySchemaShard(ctx, sourceShardInfo.MasterAlias, tables, excludeTables, includeViews, destKeyspace, destShard)
|
||||
return wr.CopySchemaShard(ctx, topo.ProtoToTabletAlias(sourceShardInfo.MasterAlias), tables, excludeTables, includeViews, destKeyspace, destShard)
|
||||
}
|
||||
|
||||
// CopySchemaShard copies the schema from a source tablet to the
|
||||
|
@ -442,7 +442,7 @@ func (wr *Wrangler) CopySchemaShard(ctx context.Context, sourceTabletAlias topo.
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
destSd, err := wr.GetSchema(ctx, destShardInfo.MasterAlias, tables, excludeTables, includeViews)
|
||||
destSd, err := wr.GetSchema(ctx, topo.ProtoToTabletAlias(destShardInfo.MasterAlias), tables, excludeTables, includeViews)
|
||||
if err != nil {
|
||||
destSd = nil
|
||||
}
|
||||
|
@ -455,7 +455,7 @@ func (wr *Wrangler) CopySchemaShard(ctx context.Context, sourceTabletAlias topo.
|
|||
}
|
||||
|
||||
createSql := sourceSd.ToSQLStrings()
|
||||
destTabletInfo, err := wr.ts.GetTablet(ctx, destShardInfo.MasterAlias)
|
||||
destTabletInfo, err := wr.ts.GetTablet(ctx, topo.ProtoToTabletAlias(destShardInfo.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -7,10 +7,11 @@ package wrangler
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/tabletmanager/actionnode"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// shard related methods for Wrangler
|
||||
|
@ -27,7 +28,7 @@ func (wr *Wrangler) unlockShard(ctx context.Context, keyspace, shard string, act
|
|||
|
||||
// updateShardCellsAndMaster will update the 'Cells' and possibly
|
||||
// MasterAlias records for the shard, if needed.
|
||||
func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.ShardInfo, tabletAlias topo.TabletAlias, tabletType topo.TabletType, force bool) error {
|
||||
func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.ShardInfo, tabletAlias *pb.TabletAlias, tabletType pb.TabletType, force bool) error {
|
||||
// See if we need to update the Shard:
|
||||
// - add the tablet's cell to the shard's Cells if needed
|
||||
// - change the master if needed
|
||||
|
@ -35,7 +36,7 @@ func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.Shar
|
|||
if !si.HasCell(tabletAlias.Cell) {
|
||||
shardUpdateRequired = true
|
||||
}
|
||||
if tabletType == topo.TYPE_MASTER && si.MasterAlias != tabletAlias {
|
||||
if tabletType == pb.TabletType_MASTER && !topo.TabletAliasEqual(si.MasterAlias, tabletAlias) {
|
||||
shardUpdateRequired = true
|
||||
}
|
||||
if !shardUpdateRequired {
|
||||
|
@ -62,8 +63,8 @@ func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.Shar
|
|||
si.Cells = append(si.Cells, tabletAlias.Cell)
|
||||
wasUpdated = true
|
||||
}
|
||||
if tabletType == topo.TYPE_MASTER && si.MasterAlias != tabletAlias {
|
||||
if !si.MasterAlias.IsZero() && !force {
|
||||
if tabletType == pb.TabletType_MASTER && !topo.TabletAliasEqual(si.MasterAlias, tabletAlias) {
|
||||
if !topo.TabletAliasIsZero(si.MasterAlias) && !force {
|
||||
return wr.unlockShard(ctx, keyspace, shard, actionNode, lockPath, fmt.Errorf("creating this tablet would override old master %v in shard %v/%v", si.MasterAlias, keyspace, shard))
|
||||
}
|
||||
si.MasterAlias = tabletAlias
|
||||
|
@ -83,7 +84,7 @@ func (wr *Wrangler) updateShardCellsAndMaster(ctx context.Context, si *topo.Shar
|
|||
|
||||
// SetShardServedTypes changes the ServedTypes parameter of a shard.
|
||||
// It does not rebuild any serving graph or do any consistency check (yet).
|
||||
func (wr *Wrangler) SetShardServedTypes(ctx context.Context, keyspace, shard string, cells []string, servedType topo.TabletType, remove bool) error {
|
||||
func (wr *Wrangler) SetShardServedTypes(ctx context.Context, keyspace, shard string, cells []string, servedType pb.TabletType, remove bool) error {
|
||||
|
||||
actionNode := actionnode.SetShardServedTypes(cells, servedType)
|
||||
lockPath, err := wr.lockShard(ctx, keyspace, shard, actionNode)
|
||||
|
@ -95,7 +96,7 @@ func (wr *Wrangler) SetShardServedTypes(ctx context.Context, keyspace, shard str
|
|||
return wr.unlockShard(ctx, keyspace, shard, actionNode, lockPath, err)
|
||||
}
|
||||
|
||||
func (wr *Wrangler) setShardServedTypes(ctx context.Context, keyspace, shard string, cells []string, servedType topo.TabletType, remove bool) error {
|
||||
func (wr *Wrangler) setShardServedTypes(ctx context.Context, keyspace, shard string, cells []string, servedType pb.TabletType, remove bool) error {
|
||||
si, err := wr.ts.GetShard(ctx, keyspace, shard)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -113,7 +114,7 @@ func (wr *Wrangler) setShardServedTypes(ctx context.Context, keyspace, shard str
|
|||
// - if disableQueryService is set, tables has to be empty
|
||||
// - if disableQueryService is not set, and tables is empty, we remove
|
||||
// the TabletControl record for the cells
|
||||
func (wr *Wrangler) SetShardTabletControl(ctx context.Context, keyspace, shard string, tabletType topo.TabletType, cells []string, remove, disableQueryService bool, tables []string) error {
|
||||
func (wr *Wrangler) SetShardTabletControl(ctx context.Context, keyspace, shard string, tabletType pb.TabletType, cells []string, remove, disableQueryService bool, tables []string) error {
|
||||
|
||||
if disableQueryService && len(tables) > 0 {
|
||||
return fmt.Errorf("SetShardTabletControl cannot have both DisableQueryService set and tables set")
|
||||
|
@ -129,7 +130,7 @@ func (wr *Wrangler) SetShardTabletControl(ctx context.Context, keyspace, shard s
|
|||
return wr.unlockShard(ctx, keyspace, shard, actionNode, lockPath, err)
|
||||
}
|
||||
|
||||
func (wr *Wrangler) setShardTabletControl(ctx context.Context, keyspace, shard string, tabletType topo.TabletType, cells []string, remove, disableQueryService bool, tables []string) error {
|
||||
func (wr *Wrangler) setShardTabletControl(ctx context.Context, keyspace, shard string, tabletType pb.TabletType, cells []string, remove, disableQueryService bool, tables []string) error {
|
||||
shardInfo, err := wr.ts.GetShard(ctx, keyspace, shard)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -238,7 +239,7 @@ func (wr *Wrangler) removeShardCell(ctx context.Context, keyspace, shard, cell s
|
|||
}
|
||||
|
||||
// check the master alias is not in the cell
|
||||
if shardInfo.MasterAlias.Cell == cell {
|
||||
if shardInfo.MasterAlias != nil && shardInfo.MasterAlias.Cell == cell {
|
||||
return fmt.Errorf("master %v is in the cell '%v' we want to remove", shardInfo.MasterAlias, cell)
|
||||
}
|
||||
|
||||
|
@ -314,7 +315,7 @@ func (wr *Wrangler) sourceShardDelete(ctx context.Context, keyspace, shard strin
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
newSourceShards := make([]topo.SourceShard, 0, 0)
|
||||
newSourceShards := make([]*pb.Shard_SourceShard, 0, 0)
|
||||
for _, ss := range si.SourceShards {
|
||||
if ss.Uid != uid {
|
||||
newSourceShards = append(newSourceShards, ss)
|
||||
|
@ -331,7 +332,7 @@ func (wr *Wrangler) sourceShardDelete(ctx context.Context, keyspace, shard strin
|
|||
}
|
||||
|
||||
// SourceShardAdd will add a new SourceShard inside a shard
|
||||
func (wr *Wrangler) SourceShardAdd(ctx context.Context, keyspace, shard string, uid uint32, skeyspace, sshard string, keyRange key.KeyRange, tables []string) error {
|
||||
func (wr *Wrangler) SourceShardAdd(ctx context.Context, keyspace, shard string, uid uint32, skeyspace, sshard string, keyRange *pb.KeyRange, tables []string) error {
|
||||
actionNode := actionnode.UpdateShard()
|
||||
lockPath, err := wr.lockShard(ctx, keyspace, shard, actionNode)
|
||||
if err != nil {
|
||||
|
@ -342,7 +343,7 @@ func (wr *Wrangler) SourceShardAdd(ctx context.Context, keyspace, shard string,
|
|||
return wr.unlockShard(ctx, keyspace, shard, actionNode, lockPath, err)
|
||||
}
|
||||
|
||||
func (wr *Wrangler) sourceShardAdd(ctx context.Context, keyspace, shard string, uid uint32, skeyspace, sshard string, keyRange key.KeyRange, tables []string) error {
|
||||
func (wr *Wrangler) sourceShardAdd(ctx context.Context, keyspace, shard string, uid uint32, skeyspace, sshard string, keyRange *pb.KeyRange, tables []string) error {
|
||||
si, err := wr.ts.GetShard(ctx, keyspace, shard)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -355,7 +356,7 @@ func (wr *Wrangler) sourceShardAdd(ctx context.Context, keyspace, shard string,
|
|||
}
|
||||
}
|
||||
|
||||
si.SourceShards = append(si.SourceShards, topo.SourceShard{
|
||||
si.SourceShards = append(si.SourceShards, &pb.Shard_SourceShard{
|
||||
Uid: uid,
|
||||
Keyspace: skeyspace,
|
||||
Shard: sshard,
|
||||
|
|
|
@ -7,8 +7,11 @@ package wrangler
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
// SetSourceShards is a utility function to override the SourceShards fields
|
||||
|
@ -35,14 +38,14 @@ func (wr *Wrangler) SetSourceShards(ctx context.Context, keyspace, shard string,
|
|||
// Insert their KeyRange in the SourceShards array.
|
||||
// We use a linear 0-based id, that matches what mysqlctld/split.go
|
||||
// inserts into _vt.blp_checkpoint.
|
||||
shardInfo.SourceShards = make([]topo.SourceShard, len(sourceTablets))
|
||||
shardInfo.SourceShards = make([]*pb.Shard_SourceShard, len(sourceTablets))
|
||||
i := 0
|
||||
for _, ti := range sourceTablets {
|
||||
shardInfo.SourceShards[i] = topo.SourceShard{
|
||||
shardInfo.SourceShards[i] = &pb.Shard_SourceShard{
|
||||
Uid: uint32(i),
|
||||
Keyspace: ti.Keyspace,
|
||||
Shard: ti.Shard,
|
||||
KeyRange: ti.KeyRange,
|
||||
KeyRange: key.KeyRangeToProto(ti.KeyRange),
|
||||
Tables: tables,
|
||||
}
|
||||
i++
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
mproto "github.com/youtube/vitess/go/mysql/proto"
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/tabletmanager/actionnode"
|
||||
"github.com/youtube/vitess/go/vt/topo"
|
||||
"github.com/youtube/vitess/go/vt/topotools"
|
||||
|
@ -47,15 +48,15 @@ func (wr *Wrangler) InitTablet(ctx context.Context, tablet *topo.Tablet, force,
|
|||
if err != nil {
|
||||
return fmt.Errorf("cannot get (or create) shard %v/%v: %v", tablet.Keyspace, tablet.Shard, err)
|
||||
}
|
||||
if si.KeyRange != tablet.KeyRange {
|
||||
if key.ProtoToKeyRange(si.KeyRange) != tablet.KeyRange {
|
||||
return fmt.Errorf("shard %v/%v has a different KeyRange: %v != %v", tablet.Keyspace, tablet.Shard, si.KeyRange, tablet.KeyRange)
|
||||
}
|
||||
if tablet.Type == topo.TYPE_MASTER && !si.MasterAlias.IsZero() && si.MasterAlias != tablet.Alias && !force {
|
||||
if tablet.Type == topo.TYPE_MASTER && !topo.TabletAliasIsZero(si.MasterAlias) && topo.ProtoToTabletAlias(si.MasterAlias) != tablet.Alias && !force {
|
||||
return fmt.Errorf("creating this tablet would override old master %v in shard %v/%v", si.MasterAlias, tablet.Keyspace, tablet.Shard)
|
||||
}
|
||||
|
||||
// update the shard record if needed
|
||||
if err := wr.updateShardCellsAndMaster(ctx, si, tablet.Alias, tablet.Type, force); err != nil {
|
||||
if err := wr.updateShardCellsAndMaster(ctx, si, topo.TabletAliasToProto(tablet.Alias), topo.TabletTypeToProto(tablet.Type), force); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -150,8 +151,8 @@ func (wr *Wrangler) Scrap(ctx context.Context, tabletAlias topo.TabletAlias, for
|
|||
}
|
||||
|
||||
// update it if the right alias is there
|
||||
if si.MasterAlias == tabletAlias {
|
||||
si.MasterAlias = topo.TabletAlias{}
|
||||
if topo.TabletAliasEqual(si.MasterAlias, topo.TabletAliasToProto(tabletAlias)) {
|
||||
si.MasterAlias = nil
|
||||
|
||||
// write it back
|
||||
if err := topo.UpdateShard(ctx, wr.ts, si); err != nil {
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"golang.org/x/net/context"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
"github.com/youtube/vitess/go/vt/key"
|
||||
"github.com/youtube/vitess/go/vt/mysqlctl"
|
||||
"github.com/youtube/vitess/go/vt/tabletmanager"
|
||||
"github.com/youtube/vitess/go/vt/tabletmanager/grpctmserver"
|
||||
|
@ -69,11 +70,12 @@ type TabletOption func(tablet *topo.Tablet)
|
|||
func TabletKeyspaceShard(t *testing.T, keyspace, shard string) TabletOption {
|
||||
return func(tablet *topo.Tablet) {
|
||||
tablet.Keyspace = keyspace
|
||||
var err error
|
||||
tablet.Shard, tablet.KeyRange, err = topo.ValidateShardName(shard)
|
||||
shard, ks, err := topo.ValidateShardName(shard)
|
||||
if err != nil {
|
||||
t.Fatalf("cannot ValidateShardName value %v", shard)
|
||||
}
|
||||
tablet.Shard = shard
|
||||
tablet.KeyRange = key.ProtoToKeyRange(ks)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,7 +104,7 @@ func TestInitMasterShard(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
if si.MasterAlias != master.Tablet.Alias {
|
||||
if topo.ProtoToTabletAlias(si.MasterAlias) != master.Tablet.Alias {
|
||||
t.Errorf("unexpected shard master alias, got %v expected %v", si.MasterAlias, master.Tablet.Alias)
|
||||
}
|
||||
if err := master.FakeMysqlDaemon.CheckSuperQueryList(); err != nil {
|
||||
|
@ -241,7 +241,7 @@ func TestInitMasterShardOneSlaveFails(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
if si.MasterAlias != master.Tablet.Alias {
|
||||
if topo.ProtoToTabletAlias(si.MasterAlias) != master.Tablet.Alias {
|
||||
t.Errorf("unexpected shard master alias, got %v expected %v", si.MasterAlias, master.Tablet.Alias)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,7 +125,12 @@ func TestMigrateServedFrom(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
if len(si.TabletControlMap) != 1 || !reflect.DeepEqual(si.TabletControlMap[topo.TYPE_RDONLY].BlacklistedTables, []string{"gone1", "gone2"}) {
|
||||
if len(si.TabletControls) != 1 || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
BlacklistedTables: []string{"gone1", "gone2"},
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("rdonly type doesn't have right blacklisted tables")
|
||||
}
|
||||
|
||||
|
@ -148,7 +153,16 @@ func TestMigrateServedFrom(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
if len(si.TabletControlMap) != 2 || !reflect.DeepEqual(si.TabletControlMap[topo.TYPE_REPLICA].BlacklistedTables, []string{"gone1", "gone2"}) {
|
||||
if len(si.TabletControls) != 2 || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
BlacklistedTables: []string{"gone1", "gone2"},
|
||||
},
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
BlacklistedTables: []string{"gone1", "gone2"},
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("replica type doesn't have right blacklisted tables")
|
||||
}
|
||||
|
||||
|
@ -171,7 +185,20 @@ func TestMigrateServedFrom(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
if len(si.TabletControlMap) != 3 || !reflect.DeepEqual(si.TabletControlMap[topo.TYPE_MASTER].BlacklistedTables, []string{"gone1", "gone2"}) {
|
||||
if len(si.TabletControls) != 3 || !reflect.DeepEqual(si.TabletControls, []*pb.Shard_TabletControl{
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_RDONLY,
|
||||
BlacklistedTables: []string{"gone1", "gone2"},
|
||||
},
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_REPLICA,
|
||||
BlacklistedTables: []string{"gone1", "gone2"},
|
||||
},
|
||||
&pb.Shard_TabletControl{
|
||||
TabletType: pb.TabletType_MASTER,
|
||||
BlacklistedTables: []string{"gone1", "gone2"},
|
||||
},
|
||||
}) {
|
||||
t.Fatalf("master type doesn't have right blacklisted tables")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ func checkShardServedTypes(t *testing.T, ts topo.Server, shard string, expected
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
if len(si.ServedTypesMap) != expected {
|
||||
t.Fatalf("shard %v has wrong served types: %#v", shard, si.ServedTypesMap)
|
||||
if len(si.ServedTypes) != expected {
|
||||
t.Fatalf("shard %v has wrong served types: %#v", shard, si.ServedTypes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ func TestPermissions(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
si.MasterAlias = master.Tablet.Alias
|
||||
si.MasterAlias = topo.TabletAliasToProto(master.Tablet.Alias)
|
||||
if err := topo.UpdateShard(ctx, ts, si); err != nil {
|
||||
t.Fatalf("UpdateShard failed: %v", err)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ func TestShardReplicationStatuses(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
si.MasterAlias = master.Tablet.Alias
|
||||
si.MasterAlias = topo.TabletAliasToProto(master.Tablet.Alias)
|
||||
if err := topo.UpdateShard(ctx, ts, si); err != nil {
|
||||
t.Fatalf("UpdateShard failed: %v", err)
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ func TestReparentTablet(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatalf("GetShard failed: %v", err)
|
||||
}
|
||||
si.MasterAlias = master.Tablet.Alias
|
||||
si.MasterAlias = topo.TabletAliasToProto(master.Tablet.Alias)
|
||||
if err := topo.UpdateShard(ctx, ts, si); err != nil {
|
||||
t.Fatalf("UpdateShard failed: %v", err)
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ func (wr *Wrangler) validateShard(ctx context.Context, keyspace, shard string, p
|
|||
|
||||
if masterAlias.Cell == "" {
|
||||
results <- fmt.Errorf("no master for shard %v/%v", keyspace, shard)
|
||||
} else if shardInfo.MasterAlias != masterAlias {
|
||||
} else if !topo.TabletAliasEqual(shardInfo.MasterAlias, topo.TabletAliasToProto(masterAlias)) {
|
||||
results <- fmt.Errorf("master mismatch for shard %v/%v: found %v, expected %v", keyspace, shard, masterAlias, shardInfo.MasterAlias)
|
||||
}
|
||||
|
||||
|
@ -175,7 +175,7 @@ func normalizeIP(ip string) string {
|
|||
}
|
||||
|
||||
func (wr *Wrangler) validateReplication(ctx context.Context, shardInfo *topo.ShardInfo, tabletMap map[topo.TabletAlias]*topo.TabletInfo, results chan<- error) {
|
||||
masterTablet, ok := tabletMap[shardInfo.MasterAlias]
|
||||
masterTablet, ok := tabletMap[topo.ProtoToTabletAlias(shardInfo.MasterAlias)]
|
||||
if !ok {
|
||||
results <- fmt.Errorf("master %v not in tablet map", shardInfo.MasterAlias)
|
||||
return
|
||||
|
|
|
@ -93,11 +93,11 @@ func (wr *Wrangler) ValidateVersionShard(ctx context.Context, keyspace, shard st
|
|||
}
|
||||
|
||||
// get version from the master, or error
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return fmt.Errorf("No master in shard %v/%v", keyspace, shard)
|
||||
}
|
||||
log.Infof("Gathering version for master %v", si.MasterAlias)
|
||||
masterVersion, err := wr.GetVersion(ctx, si.MasterAlias)
|
||||
masterVersion, err := wr.GetVersion(ctx, topo.ProtoToTabletAlias(si.MasterAlias))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -113,12 +113,12 @@ func (wr *Wrangler) ValidateVersionShard(ctx context.Context, keyspace, shard st
|
|||
er := concurrency.AllErrorRecorder{}
|
||||
wg := sync.WaitGroup{}
|
||||
for _, alias := range aliases {
|
||||
if alias == si.MasterAlias {
|
||||
if alias == topo.ProtoToTabletAlias(si.MasterAlias) {
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go wr.diffVersion(ctx, masterVersion, si.MasterAlias, alias, &wg, &er)
|
||||
go wr.diffVersion(ctx, masterVersion, topo.ProtoToTabletAlias(si.MasterAlias), alias, &wg, &er)
|
||||
}
|
||||
wg.Wait()
|
||||
if er.HasErrors() {
|
||||
|
@ -150,10 +150,10 @@ func (wr *Wrangler) ValidateVersionKeyspace(ctx context.Context, keyspace string
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if si.MasterAlias.IsZero() {
|
||||
if topo.TabletAliasIsZero(si.MasterAlias) {
|
||||
return fmt.Errorf("No master in shard %v/%v", keyspace, shards[0])
|
||||
}
|
||||
referenceAlias := si.MasterAlias
|
||||
referenceAlias := topo.ProtoToTabletAlias(si.MasterAlias)
|
||||
log.Infof("Gathering version for reference master %v", referenceAlias)
|
||||
referenceVersion, err := wr.GetVersion(ctx, referenceAlias)
|
||||
if err != nil {
|
||||
|
@ -171,7 +171,7 @@ func (wr *Wrangler) ValidateVersionKeyspace(ctx context.Context, keyspace string
|
|||
}
|
||||
|
||||
for _, alias := range aliases {
|
||||
if alias == si.MasterAlias {
|
||||
if alias == topo.ProtoToTabletAlias(si.MasterAlias) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@ import (
|
|||
"github.com/youtube/vitess/go/zk"
|
||||
"golang.org/x/net/context"
|
||||
"launchpad.net/gozk/zookeeper"
|
||||
|
||||
pb "github.com/youtube/vitess/go/vt/proto/topodata"
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -24,7 +26,7 @@ This file contains the shard management code for zktopo.Server
|
|||
*/
|
||||
|
||||
// CreateShard is part of the topo.Server interface
|
||||
func (zkts *Server) CreateShard(ctx context.Context, keyspace, shard string, value *topo.Shard) error {
|
||||
func (zkts *Server) CreateShard(ctx context.Context, keyspace, shard string, value *pb.Shard) error {
|
||||
shardPath := path.Join(globalKeyspacesPath, keyspace, "shards", shard)
|
||||
pathList := []string{
|
||||
shardPath,
|
||||
|
@ -103,7 +105,7 @@ func (zkts *Server) GetShard(ctx context.Context, keyspace, shard string) (*topo
|
|||
return nil, err
|
||||
}
|
||||
|
||||
s := &topo.Shard{}
|
||||
s := &pb.Shard{}
|
||||
if err = json.Unmarshal([]byte(data), s); err != nil {
|
||||
return nil, fmt.Errorf("bad shard data %v", err)
|
||||
}
|
||||
|
|
|
@ -99,14 +99,18 @@ message Tablet {
|
|||
|
||||
// A Shard contains data about a subset of the data whithin a keyspace.
|
||||
message Shard {
|
||||
// There can be only at most one master, but there may be none. (0)
|
||||
// master_alias is the tablet alias of the master for the shard.
|
||||
// If it is unset, then there is no master in this shard yet.
|
||||
TabletAlias master_alias = 1;
|
||||
|
||||
// key_range is the KeyRange for this shard. It can be unset if:
|
||||
// - we are not using range-based sharding in this shard.
|
||||
// - the shard covers the entire keyrange.
|
||||
// This must match the shard name based on our other conventions, but
|
||||
// helpful to have it decomposed here.
|
||||
KeyRange key_range = 2;
|
||||
|
||||
// ShardServedType is an entry in the served_types
|
||||
// ServedType is an entry in the served_types
|
||||
message ServedType {
|
||||
TabletType tablet_type = 1;
|
||||
repeated string cells = 2;
|
||||
|
|
|
@ -106,7 +106,7 @@ class TestCustomSharding(unittest.TestCase):
|
|||
self.assertEqual(len(ks['Partitions']['master']['ShardReferences']), 1)
|
||||
self.assertEqual(len(ks['Partitions']['rdonly']['ShardReferences']), 1)
|
||||
s = utils.run_vtctl_json(['GetShard', 'test_keyspace/0'])
|
||||
self.assertEqual(len(s['ServedTypesMap']), 3)
|
||||
self.assertEqual(len(s['served_types']), 3)
|
||||
|
||||
# create a table on shard 0
|
||||
sql = '''create table data(
|
||||
|
@ -131,7 +131,7 @@ primary key (id)
|
|||
for t in [shard_1_master, shard_1_rdonly]:
|
||||
t.wait_for_vttablet_state('NOT_SERVING')
|
||||
s = utils.run_vtctl_json(['GetShard', 'test_keyspace/1'])
|
||||
self.assertEqual(len(s['ServedTypesMap']), 3)
|
||||
self.assertEqual(len(s['served_types']), 3)
|
||||
|
||||
utils.run_vtctl(['InitShardMaster', 'test_keyspace/1',
|
||||
shard_1_master.tablet_alias], auto_log=True)
|
||||
|
|
|
@ -226,8 +226,8 @@ class TestReparent(unittest.TestCase):
|
|||
tablet_62344.init_tablet('master', 'test_keyspace', shard_id, start=True,
|
||||
wait_for_start=False)
|
||||
shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id])
|
||||
self.assertEqual(shard['Cells'], ['test_nj'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['Cells']))
|
||||
self.assertEqual(shard['cells'], ['test_nj'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['cells']))
|
||||
|
||||
# Create a few slaves for testing reparenting.
|
||||
tablet_62044.init_tablet('replica', 'test_keyspace', shard_id, start=True,
|
||||
|
@ -240,8 +240,8 @@ class TestReparent(unittest.TestCase):
|
|||
t.wait_for_vttablet_state('SERVING')
|
||||
shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id])
|
||||
self.assertEqual(
|
||||
shard['Cells'], ['test_nj', 'test_ny'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['Cells']))
|
||||
shard['cells'], ['test_nj', 'test_ny'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['cells']))
|
||||
|
||||
# Recompute the shard layout node - until you do that, it might not be
|
||||
# valid.
|
||||
|
@ -305,8 +305,8 @@ class TestReparent(unittest.TestCase):
|
|||
tablet_62344.init_tablet('master', 'test_keyspace', shard_id, start=True)
|
||||
if environment.topo_server().flavor() == 'zookeeper':
|
||||
shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id])
|
||||
self.assertEqual(shard['Cells'], ['test_nj'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['Cells']))
|
||||
self.assertEqual(shard['cells'], ['test_nj'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['cells']))
|
||||
|
||||
# Create a few slaves for testing reparenting.
|
||||
tablet_62044.init_tablet('replica', 'test_keyspace', shard_id, start=True,
|
||||
|
@ -319,8 +319,8 @@ class TestReparent(unittest.TestCase):
|
|||
t.wait_for_vttablet_state('SERVING')
|
||||
if environment.topo_server().flavor() == 'zookeeper':
|
||||
shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/' + shard_id])
|
||||
self.assertEqual(shard['Cells'], ['test_nj', 'test_ny'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['Cells']))
|
||||
self.assertEqual(shard['cells'], ['test_nj', 'test_ny'],
|
||||
'wrong list of cell in Shard: %s' % str(shard['cells']))
|
||||
|
||||
# Recompute the shard layout node - until you do that, it might not be
|
||||
# valid.
|
||||
|
@ -556,8 +556,10 @@ class TestReparent(unittest.TestCase):
|
|||
'Got unexpected nodes: %s != %s' % (str(expected_nodes),
|
||||
str(hashed_nodes)))
|
||||
|
||||
utils.pause("AAAAAAAAAAAAAA")
|
||||
tablet_62044_master_status = tablet_62044.get_status()
|
||||
self.assertIn('Serving graph: test_keyspace 0 master', tablet_62044_master_status)
|
||||
self.assertIn('Serving graph: test_keyspace 0 master',
|
||||
tablet_62044_master_status)
|
||||
|
||||
# See if a missing slave can be safely reparented after the fact.
|
||||
def test_reparent_with_down_slave(self, shard_id='0'):
|
||||
|
|
|
@ -676,7 +676,7 @@ primary key (name)
|
|||
utils.check_tablet_query_service(self, shard_1_slave2, True, False)
|
||||
# Destination tablets would have query service disabled for other reasons than the migration,
|
||||
# so check the shard record instead of the tablets directly
|
||||
utils.check_shard_query_services(self, destination_shards, 'replica', False)
|
||||
utils.check_shard_query_services(self, destination_shards, 3, False)
|
||||
utils.check_srv_keyspace('test_nj', 'test_keyspace',
|
||||
'Partitions(master): -80 80-\n' +
|
||||
'Partitions(rdonly): -80 80-c0 c0-\n' +
|
||||
|
@ -689,7 +689,7 @@ primary key (name)
|
|||
utils.check_tablet_query_service(self, shard_1_slave2, False, True)
|
||||
# Destination tablets would have query service disabled for other reasons than the migration,
|
||||
# so check the shard record instead of the tablets directly
|
||||
utils.check_shard_query_services(self, destination_shards, 'replica', True)
|
||||
utils.check_shard_query_services(self, destination_shards, 3, True)
|
||||
utils.check_srv_keyspace('test_nj', 'test_keyspace',
|
||||
'Partitions(master): -80 80-\n' +
|
||||
'Partitions(rdonly): -80 80-c0 c0-\n' +
|
||||
|
@ -775,8 +775,7 @@ primary key (name)
|
|||
utils.run_vtctl(['RemoveShardCell', 'test_keyspace/80-', 'test_nj'], auto_log=True)
|
||||
utils.run_vtctl(['RemoveShardCell', 'test_keyspace/80-', 'test_ny'], auto_log=True)
|
||||
shard = utils.run_vtctl_json(['GetShard', 'test_keyspace/80-'])
|
||||
if shard['Cells']:
|
||||
self.fail("Non-empty Cells record for shard: %s" % str(shard))
|
||||
self.assertNotIn('cells', shard)
|
||||
|
||||
# delete the original shard
|
||||
utils.run_vtctl(['DeleteShard', 'test_keyspace/80-'], auto_log=True)
|
||||
|
|
|
@ -799,12 +799,12 @@ def check_shard_query_service(testcase, shard_name, tablet_type, expected_state)
|
|||
"""Makes assertions about the state of DisableQueryService in the shard record's TabletControlMap."""
|
||||
# We assume that query service should be enabled unless DisableQueryService is explicitly True
|
||||
query_service_enabled = True
|
||||
tablet_control_map = run_vtctl_json(['GetShard', shard_name]).get('TabletControlMap')
|
||||
if tablet_control_map:
|
||||
disable_query_service = tablet_control_map.get(tablet_type, {}).get('DisableQueryService')
|
||||
|
||||
if disable_query_service:
|
||||
query_service_enabled = False
|
||||
tablet_controls = run_vtctl_json(['GetShard', shard_name]).get('tablet_controls')
|
||||
if tablet_controls:
|
||||
for tc in tablet_controls:
|
||||
if tc['tablet_type'] == tablet_type:
|
||||
if tc.get('disable_query_service', False):
|
||||
query_service_enabled = False
|
||||
|
||||
testcase.assertEqual(
|
||||
query_service_enabled,
|
||||
|
@ -813,8 +813,8 @@ def check_shard_query_service(testcase, shard_name, tablet_type, expected_state)
|
|||
)
|
||||
|
||||
def check_shard_query_services(testcase, shard_names, tablet_type, expected_state):
|
||||
for shard_names in shard_names:
|
||||
check_shard_query_service(testcase, shard_names, tablet_type, expected_state)
|
||||
for shard_name in shard_names:
|
||||
check_shard_query_service(testcase, shard_name, tablet_type, expected_state)
|
||||
|
||||
def check_tablet_query_service(testcase, tablet, serving, tablet_control_disabled):
|
||||
"""check_tablet_query_service will check that the query service is enabled
|
||||
|
|
|
@ -498,14 +498,16 @@ index by_msg (msg)
|
|||
utils.run_vtctl(['SetShardTabletControl', '--remove', 'source_keyspace/0',
|
||||
'rdonly'], auto_log=True)
|
||||
shard_json = utils.run_vtctl_json(['GetShard', 'source_keyspace/0'])
|
||||
self.assertNotIn('rdonly', shard_json['TabletControlMap'])
|
||||
self.assertIn('replica', shard_json['TabletControlMap'])
|
||||
self.assertIn('master', shard_json['TabletControlMap'])
|
||||
self.assertEqual(len(shard_json['tablet_controls']), 2)
|
||||
for tc in shard_json['tablet_controls']:
|
||||
self.assertTrue(tc['tablet_type'] == 2 or tc['tablet_type'] == 3)
|
||||
utils.run_vtctl(['SetShardTabletControl', '--tables=moving.*,view1',
|
||||
'source_keyspace/0', 'rdonly'], auto_log=True)
|
||||
shard_json = utils.run_vtctl_json(['GetShard', 'source_keyspace/0'])
|
||||
self.assertEqual(['moving.*', 'view1'],
|
||||
shard_json['TabletControlMap']['rdonly']['BlacklistedTables'])
|
||||
for tc in shard_json['tablet_controls']:
|
||||
if tc['tablet_type'] == 4:
|
||||
break
|
||||
self.assertEqual(['moving.*', 'view1'], tc['blacklisted_tables'])
|
||||
utils.run_vtctl(['SetShardTabletControl', '--remove', 'source_keyspace/0',
|
||||
'rdonly'], auto_log=True)
|
||||
utils.run_vtctl(['SetShardTabletControl', '--remove', 'source_keyspace/0',
|
||||
|
@ -513,7 +515,7 @@ index by_msg (msg)
|
|||
utils.run_vtctl(['SetShardTabletControl', '--remove', 'source_keyspace/0',
|
||||
'master'], auto_log=True)
|
||||
shard_json = utils.run_vtctl_json(['GetShard', 'source_keyspace/0'])
|
||||
self.assertEqual(None, shard_json['TabletControlMap'])
|
||||
self.assertNotIn('tablet_controls', shard_json)
|
||||
|
||||
# check the binlog player is gone now
|
||||
destination_master.wait_for_binlog_player_count(0)
|
||||
|
|
Загрузка…
Ссылка в новой задаче