forked from vitessio/vitess
/
replication.go
154 lines (135 loc) · 4.81 KB
/
replication.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2013, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package topo
import (
"code.google.com/p/go.net/context"
log "github.com/golang/glog"
"github.com/henryanand/vitess/go/trace"
"github.com/henryanand/vitess/go/vt/logutil"
)
// ReplicationLink describes a MySQL replication relationship.
// For now, we only insert ReplicationLink for slave tablets.
// We want to add records for master tablets as well, with a Parent.IsZero().
type ReplicationLink struct {
TabletAlias TabletAlias
Parent TabletAlias
}
// ShardReplication describes the MySQL replication relationships
// whithin a cell.
type ShardReplication struct {
// Note there can be only one ReplicationLink in this array
// for a given Slave (each Slave can only have one parent)
ReplicationLinks []ReplicationLink
}
// GetReplicationLink find a link for a given tablet.
func (sr *ShardReplication) GetReplicationLink(tabletAlias TabletAlias) (ReplicationLink, error) {
for _, rl := range sr.ReplicationLinks {
if rl.TabletAlias == tabletAlias {
return rl, nil
}
}
return ReplicationLink{}, ErrNoNode
}
// ShardReplicationInfo is the companion structure for ShardReplication.
type ShardReplicationInfo struct {
*ShardReplication
cell string
keyspace string
shard string
}
// NewShardReplicationInfo is for topo.Server implementations to
// create the structure
func NewShardReplicationInfo(sr *ShardReplication, cell, keyspace, shard string) *ShardReplicationInfo {
return &ShardReplicationInfo{
ShardReplication: sr,
cell: cell,
keyspace: keyspace,
shard: shard,
}
}
// Cell returns the cell for a ShardReplicationInfo
func (sri *ShardReplicationInfo) Cell() string {
return sri.cell
}
// Keyspace returns the keyspace for a ShardReplicationInfo
func (sri *ShardReplicationInfo) Keyspace() string {
return sri.keyspace
}
// Shard returns the shard for a ShardReplicationInfo
func (sri *ShardReplicationInfo) Shard() string {
return sri.shard
}
// UpdateShardReplicationRecord is a low level function to add / update an
// entry to the ShardReplication object.
func UpdateShardReplicationRecord(ctx context.Context, ts Server, keyspace, shard string, tabletAlias, parent TabletAlias) error {
span := trace.NewSpanFromContext(ctx)
span.StartClient("TopoServer.UpdateShardReplicationFields")
span.Annotate("keyspace", keyspace)
span.Annotate("shard", shard)
span.Annotate("tablet", tabletAlias.String())
defer span.Finish()
return ts.UpdateShardReplicationFields(tabletAlias.Cell, keyspace, shard, func(sr *ShardReplication) error {
// not very efficient, but easy to read
links := make([]ReplicationLink, 0, len(sr.ReplicationLinks)+1)
found := false
for _, link := range sr.ReplicationLinks {
if link.TabletAlias == tabletAlias {
if found {
log.Warningf("Found a second ReplicationLink for tablet %v, deleting it", tabletAlias)
continue
}
found = true
// update the master
link.Parent = parent
}
links = append(links, link)
}
if !found {
links = append(links, ReplicationLink{TabletAlias: tabletAlias, Parent: parent})
}
sr.ReplicationLinks = links
return nil
})
}
// RemoveShardReplicationRecord is a low level function to remove an
// entry from the ShardReplication object.
func RemoveShardReplicationRecord(ts Server, cell, keyspace, shard string, tabletAlias TabletAlias) error {
err := ts.UpdateShardReplicationFields(cell, keyspace, shard, func(sr *ShardReplication) error {
links := make([]ReplicationLink, 0, len(sr.ReplicationLinks))
for _, link := range sr.ReplicationLinks {
if link.TabletAlias != tabletAlias {
links = append(links, link)
}
}
sr.ReplicationLinks = links
return nil
})
return err
}
// FixShardReplication will fix the first problem it encounters within
// a ShardReplication object
func FixShardReplication(ts Server, logger logutil.Logger, cell, keyspace, shard string) error {
sri, err := ts.GetShardReplication(cell, keyspace, shard)
if err != nil {
return err
}
for _, rl := range sri.ReplicationLinks {
ti, err := ts.GetTablet(rl.TabletAlias)
if err == ErrNoNode {
logger.Warningf("Tablet %v is in the replication graph, but does not exist, removing it", rl.TabletAlias)
return RemoveShardReplicationRecord(ts, cell, keyspace, shard, rl.TabletAlias)
}
if err != nil {
// unknown error, we probably don't want to continue
return err
}
if ti.Type == TYPE_SCRAP {
logger.Warningf("Tablet %v is in the replication graph, but is scrapped, removing it", rl.TabletAlias)
return RemoveShardReplicationRecord(ts, cell, keyspace, shard, rl.TabletAlias)
}
logger.Infof("Keeping tablet %v in the replication graph", rl.TabletAlias)
}
logger.Infof("All entries in replication graph are valid")
return nil
}