Skip to content

Commit 9dc2771

Browse files
fix Region Exception occurred EpochNotMatch (#305)
1 parent ae0eae5 commit 9dc2771

File tree

4 files changed

+95
-5
lines changed

4 files changed

+95
-5
lines changed

src/main/java/org/tikv/common/operation/RegionErrorHandler.java

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,21 @@
33
import com.google.protobuf.ByteString;
44
import io.grpc.Status;
55
import io.grpc.StatusRuntimeException;
6+
import java.util.ArrayList;
7+
import java.util.List;
68
import java.util.function.Function;
79
import org.slf4j.Logger;
810
import org.slf4j.LoggerFactory;
911
import org.tikv.common.codec.KeyUtils;
1012
import org.tikv.common.exception.GrpcException;
13+
import org.tikv.common.exception.TiKVException;
1114
import org.tikv.common.region.RegionErrorReceiver;
1215
import org.tikv.common.region.RegionManager;
1316
import org.tikv.common.region.TiRegion;
1417
import org.tikv.common.util.BackOffFunction;
1518
import org.tikv.common.util.BackOffer;
1619
import org.tikv.kvproto.Errorpb;
20+
import org.tikv.kvproto.Metapb;
1721

1822
public class RegionErrorHandler<RespT> implements ErrorHandler<RespT> {
1923
private static final Logger logger = LoggerFactory.getLogger(RegionErrorHandler.class);
@@ -115,11 +119,11 @@ public boolean handleRegionError(BackOffer backOffer, Errorpb.Error error) {
115119
// throwing it out.
116120
return false;
117121
} else if (error.hasEpochNotMatch()) {
118-
// this error is reported from raftstore:
119-
// region has outdated version,please try later.
120-
logger.warn(String.format("Stale Epoch encountered for region [%s]", recv.getRegion()));
121-
this.regionManager.onRegionStale(recv.getRegion());
122-
return false;
122+
logger.warn(
123+
String.format(
124+
"tikv reports `EpochNotMatch` retry later, region: %s, EpochNotMatch: %s",
125+
recv.getRegion(), error.getEpochNotMatch()));
126+
return onRegionEpochNotMatch(backOffer, error.getEpochNotMatch().getCurrentRegionsList());
123127
} else if (error.hasServerIsBusy()) {
124128
// this error is reported from kv:
125129
// will occur when write pressure is high. Please try later.
@@ -171,6 +175,54 @@ public boolean handleRegionError(BackOffer backOffer, Errorpb.Error error) {
171175
return false;
172176
}
173177

178+
// ref: https://github.com/tikv/client-go/blob/tidb-5.2/internal/locate/region_request.go#L985
179+
// OnRegionEpochNotMatch removes the old region and inserts new regions into the cache.
180+
// It returns whether retries the request because it's possible the region epoch is ahead of
181+
// TiKV's due to slow appling.
182+
private boolean onRegionEpochNotMatch(BackOffer backOffer, List<Metapb.Region> currentRegions) {
183+
if (currentRegions.size() == 0) {
184+
this.regionManager.onRegionStale(recv.getRegion());
185+
return false;
186+
}
187+
188+
// Find whether the region epoch in `ctx` is ahead of TiKV's. If so, backoff.
189+
for (Metapb.Region meta : currentRegions) {
190+
if (meta.getId() == recv.getRegion().getId()
191+
&& (meta.getRegionEpoch().getConfVer() < recv.getRegion().getVerID().getConfVer()
192+
|| meta.getRegionEpoch().getVersion() < recv.getRegion().getVerID().getVer())) {
193+
String errorMsg =
194+
String.format(
195+
"region epoch is ahead of tikv, region: %s, currentRegions: %s",
196+
recv.getRegion(), currentRegions);
197+
logger.info(errorMsg);
198+
backOffer.doBackOff(
199+
BackOffFunction.BackOffFuncType.BoRegionMiss, new TiKVException(errorMsg));
200+
return true;
201+
}
202+
}
203+
204+
boolean needInvalidateOld = true;
205+
List<TiRegion> newRegions = new ArrayList<>(currentRegions.size());
206+
// If the region epoch is not ahead of TiKV's, replace region meta in region cache.
207+
for (Metapb.Region meta : currentRegions) {
208+
TiRegion region = regionManager.createRegion(meta, backOffer);
209+
newRegions.add(region);
210+
if (recv.getRegion().getVerID() == region.getVerID()) {
211+
needInvalidateOld = false;
212+
}
213+
}
214+
215+
if (needInvalidateOld) {
216+
this.regionManager.onRegionStale(recv.getRegion());
217+
}
218+
219+
for (TiRegion region : newRegions) {
220+
regionManager.insertRegionToCache(region);
221+
}
222+
223+
return false;
224+
}
225+
174226
@Override
175227
public boolean handleRequestError(BackOffer backOffer, Exception e) {
176228
if (recv.onStoreUnreachable()) {

src/main/java/org/tikv/common/region/RegionCache.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,18 @@ public synchronized void invalidateRegion(TiRegion region) {
9292
}
9393
}
9494

95+
public synchronized void insertRegionToCache(TiRegion region) {
96+
try {
97+
TiRegion oldRegion = regionCache.get(region.getId());
98+
if (oldRegion != null) {
99+
keyToRegionIdCache.remove(makeRange(oldRegion.getStartKey(), oldRegion.getEndKey()));
100+
}
101+
regionCache.put(region.getId(), region);
102+
keyToRegionIdCache.put(makeRange(region.getStartKey(), region.getEndKey()), region.getId());
103+
} catch (Exception ignore) {
104+
}
105+
}
106+
95107
public synchronized boolean updateRegion(TiRegion expected, TiRegion region) {
96108
try {
97109
if (logger.isDebugEnabled()) {

src/main/java/org/tikv/common/region/RegionManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ public Pair<TiRegion, TiStore> getRegionStorePairByKey(
181181
return Pair.create(region, store);
182182
}
183183

184+
public TiRegion createRegion(Metapb.Region region, BackOffer backOffer) {
185+
List<Metapb.Peer> peers = region.getPeersList();
186+
List<TiStore> stores = getRegionStore(peers, backOffer);
187+
return new TiRegion(conf, region, null, peers, stores);
188+
}
189+
184190
private TiRegion createRegion(Metapb.Region region, Metapb.Peer leader, BackOffer backOffer) {
185191
List<Metapb.Peer> peers = region.getPeersList();
186192
List<TiStore> stores = getRegionStore(peers, backOffer);
@@ -262,6 +268,10 @@ public void invalidateRegion(TiRegion region) {
262268
cache.invalidateRegion(region);
263269
}
264270

271+
public void insertRegionToCache(TiRegion region) {
272+
cache.insertRegionToCache(region);
273+
}
274+
265275
private BackOffer defaultBackOff() {
266276
return ConcreteBackOffer.newCustomBackOff(conf.getRawKVDefaultBackoffInMS());
267277
}

src/main/java/org/tikv/common/region/TiRegion.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ public TiRegion(
8282
replicaIdx = 0;
8383
}
8484

85+
public TiConfiguration getConf() {
86+
return conf;
87+
}
88+
8589
public Peer getLeader() {
8690
return leader;
8791
}
@@ -271,6 +275,18 @@ public class RegionVerID {
271275
this.ver = ver;
272276
}
273277

278+
public long getId() {
279+
return id;
280+
}
281+
282+
public long getConfVer() {
283+
return confVer;
284+
}
285+
286+
public long getVer() {
287+
return ver;
288+
}
289+
274290
@Override
275291
public boolean equals(Object other) {
276292
if (this == other) {

0 commit comments

Comments
 (0)