org.apache.hadoop.hbase.regionserver.CellFlatMap Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hbase-server Show documentation
Show all versions of hbase-server Show documentation
Server functionality for HBase
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.regionserver;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableMap;
import java.util.NavigableSet;
import java.util.Set;
import org.apache.hadoop.hbase.Cell;
import org.apache.yetus.audience.InterfaceAudience;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* CellFlatMap stores a constant number of elements and is immutable after creation stage. Being
* immutable, the CellFlatMap can be implemented as array. The actual array can be on- or off-heap
* and is implemented in concrete class derived from CellFlatMap. The CellFlatMap uses no
* synchronization primitives, it is assumed to be created by a single thread and then it can be
* read-only by multiple threads. The "flat" in the name, means that the memory layout of the Map is
* sequential array and thus requires less memory than ConcurrentSkipListMap.
*/
@InterfaceAudience.Private
public abstract class CellFlatMap implements NavigableMap {
private static final Logger LOG = LoggerFactory.getLogger(CellFlatMap.class);
private final Comparator super Cell> comparator;
protected int minCellIdx = 0; // the index of the minimal cell (for sub-sets)
protected int maxCellIdx = 0; // the index of the cell after the maximal cell (for sub-sets)
private boolean descending = false;
/* C-tor */
public CellFlatMap(Comparator super Cell> comparator, int min, int max, boolean d) {
this.comparator = comparator;
this.minCellIdx = min;
this.maxCellIdx = max;
this.descending = d;
}
/* Used for abstract CellFlatMap creation, implemented by derived class */
protected abstract CellFlatMap createSubCellFlatMap(int min, int max, boolean descending);
/* Returns the i-th cell in the cell block */
protected abstract Cell getCell(int i);
/**
* Binary search for a given key in between given boundaries of the array. Positive returned
* numbers mean the index. Negative returned numbers means the key not found. The absolute value
* of the output is the possible insert index for the searched key In twos-complement, (-1 *
* insertion point)-1 is the bitwise not of the insert point.
* @param needle The key to look for in all of the entries
* @return Same return value as Arrays.binarySearch.
*/
private int find(Cell needle) {
int begin = minCellIdx;
int end = maxCellIdx - 1;
while (begin <= end) {
int mid = begin + ((end - begin) >> 1);
Cell midCell = getCell(mid);
int compareRes = comparator.compare(midCell, needle);
if (compareRes == 0) {
return mid; // 0 means equals. We found the key
}
// Key not found. Check the comparison results; reverse the meaning of
// the comparison in case the order is descending (using XOR)
if ((compareRes < 0) ^ descending) {
// midCell is less than needle so we need to look at farther up
begin = mid + 1;
} else {
// midCell is greater than needle so we need to look down
end = mid - 1;
}
}
return (-1 * begin) - 1;
}
/**
* Get the index of the given anchor key for creating subsequent set. It doesn't matter whether
* the given key exists in the set or not. taking into consideration whether the key should be
* inclusive or exclusive.
*/
private int getValidIndex(Cell key, boolean inclusive, boolean tail) {
final int index = find(key);
// get the valid (positive) insertion point from the output of the find() method
int insertionPoint = index < 0 ? ~index : index;
// correct the insertion point in case the given anchor key DOES EXIST in the set
if (index >= 0) {
if (descending && !(tail ^ inclusive)) {
// for the descending case
// if anchor for head set (tail=false) AND anchor is not inclusive -> move the insertion pt
// if anchor for tail set (tail=true) AND the keys is inclusive -> move the insertion point
// because the end index of a set is the index of the cell after the maximal cell
insertionPoint += 1;
} else if (!descending && (tail ^ inclusive)) {
// for the ascending case
// if anchor for head set (tail=false) AND anchor is inclusive -> move the insertion point
// because the end index of a set is the index of the cell after the maximal cell
// if anchor for tail set (tail=true) AND the keys is not inclusive -> move the insertion pt
insertionPoint += 1;
}
}
// insert the insertion point into the valid range,
// as we may enlarge it too much in the above correction
return Math.min(Math.max(insertionPoint, minCellIdx), maxCellIdx);
}
@Override
public Comparator super Cell> comparator() {
return comparator;
}
@Override
public int size() {
return maxCellIdx - minCellIdx;
}
@Override
public boolean isEmpty() {
return (size() == 0);
}
// ---------------- Sub-Maps ----------------
@Override
public NavigableMap subMap(Cell fromKey, boolean fromInclusive, Cell toKey,
boolean toInclusive) {
final int lessCellIndex = getValidIndex(fromKey, fromInclusive, true);
final int greaterCellIndex = getValidIndex(toKey, toInclusive, false);
if (descending) {
return createSubCellFlatMap(greaterCellIndex, lessCellIndex, descending);
} else {
return createSubCellFlatMap(lessCellIndex, greaterCellIndex, descending);
}
}
@Override
public NavigableMap headMap(Cell toKey, boolean inclusive) {
if (descending) {
return createSubCellFlatMap(getValidIndex(toKey, inclusive, false), maxCellIdx, descending);
} else {
return createSubCellFlatMap(minCellIdx, getValidIndex(toKey, inclusive, false), descending);
}
}
@Override
public NavigableMap tailMap(Cell fromKey, boolean inclusive) {
if (descending) {
return createSubCellFlatMap(minCellIdx, getValidIndex(fromKey, inclusive, true), descending);
} else {
return createSubCellFlatMap(getValidIndex(fromKey, inclusive, true), maxCellIdx, descending);
}
}
@Override
public NavigableMap descendingMap() {
return createSubCellFlatMap(minCellIdx, maxCellIdx, true);
}
@Override
public NavigableMap subMap(Cell k1, Cell k2) {
return this.subMap(k1, true, k2, true);
}
@Override
public NavigableMap headMap(Cell k) {
return this.headMap(k, true);
}
@Override
public NavigableMap tailMap(Cell k) {
return this.tailMap(k, true);
}
// -------------------------------- Key's getters --------------------------------
@Override
public Cell firstKey() {
if (isEmpty()) {
return null;
}
return descending ? getCell(maxCellIdx - 1) : getCell(minCellIdx);
}
@Override
public Cell lastKey() {
if (isEmpty()) {
return null;
}
return descending ? getCell(minCellIdx) : getCell(maxCellIdx - 1);
}
@Override
public Cell lowerKey(Cell k) {
if (isEmpty()) {
return null;
}
int index = find(k);
// If index>=0 there's a key exactly equal
index = (index >= 0) ? index - 1 : -(index);
return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
}
@Override
public Cell floorKey(Cell k) {
if (isEmpty()) {
return null;
}
int index = find(k);
index = (index >= 0) ? index : -(index);
return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
}
@Override
public Cell ceilingKey(Cell k) {
if (isEmpty()) {
return null;
}
int index = find(k);
index = (index >= 0) ? index : -(index) + 1;
return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
}
@Override
public Cell higherKey(Cell k) {
if (isEmpty()) {
return null;
}
int index = find(k);
index = (index >= 0) ? index + 1 : -(index) + 1;
return (index < minCellIdx || index >= maxCellIdx) ? null : getCell(index);
}
@Override
public boolean containsKey(Object o) {
int index = find((Cell) o);
return (index >= 0);
}
@Override
public boolean containsValue(Object o) { // use containsKey(Object o) instead
throw new UnsupportedOperationException("Use containsKey(Object o) instead");
}
@Override
public Cell get(Object o) {
int index = find((Cell) o);
return (index >= 0) ? getCell(index) : null;
}
// -------------------------------- Entry's getters --------------------------------
private static class CellFlatMapEntry implements Entry {
private final Cell cell;
public CellFlatMapEntry(Cell cell) {
this.cell = cell;
}
@Override
public Cell getKey() {
return cell;
}
@Override
public Cell getValue() {
return cell;
}
@Override
public Cell setValue(Cell value) {
throw new UnsupportedOperationException();
}
}
@Override
public Entry lowerEntry(Cell k) {
Cell cell = lowerKey(k);
if (cell == null) {
return null;
}
return new CellFlatMapEntry(cell);
}
@Override
public Entry higherEntry(Cell k) {
Cell cell = higherKey(k);
if (cell == null) {
return null;
}
return new CellFlatMapEntry(cell);
}
@Override
public Entry ceilingEntry(Cell k) {
Cell cell = ceilingKey(k);
if (cell == null) {
return null;
}
return new CellFlatMapEntry(cell);
}
@Override
public Entry floorEntry(Cell k) {
Cell cell = floorKey(k);
if (cell == null) {
return null;
}
return new CellFlatMapEntry(cell);
}
@Override
public Entry firstEntry() {
Cell cell = firstKey();
if (cell == null) {
return null;
}
return new CellFlatMapEntry(cell);
}
@Override
public Entry lastEntry() {
Cell cell = lastKey();
if (cell == null) {
return null;
}
return new CellFlatMapEntry(cell);
}
// The following 2 methods (pollFirstEntry, pollLastEntry) are unsupported because these are
// updating methods.
@Override
public Entry pollFirstEntry() {
throw new UnsupportedOperationException();
}
@Override
public Entry pollLastEntry() {
throw new UnsupportedOperationException();
}
// -------------------------------- Updates --------------------------------
// All updating methods below are unsupported.
// Assuming an array of Cells will be allocated externally,
// fill up with Cells and provided in construction time.
// Later the structure is immutable.
@Override
public Cell put(Cell k, Cell v) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public Cell remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public void putAll(Map extends Cell, ? extends Cell> map) {
throw new UnsupportedOperationException();
}
// -------------------------------- Sub-Sets --------------------------------
@Override
public NavigableSet navigableKeySet() {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet descendingKeySet() {
throw new UnsupportedOperationException();
}
@Override
public NavigableSet keySet() {
throw new UnsupportedOperationException();
}
@Override
public Collection values() {
return new CellFlatMapCollection();
}
@Override
public Set> entrySet() {
throw new UnsupportedOperationException();
}
// -------------------------------- Iterator K --------------------------------
private final class CellFlatMapIterator implements Iterator {
int index;
private CellFlatMapIterator() {
index = descending ? maxCellIdx - 1 : minCellIdx;
}
@Override
public boolean hasNext() {
return descending ? (index >= minCellIdx) : (index < maxCellIdx);
}
@Override
public Cell next() {
Cell result = getCell(index);
if (descending) {
index--;
} else {
index++;
}
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
}
// -------------------------------- Collection --------------------------------
private final class CellFlatMapCollection implements Collection {
@Override
public int size() {
return CellFlatMap.this.size();
}
@Override
public boolean isEmpty() {
return CellFlatMap.this.isEmpty();
}
@Override
public void clear() {
throw new UnsupportedOperationException();
}
@Override
public boolean contains(Object o) {
return containsKey(o);
}
@Override
public Iterator iterator() {
return new CellFlatMapIterator();
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public T[] toArray(T[] ts) {
throw new UnsupportedOperationException();
}
@Override
public boolean add(Cell k) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection> collection) {
throw new UnsupportedOperationException();
}
@Override
public boolean addAll(Collection extends Cell> collection) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeAll(Collection> collection) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection> collection) {
throw new UnsupportedOperationException();
}
}
}
| | | | | | | | | | | | | | | | | | | | | | | |