vitess.io/vitess@v0.16.2/go/vt/topotools/utils.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 topotools
    18  
    19  import (
    20  	"reflect"
    21  	"sync"
    22  
    23  	"context"
    24  
    25  	"vitess.io/vitess/go/vt/topo"
    26  
    27  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    28  )
    29  
    30  // FindTabletByHostAndPort searches within a tablet map for tablets.
    31  func FindTabletByHostAndPort(tabletMap map[string]*topo.TabletInfo, addr, portName string, port int32) (*topodatapb.TabletAlias, error) {
    32  	for _, ti := range tabletMap {
    33  		if ti.Hostname == addr && ti.PortMap[portName] == port {
    34  			return ti.Alias, nil
    35  		}
    36  	}
    37  	return nil, topo.NewError(topo.NoNode, addr+":"+portName)
    38  }
    39  
    40  // GetTabletMapForCell returns a map of TabletInfo keyed by alias as string
    41  func GetTabletMapForCell(ctx context.Context, ts *topo.Server, cell string) (map[string]*topo.TabletInfo, error) {
    42  	aliases, err := ts.GetTabletAliasesByCell(ctx, cell)
    43  	if err != nil {
    44  		return nil, err
    45  	}
    46  	tabletMap, err := ts.GetTabletMap(ctx, aliases)
    47  	if err != nil {
    48  		// we got another error than topo.ErrNoNode
    49  		return nil, err
    50  	}
    51  	return tabletMap, nil
    52  }
    53  
    54  // GetAllTabletsAcrossCells returns all tablets from known cells.
    55  // If it returns topo.ErrPartialResult, then the list is valid, but partial.
    56  func GetAllTabletsAcrossCells(ctx context.Context, ts *topo.Server) ([]*topo.TabletInfo, error) {
    57  	cells, err := ts.GetKnownCells(ctx)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	results := make([][]*topo.TabletInfo, len(cells))
    63  	errors := make([]error, len(cells))
    64  	wg := sync.WaitGroup{}
    65  	wg.Add(len(cells))
    66  	for i, cell := range cells {
    67  		go func(i int, cell string) {
    68  			results[i], errors[i] = ts.GetTabletsByCell(ctx, cell)
    69  			wg.Done()
    70  		}(i, cell)
    71  	}
    72  	wg.Wait()
    73  
    74  	err = nil
    75  	var allTablets []*topo.TabletInfo
    76  	for i := range cells {
    77  		if errors[i] == nil {
    78  			allTablets = append(allTablets, results[i]...)
    79  		} else {
    80  			err = topo.NewError(topo.PartialResult, "")
    81  		}
    82  	}
    83  	return allTablets, err
    84  }
    85  
    86  // SortedTabletMap returns two maps:
    87  //   - The replicaMap contains all the non-primary non-scrapped hosts.
    88  //     This can be used as a list of replicas to fix up for reparenting
    89  //   - The primaryMap contains all the tablets without parents
    90  //     (scrapped or not). This can be used to special case
    91  //     the old primary, and any tablet in a weird state, left over, ...
    92  func SortedTabletMap(tabletMap map[string]*topo.TabletInfo) (map[string]*topo.TabletInfo, map[string]*topo.TabletInfo) {
    93  	replicaMap := make(map[string]*topo.TabletInfo)
    94  	primaryMap := make(map[string]*topo.TabletInfo)
    95  	for alias, ti := range tabletMap {
    96  		if ti.Type == topodatapb.TabletType_PRIMARY {
    97  			primaryMap[alias] = ti
    98  		} else {
    99  			replicaMap[alias] = ti
   100  		}
   101  	}
   102  	return replicaMap, primaryMap
   103  }
   104  
   105  // CopyMapKeys copies keys from map m into a new slice with the
   106  // type specified by typeHint.  Reflection can't make a new slice type
   107  // just based on the key type AFAICT.
   108  func CopyMapKeys(m any, typeHint any) any {
   109  	mapVal := reflect.ValueOf(m)
   110  	keys := reflect.MakeSlice(reflect.TypeOf(typeHint), 0, mapVal.Len())
   111  	for _, k := range mapVal.MapKeys() {
   112  		keys = reflect.Append(keys, k)
   113  	}
   114  	return keys.Interface()
   115  }
   116  
   117  // CopyMapValues copies values from map m into a new slice with the
   118  // type specified by typeHint.  Reflection can't make a new slice type
   119  // just based on the key type AFAICT.
   120  func CopyMapValues(m any, typeHint any) any {
   121  	mapVal := reflect.ValueOf(m)
   122  	vals := reflect.MakeSlice(reflect.TypeOf(typeHint), 0, mapVal.Len())
   123  	for _, k := range mapVal.MapKeys() {
   124  		vals = reflect.Append(vals, mapVal.MapIndex(k))
   125  	}
   126  	return vals.Interface()
   127  }
   128  
   129  // MapKeys returns an array with th provided map keys.
   130  func MapKeys(m any) []any {
   131  	keys := make([]any, 0, 16)
   132  	mapVal := reflect.ValueOf(m)
   133  	for _, kv := range mapVal.MapKeys() {
   134  		keys = append(keys, kv.Interface())
   135  	}
   136  	return keys
   137  }