/
naming.go
129 lines (114 loc) · 3.41 KB
/
naming.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
// Copyright 2012, 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
/*
Handle logical name resolution - sort of like DNS but tailored to
vt and using the topology server.
Naming is disconnected from the backend discovery and is used for
front end clients.
The common query is "resolve keyspace.shard.db_type" and return a list
of host:port tuples that export our default server (vttablet). You can
get all shards with "keyspace.*.db_type".
In zk, this is in /zk/local/vt/ns/<keyspace>/<shard>/<db type>
*/
import (
"fmt"
"net"
log "github.com/golang/glog"
"github.com/youtube/vitess/go/netutil"
"golang.org/x/net/context"
pb "github.com/youtube/vitess/go/vt/proto/topodata"
)
const (
// DefaultPortName is the port named used by SrvEntries
// if "" is given as the named port.
DefaultPortName = "vt"
)
// NewEndPoint returns a new empty EndPoint
func NewEndPoint(uid uint32, host string) *pb.EndPoint {
return &pb.EndPoint{
Uid: uid,
Host: host,
PortMap: make(map[string]int32),
}
}
// EndPointEquality returns true iff two EndPoint are representing the same data
func EndPointEquality(left, right *pb.EndPoint) bool {
if left.Uid != right.Uid {
return false
}
if left.Host != right.Host {
return false
}
if len(left.PortMap) != len(right.PortMap) {
return false
}
for key, lvalue := range left.PortMap {
rvalue, ok := right.PortMap[key]
if !ok {
return false
}
if lvalue != rvalue {
return false
}
}
if len(left.HealthMap) != len(right.HealthMap) {
return false
}
for key, lvalue := range left.HealthMap {
rvalue, ok := right.HealthMap[key]
if !ok {
return false
}
if lvalue != rvalue {
return false
}
}
return true
}
// NewEndPoints creates a EndPoints with a pre-allocated slice for Entries.
func NewEndPoints() *pb.EndPoints {
return &pb.EndPoints{Entries: make([]*pb.EndPoint, 0, 8)}
}
// LookupVtName gets the list of EndPoints for a
// cell/keyspace/shard/tablet type and converts the list to net.SRV records
func LookupVtName(ctx context.Context, ts Server, cell, keyspace, shard string, tabletType pb.TabletType, namedPort string) ([]*net.SRV, error) {
addrs, _, err := ts.GetEndPoints(ctx, cell, keyspace, shard, tabletType)
if err != nil {
return nil, fmt.Errorf("LookupVtName(%v,%v,%v,%v) failed: %v", cell, keyspace, shard, tabletType, err)
}
srvs, err := SrvEntries(addrs, namedPort)
if err != nil {
return nil, fmt.Errorf("LookupVtName(%v,%v,%v,%v) failed: %v", cell, keyspace, shard, tabletType, err)
}
return srvs, err
}
// SrvEntries converts EndPoints to net.SRV for a given port.
// FIXME(msolomon) merge with zkns
func SrvEntries(addrs *pb.EndPoints, namedPort string) (srvs []*net.SRV, err error) {
srvs = make([]*net.SRV, 0, len(addrs.Entries))
var srvErr error
for _, entry := range addrs.Entries {
host := entry.Host
port := 0
if namedPort == "" {
namedPort = DefaultPortName
}
port = int(entry.PortMap[namedPort])
if port == 0 {
log.Warningf("vtns: bad port %v %v", namedPort, entry)
continue
}
srvs = append(srvs, &net.SRV{Target: host, Port: uint16(port)})
}
netutil.SortRfc2782(srvs)
if srvErr != nil && len(srvs) == 0 {
return nil, fmt.Errorf("SrvEntries failed: no valid endpoints found")
}
return
}
// SrvAddr prints a net.SRV
func SrvAddr(srv *net.SRV) string {
return fmt.Sprintf("%s:%d", srv.Target, srv.Port)
}