1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.hadoop.hbase.client;
20
21 import static org.apache.hadoop.hbase.client.ConnectionUtils.createCloseRowBefore;
22 import static org.apache.hadoop.hbase.client.ConnectionUtils.isEmptyStartRow;
23
24 import java.io.IOException;
25 import java.io.InterruptedIOException;
26 import java.util.ArrayList;
27 import java.util.List;
28
29 import org.apache.hadoop.hbase.DoNotRetryIOException;
30 import org.apache.hadoop.hbase.HConstants;
31 import org.apache.hadoop.hbase.HRegionLocation;
32 import org.apache.hadoop.hbase.RegionLocations;
33 import org.apache.hadoop.hbase.TableName;
34 import org.apache.hadoop.hbase.classification.InterfaceAudience;
35 import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
36 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
37 import org.apache.hadoop.hbase.util.Bytes;
38
39
40
41
42
43 @InterfaceAudience.Private
44 public class ReversedScannerCallable extends ScannerCallable {
45
46
47
48
49
50
51
52
53
54 public ReversedScannerCallable(ClusterConnection connection, TableName tableName, Scan scan,
55 ScanMetrics scanMetrics, RpcControllerFactory rpcFactory) {
56 super(connection, tableName, scan, scanMetrics, rpcFactory);
57 }
58
59
60
61
62
63
64
65
66
67
68 public ReversedScannerCallable(ClusterConnection connection, TableName tableName, Scan scan,
69 ScanMetrics scanMetrics, RpcControllerFactory rpcFactory, int replicaId) {
70 super(connection, tableName, scan, scanMetrics, rpcFactory, replicaId);
71 }
72
73
74
75
76
77 @Override
78 public void prepare(boolean reload) throws IOException {
79 if (Thread.interrupted()) {
80 throw new InterruptedIOException();
81 }
82 if (!instantiated || reload) {
83
84
85
86 if (scan.includeStartRow() && !isEmptyStartRow(getRow())) {
87
88 RegionLocations rl = RpcRetryingCallerWithReadReplicas.getRegionLocations(!reload, id,
89 getConnection(), getTableName(), getRow());
90 this.location = id < rl.size() ? rl.getRegionLocation(id) : null;
91 if (location == null || location.getServerName() == null) {
92 throw new IOException("Failed to find location, tableName="
93 + tableName + ", row=" + Bytes.toStringBinary(row) + ", reload="
94 + reload);
95 }
96 } else {
97
98
99 byte[] locateStartRow = createCloseRowBefore(getRow());
100 List<HRegionLocation> locatedRegions = locateRegionsInRange(
101 locateStartRow, row, reload);
102 if (locatedRegions.isEmpty()) {
103 throw new DoNotRetryIOException(
104 "Does hbase:meta exist hole? Couldn't get regions for the range from "
105 + Bytes.toStringBinary(locateStartRow) + " to "
106 + Bytes.toStringBinary(row));
107 }
108 this.location = locatedRegions.get(locatedRegions.size() - 1);
109 }
110 setStub(getConnection().getClient(getLocation().getServerName()));
111 checkIfRegionServerIsRemote();
112 instantiated = true;
113 }
114
115
116
117
118 if (reload && this.scanMetrics != null) {
119 this.scanMetrics.countOfRPCRetries.incrementAndGet();
120 if (isRegionServerRemote) {
121 this.scanMetrics.countOfRemoteRPCRetries.incrementAndGet();
122 }
123 }
124 }
125
126
127
128
129
130
131
132
133
134
135 @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="NP_NULL_ON_SOME_PATH",
136 justification="I thought I'd fixed it but FB still complains; see below")
137 private List<HRegionLocation> locateRegionsInRange(byte[] startKey,
138 byte[] endKey, boolean reload) throws IOException {
139 final boolean endKeyIsEndOfTable = Bytes.equals(endKey,
140 HConstants.EMPTY_END_ROW);
141 if ((Bytes.compareTo(startKey, endKey) > 0) && !endKeyIsEndOfTable) {
142 throw new IllegalArgumentException("Invalid range: "
143 + Bytes.toStringBinary(startKey) + " > "
144 + Bytes.toStringBinary(endKey));
145 }
146 List<HRegionLocation> regionList = new ArrayList<HRegionLocation>();
147 byte[] currentKey = startKey;
148 do {
149 RegionLocations rl = RpcRetryingCallerWithReadReplicas.getRegionLocations(!reload, id,
150 getConnection(), getTableName(), currentKey);
151 HRegionLocation regionLocation = id < rl.size() ? rl.getRegionLocation(id) : null;
152 if (regionLocation != null && regionLocation.getRegionInfo().containsRow(currentKey)) {
153 regionList.add(regionLocation);
154 } else {
155
156 throw new DoNotRetryIOException("Does hbase:meta exist hole? Locating row "
157 + Bytes.toStringBinary(currentKey) + " returns incorrect region "
158 + (regionLocation != null? regionLocation.getRegionInfo(): null));
159 }
160 currentKey = regionLocation.getRegionInfo().getEndKey();
161 } while (!Bytes.equals(currentKey, HConstants.EMPTY_END_ROW)
162 && (endKeyIsEndOfTable || Bytes.compareTo(currentKey, endKey) < 0));
163 return regionList;
164 }
165
166 @Override
167 public ScannerCallable getScannerCallableForReplica(int id) {
168 ReversedScannerCallable r = new ReversedScannerCallable(getConnection(), getTableName(),
169 this.getScan(), this.scanMetrics, controllerFactory, id);
170 r.setCaching(this.getCaching());
171 return r;
172 }
173 }