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 java.io.IOException;
22 import java.util.Arrays;
23 import java.util.concurrent.ExecutorService;
24
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.apache.hadoop.hbase.classification.InterfaceAudience;
28 import org.apache.hadoop.conf.Configuration;
29 import org.apache.hadoop.hbase.HConstants;
30 import org.apache.hadoop.hbase.TableName;
31 import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
32 import org.apache.hadoop.hbase.util.Bytes;
33 import org.apache.hadoop.hbase.util.ExceptionUtil;
34
35
36
37
38 @InterfaceAudience.Private
39 public class ReversedClientScanner extends ClientScanner {
40 private static final Log LOG = LogFactory.getLog(ReversedClientScanner.class);
41
42
43 static byte[] MAX_BYTE_ARRAY = Bytes.createMaxByteArray(9);
44
45
46
47
48
49
50
51
52
53
54
55
56 public ReversedClientScanner(Configuration conf, Scan scan,
57 TableName tableName, ClusterConnection connection,
58 RpcRetryingCallerFactory rpcFactory, RpcControllerFactory controllerFactory,
59 ExecutorService pool, int primaryOperationTimeout) throws IOException {
60 super(conf, scan, tableName, connection, rpcFactory, controllerFactory, pool, primaryOperationTimeout);
61 }
62
63 @Override
64 protected boolean nextScanner(int nbRows, final boolean done)
65 throws IOException {
66
67 if (this.callable != null) {
68 this.callable.setClose();
69
70
71 this.caller.callWithoutRetries(callable, scannerTimeout);
72 this.callable = null;
73 }
74
75
76 byte[] localStartKey;
77 boolean locateTheClosestFrontRow = true;
78
79 if (this.currentRegion != null) {
80 byte[] startKey = this.currentRegion.getStartKey();
81 if (startKey == null
82 || Bytes.equals(startKey, HConstants.EMPTY_BYTE_ARRAY)
83 || checkScanStopRow(startKey) || done) {
84 close();
85 if (LOG.isDebugEnabled()) {
86 LOG.debug("Finished " + this.currentRegion);
87 }
88 return false;
89 }
90 localStartKey = startKey;
91 if (LOG.isDebugEnabled()) {
92 LOG.debug("Finished " + this.currentRegion);
93 }
94 } else {
95 localStartKey = this.scan.getStartRow();
96 if (!Bytes.equals(localStartKey, HConstants.EMPTY_BYTE_ARRAY)) {
97 locateTheClosestFrontRow = false;
98 }
99 }
100
101 if (LOG.isDebugEnabled() && this.currentRegion != null) {
102
103 LOG.debug("Advancing internal scanner to startKey at '"
104 + Bytes.toStringBinary(localStartKey) + "'");
105 }
106 try {
107
108
109
110
111
112
113
114 byte[] locateStartRow = locateTheClosestFrontRow ? createClosestRowBefore(localStartKey)
115 : null;
116 callable = getScannerCallable(localStartKey, nbRows, locateStartRow);
117
118
119
120
121 this.caller.callWithoutRetries(callable, scannerTimeout);
122 this.currentRegion = callable.getHRegionInfo();
123 if (this.scanMetrics != null) {
124 this.scanMetrics.countOfRegions.incrementAndGet();
125 }
126 } catch (IOException e) {
127 ExceptionUtil.rethrowIfInterrupt(e);
128 close();
129 throw e;
130 }
131 return true;
132 }
133
134 protected ScannerCallableWithReplicas getScannerCallable(byte[] localStartKey,
135 int nbRows, byte[] locateStartRow) {
136 scan.setStartRow(localStartKey);
137 ScannerCallable s =
138 new ReversedScannerCallable(getConnection(), getTable(), scan, this.scanMetrics,
139 locateStartRow, this.rpcControllerFactory);
140 s.setCaching(nbRows);
141 ScannerCallableWithReplicas sr = new ScannerCallableWithReplicas(getTable(), getConnection(),
142 s, pool, primaryOperationTimeout, scan,
143 getRetries(), getScannerTimeout(), caching, getConf(), caller);
144 return sr;
145 }
146
147 @Override
148
149 protected boolean checkScanStopRow(final byte[] startKey) {
150 if (this.scan.getStopRow().length > 0) {
151
152 byte[] stopRow = scan.getStopRow();
153 int cmp = Bytes.compareTo(stopRow, 0, stopRow.length, startKey, 0,
154 startKey.length);
155 if (cmp >= 0) {
156
157
158 return true;
159 }
160 }
161 return false;
162 }
163
164
165
166
167
168
169 protected byte[] createClosestRowBefore(byte[] row) {
170 if (row == null) {
171 throw new IllegalArgumentException("The passed row is empty");
172 }
173 if (Bytes.equals(row, HConstants.EMPTY_BYTE_ARRAY)) {
174 return MAX_BYTE_ARRAY;
175 }
176 if (row[row.length - 1] == 0) {
177 return Arrays.copyOf(row, row.length - 1);
178 } else {
179 byte[] closestFrontRow = Arrays.copyOf(row, row.length);
180 closestFrontRow[row.length - 1] = (byte) ((closestFrontRow[row.length - 1] & 0xff) - 1);
181 closestFrontRow = Bytes.add(closestFrontRow, MAX_BYTE_ARRAY);
182 return closestFrontRow;
183 }
184 }
185 }