vitess.io/vitess@v0.16.2/go/vt/topo/topoproto/tablet.go (about)

     1  /*
     2  Copyright 2019 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package topoproto contains utility functions to deal with the proto3
    18  // structures defined in proto/topodata.
    19  package topoproto
    20  
    21  import (
    22  	"fmt"
    23  	"net"
    24  	"regexp"
    25  	"sort"
    26  	"strconv"
    27  	"strings"
    28  
    29  	"google.golang.org/protobuf/proto"
    30  
    31  	"k8s.io/apimachinery/pkg/util/sets"
    32  
    33  	"vitess.io/vitess/go/netutil"
    34  	"vitess.io/vitess/go/vt/vterrors"
    35  
    36  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    37  )
    38  
    39  // This file contains the topodata.Tablet utility functions.
    40  
    41  const (
    42  	// VtDbPrefix + keyspace is the default name for databases.
    43  	VtDbPrefix = "vt_"
    44  )
    45  
    46  // cache the conversion from tablet type enum to lower case string.
    47  var tabletTypeLowerName map[int32]string
    48  
    49  func init() {
    50  	tabletTypeLowerName = make(map[int32]string, len(topodatapb.TabletType_name))
    51  	for k, v := range topodatapb.TabletType_name {
    52  		tabletTypeLowerName[k] = strings.ToLower(v)
    53  	}
    54  }
    55  
    56  // TabletAliasIsZero returns true iff cell and uid are empty
    57  func TabletAliasIsZero(ta *topodatapb.TabletAlias) bool {
    58  	return ta == nil || (ta.Cell == "" && ta.Uid == 0)
    59  }
    60  
    61  // TabletAliasEqual returns true if two TabletAlias match
    62  func TabletAliasEqual(left, right *topodatapb.TabletAlias) bool {
    63  	return proto.Equal(left, right)
    64  }
    65  
    66  // IsTabletInList returns true if the tablet is in the list of tablets given
    67  func IsTabletInList(tablet *topodatapb.Tablet, allTablets []*topodatapb.Tablet) bool {
    68  	for _, tab := range allTablets {
    69  		if TabletAliasEqual(tablet.Alias, tab.Alias) {
    70  			return true
    71  		}
    72  	}
    73  	return false
    74  }
    75  
    76  // TabletAliasString formats a TabletAlias
    77  func TabletAliasString(ta *topodatapb.TabletAlias) string {
    78  	if ta == nil {
    79  		return "<nil>"
    80  	}
    81  	return fmt.Sprintf("%v-%010d", ta.Cell, ta.Uid)
    82  }
    83  
    84  // TabletAliasUIDStr returns a string version of the uid
    85  func TabletAliasUIDStr(ta *topodatapb.TabletAlias) string {
    86  	return fmt.Sprintf("%010d", ta.Uid)
    87  }
    88  
    89  const tabletAliasFormat = "^(?P<cell>[-_.a-zA-Z0-9]+)-(?P<uid>[0-9]+)$"
    90  
    91  var tabletAliasRegexp = regexp.MustCompile(tabletAliasFormat)
    92  
    93  // ParseTabletAlias returns a TabletAlias for the input string,
    94  // of the form <cell>-<uid>
    95  func ParseTabletAlias(aliasStr string) (*topodatapb.TabletAlias, error) {
    96  	nameParts := tabletAliasRegexp.FindStringSubmatch(aliasStr)
    97  	if len(nameParts) != 3 {
    98  		return nil, fmt.Errorf("invalid tablet alias: '%s', expecting format: '%s'", aliasStr, tabletAliasFormat)
    99  	}
   100  	uid, err := ParseUID(nameParts[tabletAliasRegexp.SubexpIndex("uid")])
   101  	if err != nil {
   102  		return nil, vterrors.Wrapf(err, "invalid tablet uid in alias '%s'", aliasStr)
   103  	}
   104  	return &topodatapb.TabletAlias{
   105  		Cell: nameParts[tabletAliasRegexp.SubexpIndex("cell")],
   106  		Uid:  uid,
   107  	}, nil
   108  }
   109  
   110  // ParseTabletSet returns a set of tablets based on a provided comma separated list of tablets.
   111  func ParseTabletSet(tabletListStr string) sets.Set[string] {
   112  	set := sets.New[string]()
   113  	if tabletListStr == "" {
   114  		return set
   115  	}
   116  	list := strings.Split(tabletListStr, ",")
   117  	set.Insert(list...)
   118  	return set
   119  }
   120  
   121  // ParseUID parses just the uid (a number)
   122  func ParseUID(value string) (uint32, error) {
   123  	uid, err := strconv.ParseUint(value, 10, 32)
   124  	if err != nil {
   125  		return 0, vterrors.Wrap(err, "bad tablet uid")
   126  	}
   127  	return uint32(uid), nil
   128  }
   129  
   130  // TabletAliasList is used mainly for sorting
   131  type TabletAliasList []*topodatapb.TabletAlias
   132  
   133  // Len is part of sort.Interface
   134  func (tal TabletAliasList) Len() int {
   135  	return len(tal)
   136  }
   137  
   138  // Less is part of sort.Interface
   139  func (tal TabletAliasList) Less(i, j int) bool {
   140  	if tal[i].Cell < tal[j].Cell {
   141  		return true
   142  	} else if tal[i].Cell > tal[j].Cell {
   143  		return false
   144  	}
   145  	return tal[i].Uid < tal[j].Uid
   146  }
   147  
   148  // Swap is part of sort.Interface
   149  func (tal TabletAliasList) Swap(i, j int) {
   150  	tal[i], tal[j] = tal[j], tal[i]
   151  }
   152  
   153  // ToStringSlice returns a slice which is the result of mapping
   154  // TabletAliasString over a slice of TabletAliases.
   155  func (tal TabletAliasList) ToStringSlice() []string {
   156  	result := make([]string, len(tal))
   157  
   158  	for i, alias := range tal {
   159  		result[i] = TabletAliasString(alias)
   160  	}
   161  
   162  	return result
   163  }
   164  
   165  // AllTabletTypes lists all the possible tablet types
   166  var AllTabletTypes = []topodatapb.TabletType{
   167  	topodatapb.TabletType_PRIMARY,
   168  	topodatapb.TabletType_REPLICA,
   169  	topodatapb.TabletType_RDONLY,
   170  	topodatapb.TabletType_BATCH,
   171  	topodatapb.TabletType_SPARE,
   172  	topodatapb.TabletType_EXPERIMENTAL,
   173  	topodatapb.TabletType_BACKUP,
   174  	topodatapb.TabletType_RESTORE,
   175  	topodatapb.TabletType_DRAINED,
   176  }
   177  
   178  // ParseTabletType parses the tablet type into the enum.
   179  func ParseTabletType(param string) (topodatapb.TabletType, error) {
   180  	value, ok := topodatapb.TabletType_value[strings.ToUpper(param)]
   181  	if !ok {
   182  		return topodatapb.TabletType_UNKNOWN, fmt.Errorf("unknown TabletType %v", param)
   183  	}
   184  	return topodatapb.TabletType(value), nil
   185  }
   186  
   187  // ParseTabletTypes parses a comma separated list of tablet types and returns a slice with the respective enums.
   188  func ParseTabletTypes(param string) ([]topodatapb.TabletType, error) {
   189  	var tabletTypes []topodatapb.TabletType
   190  	for _, typeStr := range strings.Split(param, ",") {
   191  		t, err := ParseTabletType(typeStr)
   192  		if err != nil {
   193  			return nil, err
   194  		}
   195  		tabletTypes = append(tabletTypes, t)
   196  	}
   197  	return tabletTypes, nil
   198  }
   199  
   200  // TabletTypeLString returns a lower case version of the tablet type,
   201  // or "unknown" if not known.
   202  func TabletTypeLString(tabletType topodatapb.TabletType) string {
   203  	value, ok := tabletTypeLowerName[int32(tabletType)]
   204  	if !ok {
   205  		return "unknown"
   206  	}
   207  	return value
   208  }
   209  
   210  // IsTypeInList returns true if the given type is in the list.
   211  // Use it with AllTabletTypes for instance.
   212  func IsTypeInList(tabletType topodatapb.TabletType, types []topodatapb.TabletType) bool {
   213  	for _, t := range types {
   214  		if tabletType == t {
   215  			return true
   216  		}
   217  	}
   218  	return false
   219  }
   220  
   221  // MakeStringTypeList returns a list of strings that match the input list.
   222  func MakeStringTypeList(types []topodatapb.TabletType) []string {
   223  	strs := make([]string, len(types))
   224  	for i, t := range types {
   225  		strs[i] = strings.ToLower(t.String())
   226  	}
   227  	sort.Strings(strs)
   228  	return strs
   229  }
   230  
   231  // MysqlAddr returns the host:port of the mysql server.
   232  func MysqlAddr(tablet *topodatapb.Tablet) string {
   233  	return netutil.JoinHostPort(tablet.MysqlHostname, tablet.MysqlPort)
   234  }
   235  
   236  // MySQLIP returns the MySQL server's IP by resolving the hostname.
   237  func MySQLIP(tablet *topodatapb.Tablet) (string, error) {
   238  	ipAddrs, err := net.LookupHost(tablet.MysqlHostname)
   239  	if err != nil {
   240  		return "", err
   241  	}
   242  	return ipAddrs[0], nil
   243  }
   244  
   245  // TabletDbName is usually implied by keyspace. Having the shard
   246  // information in the database name complicates mysql replication.
   247  func TabletDbName(tablet *topodatapb.Tablet) string {
   248  	if tablet.DbNameOverride != "" {
   249  		return tablet.DbNameOverride
   250  	}
   251  	if tablet.Keyspace == "" {
   252  		return ""
   253  	}
   254  	return VtDbPrefix + tablet.Keyspace
   255  }
   256  
   257  // TabletIsAssigned returns if this tablet is assigned to a keyspace and shard.
   258  // A "scrap" node will show up as assigned even though its data cannot be used
   259  // for serving.
   260  func TabletIsAssigned(tablet *topodatapb.Tablet) bool {
   261  	return tablet != nil && tablet.Keyspace != "" && tablet.Shard != ""
   262  }
   263  
   264  // IsServingType returns true if the tablet type is one that should be serving to be healthy, or false if the tablet type
   265  // should not be serving in it's healthy state.
   266  func IsServingType(tabletType topodatapb.TabletType) bool {
   267  	switch tabletType {
   268  	case topodatapb.TabletType_PRIMARY, topodatapb.TabletType_REPLICA, topodatapb.TabletType_BATCH, topodatapb.TabletType_EXPERIMENTAL:
   269  		return true
   270  	default:
   271  		return false
   272  	}
   273  }