1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.tikv.common.region;
19
20 import com.google.protobuf.ByteString;
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.List;
24 import java.util.Objects;
25 import java.util.Set;
26 import java.util.stream.Collectors;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.tikv.common.TiConfiguration;
30 import org.tikv.common.codec.KeyUtils;
31 import org.tikv.common.exception.TiClientInternalException;
32 import org.tikv.common.key.Key;
33 import org.tikv.common.replica.ReplicaSelector;
34 import org.tikv.common.util.FastByteComparisons;
35 import org.tikv.common.util.KeyRangeUtils;
36 import org.tikv.kvproto.Kvrpcpb;
37 import org.tikv.kvproto.Kvrpcpb.IsolationLevel;
38 import org.tikv.kvproto.Metapb;
39 import org.tikv.kvproto.Metapb.Peer;
40 import org.tikv.kvproto.Metapb.Region;
41
42 public class TiRegion implements Serializable {
43
44 private static final Logger logger = LoggerFactory.getLogger(TiRegion.class);
45
46 private final Region meta;
47 private final IsolationLevel isolationLevel;
48 private final Kvrpcpb.CommandPri commandPri;
49 private final TiConfiguration conf;
50 private final Peer leader;
51 private final ReplicaSelector replicaSelector;
52 private final List<Peer> replicaList;
53 private int replicaIdx;
54 private final List<Peer> peers;
55 private final List<TiStore> stores;
56
57 public TiRegion(
58 TiConfiguration conf, Region meta, Peer leader, List<Peer> peers, List<TiStore> stores) {
59 this.conf = Objects.requireNonNull(conf, "conf is null");
60 this.meta = Objects.requireNonNull(meta, "meta is null");
61 this.isolationLevel = conf.getIsolationLevel();
62 this.commandPri = conf.getCommandPriority();
63 this.peers = peers;
64 this.stores = stores;
65 this.replicaSelector = conf.getReplicaSelector();
66 if (leader == null || leader.getId() == 0) {
67 if (meta.getPeersCount() == 0) {
68 throw new TiClientInternalException("Empty peer list for region " + meta.getId());
69 }
70
71 this.leader = meta.getPeers(0);
72 } else {
73 this.leader = leader;
74 }
75
76
77 replicaList =
78 replicaSelector
79 .select(new org.tikv.common.replica.Region(meta, this.leader, peers, stores))
80 .stream()
81 .map(org.tikv.common.replica.Store::getPeer)
82 .collect(Collectors.toList());
83 replicaIdx = 0;
84 }
85
86 public TiConfiguration getConf() {
87 return conf;
88 }
89
90 public Peer getLeader() {
91 return leader;
92 }
93
94 public List<Peer> getFollowerList() {
95 List<Peer> peers = new ArrayList<>();
96 for (Peer peer : getMeta().getPeersList()) {
97 if (!peer.equals(this.leader)) {
98 if (peer.getRole().equals(Metapb.PeerRole.Voter)) {
99 peers.add(peer);
100 }
101 }
102 }
103 return peers;
104 }
105
106 public List<Peer> getLearnerList() {
107 List<Peer> peers = new ArrayList<>();
108 for (Peer peer : getMeta().getPeersList()) {
109 if (peer.getRole().equals(Metapb.PeerRole.Learner)) {
110 peers.add(peer);
111 }
112 }
113 return peers;
114 }
115
116 public List<Peer> getPeersList() {
117 return getMeta().getPeersList();
118 }
119
120 public Peer getCurrentReplica() {
121 return replicaList.get(replicaIdx);
122 }
123
124 public Peer getNextReplica() {
125 replicaIdx = (replicaIdx + 1) % replicaList.size();
126 return getCurrentReplica();
127 }
128
129 public void setReplicaIdx(int idx) {
130 replicaIdx = idx;
131 }
132
133 public List<Peer> getReplicaList() {
134 return replicaList;
135 }
136
137 private boolean isLeader(Peer peer) {
138 return getLeader().equals(peer);
139 }
140
141 public long getId() {
142 return this.meta.getId();
143 }
144
145 public ByteString getStartKey() {
146 return meta.getStartKey();
147 }
148
149 public boolean contains(Key key) {
150 return KeyRangeUtils.makeRange(this.getStartKey(), this.getEndKey()).contains(key);
151 }
152
153 public ByteString getEndKey() {
154 return meta.getEndKey();
155 }
156
157 public Kvrpcpb.Context getLeaderContext() {
158 return getContext(this.leader, java.util.Collections.emptySet(), false);
159 }
160
161 public Kvrpcpb.Context getReplicaContext(Set<Long> resolvedLocks, TiStoreType storeType) {
162 Peer currentPeer = getCurrentReplica();
163 boolean replicaRead = !isLeader(currentPeer) && TiStoreType.TiKV.equals(storeType);
164 return getContext(currentPeer, resolvedLocks, replicaRead);
165 }
166
167 public Kvrpcpb.Context getReplicaContext(Peer currentPeer, Set<Long> resolvedLocks) {
168 return getContext(currentPeer, resolvedLocks, false);
169 }
170
171 public Kvrpcpb.Context getReplicaContext(Peer currentPeer) {
172 return getContext(currentPeer, java.util.Collections.emptySet(), false);
173 }
174
175 private Kvrpcpb.Context getContext(
176 Peer currentPeer, Set<Long> resolvedLocks, boolean replicaRead) {
177
178 Kvrpcpb.Context.Builder builder = Kvrpcpb.Context.newBuilder();
179 builder
180 .setApiVersion(conf.getApiVersion().toPb())
181 .setIsolationLevel(this.isolationLevel)
182 .setPriority(this.commandPri)
183 .setRegionId(meta.getId())
184 .setPeer(currentPeer)
185 .setReplicaRead(replicaRead)
186 .setRegionEpoch(this.meta.getRegionEpoch());
187 builder.addAllResolvedLocks(resolvedLocks);
188 return builder.build();
189 }
190
191
192 public RegionVerID getVerID() {
193 return new RegionVerID(
194 meta.getId(), meta.getRegionEpoch().getConfVer(), meta.getRegionEpoch().getVersion());
195 }
196
197
198
199
200
201
202
203
204 public TiRegion switchPeer(long leaderStoreID) {
205 List<Peer> peers = meta.getPeersList();
206 for (Peer p : peers) {
207 if (p.getStoreId() == leaderStoreID) {
208 return new TiRegion(this.conf, this.meta, p, peers, this.stores);
209 }
210 }
211 return null;
212 }
213
214 public boolean isMoreThan(ByteString key) {
215 return FastByteComparisons.compareTo(
216 meta.getStartKey().toByteArray(),
217 0,
218 meta.getStartKey().size(),
219 key.toByteArray(),
220 0,
221 key.size())
222 > 0;
223 }
224
225 public boolean isLessThan(ByteString key) {
226 return FastByteComparisons.compareTo(
227 meta.getEndKey().toByteArray(),
228 0,
229 meta.getEndKey().size(),
230 key.toByteArray(),
231 0,
232 key.size())
233 <= 0;
234 }
235
236 public boolean contains(ByteString key) {
237 return !isMoreThan(key) && !isLessThan(key);
238 }
239
240 public boolean isValid() {
241 return leader != null && meta != null;
242 }
243
244 public Metapb.RegionEpoch getRegionEpoch() {
245 return this.meta.getRegionEpoch();
246 }
247
248 public Region getMeta() {
249 return meta;
250 }
251
252 @Override
253 public boolean equals(final Object another) {
254 if (!(another instanceof TiRegion)) {
255 return false;
256 }
257 TiRegion anotherRegion = ((TiRegion) another);
258 return anotherRegion.meta.equals(this.meta)
259 && anotherRegion.leader.equals(this.leader)
260 && anotherRegion.commandPri.equals(this.commandPri)
261 && anotherRegion.isolationLevel.equals(this.isolationLevel);
262 }
263
264 @Override
265 public int hashCode() {
266 return Objects.hash(meta, leader, isolationLevel, commandPri);
267 }
268
269 @Override
270 public String toString() {
271 return String.format(
272 "{Region[%d] ConfVer[%d] Version[%d] Store[%d] KeyRange[%s]:[%s]}",
273 getId(),
274 getRegionEpoch().getConfVer(),
275 getRegionEpoch().getVersion(),
276 getLeader().getStoreId(),
277 KeyUtils.formatBytesUTF8(getStartKey()),
278 KeyUtils.formatBytesUTF8(getEndKey()));
279 }
280
281 public class RegionVerID {
282
283 final long id;
284 final long confVer;
285 final long ver;
286
287 RegionVerID(long id, long confVer, long ver) {
288 this.id = id;
289 this.confVer = confVer;
290 this.ver = ver;
291 }
292
293 public long getId() {
294 return id;
295 }
296
297 public long getConfVer() {
298 return confVer;
299 }
300
301 public long getVer() {
302 return ver;
303 }
304
305 @Override
306 public boolean equals(Object other) {
307 if (this == other) {
308 return true;
309 }
310 if (!(other instanceof RegionVerID)) {
311 return false;
312 }
313
314 RegionVerID that = (RegionVerID) other;
315 return id == that.id && confVer == that.confVer && ver == that.ver;
316 }
317
318 @Override
319 public int hashCode() {
320 int hash = Long.hashCode(id);
321 hash = hash * 31 + Long.hashCode(confVer);
322 hash = hash * 31 + Long.hashCode(ver);
323 return hash;
324 }
325 }
326 }