1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.client;
21
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.hbase.classification.InterfaceAudience;
26 import org.apache.hadoop.hbase.classification.InterfaceStability;
27 import org.apache.hadoop.conf.Configuration;
28 import org.apache.hadoop.hbase.Cell;
29 import org.apache.hadoop.hbase.HConstants;
30 import org.apache.hadoop.hbase.KeyValueUtil;
31 import org.apache.hadoop.hbase.TableName;
32 import org.apache.hadoop.hbase.client.ClientSmallScanner.SmallScannerCallableFactory;
33 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
34 import org.apache.hadoop.hbase.util.Bytes;
35
36 import com.google.common.annotations.VisibleForTesting;
37
38 import java.io.IOException;
39
40
41
42
43
44
45
46
47 @InterfaceAudience.Public
48 @InterfaceStability.Evolving
49 public class ClientSmallReversedScanner extends ReversedClientScanner {
50 private static final Log LOG = LogFactory.getLog(ClientSmallReversedScanner.class);
51 private RegionServerCallable<Result[]> smallScanCallable = null;
52 private SmallScannerCallableFactory callableFactory;
53
54
55
56
57
58
59
60
61
62
63
64 public ClientSmallReversedScanner(Configuration conf, Scan scan, TableName tableName,
65 HConnection connection) throws IOException {
66 this(conf, scan, tableName, connection, new SmallScannerCallableFactory());
67 }
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86 @VisibleForTesting
87 ClientSmallReversedScanner(Configuration conf, Scan scan, TableName tableName,
88 HConnection connection, SmallScannerCallableFactory callableFactory) throws IOException {
89 super(conf, scan, tableName, connection);
90 this.callableFactory = callableFactory;
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105 private boolean nextScanner(int nbRows, final boolean done,
106 boolean currentRegionDone) throws IOException {
107
108 byte[] localStartKey;
109 int cacheNum = nbRows;
110 boolean regionChanged = true;
111
112 if (this.currentRegion != null && currentRegionDone) {
113 byte[] startKey = this.currentRegion.getStartKey();
114 if (startKey == null
115 || Bytes.equals(startKey, HConstants.EMPTY_BYTE_ARRAY)
116 || checkScanStopRow(startKey) || done) {
117 close();
118 if (LOG.isDebugEnabled()) {
119 LOG.debug("Finished with small scan at " + this.currentRegion);
120 }
121 return false;
122 }
123
124 localStartKey = createClosestRowBefore(startKey);
125 if (LOG.isDebugEnabled()) {
126 LOG.debug("Finished with region " + this.currentRegion);
127 }
128 } else if (this.lastResult != null) {
129 regionChanged = false;
130 localStartKey = createClosestRowBefore(lastResult.getRow());
131 } else {
132 localStartKey = this.scan.getStartRow();
133 }
134
135 if (LOG.isTraceEnabled()) {
136 LOG.trace("Advancing internal small scanner to startKey at '"
137 + Bytes.toStringBinary(localStartKey) + "'");
138 }
139
140 smallScanCallable = callableFactory.getCallable(
141 scan, getConnection(), getTable(), scanMetrics, localStartKey, cacheNum,
142 rpcControllerFactory);
143
144 if (this.scanMetrics != null && regionChanged) {
145 this.scanMetrics.countOfRegions.incrementAndGet();
146 }
147 return true;
148 }
149
150 @Override
151 public Result next() throws IOException {
152
153
154 if (cache.size() == 0 && this.closed) {
155 return null;
156 }
157 if (cache.size() == 0) {
158 loadCache();
159 }
160
161 if (cache.size() > 0) {
162 return cache.poll();
163 }
164
165
166 writeScanMetrics();
167 return null;
168 }
169
170 @Override
171 protected void loadCache() throws IOException {
172 Result[] values = null;
173 long remainingResultSize = maxScannerResultSize;
174 int countdown = this.caching;
175 boolean currentRegionDone = false;
176
177 while (remainingResultSize > 0 && countdown > 0
178 && nextScanner(countdown, values == null, currentRegionDone)) {
179
180
181
182 values = this.caller.callWithRetries(smallScanCallable, scannerTimeout);
183 this.currentRegion = smallScanCallable.getHRegionInfo();
184 long currentTime = System.currentTimeMillis();
185 if (this.scanMetrics != null) {
186 this.scanMetrics.sumOfMillisSecBetweenNexts.addAndGet(currentTime
187 - lastNext);
188 }
189 lastNext = currentTime;
190 if (values != null && values.length > 0) {
191 for (int i = 0; i < values.length; i++) {
192 Result rs = values[i];
193 cache.add(rs);
194 for (Cell kv : rs.rawCells()) {
195 remainingResultSize -= KeyValueUtil.ensureKeyValue(kv).heapSize();
196 }
197 countdown--;
198 this.lastResult = rs;
199 }
200 }
201 if (smallScanCallable.hasMoreResultsContext()) {
202 currentRegionDone = !smallScanCallable.getServerHasMoreResults();
203 } else {
204 currentRegionDone = countdown > 0;
205 }
206 }
207 }
208
209 @Override
210 protected void initializeScannerInConstruction() throws IOException {
211
212
213 }
214
215 @Override
216 public void close() {
217 if (!scanMetricsPublished) writeScanMetrics();
218 closed = true;
219 }
220
221 @VisibleForTesting
222 protected void setScannerCallableFactory(SmallScannerCallableFactory callableFactory) {
223 this.callableFactory = callableFactory;
224 }
225
226 @VisibleForTesting
227 protected void setRpcRetryingCaller(RpcRetryingCaller<Result []> caller) {
228 this.caller = caller;
229 }
230
231 @VisibleForTesting
232 protected void setRpcControllerFactory(RpcControllerFactory rpcControllerFactory) {
233 this.rpcControllerFactory = rpcControllerFactory;
234 }
235 }