// Adds a new region to our regions cache. func (c *Client) discoverRegion(ctx context.Context, metaRow *pb.GetResponse) (*region.Client, *regioninfo.Info, error) { if metaRow.Result == nil { return nil, nil, errors.New("table not found") } var host string var port uint16 var reg *regioninfo.Info for _, cell := range metaRow.Result.Cell { switch string(cell.Qualifier) { case "regioninfo": var err error reg, err = regioninfo.InfoFromCell(cell) if err != nil { return nil, nil, err } case "server": value := cell.Value if len(value) == 0 { continue // Empty during NSRE. } colon := bytes.IndexByte(value, ':') if colon < 1 { // Colon can't be at the beginning. return nil, nil, fmt.Errorf("broken meta: no colon found in info:server %q", cell) } host = string(value[:colon]) portU64, err := strconv.ParseUint(string(value[colon+1:]), 10, 16) if err != nil { return nil, nil, err } port = uint16(portU64) default: // Other kinds of qualifiers: ignore them. // TODO: If this is the parent of a split region, there are two other // KVs that could be useful: `info:splitA' and `info:splitB'. // Need to investigate whether we can use those as a hint to update our // regions_cache with the daughter regions of the split. } } var res newRegResult ret := make(chan newRegResult) go newRegion(ret, host, port, c.rpcQueueSize, c.flushInterval) select { case res = <-ret: case <-ctx.Done(): return nil, nil, ErrDeadline } if res.Err != nil { return nil, nil, res.Err } c.addRegionToCache(reg, res.Client) return res.Client, reg, nil }
// parseMetaTableResponse parses the contents of a row from the meta table. // It's guaranteed to return a region info and a host/port OR return an error. func (c *Client) parseMetaTableResponse(metaRow *pb.GetResponse) ( *regioninfo.Info, string, uint16, error) { var reg *regioninfo.Info var host string var port uint16 for _, cell := range metaRow.Result.Cell { switch string(cell.Qualifier) { case "regioninfo": var err error reg, err = regioninfo.InfoFromCell(cell) if err != nil { return nil, "", 0, err } case "server": value := cell.Value if len(value) == 0 { continue // Empty during NSRE. } colon := bytes.IndexByte(value, ':') if colon < 1 { // Colon can't be at the beginning. return nil, "", 0, fmt.Errorf("broken meta: no colon found in info:server %q", cell) } host = string(value[:colon]) portU64, err := strconv.ParseUint(string(value[colon+1:]), 10, 16) if err != nil { return nil, "", 0, err } port = uint16(portU64) default: // Other kinds of qualifiers: ignore them. // TODO: If this is the parent of a split region, there are two other // KVs that could be useful: `info:splitA' and `info:splitB'. // Need to investigate whether we can use those as a hint to update our // regions_cache with the daughter regions of the split. } } if reg == nil { // There was no regioninfo in the row in meta, this is really not // expected. err := fmt.Errorf("Meta seems to be broken, there was no regioninfo in %s", metaRow) log.Error(err.Error()) return nil, "", 0, err } else if port == 0 { // Either both `host' and `port' are set, or both aren't. return nil, "", 0, fmt.Errorf("Meta doesn't have a server location in %s", metaRow) } return reg, host, port, nil }