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

Java tutorial

Introduction

Here is the source code for org.apache.hadoop.hbase.regionserver.Segment.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, 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.Iterator;
import java.util.SortedSet;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellComparator;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.KeyValueUtil;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.util.ByteRange;

import com.google.common.annotations.VisibleForTesting;

/**
 * This is an abstraction of a segment maintained in a memstore, e.g., the active
 * cell set or its snapshot.
 *
 * This abstraction facilitates the management of the compaction pipeline and the shifts of these
 * segments from active set to snapshot set in the default implementation.
 */
@InterfaceAudience.Private
public abstract class Segment {

    private volatile CellSet cellSet;
    private final CellComparator comparator;
    private long minSequenceId;
    private volatile MemStoreLAB memStoreLAB;
    protected final AtomicLong size;
    protected volatile boolean tagsPresent;
    private final TimeRangeTracker timeRangeTracker;

    protected Segment(CellSet cellSet, CellComparator comparator, MemStoreLAB memStoreLAB, long size) {
        this.cellSet = cellSet;
        this.comparator = comparator;
        this.minSequenceId = Long.MAX_VALUE;
        this.memStoreLAB = memStoreLAB;
        this.size = new AtomicLong(size);
        this.tagsPresent = false;
        this.timeRangeTracker = new TimeRangeTracker();
    }

    protected Segment(Segment segment) {
        this.cellSet = segment.getCellSet();
        this.comparator = segment.getComparator();
        this.minSequenceId = segment.getMinSequenceId();
        this.memStoreLAB = segment.getMemStoreLAB();
        this.size = new AtomicLong(segment.getSize());
        this.tagsPresent = segment.isTagsPresent();
        this.timeRangeTracker = segment.getTimeRangeTracker();
    }

    /**
     * Creates the scanner for the given read point
     * @return a scanner for the given read point
     */
    public SegmentScanner getSegmentScanner(long readPoint) {
        return new SegmentScanner(this, readPoint);
    }

    /**
     * Creates the scanner for the given read point, and a specific order in a list
     * @return a scanner for the given read point
     */
    public SegmentScanner getSegmentScanner(long readPoint, long order) {
        return new SegmentScanner(this, readPoint, order);
    }

    /**
     * Returns whether the segment has any cells
     * @return whether the segment has any cells
     */
    public boolean isEmpty() {
        return getCellSet().isEmpty();
    }

    /**
     * Returns number of cells in segment
     * @return number of cells in segment
     */
    public int getCellsCount() {
        return getCellSet().size();
    }

    /**
     * Returns the first cell in the segment that has equal or greater key than the given cell
     * @return the first cell in the segment that has equal or greater key than the given cell
     */
    public Cell getFirstAfter(Cell cell) {
        SortedSet<Cell> snTailSet = tailSet(cell);
        if (!snTailSet.isEmpty()) {
            return snTailSet.first();
        }
        return null;
    }

    /**
     * Closing a segment before it is being discarded
     */
    public void close() {
        MemStoreLAB mslab = getMemStoreLAB();
        if (mslab != null) {
            mslab.close();
        }
        // do not set MSLab to null as scanners may still be reading the data here and need to decrease
        // the counter when they finish
    }

    /**
     * If the segment has a memory allocator the cell is being cloned to this space, and returned;
     * otherwise the given cell is returned
     * @return either the given cell or its clone
     */
    public Cell maybeCloneWithAllocator(Cell cell) {
        if (getMemStoreLAB() == null) {
            return cell;
        }

        int len = getCellLength(cell);
        ByteRange alloc = getMemStoreLAB().allocateBytes(len);
        if (alloc == null) {
            // The allocation was too large, allocator decided
            // not to do anything with it.
            return cell;
        }
        assert alloc.getBytes() != null;
        KeyValueUtil.appendToByteArray(cell, alloc.getBytes(), alloc.getOffset());
        KeyValue newKv = new KeyValue(alloc.getBytes(), alloc.getOffset(), len);
        newKv.setSequenceId(cell.getSequenceId());
        return newKv;
    }

    /**
     * Get cell length after serialized in {@link KeyValue}
     */
    @VisibleForTesting
    int getCellLength(Cell cell) {
        return KeyValueUtil.length(cell);
    }

