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 * Scanner scans both the memstore and the MOB Store. Coalesce KeyValue stream into 036 * {@code List<KeyValue>} for a single row. 037 */ 038@InterfaceAudience.Private 039public class MobStoreScanner extends StoreScanner { 040 041 private static final Logger LOG = LoggerFactory.getLogger(MobStoreScanner.class); 042 043 private boolean cacheMobBlocks = false; 044 private boolean rawMobScan = false; 045 private boolean readEmptyValueOnMobCellMiss = false; 046 private final HMobStore mobStore; 047 private final List<MobCell> referencedMobCells; 048 049 public MobStoreScanner(HStore store, ScanInfo scanInfo, Scan scan, 050 final NavigableSet<byte[]> columns, long readPt) throws IOException { 051 super(store, scanInfo, scan, columns, readPt); 052 cacheMobBlocks = MobUtils.isCacheMobBlocks(scan); 053 rawMobScan = MobUtils.isRawMobScan(scan); 054 readEmptyValueOnMobCellMiss = MobUtils.isReadEmptyValueOnMobCellMiss(scan); 055 if (!(store instanceof HMobStore)) { 056 throw new IllegalArgumentException("The store " + store + " is not a HMobStore"); 057 } 058 mobStore = (HMobStore) store; 059 this.referencedMobCells = new ArrayList<>(); 060 } 061 062 /** 063 * Firstly reads the cells from the HBase. If the cell are a reference cell (which has the 064 * reference tag), the scanner need seek this cell from the mob file, and use the cell found 065 * from the mob file as the result. 066 */ 067 @Override 068 public boolean next(List<Cell> outResult, ScannerContext ctx) throws IOException { 069 boolean result = super.next(outResult, ctx); 070 if (!rawMobScan) { 071 // retrieve the mob data 072 if (outResult.isEmpty()) { 073 return result; 074 } 075 long mobKVCount = 0; 076 long mobKVSize = 0; 077 for (int i = 0; i < outResult.size(); i++) { 078 Cell cell = outResult.get(i); 079 if (MobUtils.isMobReferenceCell(cell)) { 080 MobCell mobCell = 081 mobStore.resolve(cell, cacheMobBlocks, readPt, readEmptyValueOnMobCellMiss); 082 mobKVCount++; 083 mobKVSize += mobCell.getCell().getValueLength(); 084 outResult.set(i, mobCell.getCell()); 085 // Keep the MobCell here unless we shipped the RPC or close the scanner. 086 referencedMobCells.add(mobCell); 087 } 088 } 089 mobStore.updateMobScanCellsCount(mobKVCount); 090 mobStore.updateMobScanCellsSize(mobKVSize); 091 } 092 return result; 093 } 094 095 private void freeAllReferencedMobCells() throws IOException { 096 for (MobCell cell : referencedMobCells) { 097 cell.close(); 098 } 099 referencedMobCells.clear(); 100 } 101 102 @Override 103 public void shipped() throws IOException { 104 super.shipped(); 105 this.freeAllReferencedMobCells(); 106 } 107 108 @Override 109 public void close() { 110 super.close(); 111 try { 112 this.freeAllReferencedMobCells(); 113 } catch (IOException e) { 114 LOG.warn("Failed to free referenced mob cells: ", e); 115 } 116 } 117}