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 */ 018 019package org.apache.hadoop.hbase.client; 020 021import java.io.IOException; 022import java.util.ArrayList; 023import java.util.List; 024 025import org.apache.hadoop.conf.Configuration; 026import org.apache.hadoop.fs.FileSystem; 027import org.apache.hadoop.fs.Path; 028import org.apache.hadoop.hbase.Cell; 029import org.apache.hadoop.hbase.PrivateCellUtil; 030import org.apache.hadoop.hbase.client.metrics.ScanMetrics; 031import org.apache.hadoop.hbase.mob.MobFileCache; 032import org.apache.hadoop.hbase.regionserver.HRegion; 033import org.apache.hadoop.hbase.regionserver.RegionScanner; 034import org.apache.hadoop.hbase.util.FSUtils; 035import org.apache.yetus.audience.InterfaceAudience; 036import org.slf4j.Logger; 037import org.slf4j.LoggerFactory; 038 039/** 040 * A client scanner for a region opened for read-only on the client side. Assumes region data 041 * is not changing. 042 */ 043@InterfaceAudience.Private 044public class ClientSideRegionScanner extends AbstractClientScanner { 045 046 private static final Logger LOG = LoggerFactory.getLogger(ClientSideRegionScanner.class); 047 048 private HRegion region; 049 RegionScanner scanner; 050 List<Cell> values; 051 052 public ClientSideRegionScanner(Configuration conf, FileSystem fs, 053 Path rootDir, TableDescriptor htd, RegionInfo hri, Scan scan, ScanMetrics scanMetrics) 054 throws IOException { 055 // region is immutable, set isolation level 056 scan.setIsolationLevel(IsolationLevel.READ_UNCOMMITTED); 057 058 htd = TableDescriptorBuilder.newBuilder(htd).setReadOnly(true).build(); 059 060 // open region from the snapshot directory 061 region = HRegion.newHRegion(FSUtils.getTableDir(rootDir, htd.getTableName()), null, fs, conf, 062 hri, htd, null); 063 region.setRestoredRegion(true); 064 // we won't initialize the MobFileCache when not running in RS process. so provided an 065 // initialized cache. Consider the case: an CF was set from an mob to non-mob. if we only 066 // initialize cache for MOB region, NPE from HMobStore will still happen. So Initialize the 067 // cache for every region although it may hasn't any mob CF, BTW the cache is very light-weight. 068 region.setMobFileCache(new MobFileCache(conf)); 069 region.initialize(); 070 071 // create an internal region scanner 072 this.scanner = region.getScanner(scan); 073 values = new ArrayList<>(); 074 075 if (scanMetrics == null) { 076 initScanMetrics(scan); 077 } else { 078 this.scanMetrics = scanMetrics; 079 } 080 region.startRegionOperation(); 081 } 082 083 @Override 084 public Result next() throws IOException { 085 values.clear(); 086 scanner.nextRaw(values); 087 if (values.isEmpty()) { 088 //we are done 089 return null; 090 } 091 092 Result result = Result.create(values); 093 if (this.scanMetrics != null) { 094 long resultSize = 0; 095 for (Cell cell : values) { 096 resultSize += PrivateCellUtil.estimatedSerializedSizeOf(cell); 097 } 098 this.scanMetrics.countOfBytesInResults.addAndGet(resultSize); 099 this.scanMetrics.countOfRowsScanned.incrementAndGet(); 100 } 101 102 return result; 103 } 104 105 @Override 106 public void close() { 107 if (this.scanner != null) { 108 try { 109 this.scanner.close(); 110 this.scanner = null; 111 } catch (IOException ex) { 112 LOG.warn("Exception while closing scanner", ex); 113 } 114 } 115 if (this.region != null) { 116 try { 117 this.region.closeRegionOperation(); 118 this.region.close(true); 119 this.region = null; 120 } catch (IOException ex) { 121 LOG.warn("Exception while closing region", ex); 122 } 123 } 124 } 125 126 @Override 127 public boolean renewLease() { 128 throw new UnsupportedOperationException(); 129 } 130}