func getKeyspaceShards(ctx context.Context, topoServ topo.SrvTopoServer, cell, keyspace string, tabletType topodatapb.TabletType) (string, *topodatapb.SrvKeyspace, []*topodatapb.ShardReference, error) { srvKeyspace, err := topoServ.GetSrvKeyspace(ctx, cell, keyspace) if err != nil { return "", nil, nil, vterrors.NewVitessError( vtrpcpb.ErrorCode_INTERNAL_ERROR, err, "keyspace %v fetch error: %v", keyspace, err, ) } // check if the keyspace has been redirected for this tabletType. for _, sf := range srvKeyspace.ServedFrom { if sf.TabletType == tabletType { keyspace = sf.Keyspace srvKeyspace, err = topoServ.GetSrvKeyspace(ctx, cell, keyspace) if err != nil { return "", nil, nil, vterrors.NewVitessError( vtrpcpb.ErrorCode_INTERNAL_ERROR, err, "keyspace %v fetch error: %v", keyspace, err, ) } } } partition := topoproto.SrvKeyspaceGetPartition(srvKeyspace, tabletType) if partition == nil { return "", nil, nil, vterrors.NewVitessError( vtrpcpb.ErrorCode_INTERNAL_ERROR, err, "No partition found for tabletType %v in keyspace %v", strings.ToLower(tabletType.String()), keyspace, ) } return keyspace, srvKeyspace, partition.ShardReferences, nil }
// findAllKeyspaceShards goes through all serving shards in the topology func findAllKeyspaceShards(ctx context.Context, ts topo.SrvTopoServer, cell string) (map[keyspaceShard]bool, error) { ksNames, err := ts.GetSrvKeyspaceNames(ctx, cell) if err != nil { return nil, err } keyspaceShards := make(map[keyspaceShard]bool) var wg sync.WaitGroup var mu sync.Mutex var errRecorder concurrency.AllErrorRecorder for _, ksName := range ksNames { wg.Add(1) go func(keyspace string) { defer wg.Done() // get SrvKeyspace for cell/keyspace ks, err := ts.GetSrvKeyspace(ctx, cell, keyspace) if err != nil { errRecorder.RecordError(err) return } // get all shard names that are used for serving mu.Lock() for _, ksPartition := range ks.Partitions { for _, shard := range ksPartition.ShardReferences { keyspaceShards[keyspaceShard{ keyspace: keyspace, shard: shard.Name, }] = true } } mu.Unlock() }(ksName) } wg.Wait() if errRecorder.HasErrors() { return nil, errRecorder.Error() } return keyspaceShards, nil }
// NewShardConn creates a new ShardConn. It creates a Balancer using // serv, cell, keyspace, tabletType and retryDelay. retryCount is the max // number of retries before a ShardConn returns an error on an operation. func NewShardConn(ctx context.Context, serv topo.SrvTopoServer, cell, keyspace, shard string, tabletType topodatapb.TabletType, retryDelay time.Duration, retryCount int, connTimeoutTotal, connTimeoutPerConn, connLife time.Duration, tabletConnectTimings *stats.MultiTimings) *ShardConn { getAddresses := func() (*topodatapb.EndPoints, error) { endpoints, _, err := serv.GetEndPoints(ctx, cell, keyspace, shard, tabletType) if err != nil { return nil, vterrors.NewVitessError( vtrpcpb.ErrorCode_INTERNAL_ERROR, err, "endpoints fetch error: %v", err, ) } return endpoints, nil } blc := NewBalancer(getAddresses, retryDelay) var ticker *timer.RandTicker if tabletType != topodatapb.TabletType_MASTER { ticker = timer.NewRandTicker(connLife, connLife/2) } sdc := &ShardConn{ keyspace: keyspace, shard: shard, tabletType: tabletType, retryDelay: retryDelay, retryCount: retryCount, connTimeoutTotal: connTimeoutTotal, connTimeoutPerConn: connTimeoutPerConn, connLife: connLife, balancer: blc, ticker: ticker, consolidator: sync2.NewConsolidator(), connectTimings: tabletConnectTimings, } if ticker != nil { go func() { for range ticker.C { sdc.closeCurrent() } }() } return sdc }