// This maps a list of keyranges to shard names. func resolveKeyRangeToShards(topoServer SrvTopoServer, cell, keyspace string, tabletType topo.TabletType, kr key.KeyRange) ([]string, error) { srvKeyspace, err := topoServer.GetSrvKeyspace(cell, keyspace) if err != nil { return nil, fmt.Errorf("Error in reading the keyspace %v", err) } tabletTypePartition, ok := srvKeyspace.Partitions[tabletType] if !ok { return nil, fmt.Errorf("No shards available for tablet type '%v' in keyspace '%v'", tabletType, keyspace) } topo.SrvShardArray(tabletTypePartition.Shards).Sort() shards := make([]string, 0, 1) if !kr.IsPartial() { for j := 0; j < len(tabletTypePartition.Shards); j++ { shards = append(shards, tabletTypePartition.Shards[j].ShardName()) } return shards, nil } for j := 0; j < len(tabletTypePartition.Shards); j++ { shard := tabletTypePartition.Shards[j] if key.KeyRangesIntersect(kr, shard.KeyRange) { shards = append(shards, shard.ShardName()) } if kr.End != key.MaxKey && kr.End < shard.KeyRange.Start { break } } return shards, nil }
// CreateShard creates a new shard and tries to fill in the right information. func CreateShard(ts Server, keyspace, shard string) error { name, keyRange, err := ValidateShardName(shard) if err != nil { return err } s := &Shard{KeyRange: keyRange} // start the shard with all serving types. If it overlaps with // other shards for some serving types, remove them. servingTypes := map[TabletType]bool{ TYPE_MASTER: true, TYPE_REPLICA: true, TYPE_RDONLY: true, } sis, err := FindAllShardsInKeyspace(ts, keyspace) if err != nil && err != ErrNoNode { return err } for _, si := range sis { if key.KeyRangesIntersect(si.KeyRange, keyRange) { for _, t := range si.ServedTypes { delete(servingTypes, t) } } } s.ServedTypes = make([]TabletType, 0, len(servingTypes)) for st := range servingTypes { s.ServedTypes = append(s.ServedTypes, st) } return ts.CreateShard(keyspace, name, s) }
// CreateShard creates a new shard and tries to fill in the right information. func CreateShard(ts Server, keyspace, shard string) error { name, keyRange, err := ValidateShardName(shard) if err != nil { return err } // start the shard with all serving types. If it overlaps with // other shards for some serving types, remove them. s := &Shard{ KeyRange: keyRange, ServedTypesMap: map[TabletType]*ShardServedType{ TYPE_MASTER: &ShardServedType{}, TYPE_REPLICA: &ShardServedType{}, TYPE_RDONLY: &ShardServedType{}, }, } sis, err := FindAllShardsInKeyspace(ts, keyspace) if err != nil && err != ErrNoNode { return err } for _, si := range sis { if key.KeyRangesIntersect(si.KeyRange, keyRange) { for t, _ := range si.ServedTypesMap { delete(s.ServedTypesMap, t) } } } if len(s.ServedTypesMap) == 0 { s.ServedTypesMap = nil } return ts.CreateShard(keyspace, name, s) }
// intersect returns true if the provided shard intersect with any shard // in the destination array func intersect(si *topo.ShardInfo, allShards []*topo.ShardInfo) bool { for _, shard := range allShards { if key.KeyRangesIntersect(si.KeyRange, shard.KeyRange) { return true } } return false }
// findIntersectingShard will go through the map and take the first // entry in there that intersect with the source array, remove it from // the map, and return it func findIntersectingShard(shardMap map[string]*topo.ShardInfo, sourceArray []*topo.ShardInfo) *topo.ShardInfo { for name, si := range shardMap { for _, sourceShardInfo := range sourceArray { if key.KeyRangesIntersect(si.KeyRange, sourceShardInfo.KeyRange) { delete(shardMap, name) return si } } } return nil }
// This maps a list of keyranges to shard names. func resolveKeyRangeToShards(allShards []*topodatapb.ShardReference, matches map[string]bool, kr *topodatapb.KeyRange) { if !key.KeyRangeIsPartial(kr) { for _, shard := range allShards { matches[shard.Name] = true } return } for _, shard := range allShards { if key.KeyRangesIntersect(kr, shard.KeyRange) { matches[shard.Name] = true } } }
// CreateShard creates a new shard and tries to fill in the right information. // This should be called while holding the keyspace lock for the shard. // (call topotools.CreateShard to do that for you). // In unit tests (that are not parallel), this function can be called directly. func (ts Server) CreateShard(ctx context.Context, keyspace, shard string) error { name, keyRange, err := ValidateShardName(shard) if err != nil { return err } // start the shard with all serving types. If it overlaps with // other shards for some serving types, remove them. servedTypes := map[topodatapb.TabletType]bool{ topodatapb.TabletType_MASTER: true, topodatapb.TabletType_REPLICA: true, topodatapb.TabletType_RDONLY: true, } value := &topodatapb.Shard{ KeyRange: keyRange, } if IsShardUsingRangeBasedSharding(name) { // if we are using range-based sharding, we don't want // overlapping shards to all serve and confuse the clients. sis, err := ts.FindAllShardsInKeyspace(ctx, keyspace) if err != nil && err != ErrNoNode { return err } for _, si := range sis { if si.KeyRange == nil || key.KeyRangesIntersect(si.KeyRange, keyRange) { for _, st := range si.ServedTypes { delete(servedTypes, st.TabletType) } } } } for st := range servedTypes { value.ServedTypes = append(value.ServedTypes, &topodatapb.Shard_ServedType{ TabletType: st, }) } if err := ts.Impl.CreateShard(ctx, keyspace, name, value); err != nil { return err } event.Dispatch(&events.ShardChange{ KeyspaceName: keyspace, ShardName: shard, Shard: value, Status: "created", }) return nil }
// This maps a list of keyranges to shard names. func resolveKeyRangeToShards(allShards []*pb.ShardReference, kr *pb.KeyRange) ([]string, error) { shards := make([]string, 0, 1) if !key.KeyRangeIsPartial(kr) { for j := 0; j < len(allShards); j++ { shards = append(shards, allShards[j].Name) } return shards, nil } for j := 0; j < len(allShards); j++ { shard := allShards[j] if key.KeyRangesIntersect(kr, shard.KeyRange) { shards = append(shards, shard.Name) } } return shards, nil }
// This maps a list of keyranges to shard names. func resolveKeyRangeToShards(allShards []topo.SrvShard, kr key.KeyRange) ([]string, error) { shards := make([]string, 0, 1) if !kr.IsPartial() { for j := 0; j < len(allShards); j++ { shards = append(shards, allShards[j].ShardName()) } return shards, nil } for j := 0; j < len(allShards); j++ { shard := allShards[j] if key.KeyRangesIntersect(kr, shard.KeyRange) { shards = append(shards, shard.ShardName()) } } return shards, nil }
// This maps a list of keyranges to shard names. func resolveKeyRangeToShards(allShards []topo.SrvShard, kr key.KeyRange) ([]string, error) { shards := make([]string, 0, 1) topo.SrvShardArray(allShards).Sort() if !kr.IsPartial() { for j := 0; j < len(allShards); j++ { shards = append(shards, allShards[j].ShardName()) } return shards, nil } for j := 0; j < len(allShards); j++ { shard := allShards[j] if key.KeyRangesIntersect(kr, shard.KeyRange) { shards = append(shards, shard.ShardName()) } if kr.End != key.MaxKey && kr.End < shard.KeyRange.Start { break } } return shards, nil }
// CreateShard creates a new shard and tries to fill in the right information. // This should be called while holding the keyspace lock for the shard. // (call topotools.CreateShard to do that for you). // In unit tests (that are not parallel), this function can be called directly. func CreateShard(ctx context.Context, ts Server, keyspace, shard string) error { name, keyRange, err := ValidateShardName(shard) if err != nil { return err } // start the shard with all serving types. If it overlaps with // other shards for some serving types, remove them. s := &Shard{ KeyRange: keyRange, ServedTypesMap: map[TabletType]*ShardServedType{ TYPE_MASTER: &ShardServedType{}, TYPE_REPLICA: &ShardServedType{}, TYPE_RDONLY: &ShardServedType{}, }, } if IsShardUsingRangeBasedSharding(name) { // if we are using range-based sharding, we don't want // overlapping shards to all serve and confuse the clients. sis, err := FindAllShardsInKeyspace(ctx, ts, keyspace) if err != nil && err != ErrNoNode { return err } for _, si := range sis { if key.KeyRangesIntersect(si.KeyRange, keyRange) { for t := range si.ServedTypesMap { delete(s.ServedTypesMap, t) } } } if len(s.ServedTypesMap) == 0 { s.ServedTypesMap = nil } } return ts.CreateShard(ctx, keyspace, name, s) }
// getConn returns the right l2VTGateConn for a given keyspace / shard. func (lg *l2VTGateGateway) getConn(keyspace, shard string) (*l2VTGateConn, error) { lg.mu.RLock() defer lg.mu.RUnlock() canonical, kr, err := topo.ValidateShardName(shard) if err != nil { return nil, fmt.Errorf("invalid shard name: %v", shard) } for _, c := range lg.connMap[keyspace] { if canonical == c.shard { // Exact match (probably a non-sharded keyspace). return c, nil } if key.KeyRangesIntersect(kr, c.keyRange) { // There is overlap, we can just send to the destination. // FIXME(alainjobart) if canonical is not entirely covered by l2vtgate, // this is probably an error. We probably want key.KeyRangeIncludes(), NYI. return c, nil } } return nil, fmt.Errorf("no configured destination for %v/%v", keyspace, shard) }