Skip to content

Commit b497e3d

Browse files
Merge pull request #124 from github/vitess-cell-support
Support polling specific Vitess cells
2 parents 5f8f6db + acea623 commit b497e3d

File tree

5 files changed

+90
-13
lines changed

5 files changed

+90
-13
lines changed

pkg/config/mysql_config.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ type MySQLConfigurationSettings struct {
5858
HttpCheckPort int // port for HTTP check. -1 to disable.
5959
HttpCheckPath string // If non-empty, requires HttpCheckPort
6060
IgnoreHosts []string // If non empty, substrings to indicate hosts to be ignored/skipped
61+
VitessCells []string // Name of the Vitess cells for polling tablet hosts
6162

6263
Clusters map[string](*MySQLClusterConfigurationSettings) // cluster name -> cluster config
6364
}
@@ -114,6 +115,9 @@ func (settings *MySQLConfigurationSettings) postReadAdjustments() error {
114115
if len(clusterSettings.IgnoreHosts) == 0 {
115116
clusterSettings.IgnoreHosts = settings.IgnoreHosts
116117
}
118+
if !clusterSettings.VitessSettings.IsEmpty() && len(clusterSettings.VitessSettings.Cells) < 1 {
119+
clusterSettings.VitessSettings.Cells = settings.VitessCells
120+
}
117121
}
118122
return nil
119123
}

pkg/config/vitess_config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package config
66

