func (krc *keyRegionCache) put(reg hrpc.RegionInfo) []hrpc.RegionInfo { krc.m.Lock() defer krc.m.Unlock() // Remove all the entries that are overlap with the range of the new region. os := krc.getOverlaps(reg) for _, o := range os { krc.regions.Delete(o.Name()) } krc.regions.Put(reg.Name(), func(interface{}, bool) (interface{}, bool) { return reg, true }) return os }
func (krc *keyRegionCache) getOverlaps(reg hrpc.RegionInfo) []hrpc.RegionInfo { var overlaps []hrpc.RegionInfo var v interface{} var err error // deal with empty tree in the beginning so that we don't have to check // EOF errors for enum later if krc.regions.Len() == 0 { return overlaps } enum, ok := krc.regions.Seek(reg.Name()) if !ok { // need to check if there are overlaps before what we found _, _, err = enum.Prev() if err == io.EOF { // we are in the end of tree, get last entry _, v = krc.regions.Last() currReg := v.(hrpc.RegionInfo) if isRegionOverlap(currReg, reg) { return append(overlaps, currReg) } } else { _, v, err = enum.Next() if err == io.EOF { // we are before the beginning of the tree now, get new enum enum.Close() enum, err = krc.regions.SeekFirst() } else { // otherwise, check for overlap before us currReg := v.(hrpc.RegionInfo) if isRegionOverlap(currReg, reg) { overlaps = append(overlaps, currReg) } } } } // now append all regions that overlap until the end of the tree // or until they don't overlap _, v, err = enum.Next() for err == nil && isRegionOverlap(v.(hrpc.RegionInfo), reg) { overlaps = append(overlaps, v.(hrpc.RegionInfo)) _, v, err = enum.Next() } enum.Close() return overlaps }
func (c *client) establishRegion(originalReg hrpc.RegionInfo, host string, port uint16) { var err error reg := originalReg backoff := backoffStart for { ctx, _ := context.WithTimeout(context.Background(), regionLookupTimeout) if port != 0 && err == nil { // If this isn't the admin or meta region, check if a client // for this host/port already exists if c.clientType != adminClient && reg != c.metaRegionInfo { client := c.clients.checkForClient(host, port) if client != nil { // There's already a client, add it to the // region and mark it as available. reg.SetClient(client) c.clients.put(client, reg) originalReg.MarkAvailable() return } } // Make this channel buffered so that if we time out we don't // block the newRegion goroutine forever. ch := make(chan newRegResult, 1) var clientType region.ClientType if c.clientType == standardClient { clientType = region.RegionClient } else { clientType = region.MasterClient } go newRegionClient(ctx, ch, clientType, host, port, c.rpcQueueSize, c.flushInterval) select { case res := <-ch: if res.Err == nil { reg.SetClient(res.Client) if c.clientType != adminClient && reg != c.metaRegionInfo { // put will set region client so that as soon as we add // it to the key->region mapping, concurrent readers are // able to find the client c.clients.put(res.Client, reg) if reg != originalReg { removed := c.regions.put(reg) for _, r := range removed { c.clients.del(r) } } } originalReg.MarkAvailable() return } else { err = res.Err } case <-ctx.Done(): err = ErrDeadline } } if err != nil { if err == TableNotFound { c.regions.del(originalReg.Name()) originalReg.MarkAvailable() return } // This will be hit if either there was an error locating the // region, or the region was located but there was an error // connecting to it. backoff, err = sleepAndIncreaseBackoff(ctx, backoff) if err != nil { continue } } if c.clientType == adminClient { host, port, err = c.zkLookup(ctx, c.master) } else if reg == c.metaRegionInfo { host, port, err = c.zkLookup(ctx, c.meta) } else { reg, host, port, err = c.locateRegion(ctx, originalReg.Table(), originalReg.StartKey()) } } }