    public abstract boolean shouldSeek(Scan scan, long oldestUnexpiredTS);

    public abstract long getMinTimestamp();

    public boolean isTagsPresent() {
        return tagsPresent;
    }

    public void incScannerCount() {
        if (getMemStoreLAB() != null) {
            getMemStoreLAB().incScannerCount();
        }
    }

    public void decScannerCount() {
        if (getMemStoreLAB() != null) {
            getMemStoreLAB().decScannerCount();
        }
    }

    /**
     * Setting the heap size of the segment - used to account for different class overheads
     * @return this object
     */

    public Segment setSize(long size) {
        this.size.set(size);
        return this;
    }

    /**
     * Returns the heap size of the segment
     * @return the heap size of the segment
     */
    public long getSize() {
        return size.get();
    }

    /**
     * Increases the heap size counter of the segment by the given delta
     */
    public void incSize(long delta) {
        size.addAndGet(delta);
    }

    public long getMinSequenceId() {
        return minSequenceId;
    }

    public TimeRangeTracker getTimeRangeTracker() {
        return this.timeRangeTracker;
    }

    //*** Methods for SegmentsScanner
    public Cell last() {
        return getCellSet().last();
    }

    public Iterator<Cell> iterator() {
        return getCellSet().iterator();
    }

    public SortedSet<Cell> headSet(Cell firstKeyOnRow) {
        return getCellSet().headSet(firstKeyOnRow);
    }

    public int compare(Cell left, Cell right) {
        return getComparator().compare(left, right);
    }

    public int compareRows(Cell left, Cell right) {
        return getComparator().compareRows(left, right);
    }

    /**
     * Returns a set of all cells in the segment
     * @return a set of all cells in the segment
     */
    protected CellSet getCellSet() {
        return cellSet;
    }

    /**
     * Returns the Cell comparator used by this segment
     * @return the Cell comparator used by this segment
     */
    protected CellComparator getComparator() {
        return comparator;
    }

    protected long internalAdd(Cell cell, boolean mslabUsed) {
        boolean succ = getCellSet().add(cell);
        long s = AbstractMemStore.heapSizeChange(cell, succ);
        // If there's already a same cell in the CellSet and we are using MSLAB, we must count in the
        // MSLAB allocation size as well, or else there will be memory leak (occupied heap size larger
        // than the counted number)
        if (!succ && mslabUsed) {
            s += getCellLength(cell);
        }
        updateMetaInfo(cell, s);
        return s;
    }

    protected void updateMetaInfo(Cell toAdd, long s) {
        getTimeRangeTracker().includeTimestamp(toAdd);
        size.addAndGet(s);
        minSequenceId = Math.min(minSequenceId, toAdd.getSequenceId());
        // In no tags case this NoTagsKeyValue.getTagsLength() is a cheap call.
        // When we use ACL CP or Visibility CP which deals with Tags during
        // mutation, the TagRewriteCell.getTagsLength() is a cheaper call. We do not
        // parse the byte[] to identify the tags length.
        if (toAdd.getTagsLength() > 0) {
            tagsPresent = true;
        }
    }

    /**
     * Returns a subset of the segment cell set, which starts with the given cell
     * @param firstCell a cell in the segment
     * @return a subset of the segment cell set, which starts with the given cell
     */
    protected SortedSet<Cell> tailSet(Cell firstCell) {
        return getCellSet().tailSet(firstCell);
    }

    @VisibleForTesting
    public MemStoreLAB getMemStoreLAB() {
        return memStoreLAB;
    }

    // Debug methods
    /**
     * Dumps all cells of the segment into the given log
     */
    void dump(Log log) {
        for (Cell cell : getCellSet()) {
            log.debug(cell);
        }
    }

    @Override
    public String toString() {
        String res = "Store segment of type " + this.getClass().getName() + "; ";
        res += "isEmpty " + (isEmpty() ? "yes" : "no") + "; ";
        res += "cellCount " + getCellsCount() + "; ";
        res += "size " + getSize() + "; ";
        res += "Min ts " + getMinTimestamp() + "; ";
        return res;
    }
}