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.ArrayList;
23 import java.util.List;
24
25 import org.apache.hadoop.classification.InterfaceAudience;
26 import org.apache.hadoop.classification.InterfaceStability;
27 import org.apache.hadoop.hbase.DoNotRetryIOException;
28 import org.apache.hadoop.hbase.HConstants;
29 import org.apache.hadoop.hbase.HRegionLocation;
30 import org.apache.hadoop.hbase.TableName;
31 import org.apache.hadoop.hbase.client.metrics.ScanMetrics;
32 import org.apache.hadoop.hbase.util.Bytes;
33
34
35
36
37 @InterfaceAudience.Public
38 @InterfaceStability.Evolving
39 public class ReversedScannerCallable extends ScannerCallable {
40
41
42
43
44
45 protected final byte[] locateStartRow;
46
47
48
49
50
51
52
53
54
55 public ReversedScannerCallable(HConnection connection, TableName tableName,
56 Scan scan, ScanMetrics scanMetrics, byte[] locateStartRow) {
57 super(connection, tableName, scan, scanMetrics);
58 this.locateStartRow = locateStartRow;
59 }
60
61
62
63
64
65 @Override
66 public void prepare(boolean reload) throws IOException {
67 if (!instantiated || reload) {
68 if (locateStartRow == null) {
69
70 this.location = connection.getRegionLocation(tableName, row, reload);
71 if (this.location == null) {
72 throw new IOException("Failed to find location, tableName="
73 + tableName + ", row=" + Bytes.toStringBinary(row) + ", reload="
74 + reload);
75 }
76 } else {
77
78
79 List<HRegionLocation> locatedRegions = locateRegionsInRange(
80 locateStartRow, row, reload);
81 if (locatedRegions.isEmpty()) {
82 throw new DoNotRetryIOException(
83 "Does hbase:meta exist hole? Couldn't get regions for the range from "
84 + Bytes.toStringBinary(locateStartRow) + " to "
85 + Bytes.toStringBinary(row));
86 }
87 this.location = locatedRegions.get(locatedRegions.size() - 1);
88 }
89 setStub(getConnection().getClient(getLocation().getServerName()));
90 checkIfRegionServerIsRemote();
91 instantiated = true;
92 }
93
94
95
96
97 if (reload && this.scanMetrics != null) {
98 this.scanMetrics.countOfRPCRetries.incrementAndGet();
99 if (isRegionServerRemote) {
100 this.scanMetrics.countOfRemoteRPCRetries.incrementAndGet();
101 }
102 }
103 }
104
105
106
107
108
109
110
111
112
113
114 private List<HRegionLocation> locateRegionsInRange(byte[] startKey,
115 byte[] endKey, boolean reload) throws IOException {
116 final boolean endKeyIsEndOfTable = Bytes.equals(endKey,
117 HConstants.EMPTY_END_ROW);
118 if ((Bytes.compareTo(startKey, endKey) > 0) && !endKeyIsEndOfTable) {
119 throw new IllegalArgumentException("Invalid range: "
120 + Bytes.toStringBinary(startKey) + " > "
121 + Bytes.toStringBinary(endKey));
122 }
123 List<HRegionLocation> regionList = new ArrayList<HRegionLocation>();
124 byte[] currentKey = startKey;
125 do {
126 HRegionLocation regionLocation = connection.getRegionLocation(tableName,
127 currentKey, reload);
128 if (regionLocation.getRegionInfo().containsRow(currentKey)) {
129 regionList.add(regionLocation);
130 } else {
131 throw new DoNotRetryIOException("Does hbase:meta exist hole? Locating row "
132 + Bytes.toStringBinary(currentKey) + " returns incorrect region "
133 + regionLocation.getRegionInfo());
134 }
135 currentKey = regionLocation.getRegionInfo().getEndKey();
136 } while (!Bytes.equals(currentKey, HConstants.EMPTY_END_ROW)
137 && (endKeyIsEndOfTable || Bytes.compareTo(currentKey, endKey) < 0));
138 return regionList;
139 }
140
141 }