All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.hadoop.hbase.regionserver.LocalIndexStoreFileScanner Maven / Gradle / Ivy

The newest version!
/**
 * 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.io.IOException;
import java.util.Map.Entry;

import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.KeyValue.Type;
import org.apache.hadoop.hbase.KeyValueUtil;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.io.hfile.HFileScanner;
import org.apache.hadoop.hbase.regionserver.StoreFile.Reader;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.index.IndexMaintainer;

import static org.apache.hadoop.hbase.KeyValue.ROW_LENGTH_SIZE;

public class LocalIndexStoreFileScanner extends StoreFileScanner{

    private IndexHalfStoreFileReader reader;
    private boolean changeBottomKeys;
    public LocalIndexStoreFileScanner(Reader reader, HFileScanner hfs, boolean useMVCC,
            boolean hasMVCC, long readPt, long scannerOrder, boolean canOptimizeForNonNullColumn) {
        super(reader, hfs, useMVCC, hasMVCC, readPt, scannerOrder, canOptimizeForNonNullColumn);
        this.reader = ((IndexHalfStoreFileReader)super.getReader());
        this.changeBottomKeys =
                this.reader.getRegionInfo().getStartKey().length == 0
                        && this.reader.getSplitRow().length != this.reader.getOffset();
    }

    @Override
    public Cell next() throws IOException {
        Cell next = super.next();
        while(next !=null && !isSatisfiedMidKeyCondition(next)) {
            next = super.next();
        }
        while(super.peek() != null && !isSatisfiedMidKeyCondition(super.peek())) {
            super.next();
        }
        if (next!=null && (reader.isTop() || changeBottomKeys)) {
            next = getChangedKey(next,  !reader.isTop() && changeBottomKeys);
        } 
        return next;
    }

    @Override
    public Cell peek() {
        Cell peek = super.peek();
        if (peek != null && (reader.isTop() || changeBottomKeys)) {
            peek = getChangedKey(peek, !reader.isTop() && changeBottomKeys);
        } 
        return peek;
    }

    private KeyValue getChangedKey(Cell next, boolean changeBottomKeys) {
        // If it is a top store file change the StartKey with SplitKey in Key
        //and produce the new value corresponding to the change in key
        byte[] changedKey = getNewRowkeyByRegionStartKeyReplacedWithSplitKey(next, changeBottomKeys);
        KeyValue changedKv =
                new KeyValue(changedKey, 0, changedKey.length, next.getFamilyArray(),
                    next.getFamilyOffset(), next.getFamilyLength(), next.getQualifierArray(),
                    next.getQualifierOffset(), next.getQualifierLength(),
                    next.getTimestamp(), Type.codeToType(next.getTypeByte()),
                    next.getValueArray(), next.getValueOffset(), next.getValueLength(),
                    next.getTagsArray(), next.getTagsOffset(), next.getTagsLength());
        return changedKv;
    }

    /**
     * Enforce seek all the time for local index store file scanner otherwise some times hbase
     * might return fake kvs not in physical files.
     */
    @Override
    public boolean requestSeek(Cell kv, boolean forward, boolean useBloom) throws IOException {
        boolean requestSeek = super.requestSeek(kv, forward, useBloom);
        if(requestSeek) {
            Cell peek = super.peek();
            if (Bytes.compareTo(kv.getRowArray(), kv.getRowOffset(), kv.getRowLength(),
                peek.getRowArray(), peek.getRowOffset(), peek.getRowLength()) == 0) {
                return forward ? reseek(kv): seek(kv);
            }
        }
        return requestSeek;
    }

    @Override
    public boolean seek(Cell key) throws IOException {
        return seekOrReseek(key, true);
    }

    @Override
    public boolean reseek(Cell key) throws IOException {
        return seekOrReseek(key, false);
    }

    @Override
    public boolean seekToPreviousRow(Cell key) throws IOException {
        KeyValue kv = KeyValueUtil.ensureKeyValue(key);
        if (reader.isTop()) {
            byte[] fk = reader.getFirstKey();
            // This will be null when the file is empty in which we can not seekBefore to
            // any key
            if (fk == null) {
                return false;
            }
            if (getComparator().compare(kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength(), fk, 0, fk.length) <= 0) {
                return super.seekToPreviousRow(key);
            }
            KeyValue replacedKey = getKeyPresentInHFiles(kv);
            boolean seekToPreviousRow = super.seekToPreviousRow(replacedKey);
            while(super.peek()!=null && !isSatisfiedMidKeyCondition(super.peek())) {
                seekToPreviousRow = super.seekToPreviousRow(super.peek());
            }
            return seekToPreviousRow;
        } else {
            // The equals sign isn't strictly necessary just here to be consistent with
            // seekTo
            if (getComparator().compare(kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength(), reader.getSplitkey(), 0, reader.getSplitkey().length) >= 0) {
                boolean seekToPreviousRow = super.seekToPreviousRow(kv);
                while(super.peek()!=null && !isSatisfiedMidKeyCondition(super.peek())) {
                    seekToPreviousRow = super.seekToPreviousRow(super.peek());
                }
                return seekToPreviousRow;
            }
        }
        boolean seekToPreviousRow = super.seekToPreviousRow(kv);
        while(super.peek()!=null && !isSatisfiedMidKeyCondition(super.peek())) {
            seekToPreviousRow = super.seekToPreviousRow(super.peek());
        }
        return seekToPreviousRow;
    }

    @Override
    public boolean seekToLastRow() throws IOException {
        boolean seekToLastRow = super.seekToLastRow();
        while(super.peek()!=null && !isSatisfiedMidKeyCondition(super.peek())) {
            seekToLastRow = super.seekToPreviousRow(super.peek());
        }
        return seekToLastRow;
    }

    private boolean isSatisfiedMidKeyCondition(Cell kv) {
        ImmutableBytesWritable rowKey =
                new ImmutableBytesWritable(kv.getRowArray(), kv.getRowOffset() + reader.getOffset(),
                        kv.getRowLength() - reader.getOffset());
        Entry entry = reader.getIndexMaintainers().entrySet().iterator().next();
        IndexMaintainer indexMaintainer = entry.getValue();
        byte[] viewIndexId = indexMaintainer.getViewIndexIdFromIndexRowKey(rowKey);
        IndexMaintainer actualIndexMaintainer = reader.getIndexMaintainers().get(new ImmutableBytesWritable(viewIndexId));
        if(actualIndexMaintainer != null) {
            byte[] dataRowKey = actualIndexMaintainer.buildDataRowKey(rowKey, reader.getViewConstants());

            int compareResult = Bytes.compareTo(dataRowKey, reader.getSplitRow());
            if (reader.isTop()) {
                if (compareResult >= 0) {
                    return true;
                }
            } else {
                if (compareResult < 0) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * In case of top half store, the passed key will be with the start key of the daughter region.
     * But in the actual HFiles, the key will be with the start key of the old parent region. In
     * order to make the real seek in the HFiles, we need to build the old key.
     *
     * The logic here is just replace daughter region start key with parent region start key
     * in the key part.
     *
     * @param key
     *
     */
    private KeyValue getKeyPresentInHFiles(Cell keyValue) {
        int rowLength = keyValue.getRowLength();
        int rowOffset = keyValue.getRowOffset();

        short length = (short) (rowLength - reader.getSplitRow().length + reader.getOffset());
        byte[] replacedKey =
                new byte[length + keyValue.getRowArray().length - (rowOffset + rowLength) + ROW_LENGTH_SIZE];
        System.arraycopy(Bytes.toBytes(length), 0, replacedKey, 0, ROW_LENGTH_SIZE);
        System.arraycopy(reader.getRegionStartKeyInHFile(), 0, replacedKey, ROW_LENGTH_SIZE, reader.getOffset());
        System.arraycopy(keyValue.getRowArray(), keyValue.getRowOffset() + reader.getSplitRow().length,
            replacedKey, reader.getOffset() + ROW_LENGTH_SIZE, rowLength
                    - reader.getSplitRow().length);
        System.arraycopy(keyValue.getRowArray(), rowOffset + rowLength, replacedKey,
            reader.getOffset() + rowLength - reader.getSplitRow().length
                    + ROW_LENGTH_SIZE, keyValue.getRowArray().length - (rowOffset + rowLength));
        return new KeyValue.KeyOnlyKeyValue(replacedKey);
    }
    
    /**
     * 
     * @param kv
     * @param isSeek pass true for seek, false for reseek.
     * @return 
     * @throws IOException
     */
    public boolean seekOrReseek(Cell cell, boolean isSeek) throws IOException{
        KeyValue kv = KeyValueUtil.ensureKeyValue(cell);
        KeyValue keyToSeek = kv;
        if (reader.isTop()) {
            if(getComparator().compare(kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength(), reader.getSplitkey(), 0, reader.getSplitkey().length) < 0){
                if(!isSeek && realSeekDone()) {
                    return true;
                }
                return seekOrReseekToProperKey(isSeek, keyToSeek);
            }
            keyToSeek = getKeyPresentInHFiles(kv);
            return seekOrReseekToProperKey(isSeek, keyToSeek);
        } else {
            if (getComparator().compare(kv.getBuffer(), kv.getKeyOffset(), kv.getKeyLength(), reader.getSplitkey(), 0, reader.getSplitkey().length) >= 0) {
                close();
                return false;
            }
            if(!isSeek && reader.getRegionInfo().getStartKey().length == 0 && reader.getSplitRow().length > reader.getRegionStartKeyInHFile().length) {
                keyToSeek = getKeyPresentInHFiles(kv);
            }
        }
        return seekOrReseekToProperKey(isSeek, keyToSeek);
    }

    private boolean seekOrReseekToProperKey(boolean isSeek, KeyValue kv)
            throws IOException {
        boolean seekOrReseek = isSeek ? super.seek(kv) : super.reseek(kv);
        while (seekOrReseek && super.peek() != null
                && !isSatisfiedMidKeyCondition(super.peek())) {
            super.next();
            seekOrReseek = super.peek() != null;
        }
        return seekOrReseek;
    }

    private byte[] getNewRowkeyByRegionStartKeyReplacedWithSplitKey(Cell kv, boolean changeBottomKeys) {
        int lenOfRemainingKey = kv.getRowLength() - reader.getOffset();
        byte[] keyReplacedStartKey = new byte[lenOfRemainingKey + reader.getSplitRow().length];
        System.arraycopy(changeBottomKeys ? new byte[reader.getSplitRow().length] : reader.getSplitRow(), 0,
                keyReplacedStartKey, 0, reader.getSplitRow().length);
        System.arraycopy(kv.getRowArray(), kv.getRowOffset() + reader.getOffset(), keyReplacedStartKey,
                reader.getSplitRow().length, lenOfRemainingKey);
        return keyReplacedStartKey;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy