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