77
type VitessConfigurationSettings struct {
88
API string
9+
Cells []string
910
Keyspace string
1011
Shard string
1112
TimeoutSecs uint

pkg/throttle/throttler.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,9 @@ func (throttler *Throttler) refreshMySQLInventory() error {
327327
if err != nil {
328328
return log.Errorf("Unable to get vitess hosts from %s, %s/%s: %+v", clusterSettings.VitessSettings.API, keyspace, shard, err)
329329
}
330-
log.Debugf("Read %+v hosts from vitess %s, %s/%s", len(tablets), clusterSettings.VitessSettings.API, keyspace, shard)
330+
log.Debugf("Read %+v hosts from vitess %s, %s/%s, cells=%s", len(tablets), clusterSettings.VitessSettings.API,
331+
keyspace, shard, strings.Join(vitess.ParseCells(clusterSettings.VitessSettings), ","),
332+
)
331333
clusterProbes := &mysql.ClusterProbes{
332334
ClusterName: clusterName,
333335
IgnoreHostsCount: clusterSettings.IgnoreHostsCount,

pkg/vitess/api_client.go

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,23 @@ const defaultTimeout = time.Duration(5) * time.Second
1616

1717
// Tablet represents information about a running instance of vttablet.
1818
type Tablet struct {
19-
MysqlHostname string `json:"mysql_hostname,omitempty"`
20-
MysqlPort int32 `json:"mysql_port,omitempty"`
21-
Type topodata.TabletType `json:"type,omitempty"`
19+
Alias *topodata.TabletAlias `json:"alias,omitempty"`
20+
MysqlHostname string `json:"mysql_hostname,omitempty"`
21+
MysqlPort int32 `json:"mysql_port,omitempty"`
22+
Type topodata.TabletType `json:"type,omitempty"`
23+
}
24+
25+
// HasValidCell returns a bool reflecting if a tablet is in a valid Vitess cell
26+
func (t Tablet) HasValidCell(validCells []string) bool {
27+
if len(validCells) == 0 {
28+
return true
29+
}
30+
for _, cell := range validCells {
31+
if t.Alias.GetCell() == cell {
32+
return true
33+
}
34+
}
35+
return false
2236
}
2337

2438
// IsValidReplica returns a bool reflecting if a tablet type is REPLICA
@@ -40,10 +54,22 @@ func constructAPIURL(settings config.VitessConfigurationSettings) (url string) {
4054
return url
4155
}
4256

57+
// ParseCells returns a slice of non-empty Vitess cell names
58+
func ParseCells(settings config.VitessConfigurationSettings) (cells []string) {
59+
for _, cell := range settings.Cells {
60+
cell = strings.TrimSpace(cell)
61+
if cell != "" {
62+
cells = append(cells, cell)
63+
}
64+
}
65+
return cells
66+
}
67+
4368
// filterReplicaTablets parses a list of tablets, returning replica tablets only
44-
func filterReplicaTablets(tablets []Tablet) (replicas []Tablet) {
69+
func filterReplicaTablets(settings config.VitessConfigurationSettings, tablets []Tablet) (replicas []Tablet) {
70+
validCells := ParseCells(settings)
4571
for _, tablet := range tablets {
46-
if tablet.IsValidReplica() {
72+
if tablet.HasValidCell(validCells) && tablet.IsValidReplica() {
4773
replicas = append(replicas, tablet)
4874
}
4975
}
@@ -72,5 +98,5 @@ func ParseTablets(settings config.VitessConfigurationSettings) (tablets []Tablet
7298
}
7399

74100
err = json.Unmarshal(body, &tablets)
75-
return filterReplicaTablets(tablets), err
101+
return filterReplicaTablets(settings, tablets), err
76102
}

pkg/vitess/api_client_test.go

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,37 @@ func TestParseTablets(t *testing.T) {
1818
case "/api/keyspace/test/tablets/00":
1919
data, _ := json.Marshal([]Tablet{
2020
{
21+
Alias: &topodata.TabletAlias{Cell: "cell1"},
2122
MysqlHostname: "master",
2223
Type: topodata.TabletType_MASTER,
2324
},
2425
{
25-
MysqlHostname: "replica",
26+
Alias: &topodata.TabletAlias{Cell: "cell2"},
27+
MysqlHostname: "replica1",
2628
Type: topodata.TabletType_REPLICA,
2729
},
2830
{
31+
Alias: &topodata.TabletAlias{Cell: "cell3"},
32+
MysqlHostname: "replica2",
33+
Type: topodata.TabletType_REPLICA,
34+
},
35+
{
36+
Alias: &topodata.TabletAlias{Cell: "cell2"},
2937
MysqlHostname: "spare",
3038
Type: topodata.TabletType_SPARE,
3139
},
3240
{
41+
Alias: &topodata.TabletAlias{Cell: "cell3"},
3342
MysqlHostname: "batch",
3443
Type: topodata.TabletType_BATCH,
3544
},
3645
{
46+
Alias: &topodata.TabletAlias{Cell: "cell2"},
3747
MysqlHostname: "backup",
3848
Type: topodata.TabletType_BACKUP,
3949
},
4050
{
41-
51+
Alias: &topodata.TabletAlias{Cell: "cell1"},
4252
MysqlHostname: "restore",
4353
Type: topodata.TabletType_RESTORE,
4454
},
@@ -62,19 +72,53 @@ func TestParseTablets(t *testing.T) {
6272
t.Fatalf("Expected no error, got %q", err)
6373
}
6474

65-
if len(tablets) != 1 {
66-
t.Fatalf("Expected 1 tablet, got %d", len(tablets))
75+
if len(tablets) != 2 {
76+
t.Fatalf("Expected 2 tablets, got %d", len(tablets))
6777
}
6878

69-
if tablets[0].MysqlHostname != "replica" {
70-
t.Fatalf("Expected hostname %q, got %q", "replica", tablets[0].MysqlHostname)
79+
if tablets[0].MysqlHostname != "replica1" {
80+
t.Fatalf("Expected hostname %q, got %q", "replica1", tablets[0].MysqlHostname)
81+
}
82+
if tablets[1].MysqlHostname != "replica2" {
83+
t.Fatalf("Expected hostname %q, got %q", "replica2", tablets[1].MysqlHostname)
7184
}
7285

7386
if httpClient.Timeout != time.Second {
7487
t.Fatalf("Expected vitess client timeout of %v, got %v", time.Second, httpClient.Timeout)
7588
}
7689
})
7790

91+
t.Run("with-cell", func(t *testing.T) {
92+
settings := config.VitessConfigurationSettings{
93+
API: vitessApi.URL,
94+
Cells: []string{"cell2"},
95+
Keyspace: "test",
96+
Shard: "00",
97+
}
98+
tablets, err := ParseTablets(settings)
99+
if err != nil {
100+
t.Fatalf("Expected no error, got %q", err)
101+
}
102+
103+
if len(tablets) != 1 {
104+
t.Fatalf("Expected 1 tablet, got %d", len(tablets))
105+
}
106+
107+
if tablets[0].MysqlHostname != "replica1" {
108+
t.Fatalf("Expected hostname %q, got %q", "replica1", tablets[0].MysqlHostname)
109+
}
110+
if tablets[0].Alias.GetCell() != "cell2" {
111+
t.Fatalf("Expected vitess cell %s, got %s", "cell2", tablets[0].Alias.GetCell())
112+
}
113+
114+
// empty cell names should cause no filtering
115+
settings.Cells = []string{"", ""}
116+
tablets, _ = ParseTablets(settings)
117+
if len(tablets) != 2 {
118+
t.Fatalf("Expected 2 tablet, got %d", len(tablets))
119+
}
120+
})
121+
78122
t.Run("not-found", func(t *testing.T) {
79123
tablets, err := ParseTablets(config.VitessConfigurationSettings{
80124
API: vitessApi.URL,

0 commit comments

Comments
 (0)