func reportRegionError(e *errorpb.Error) { if e.GetNotLeader() != nil { regionErrorCounter.WithLabelValues("not_leader").Inc() } else if e.GetRegionNotFound() != nil { regionErrorCounter.WithLabelValues("region_not_found").Inc() } else if e.GetKeyNotInRegion() != nil { regionErrorCounter.WithLabelValues("key_not_in_region").Inc() } else if e.GetStaleEpoch() != nil { regionErrorCounter.WithLabelValues("stale_epoch").Inc() } else if e.GetServerIsBusy() != nil { regionErrorCounter.WithLabelValues("server_is_busy").Inc() } else { regionErrorCounter.WithLabelValues("unknown").Inc() } }
func (s *RegionRequestSender) onRegionError(ctx *RPCContext, regionErr *errorpb.Error) (retry bool, err error) { reportRegionError(regionErr) if notLeader := regionErr.GetNotLeader(); notLeader != nil { // Retry if error is `NotLeader`. log.Warnf("tikv reports `NotLeader`: %s, ctx: %s, retry later", notLeader, ctx.KVCtx) s.regionCache.UpdateLeader(ctx.Region, notLeader.GetLeader().GetStoreId()) if notLeader.GetLeader() == nil { err = s.bo.Backoff(boRegionMiss, errors.Errorf("not leader: %v, ctx: %s", notLeader, ctx.KVCtx)) if err != nil { return false, errors.Trace(err) } } return true, nil } if staleEpoch := regionErr.GetStaleEpoch(); staleEpoch != nil { log.Warnf("tikv reports `StaleEpoch`, ctx: %s, retry later", ctx.KVCtx) err = s.regionCache.OnRegionStale(ctx, staleEpoch.NewRegions) return false, errors.Trace(err) } if regionErr.GetServerIsBusy() != nil { log.Warnf("tikv reports `ServerIsBusy`, ctx: %s, retry later", ctx.KVCtx) err = s.bo.Backoff(boServerBusy, errors.Errorf("server is busy, ctx: %s", ctx.KVCtx)) if err != nil { return false, errors.Trace(err) } return true, nil } if regionErr.GetStaleCommand() != nil { log.Warnf("tikv reports `StaleCommand`, ctx: %s", ctx.KVCtx) return true, nil } // For other errors, we only drop cache here. // Because caller may need to re-split the request. log.Warnf("tikv reports region error: %s, ctx: %s", regionErr, ctx.KVCtx) s.regionCache.DropRegion(ctx.Region) return false, nil }