17
17
*/
18
18
package org .apache .hadoop .hbase .client ;
19
19
20
+ import static org .junit .Assert .assertEquals ;
21
+ import static org .junit .Assert .assertFalse ;
20
22
import static org .junit .Assert .assertNotNull ;
21
23
import static org .junit .Assert .assertNull ;
22
24
import static org .junit .Assert .assertTrue ;
25
+ import static org .mockito .ArgumentMatchers .anyList ;
26
+ import static org .mockito .Mockito .spy ;
27
+ import static org .mockito .Mockito .times ;
28
+ import static org .mockito .Mockito .verify ;
23
29
24
30
import java .io .IOException ;
31
+ import java .util .Arrays ;
25
32
import org .apache .hadoop .conf .Configuration ;
26
33
import org .apache .hadoop .fs .FileSystem ;
27
34
import org .apache .hadoop .fs .Path ;
35
+ import org .apache .hadoop .hbase .Cell ;
28
36
import org .apache .hadoop .hbase .HBaseClassTestRule ;
29
37
import org .apache .hadoop .hbase .HBaseTestingUtility ;
30
38
import org .apache .hadoop .hbase .HConstants ;
31
39
import org .apache .hadoop .hbase .TableName ;
40
+ import org .apache .hadoop .hbase .filter .FilterBase ;
32
41
import org .apache .hadoop .hbase .io .hfile .BlockCache ;
33
42
import org .apache .hadoop .hbase .io .hfile .IndexOnlyLruBlockCache ;
43
+ import org .apache .hadoop .hbase .regionserver .RegionScanner ;
44
+ import org .apache .hadoop .hbase .regionserver .StoreScanner ;
34
45
import org .apache .hadoop .hbase .testclassification .ClientTests ;
35
46
import org .apache .hadoop .hbase .testclassification .SmallTests ;
47
+ import org .apache .hadoop .hbase .util .Bytes ;
36
48
import org .junit .AfterClass ;
37
49
import org .junit .Before ;
38
50
import org .junit .BeforeClass ;
@@ -47,6 +59,8 @@ public class TestClientSideRegionScanner {
47
59
HBaseClassTestRule .forClass (TestClientSideRegionScanner .class );
48
60
49
61
private final static HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility ();
62
+ private static final TableName TABLE_NAME = TableName .valueOf ("test" );
63
+ private static final byte [] FAM_NAME = Bytes .toBytes ("f" );
50
64
51
65
private Configuration conf ;
52
66
private Path rootDir ;
@@ -113,4 +127,78 @@ public void testNoBlockCache() throws IOException {
113
127
BlockCache blockCache = clientSideRegionScanner .getRegion ().getBlockCache ();
114
128
assertNull (blockCache );
115
129
}
130
+
131
+ @ Test
132
+ public void testContinuesToScanIfHasMore () throws IOException {
133
+ // Conditions for this test to set up RegionScannerImpl to bail on the scan
134
+ // after a single iteration
135
+ // 1. Configure preadMaxBytes to something small to trigger scannerContext#returnImmediately
136
+ // 2. Configure a filter to filter out some rows, in this case rows with values < 5
137
+ // 3. Configure the filter's hasFilterRow to return true so RegionScannerImpl sets
138
+ // the limitScope to something with a depth of 0, so we bail on the scan after the first
139
+ // iteration
140
+
141
+ Configuration copyConf = new Configuration (conf );
142
+ copyConf .setLong (StoreScanner .STORESCANNER_PREAD_MAX_BYTES , 1 );
143
+ Scan scan = new Scan ();
144
+ scan .setFilter (new FiltersRowsLessThan5 ());
145
+ scan .setLimit (1 );
146
+
147
+ try (Table table = TEST_UTIL .createTable (TABLE_NAME , FAM_NAME )) {
148
+ TableDescriptor htd = TEST_UTIL .getAdmin ().getDescriptor (TABLE_NAME );
149
+ RegionInfo hri = TEST_UTIL .getAdmin ().getRegions (TABLE_NAME ).get (0 );
150
+
151
+ for (int i = 0 ; i < 10 ; ++i ) {
152
+ table .put (createPut (i ));
153
+ }
154
+
155
+ // Flush contents to disk so we can scan the fs
156
+ TEST_UTIL .getAdmin ().flush (TABLE_NAME );
157
+
158
+ ClientSideRegionScanner clientSideRegionScanner =
159
+ new ClientSideRegionScanner (copyConf , fs , rootDir , htd , hri , scan , null );
160
+ RegionScanner scannerSpy = spy (clientSideRegionScanner .scanner );
161
+ clientSideRegionScanner .scanner = scannerSpy ;
162
+ Result result = clientSideRegionScanner .next ();
163
+
164
+ verify (scannerSpy , times (6 )).nextRaw (anyList ());
165
+ assertNotNull (result );
166
+ assertEquals (Bytes .toInt (result .getRow ()), 5 );
167
+ assertTrue (clientSideRegionScanner .hasMore );
168
+
169
+ for (int i = 6 ; i < 10 ; ++i ) {
170
+ result = clientSideRegionScanner .next ();
171
+ verify (scannerSpy , times (i + 1 )).nextRaw (anyList ());
172
+ assertNotNull (result );
173
+ assertEquals (Bytes .toInt (result .getRow ()), i );
174
+ }
175
+
176
+ result = clientSideRegionScanner .next ();
177
+ assertNull (result );
178
+ assertFalse (clientSideRegionScanner .hasMore );
179
+ }
180
+ }
181
+
182
+ private static Put createPut (int rowAsInt ) {
183
+ byte [] row = Bytes .toBytes (rowAsInt );
184
+ Put put = new Put (row );
185
+ put .addColumn (FAM_NAME , row , row );
186
+ return put ;
187
+ }
188
+
189
+ private static class FiltersRowsLessThan5 extends FilterBase {
190
+
191
+ @ Override
192
+ public boolean filterRowKey (Cell cell ) {
193
+ byte [] rowKey = Arrays .copyOfRange (cell .getRowArray (), cell .getRowOffset (),
194
+ cell .getRowLength () + cell .getRowOffset ());
195
+ int intValue = Bytes .toInt (rowKey );
196
+ return intValue < 5 ;
197
+ }
198
+
199
+ @ Override
200
+ public boolean hasFilterRow () {
201
+ return true ;
202
+ }
203
+ }
116
204
}
0 commit comments