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