org.apache.hadoop.hbase.regionserver.CellFlatMap.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.regionserver.CellFlatMap.java

Source

/**
 *
 * 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, Cellersion 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 CellIND, 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 org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.classification.InterfaceAudience;

import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NavigableSet;
import java.util.NavigableMap;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 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<Cell, Cell> {
    private static final Log LOG = LogFactory.getLog(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) >>> 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<Cell, Cell> 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<Cell, Cell> 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<Cell, Cell> 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<Cell, Cell> descendingMap() {
        return createSubCellFlatMap(minCellIdx, maxCellIdx, true);
    }

    @Override
    public NavigableMap<Cell, Cell> subMap(Cell k1, Cell k2) {
        return this.subMap(k1, true, k2, true);
    }

    @Override
    public NavigableMap<Cell, Cell> headMap(Cell k) {
        return this.headMap(k, true);
    }

    @Override
    public NavigableMap<Cell, Cell> 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 --------------------------------
    // all interfaces returning Entries are unsupported because we are dealing only with the keys
    @Override
    public Entry<Cell, Cell> lowerEntry(Cell k) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> higherEntry(Cell k) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> ceilingEntry(Cell k) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> floorEntry(Cell k) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> firstEntry() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> lastEntry() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> pollFirstEntry() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Entry<Cell, Cell> 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<Cell> navigableKeySet() {
        throw new UnsupportedOperationException();
    }

    @Override
    public NavigableSet<Cell> descendingKeySet() {
        throw new UnsupportedOperationException();
    }

    @Override
    public NavigableSet<Cell> keySet() {
        throw new UnsupportedOperationException();
    }

    @Override
    public Collection<Cell> values() {
        return new CellFlatMapCollection();
    }

    @Override
    public Set<Entry<Cell, Cell>> entrySet() {
        throw new UnsupportedOperationException();
    }

    // -------------------------------- Iterator K --------------------------------
    private final class CellFlatMapIterator implements Iterator<Cell> {
        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<Cell> {

        @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<Cell> iterator() {
            return new CellFlatMapIterator();
        }

        @Override
        public Object[] toArray() {
            throw new UnsupportedOperationException();
        }

        @Override
        public <T> 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();
        }
    }
}