1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.regionserver;
21
22 import java.io.IOException;
23 import java.util.Comparator;
24 import java.util.List;
25 import java.util.PriorityQueue;
26
27 import org.apache.hadoop.classification.InterfaceAudience;
28 import org.apache.hadoop.hbase.Cell;
29 import org.apache.hadoop.hbase.KeyValue;
30 import org.apache.hadoop.hbase.KeyValue.KVComparator;
31
32
33
34
35
36
37
38
39
40
41
42
43
44 @InterfaceAudience.Private
45 public class KeyValueHeap extends NonLazyKeyValueScanner
46 implements KeyValueScanner, InternalScanner {
47 private PriorityQueue<KeyValueScanner> heap = null;
48
49
50
51
52
53
54
55
56
57
58
59 private KeyValueScanner current = null;
60
61 private KVScannerComparator comparator;
62
63
64
65
66
67
68
69 public KeyValueHeap(List<? extends KeyValueScanner> scanners,
70 KVComparator comparator) throws IOException {
71 this.comparator = new KVScannerComparator(comparator);
72 if (!scanners.isEmpty()) {
73 this.heap = new PriorityQueue<KeyValueScanner>(scanners.size(),
74 this.comparator);
75 for (KeyValueScanner scanner : scanners) {
76 if (scanner.peek() != null) {
77 this.heap.add(scanner);
78 } else {
79 scanner.close();
80 }
81 }
82 this.current = pollRealKV();
83 }
84 }
85
86 public KeyValue peek() {
87 if (this.current == null) {
88 return null;
89 }
90 return this.current.peek();
91 }
92
93 public KeyValue next() throws IOException {
94 if(this.current == null) {
95 return null;
96 }
97 KeyValue kvReturn = this.current.next();
98 KeyValue kvNext = this.current.peek();
99 if (kvNext == null) {
100 this.current.close();
101 this.current = pollRealKV();
102 } else {
103 KeyValueScanner topScanner = this.heap.peek();
104 if (topScanner == null ||
105 this.comparator.compare(kvNext, topScanner.peek()) >= 0) {
106 this.heap.add(this.current);
107 this.current = pollRealKV();
108 }
109 }
110 return kvReturn;
111 }
112
113
114
115
116
117
118
119
120
121
122
123
124 public boolean next(List<Cell> result, int limit) throws IOException {
125 if (this.current == null) {
126 return false;
127 }
128 InternalScanner currentAsInternal = (InternalScanner)this.current;
129 boolean mayContainMoreRows = currentAsInternal.next(result, limit);
130 KeyValue pee = this.current.peek();
131
132
133
134
135
136
137
138 if (pee == null || !mayContainMoreRows) {
139 this.current.close();
140 } else {
141 this.heap.add(this.current);
142 }
143 this.current = pollRealKV();
144 return (this.current != null);
145 }
146
147
148
149
150
151
152
153
154
155
156
157 public boolean next(List<Cell> result) throws IOException {
158 return next(result, -1);
159 }
160
161 private static class KVScannerComparator implements Comparator<KeyValueScanner> {
162 private KVComparator kvComparator;
163
164
165
166
167 public KVScannerComparator(KVComparator kvComparator) {
168 this.kvComparator = kvComparator;
169 }
170 public int compare(KeyValueScanner left, KeyValueScanner right) {
171 int comparison = compare(left.peek(), right.peek());
172 if (comparison != 0) {
173 return comparison;
174 } else {
175
176
177 long leftSequenceID = left.getSequenceID();
178 long rightSequenceID = right.getSequenceID();
179 if (leftSequenceID > rightSequenceID) {
180 return -1;
181 } else if (leftSequenceID < rightSequenceID) {
182 return 1;
183 } else {
184 return 0;
185 }
186 }
187 }
188
189
190
191
192
193
194 public int compare(KeyValue left, KeyValue right) {
195 return this.kvComparator.compare(left, right);
196 }
197
198
199
200 public KVComparator getComparator() {
201 return this.kvComparator;
202 }
203 }
204
205 public void close() {
206 if (this.current != null) {
207 this.current.close();
208 }
209 if (this.heap != null) {
210 KeyValueScanner scanner;
211 while ((scanner = this.heap.poll()) != null) {
212 scanner.close();
213 }
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232 @Override
233 public boolean seek(KeyValue seekKey) throws IOException {
234 return generalizedSeek(false,
235 seekKey,
236 false,
237 false);
238 }
239
240
241
242
243
244 @Override
245 public boolean reseek(KeyValue seekKey) throws IOException {
246 return generalizedSeek(false,
247 seekKey,
248 true,
249 false);
250 }
251
252
253
254
255 @Override
256 public boolean requestSeek(KeyValue key, boolean forward,
257 boolean useBloom) throws IOException {
258 return generalizedSeek(true, key, forward, useBloom);
259 }
260
261
262
263
264
265
266
267
268
269 private boolean generalizedSeek(boolean isLazy, KeyValue seekKey,
270 boolean forward, boolean useBloom) throws IOException {
271 if (!isLazy && useBloom) {
272 throw new IllegalArgumentException("Multi-column Bloom filter " +
273 "optimization requires a lazy seek");
274 }
275
276 if (current == null) {
277 return false;
278 }
279 heap.add(current);
280 current = null;
281
282 KeyValueScanner scanner;
283 while ((scanner = heap.poll()) != null) {
284 KeyValue topKey = scanner.peek();
285 if (comparator.getComparator().compare(seekKey, topKey) <= 0) {
286
287
288
289
290
291
292 heap.add(scanner);
293 current = pollRealKV();
294 return current != null;
295 }
296
297 boolean seekResult;
298 if (isLazy && heap.size() > 0) {
299
300 seekResult = scanner.requestSeek(seekKey, forward, useBloom);
301 } else {
302 seekResult = NonLazyKeyValueScanner.doRealSeek(
303 scanner, seekKey, forward);
304 }
305
306 if (!seekResult) {
307 scanner.close();
308 } else {
309 heap.add(scanner);
310 }
311 }
312
313
314 return false;
315 }
316
317
318
319
320
321
322
323
324
325
326
327
328 private KeyValueScanner pollRealKV() throws IOException {
329 KeyValueScanner kvScanner = heap.poll();
330 if (kvScanner == null) {
331 return null;
332 }
333
334 while (kvScanner != null && !kvScanner.realSeekDone()) {
335 if (kvScanner.peek() != null) {
336 kvScanner.enforceSeek();
337 KeyValue curKV = kvScanner.peek();
338 if (curKV != null) {
339 KeyValueScanner nextEarliestScanner = heap.peek();
340 if (nextEarliestScanner == null) {
341
342 return kvScanner;
343 }
344
345
346
347 KeyValue nextKV = nextEarliestScanner.peek();
348 if (nextKV == null || comparator.compare(curKV, nextKV) < 0) {
349
350 return kvScanner;
351 }
352
353
354
355
356 heap.add(kvScanner);
357 } else {
358
359
360 kvScanner.close();
361 }
362 } else {
363
364
365 kvScanner.close();
366 }
367 kvScanner = heap.poll();
368 }
369
370 return kvScanner;
371 }
372
373
374
375
376 public PriorityQueue<KeyValueScanner> getHeap() {
377 return this.heap;
378 }
379
380 @Override
381 public long getSequenceID() {
382 return 0;
383 }
384
385 KeyValueScanner getCurrentForTesting() {
386 return current;
387 }
388 }