24
24
25
25
import java .io .IOException ;
26
26
import java .io .InterruptedIOException ;
27
- import java .util .ArrayList ;
28
- import java .util .List ;
29
27
30
28
import org .apache .hadoop .hbase .DoNotRetryIOException ;
31
29
import org .apache .hadoop .hbase .HConstants ;
32
30
import org .apache .hadoop .hbase .HRegionLocation ;
33
31
import org .apache .hadoop .hbase .RegionLocations ;
34
32
import org .apache .hadoop .hbase .TableName ;
33
+ import org .apache .hadoop .hbase .TableNotEnabledException ;
34
+ import org .apache .hadoop .hbase .util .Pair ;
35
35
import org .apache .yetus .audience .InterfaceAudience ;
36
36
import org .apache .hadoop .hbase .client .metrics .ScanMetrics ;
37
37
import org .apache .hadoop .hbase .ipc .RpcControllerFactory ;
44
44
@ InterfaceAudience .Private
45
45
public class ReversedScannerCallable extends ScannerCallable {
46
46
47
+ private byte [] locationSearchKey ;
48
+
47
49
/**
48
50
* @param connection which connection
49
51
* @param tableName table callable is on
@@ -59,6 +61,18 @@ public ReversedScannerCallable(ClusterConnection connection, TableName tableName
59
61
super (connection , tableName , scan , scanMetrics , rpcFactory , replicaId );
60
62
}
61
63
64
+ @ Override
65
+ public void throwable (Throwable t , boolean retrying ) {
66
+ // for reverse scans, we need to update cache using the search key found for the reverse scan
67
+ // range in prepare. Otherwise, we will see weird behavior at the table boundaries,
68
+ // when trying to clear cache for an empty row.
69
+ if (location != null && locationSearchKey != null ) {
70
+ getConnection ().updateCachedLocations (getTableName (),
71
+ location .getRegionInfo ().getRegionName (),
72
+ locationSearchKey , t , location .getServerName ());
73
+ }
74
+ }
75
+
62
76
/**
63
77
* @param reload force reload of server location
64
78
*/
@@ -67,33 +81,37 @@ public void prepare(boolean reload) throws IOException {
67
81
if (Thread .interrupted ()) {
68
82
throw new InterruptedIOException ();
69
83
}
84
+
85
+ if (reload && getTableName () != null && !getTableName ().equals (TableName .META_TABLE_NAME )
86
+ && getConnection ().isTableDisabled (getTableName ())) {
87
+ throw new TableNotEnabledException (getTableName ().getNameAsString () + " is disabled." );
88
+ }
89
+
70
90
if (!instantiated || reload ) {
71
91
// we should use range locate if
72
92
// 1. we do not want the start row
73
93
// 2. the start row is empty which means we need to locate to the last region.
74
94
if (scan .includeStartRow () && !isEmptyStartRow (getRow ())) {
75
95
// Just locate the region with the row
76
- RegionLocations rl = getRegionLocations ( reload , getRow ());
96
+ RegionLocations rl = getRegionLocationsForPrepare ( getRow ());
77
97
this .location = getLocationForReplica (rl );
78
- if (location == null || location .getServerName () == null ) {
79
- throw new IOException ("Failed to find location, tableName="
80
- + getTableName () + ", row=" + Bytes .toStringBinary (getRow ()) + ", reload="
81
- + reload );
82
- }
98
+ this .locationSearchKey = getRow ();
83
99
} else {
84
- // Need to locate the regions with the range, and the target location is
85
- // the last one which is the previous region of last region scanner
100
+ // The locateStart row is an approximation. So we need to search between
101
+ // that and the actual row in order to really find the last region
86
102
byte [] locateStartRow = createCloseRowBefore (getRow ());
87
- List <HRegionLocation > locatedRegions = locateRegionsInRange (
88
- locateStartRow , getRow (), reload );
89
- if (locatedRegions .isEmpty ()) {
90
- throw new DoNotRetryIOException (
91
- "Does hbase:meta exist hole? Couldn't get regions for the range from "
92
- + Bytes .toStringBinary (locateStartRow ) + " to "
93
- + Bytes .toStringBinary (getRow ()));
94
- }
95
- this .location = locatedRegions .get (locatedRegions .size () - 1 );
103
+ Pair <HRegionLocation , byte []> lastRegionAndKey = locateLastRegionInRange (
104
+ locateStartRow , getRow ());
105
+ this .location = lastRegionAndKey .getFirst ();
106
+ this .locationSearchKey = lastRegionAndKey .getSecond ();
96
107
}
108
+
109
+ if (location == null || location .getServerName () == null ) {
110
+ throw new IOException ("Failed to find location, tableName="
111
+ + getTableName () + ", row=" + Bytes .toStringBinary (getRow ()) + ", reload="
112
+ + reload );
113
+ }
114
+
97
115
setStub (getConnection ().getClient (getLocation ().getServerName ()));
98
116
checkIfRegionServerIsRemote ();
99
117
instantiated = true ;
@@ -106,29 +124,32 @@ public void prepare(boolean reload) throws IOException {
106
124
}
107
125
108
126
/**
109
- * Get the corresponding regions for an arbitrary range of keys.
127
+ * Get the last region before the endkey, which will be used to execute the reverse scan
110
128
* @param startKey Starting row in range, inclusive
111
129
* @param endKey Ending row in range, exclusive
112
- * @param reload force reload of server location
113
- * @return A list of HRegionLocation corresponding to the regions that contain
114
- * the specified range
130
+ * @return The last location, and the rowKey used to find it. May be null,
131
+ * if a region could not be found.
115
132
*/
116
- private List <HRegionLocation > locateRegionsInRange (byte [] startKey ,
117
- byte [] endKey , boolean reload ) throws IOException {
133
+ private Pair <HRegionLocation , byte []> locateLastRegionInRange (byte [] startKey , byte [] endKey )
134
+ throws IOException {
118
135
final boolean endKeyIsEndOfTable = Bytes .equals (endKey ,
119
136
HConstants .EMPTY_END_ROW );
120
137
if ((Bytes .compareTo (startKey , endKey ) > 0 ) && !endKeyIsEndOfTable ) {
121
138
throw new IllegalArgumentException ("Invalid range: "
122
139
+ Bytes .toStringBinary (startKey ) + " > "
123
140
+ Bytes .toStringBinary (endKey ));
124
141
}
125
- List <HRegionLocation > regionList = new ArrayList <>();
142
+
143
+ HRegionLocation lastRegion = null ;
144
+ byte [] lastFoundKey = null ;
126
145
byte [] currentKey = startKey ;
146
+
127
147
do {
128
- RegionLocations rl = getRegionLocations ( reload , currentKey );
148
+ RegionLocations rl = getRegionLocationsForPrepare ( currentKey );
129
149
HRegionLocation regionLocation = getLocationForReplica (rl );
130
150
if (regionLocation .getRegionInfo ().containsRow (currentKey )) {
131
- regionList .add (regionLocation );
151
+ lastFoundKey = currentKey ;
152
+ lastRegion = regionLocation ;
132
153
} else {
133
154
throw new DoNotRetryIOException (
134
155
"Does hbase:meta exist hole? Locating row " + Bytes .toStringBinary (currentKey ) +
@@ -137,7 +158,8 @@ private List<HRegionLocation> locateRegionsInRange(byte[] startKey,
137
158
currentKey = regionLocation .getRegionInfo ().getEndKey ();
138
159
} while (!Bytes .equals (currentKey , HConstants .EMPTY_END_ROW )
139
160
&& (endKeyIsEndOfTable || Bytes .compareTo (currentKey , endKey ) < 0 ));
140
- return regionList ;
161
+
162
+ return new Pair <>(lastRegion , lastFoundKey );
141
163
}
142
164
143
165
@ Override
0 commit comments