001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.regionserver;
019
020import java.util.Collection;
021import java.util.Comparator;
022import java.util.Iterator;
023import java.util.Map;
024import java.util.NavigableMap;
025import java.util.NavigableSet;
026import java.util.Set;
027import org.apache.hadoop.hbase.Cell;
028import org.apache.yetus.audience.InterfaceAudience;
029
030/**
031 * CellFlatMap stores a constant number of elements and is immutable after creation stage. Being
032 * immutable, the CellFlatMap can be implemented as array. The actual array can be on- or off-heap
033 * and is implemented in concrete class derived from CellFlatMap. The CellFlatMap uses no
034 * synchronization primitives, it is assumed to be created by a single thread and then it can be
035 * read-only by multiple threads. The "flat" in the name, means that the memory layout of the Map is
036 * sequential array and thus requires less memory than ConcurrentSkipListMap.
037 */
038@InterfaceAudience.Private
039public abstract class CellFlatMap<T extends Cell> implements NavigableMap<T, T> {
040
041  private final Comparator<? super T> comparator;
042  protected int minCellIdx = 0; // the index of the minimal cell (for sub-sets)
043  protected int maxCellIdx = 0; // the index of the cell after the maximal cell (for sub-sets)
044  private boolean descending = false;
045
046  /* C-tor */
047  public CellFlatMap(Comparator<? super T> comparator, int min, int max, boolean d) {
048    this.comparator = comparator;
049    this.minCellIdx = min;
050    this.maxCellIdx = max;
051    this.descending = d;
052  }
053
054  /* Used for abstract CellFlatMap creation, implemented by derived class */
055  protected abstract CellFlatMap<T> createSubCellFlatMap(int min, int max, boolean descending);
056
057  /* Returns the i-th cell in the cell block */
058  protected abstract T getCell(int i);
059
060  /**
061   * Binary search for a given key in between given boundaries of the array. Positive returned
062   * numbers mean the index. Negative returned numbers means the key not found. The absolute value
063   * of the output is the possible insert index for the searched key In twos-complement, (-1 *
064   * insertion point)-1 is the bitwise not of the insert point.
065   * @param needle The key to look for in all of the entries
066   * @return Same return value as Arrays.binarySearch.
067   */
068  private int find(T needle) {
069    int begin = minCellIdx;
070    int end = maxCellIdx - 1;
071
072    while (begin <= end) {
073      int mid = begin + ((end - begin) >> 1);
074      T midCell = getCell(mid);
075      int compareRes = comparator.compare(midCell, needle);
076
077      if (compareRes == 0) {
078        return mid; // 0 means equals. We found the key
079      }
080      // Key not found. Check the comparison results; reverse the meaning of
081      // the comparison in case the order is descending (using XOR)
082      if ((compareRes < 0) ^ descending) {
083        // midCell is less than needle so we need to look at farther up
084        begin = mid + 1;
085      } else {
086        // midCell is greater than needle so we need to look down
087        end = mid - 1;
088      }
089    }
090
091    return (-1 * begin) - 1;
092  }
093
094  /**
095   * Get the index of the given anchor key for creating subsequent set. It doesn't matter whether
096   * the given key exists in the set or not. taking into consideration whether the key should be
097   * inclusive or exclusive.
098   */
099  private int getValidIndex(T key, boolean inclusive, boolean tail) {
100    final int index = find(key);
101    // get the valid (positive) insertion point from the output of the find() method
102    int insertionPoint = index < 0 ? ~index : index;
103
104    // correct the insertion point in case the given anchor key DOES EXIST in the set
105    if (index >= 0) {
106      if (descending && !(tail ^ inclusive)) {
107        // for the descending case
108        // if anchor for head set (tail=false) AND anchor is not inclusive -> move the insertion pt
109        // if anchor for tail set (tail=true) AND the keys is inclusive -> move the insertion point
110        // because the end index of a set is the index of the cell after the maximal cell
111        insertionPoint += 1;
112      } else if (!descending && (tail ^ inclusive)) {
113        // for the ascending case
114        // if anchor for head set (tail=false) AND anchor is inclusive -> move the insertion point
115        // because the end index of a set is the index of the cell after the maximal cell
116        // if anchor for tail set (tail=true) AND the keys is not inclusive -> move the insertion pt
117        insertionPoint += 1;
118      }
119    }
120    // insert the insertion point into the valid range,
121    // as we may enlarge it too much in the above correction
122    return Math.min(Math.max(insertionPoint, minCellIdx), maxCellIdx);
123  }
124
125  @Override
126  public Comparator<? super T> comparator() {
127    return comparator;
128  }
129
130  @Override
131  public int size() {
132    return maxCellIdx - minCellIdx;
133  }
134
135  @Override
136  public boolean isEmpty() {
137    return (size() == 0);
138  }
139
140  // ---------------- Sub-Maps ----------------
141  @Override
142  public NavigableMap<T, T> subMap(T fromKey, boolean fromInclusive, T toKey, boolean toInclusive) {
143    final int lessCellIndex = getValidIndex(fromKey, fromInclusive, true);
144    final int greaterCellIndex = getValidIndex(toKey, toInclusive, false);
145    if (descending) {
146      return createSubCellFlatMap(greaterCellIndex, lessCellIndex, descending);
147    } else {
148      return createSubCellFlatMap(lessCellIndex, greaterCellIndex, descending);
149    }
150  }
151
152  @Override
153  public NavigableMap<T, T> headMap(T toKey, boolean inclusive) {
154    if (descending) {
155      return createSubCellFlatMap(getValidIndex(toKey, inclusive, false), maxCellIdx, descending);
156    } else {
157      return createSubCellFlatMap(minCellIdx, getValidIndex(toKey, inclusive, false), descending);
158    }
159  }
160
161  @Override
162  public NavigableMap<T, T> tailMap(T fromKey, boolean inclusive) {
163    if (descending) {
164      return createSubCellFlatMap(minCellIdx, getValidIndex(fromKey, inclusive, true), descending);
165    } else {
166      return createSubCellFlatMap(getValidIndex(fromKey, inclusive, true), maxCellIdx, descending);
167    }
168  }
169
170  @Override
171  public NavigableMap<T, T> descendingMap() {
172    return createSubCellFlatMap(minCellIdx, maxCellIdx, true);
173  }
174
175  @Override
176  public NavigableMap<T, T> subMap(T k1, T k2) {
177    return this.subMap(k1, true, k2, true);
178  }
179
180  @Override
181  public NavigableMap<T, T> headMap(T k) {
182    return this.headMap(k, true);
183  }
184
185  @Override
186  public NavigableMap<T, T> tailMap(T k) {
187    return this.tailMap(k, true);
188  }
189
190  // -------------------------------- Key's getters --------------------------------
191  @Override
192  public T firstKey() {
193    if (isEmpty()) {
194      return null;
195    }
196    return descending ? getCell(maxCellIdx - 1) : getCell(minCellIdx);
197  }
198
199  @Override
200  public T lastKey() {
201    if (isEmpty()) {
202      return null;
203    }
204    return descending ? getCell(minCellIdx) : getCell(maxCellIdx - 1);
205  }
206
207  @Override
208  public T lowerKey(T k) {
209    if (isEmpty()) {
210      return null;
211    }
212    int index = find(k);
213    // If index>=0 there's a key exactly equal
214    index = (index >= 0) ? index - 1 : -(index);
215    return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
216  }
217
218  @Override
219  public T floorKey(T k) {
220    if (isEmpty()) {
221      return null;
222    }
223    int index = find(k);
224    index = (index >= 0) ? index : -(index);
225    return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
226  }
227
228  @Override
229  public T ceilingKey(T k) {
230    if (isEmpty()) {
231      return null;
232    }
233    int index = find(k);
234    index = (index >= 0) ? index : -(index) + 1;
235    return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
236  }
237
238  @Override
239  public T higherKey(T k) {
240    if (isEmpty()) {
241      return null;
242    }
243    int index = find(k);
244    index = (index >= 0) ? index + 1 : -(index) + 1;
245    return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
246  }
247
248  @Override
249  public boolean containsKey(Object o) {
250    int index = find((T) o);
251    return (index >= 0);
252  }
253
254  @Override
255  public boolean containsValue(Object o) { // use containsKey(Object o) instead
256    throw new UnsupportedOperationException("Use containsKey(Object o) instead");
257  }
258
259  @Override
260  public T get(Object o) {
261    int index = find((T) o);
262    return (index >= 0) ? getCell(index) : null;
263  }
264
265  // -------------------------------- Entry's getters --------------------------------
266
267  private static class CellFlatMapEntry<T> implements Entry<T, T> {
268    private final T cell;
269
270    public CellFlatMapEntry(T cell) {
271      this.cell = cell;
272    }
273
274    @Override
275    public T getKey() {
276      return cell;
277    }
278
279    @Override
280    public T getValue() {
281      return cell;
282    }
283
284    @Override
285    public T setValue(T value) {
286      throw new UnsupportedOperationException();
287    }
288  }
289
290  @Override
291  public Entry<T, T> lowerEntry(T k) {
292    T cell = lowerKey(k);
293    if (cell == null) {
294      return null;
295    }
296    return new CellFlatMapEntry<>(cell);
297  }
298
299  @Override
300  public Entry<T, T> higherEntry(T k) {
301    T cell = higherKey(k);
302    if (cell == null) {
303      return null;
304    }
305    return new CellFlatMapEntry<>(cell);
306  }
307
308  @Override
309  public Entry<T, T> ceilingEntry(T k) {
310    T cell = ceilingKey(k);
311    if (cell == null) {
312      return null;
313    }
314    return new CellFlatMapEntry<>(cell);
315  }
316
317  @Override
318  public Entry<T, T> floorEntry(T k) {
319    T cell = floorKey(k);
320    if (cell == null) {
321      return null;
322    }
323    return new CellFlatMapEntry<>(cell);
324  }
325
326  @Override
327  public Entry<T, T> firstEntry() {
328    T cell = firstKey();
329    if (cell == null) {
330      return null;
331    }
332    return new CellFlatMapEntry<>(cell);
333  }
334
335  @Override
336  public Entry<T, T> lastEntry() {
337    T cell = lastKey();
338    if (cell == null) {
339      return null;
340    }
341    return new CellFlatMapEntry<>(cell);
342  }
343
344  // The following 2 methods (pollFirstEntry, pollLastEntry) are unsupported because these are
345  // updating methods.
346  @Override
347  public Entry<T, T> pollFirstEntry() {
348    throw new UnsupportedOperationException();
349  }
350
351  @Override
352  public Entry<T, T> pollLastEntry() {
353    throw new UnsupportedOperationException();
354  }
355
356  // -------------------------------- Updates --------------------------------
357  // All updating methods below are unsupported.
358  // Assuming an array of Cells will be allocated externally,
359  // fill up with Cells and provided in construction time.
360  // Later the structure is immutable.
361  @Override
362  public T put(T k, T v) {
363    throw new UnsupportedOperationException();
364  }
365
366  @Override
367  public void clear() {
368    throw new UnsupportedOperationException();
369  }
370
371  @Override
372  public T remove(Object o) {
373    throw new UnsupportedOperationException();
374  }
375
376  @Override
377  public void putAll(Map<? extends T, ? extends T> map) {
378    throw new UnsupportedOperationException();
379  }
380
381  // -------------------------------- Sub-Sets --------------------------------
382  @Override
383  public NavigableSet<T> navigableKeySet() {
384    throw new UnsupportedOperationException();
385  }
386
387  @Override
388  public NavigableSet<T> descendingKeySet() {
389    throw new UnsupportedOperationException();
390  }
391
392  @Override
393  public NavigableSet<T> keySet() {
394    throw new UnsupportedOperationException();
395  }
396
397  @Override
398  public Collection<T> values() {
399    return new CellFlatMapCollection();
400  }
401
402  @Override
403  public Set<Entry<T, T>> entrySet() {
404    throw new UnsupportedOperationException();
405  }
406
407  // -------------------------------- Iterator K --------------------------------
408  private final class CellFlatMapIterator implements Iterator<T> {
409    int index;
410
411    private CellFlatMapIterator() {
412      index = descending ? maxCellIdx - 1 : minCellIdx;
413    }
414
415    @Override
416    public boolean hasNext() {
417      return descending ? (index >= minCellIdx) : (index < maxCellIdx);
418    }
419
420    @Override
421    public T next() {
422      T result = getCell(index);
423      if (descending) {
424        index--;
425      } else {
426        index++;
427      }
428      return result;
429    }
430
431    @Override
432    public void remove() {
433      throw new UnsupportedOperationException();
434    }
435  }
436
437  // -------------------------------- Collection --------------------------------
438  private final class CellFlatMapCollection implements Collection<T> {
439
440    @Override
441    public int size() {
442      return CellFlatMap.this.size();
443    }
444
445    @Override
446    public boolean isEmpty() {
447      return CellFlatMap.this.isEmpty();
448    }
449
450    @Override
451    public void clear() {
452      throw new UnsupportedOperationException();
453    }
454
455    @Override
456    public boolean contains(Object o) {
457      return containsKey(o);
458    }
459
460    @Override
461    public Iterator<T> iterator() {
462      return new CellFlatMapIterator();
463    }
464
465    @Override
466    public Object[] toArray() {
467      throw new UnsupportedOperationException();
468    }
469
470    @Override
471    public <T> T[] toArray(T[] ts) {
472      throw new UnsupportedOperationException();
473    }
474
475    @Override
476    public boolean add(T k) {
477      throw new UnsupportedOperationException();
478    }
479
480    @Override
481    public boolean remove(Object o) {
482      throw new UnsupportedOperationException();
483    }
484
485    @Override
486    public boolean containsAll(Collection<?> collection) {
487      throw new UnsupportedOperationException();
488    }
489
490    @Override
491    public boolean addAll(Collection<? extends T> collection) {
492      throw new UnsupportedOperationException();
493    }
494
495    @Override
496    public boolean removeAll(Collection<?> collection) {
497      throw new UnsupportedOperationException();
498    }
499
500    @Override
501    public boolean retainAll(Collection<?> collection) {
502      throw new UnsupportedOperationException();
503    }
504  }
505}