1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.hadoop.hbase.regionserver;
22
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.hadoop.hbase.KeyValue;
26 import org.apache.hadoop.hbase.client.Scan;
27
28 import java.io.IOException;
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.NavigableSet;
32
33
34
35
36
37 class StoreScanner implements KeyValueScanner, InternalScanner, ChangedReadersObserver {
38 static final Log LOG = LogFactory.getLog(StoreScanner.class);
39 private Store store;
40 private ScanQueryMatcher matcher;
41 private KeyValueHeap heap;
42 private boolean cacheBlocks;
43
44
45
46 private boolean closing = false;
47 private final boolean isGet;
48
49
50 private KeyValue lastTop = null;
51
52
53
54
55
56
57
58
59
60 StoreScanner(Store store, Scan scan, final NavigableSet<byte[]> columns) throws IOException {
61 this.store = store;
62 this.cacheBlocks = scan.getCacheBlocks();
63 matcher = new ScanQueryMatcher(scan, store.getFamily().getName(),
64 columns, store.ttl, store.comparator.getRawComparator(),
65 store.versionsToReturn(scan.getMaxVersions()));
66
67 this.isGet = scan.isGetScan();
68
69 List<KeyValueScanner> scanners = getScanners(scan, columns);
70
71
72 for(KeyValueScanner scanner : scanners) {
73 scanner.seek(matcher.getStartKey());
74 }
75
76
77 heap = new KeyValueHeap(scanners, store.comparator);
78
79 this.store.addChangedReaderObserver(this);
80 }
81
82
83
84
85
86
87
88
89
90 StoreScanner(Store store, Scan scan, List<? extends KeyValueScanner> scanners)
91 throws IOException {
92 this.store = store;
93 this.cacheBlocks = false;
94 this.isGet = false;
95 matcher = new ScanQueryMatcher(scan, store.getFamily().getName(),
96 null, store.ttl, store.comparator.getRawComparator(),
97 store.versionsToReturn(scan.getMaxVersions()));
98
99
100 for(KeyValueScanner scanner : scanners) {
101 scanner.seek(matcher.getStartKey());
102 }
103
104
105 heap = new KeyValueHeap(scanners, store.comparator);
106 }
107
108
109 StoreScanner(final Scan scan, final byte [] colFamily, final long ttl,
110 final KeyValue.KVComparator comparator,
111 final NavigableSet<byte[]> columns,
112 final List<KeyValueScanner> scanners)
113 throws IOException {
114 this.store = null;
115 this.isGet = false;
116 this.cacheBlocks = scan.getCacheBlocks();
117 this.matcher = new ScanQueryMatcher(scan, colFamily, columns, ttl,
118 comparator.getRawComparator(), scan.getMaxVersions());
119
120
121 for(KeyValueScanner scanner : scanners) {
122 scanner.seek(matcher.getStartKey());
123 }
124 heap = new KeyValueHeap(scanners, comparator);
125 }
126
127
128
129
130 private List<KeyValueScanner> getScanners() throws IOException {
131
132
133
134
135
136 List<StoreFileScanner> sfScanners = StoreFileScanner
137 .getScannersForStoreFiles(store.getStorefiles(), cacheBlocks, isGet);
138 List<KeyValueScanner> scanners =
139 new ArrayList<KeyValueScanner>(sfScanners.size()+1);
140 scanners.addAll(sfScanners);
141
142 scanners.addAll(this.store.memstore.getScanners());
143 return scanners;
144 }
145
146
147
148
149 private List<KeyValueScanner> getScanners(Scan scan,
150 final NavigableSet<byte[]> columns) throws IOException {
151
152 List<StoreFileScanner> sfScanners = StoreFileScanner
153 .getScannersForStoreFiles(store.getStorefiles(), cacheBlocks, isGet);
154 List<KeyValueScanner> scanners =
155 new ArrayList<KeyValueScanner>(sfScanners.size()+1);
156
157
158 for (StoreFileScanner sfs : sfScanners) {
159 if (sfs.shouldSeek(scan, columns)) {
160 scanners.add(sfs);
161 }
162 }
163
164
165 if (this.store.memstore.shouldSeek(scan)) {
166 scanners.addAll(this.store.memstore.getScanners());
167 }
168 return scanners;
169 }
170
171 public synchronized KeyValue peek() {
172 if (this.heap == null) {
173 return this.lastTop;
174 }
175 return this.heap.peek();
176 }
177
178 public KeyValue next() {
179
180 throw new RuntimeException("Never call StoreScanner.next()");
181 }
182
183 public synchronized void close() {
184 if (this.closing) return;
185 this.closing = true;
186
187 if (this.store != null)
188 this.store.deleteChangedReaderObserver(this);
189 if (this.heap != null)
190 this.heap.close();
191 this.heap = null;
192 this.lastTop = null;
193 }
194
195 public synchronized boolean seek(KeyValue key) throws IOException {
196 if (this.heap == null) {
197
198 List<KeyValueScanner> scanners = getScanners();
199
200 heap = new KeyValueHeap(scanners, store.comparator);
201 }
202
203 return this.heap.seek(key);
204 }
205
206
207
208
209
210
211
212 public synchronized boolean next(List<KeyValue> outResult, int limit) throws IOException {
213
214
215 checkReseek();
216
217
218
219 if (this.heap == null) {
220 close();
221 return false;
222 }
223
224 KeyValue peeked = this.heap.peek();
225 if (peeked == null) {
226 close();
227 return false;
228 }
229
230
231
232 if ((matcher.row == null) || !peeked.matchingRow(matcher.row)) {
233 matcher.setRow(peeked.getRow());
234 }
235
236 KeyValue kv;
237 List<KeyValue> results = new ArrayList<KeyValue>();
238 LOOP: while((kv = this.heap.peek()) != null) {
239 ScanQueryMatcher.MatchCode qcode = matcher.match(kv);
240
241 switch(qcode) {
242 case INCLUDE:
243 KeyValue next = this.heap.next();
244 results.add(next);
245 if (limit > 0 && (results.size() == limit)) {
246 break LOOP;
247 }
248 continue;
249
250 case DONE:
251
252 outResult.addAll(results);
253 return true;
254
255 case DONE_SCAN:
256 close();
257
258
259 outResult.addAll(results);
260
261 return false;
262
263 case SEEK_NEXT_ROW:
264 if (!matcher.moreRowsMayExistAfter(kv)) {
265 outResult.addAll(results);
266 return false;
267 }
268 heap.next();
269 break;
270
271 case SEEK_NEXT_COL:
272
273
274
275 heap.next();
276 break;
277
278 case SKIP:
279 this.heap.next();
280 break;
281
282 default:
283 throw new RuntimeException("UNEXPECTED");
284 }
285 }
286
287 if (!results.isEmpty()) {
288
289 outResult.addAll(results);
290 return true;
291 }
292
293
294 close();
295 return false;
296 }
297
298 public synchronized boolean next(List<KeyValue> outResult) throws IOException {
299 return next(outResult, -1);
300 }
301
302
303 public synchronized void updateReaders() throws IOException {
304 if (this.closing) return;
305
306
307
308
309
310
311 if (this.heap == null) return;
312
313
314 this.lastTop = this.peek();
315
316
317
318
319 this.heap.close();
320 this.heap = null;
321
322
323 }
324
325 private void checkReseek() throws IOException {
326 if (this.heap == null && this.lastTop != null) {
327
328 reseek(this.lastTop);
329 this.lastTop = null;
330 }
331
332 }
333
334 private void reseek(KeyValue lastTopKey) throws IOException {
335 if (heap != null) {
336 throw new RuntimeException("StoreScanner.reseek run on an existing heap!");
337 }
338
339 List<KeyValueScanner> scanners = getScanners();
340
341 for(KeyValueScanner scanner : scanners) {
342 scanner.seek(lastTopKey);
343 }
344
345
346 heap = new KeyValueHeap(scanners, store.comparator);
347
348
349 matcher.reset();
350 KeyValue kv = heap.peek();
351 matcher.setRow((kv == null ? lastTopKey : kv).getRow());
352 }
353 }