/
utils.go
168 lines (148 loc) · 5.11 KB
/
utils.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
/*
Copyright 2019 The Vitess Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package topotools
import (
"reflect"
"sort"
"sync"
"context"
"vitess.io/vitess/go/vt/log"
"vitess.io/vitess/go/vt/topo"
"vitess.io/vitess/go/vt/topo/topoproto"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
)
// FindTabletByHostAndPort searches within a tablet map for tablets.
func FindTabletByHostAndPort(tabletMap map[string]*topo.TabletInfo, addr, portName string, port int32) (*topodatapb.TabletAlias, error) {
for _, ti := range tabletMap {
if ti.Hostname == addr && ti.PortMap[portName] == port {
return ti.Alias, nil
}
}
return nil, topo.NewError(topo.NoNode, addr+":"+portName)
}
// GetAllTablets returns a sorted list of tablets.
func GetAllTablets(ctx context.Context, ts *topo.Server, cell string) ([]*topo.TabletInfo, error) {
aliases, err := ts.GetTabletsByCell(ctx, cell)
if err != nil {
return nil, err
}
sort.Sort(topoproto.TabletAliasList(aliases))
tabletMap, err := ts.GetTabletMap(ctx, aliases)
if err != nil {
// we got another error than topo.ErrNoNode
return nil, err
}
tablets := make([]*topo.TabletInfo, 0, len(aliases))
for _, tabletAlias := range aliases {
tabletInfo, ok := tabletMap[topoproto.TabletAliasString(tabletAlias)]
if !ok {
// tablet disappeared on us (GetTabletMap ignores
// topo.ErrNoNode), just echo a warning
log.Warningf("failed to load tablet %v", tabletAlias)
} else {
tablets = append(tablets, tabletInfo)
}
}
return tablets, nil
}
// GetTabletMapForCell returns a map of TabletInfo keyed by alias as string
func GetTabletMapForCell(ctx context.Context, ts *topo.Server, cell string) (map[string]*topo.TabletInfo, error) {
aliases, err := ts.GetTabletsByCell(ctx, cell)
if err != nil {
return nil, err
}
tabletMap, err := ts.GetTabletMap(ctx, aliases)
if err != nil {
// we got another error than topo.ErrNoNode
return nil, err
}
return tabletMap, nil
}
// GetAllTabletsAcrossCells returns all tablets from known cells.
// If it returns topo.ErrPartialResult, then the list is valid, but partial.
func GetAllTabletsAcrossCells(ctx context.Context, ts *topo.Server) ([]*topo.TabletInfo, error) {
cells, err := ts.GetKnownCells(ctx)
if err != nil {
return nil, err
}
results := make([][]*topo.TabletInfo, len(cells))
errors := make([]error, len(cells))
wg := sync.WaitGroup{}
wg.Add(len(cells))
for i, cell := range cells {
go func(i int, cell string) {
results[i], errors[i] = GetAllTablets(ctx, ts, cell)
wg.Done()
}(i, cell)
}
wg.Wait()
err = nil
var allTablets []*topo.TabletInfo
for i := range cells {
if errors[i] == nil {
allTablets = append(allTablets, results[i]...)
} else {
err = topo.NewError(topo.PartialResult, "")
}
}
return allTablets, err
}
// SortedTabletMap returns two maps:
// - The replicaMap contains all the non-master non-scrapped hosts.
// This can be used as a list of replicas to fix up for reparenting
// - The masterMap contains all the tablets without parents
// (scrapped or not). This can be used to special case
// the old master, and any tablet in a weird state, left over, ...
func SortedTabletMap(tabletMap map[string]*topo.TabletInfo) (map[string]*topo.TabletInfo, map[string]*topo.TabletInfo) {
replicaMap := make(map[string]*topo.TabletInfo)
masterMap := make(map[string]*topo.TabletInfo)
for alias, ti := range tabletMap {
if ti.Type == topodatapb.TabletType_MASTER {
masterMap[alias] = ti
} else {
replicaMap[alias] = ti
}
}
return replicaMap, masterMap
}
// CopyMapKeys copies keys from map m into a new slice with the
// type specified by typeHint. Reflection can't make a new slice type
// just based on the key type AFAICT.
func CopyMapKeys(m interface{}, typeHint interface{}) interface{} {
mapVal := reflect.ValueOf(m)
keys := reflect.MakeSlice(reflect.TypeOf(typeHint), 0, mapVal.Len())
for _, k := range mapVal.MapKeys() {
keys = reflect.Append(keys, k)
}
return keys.Interface()
}
// CopyMapValues copies values from map m into a new slice with the
// type specified by typeHint. Reflection can't make a new slice type
// just based on the key type AFAICT.
func CopyMapValues(m interface{}, typeHint interface{}) interface{} {
mapVal := reflect.ValueOf(m)
vals := reflect.MakeSlice(reflect.TypeOf(typeHint), 0, mapVal.Len())
for _, k := range mapVal.MapKeys() {
vals = reflect.Append(vals, mapVal.MapIndex(k))
}
return vals.Interface()
}
// MapKeys returns an array with th provided map keys.
func MapKeys(m interface{}) []interface{} {
keys := make([]interface{}, 0, 16)
mapVal := reflect.ValueOf(m)
for _, kv := range mapVal.MapKeys() {
keys = append(keys, kv.Interface())
}
return keys
}