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.hadoop.hbase.KeyValue;
24 import org.apache.hadoop.hbase.KeyValue.KVComparator;
25
26 import java.io.IOException;
27 import java.util.Comparator;
28 import java.util.List;
29 import java.util.PriorityQueue;
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class KeyValueHeap implements KeyValueScanner, InternalScanner {
44 private PriorityQueue<KeyValueScanner> heap = null;
45 private KeyValueScanner current = null;
46 private KVScannerComparator comparator;
47
48
49
50
51
52 public enum SeekType {
53 NORMAL {
54 @Override
55 public boolean seek(KeyValueScanner scanner, KeyValue kv,
56 boolean forward) throws IOException {
57 return forward ? scanner.reseek(kv) : scanner.seek(kv);
58 }
59 },
60 EXACT {
61 @Override
62 public boolean seek(KeyValueScanner scanner, KeyValue kv,
63 boolean forward) throws IOException {
64 return scanner.seekExactly(kv, forward);
65 }
66 };
67
68 public abstract boolean seek(KeyValueScanner scanner, KeyValue kv,
69 boolean forward) throws IOException;
70 }
71
72
73
74
75
76
77
78 public KeyValueHeap(List<? extends KeyValueScanner> scanners,
79 KVComparator comparator) {
80 this.comparator = new KVScannerComparator(comparator);
81 if (!scanners.isEmpty()) {
82 this.heap = new PriorityQueue<KeyValueScanner>(scanners.size(),
83 this.comparator);
84 for (KeyValueScanner scanner : scanners) {
85 if (scanner.peek() != null) {
86 this.heap.add(scanner);
87 } else {
88 scanner.close();
89 }
90 }
91 this.current = heap.poll();
92 }
93 }
94
95 public KeyValue peek() {
96 if (this.current == null) {
97 return null;
98 }
99 return this.current.peek();
100 }
101
102 public KeyValue next() throws IOException {
103 if(this.current == null) {
104 return null;
105 }
106 KeyValue kvReturn = this.current.next();
107 KeyValue kvNext = this.current.peek();
108 if (kvNext == null) {
109 this.current.close();
110 this.current = this.heap.poll();
111 } else {
112 KeyValueScanner topScanner = this.heap.peek();
113 if (topScanner == null ||
114 this.comparator.compare(kvNext, topScanner.peek()) >= 0) {
115 this.heap.add(this.current);
116 this.current = this.heap.poll();
117 }
118 }
119 return kvReturn;
120 }
121
122
123
124
125
126
127
128
129
130
131
132
133 public boolean next(List<KeyValue> result, int limit) throws IOException {
134 if (this.current == null) {
135 return false;
136 }
137 InternalScanner currentAsInternal = (InternalScanner)this.current;
138 boolean mayContainsMoreRows = currentAsInternal.next(result, limit);
139 KeyValue pee = this.current.peek();
140
141
142
143
144
145
146
147 if (pee == null || !mayContainsMoreRows) {
148 this.current.close();
149 } else {
150 this.heap.add(this.current);
151 }
152 this.current = this.heap.poll();
153 return (this.current != null);
154 }
155
156
157
158
159
160
161
162
163
164
165
166 public boolean next(List<KeyValue> result) throws IOException {
167 return next(result, -1);
168 }
169
170 private static class KVScannerComparator implements Comparator<KeyValueScanner> {
171 private KVComparator kvComparator;
172
173
174
175
176 public KVScannerComparator(KVComparator kvComparator) {
177 this.kvComparator = kvComparator;
178 }
179 public int compare(KeyValueScanner left, KeyValueScanner right) {
180 int comparison = compare(left.peek(), right.peek());
181 if (comparison != 0) {
182 return comparison;
183 } else {
184
185
186 long leftSequenceID = left.getSequenceID();
187 long rightSequenceID = right.getSequenceID();
188 if (leftSequenceID > rightSequenceID) {
189 return -1;
190 } else if (leftSequenceID < rightSequenceID) {
191 return 1;
192 } else {
193 return 0;
194 }
195 }
196 }
197
198
199
200
201
202
203 public int compare(KeyValue left, KeyValue right) {
204 return this.kvComparator.compare(left, right);
205 }
206
207
208
209 public KVComparator getComparator() {
210 return this.kvComparator;
211 }
212 }
213
214 public void close() {
215 if (this.current != null) {
216 this.current.close();
217 }
218 if (this.heap != null) {
219 KeyValueScanner scanner;
220 while ((scanner = this.heap.poll()) != null) {
221 scanner.close();
222 }
223 }
224 }
225
226
227
228
229
230
231
232
233
234
235
236
237 @Override
238 public boolean seek(KeyValue seekKey) throws IOException {
239 return generalizedSeek(seekKey, SeekType.NORMAL, false);
240 }
241
242
243
244
245
246 @Override
247 public boolean reseek(KeyValue seekKey) throws IOException {
248 return generalizedSeek(seekKey, SeekType.NORMAL, true);
249 }
250
251
252
253
254 @Override
255 public boolean seekExactly(KeyValue seekKey, boolean forward)
256 throws IOException {
257 return generalizedSeek(seekKey, SeekType.EXACT, forward);
258 }
259
260 private boolean generalizedSeek(KeyValue seekKey, SeekType seekType,
261 boolean forward) throws IOException {
262 if (current == null) {
263 return false;
264 }
265 heap.add(current);
266 current = null;
267
268 KeyValueScanner scanner;
269 while ((scanner = heap.poll()) != null) {
270 KeyValue topKey = scanner.peek();
271 if (comparator.getComparator().compare(seekKey, topKey) <= 0) {
272
273 current = scanner;
274 return true;
275 }
276
277 if (!seekType.seek(scanner, seekKey, forward)) {
278 scanner.close();
279 } else {
280 heap.add(scanner);
281 }
282 }
283
284
285 return false;
286 }
287
288
289
290
291 public PriorityQueue<KeyValueScanner> getHeap() {
292 return this.heap;
293 }
294
295 @Override
296 public long getSequenceID() {
297 return 0;
298 }
299
300 KeyValueScanner getCurrentForTesting() {
301 return current;
302 }
303 }