Now using proto3's Shard record.

This commit is contained in:
Alain Jobart 2015-08-04 12:44:19 -07:00
Родитель a88afc2cd4
Коммит f1b1c1ea18
67 изменённых файлов: 721 добавлений и 540 удалений

Просмотреть файл

@ -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)