001/**
002 *
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *     http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019package org.apache.hadoop.hbase.regionserver;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.List;
024import java.util.NavigableSet;
025
026import org.apache.hadoop.hbase.Cell;
027import org.apache.hadoop.hbase.client.Scan;
028import org.apache.hadoop.hbase.mob.MobCell;
029import org.apache.hadoop.hbase.mob.MobUtils;
030import org.apache.yetus.audience.InterfaceAudience;
031import org.slf4j.Logger;
032import org.slf4j.LoggerFactory;
033
034/**
035 * ReversedMobStoreScanner extends from ReversedStoreScanner, and is used to support reversed
036 * scanning in both the memstore and the MOB store.
037 */
038@InterfaceAudience.Private
039public class ReversedMobStoreScanner extends ReversedStoreScanner {
040
041  private static final Logger LOG = LoggerFactory.getLogger(ReversedMobStoreScanner.class);
042  private boolean cacheMobBlocks = false;
043  private boolean rawMobScan = false;
044  private boolean readEmptyValueOnMobCellMiss = false;
045  private final HMobStore mobStore;
046  private final List<MobCell> referencedMobCells;
047
048  ReversedMobStoreScanner(HStore store, ScanInfo scanInfo, Scan scan, NavigableSet<byte[]> columns,
049      long readPt) throws IOException {
050    super(store, scanInfo, scan, columns, readPt);
051    cacheMobBlocks = MobUtils.isCacheMobBlocks(scan);
052    rawMobScan = MobUtils.isRawMobScan(scan);
053    readEmptyValueOnMobCellMiss = MobUtils.isReadEmptyValueOnMobCellMiss(scan);
054    if (!(store instanceof HMobStore)) {
055      throw new IllegalArgumentException("The store " + store + " is not a HMobStore");
056    }
057    mobStore = (HMobStore) store;
058    this.referencedMobCells = new ArrayList<>();
059  }
060
061  /**
062   * Firstly reads the cells from the HBase. If the cell is a reference cell (which has the
063   * reference tag), the scanner need seek this cell from the mob file, and use the cell found
064   * from the mob file as the result.
065   */
066  @Override
067  public boolean next(List<Cell> outResult, ScannerContext ctx) throws IOException {
068    boolean result = super.next(outResult, ctx);
069    if (!rawMobScan) {
070      // retrieve the mob data
071      if (outResult.isEmpty()) {
072        return result;
073      }
074      long mobKVCount = 0;
075      long mobKVSize = 0;
076      for (int i = 0; i < outResult.size(); i++) {
077        Cell cell = outResult.get(i);
078        if (MobUtils.isMobReferenceCell(cell)) {
079          MobCell mobCell =
080              mobStore.resolve(cell, cacheMobBlocks, readPt, readEmptyValueOnMobCellMiss);
081          mobKVCount++;
082          mobKVSize += mobCell.getCell().getValueLength();
083          outResult.set(i, mobCell.getCell());
084          // Keep the MobCell here unless we shipped the RPC or close the scanner.
085          referencedMobCells.add(mobCell);
086        }
087      }
088      mobStore.updateMobScanCellsCount(mobKVCount);
089      mobStore.updateMobScanCellsSize(mobKVSize);
090    }
091    return result;
092  }
093
094  private void freeAllReferencedMobCells() throws IOException {
095    for (MobCell mobCell : referencedMobCells) {
096      mobCell.close();
097    }
098    referencedMobCells.clear();
099  }
100
101  @Override
102  public void shipped() throws IOException {
103    super.shipped();
104    this.freeAllReferencedMobCells();
105  }
106
107  @Override
108  public void close() {
109    super.close();
110    try {
111      this.freeAllReferencedMobCells();
112    } catch (IOException e) {
113      LOG.warn("Failed to free referenced mob cells: ", e);
114    }
115  }
116}