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.master.cleaner; 019 020import java.io.IOException; 021import java.util.concurrent.locks.ReentrantReadWriteLock; 022import org.apache.hadoop.conf.Configuration; 023import org.apache.hadoop.fs.FileStatus; 024import org.apache.hadoop.fs.FileSystem; 025import org.apache.hadoop.fs.Path; 026import org.apache.hadoop.hbase.HBaseInterfaceAudience; 027import org.apache.hadoop.hbase.HConstants; 028import org.apache.hadoop.hbase.io.HFileLink; 029import org.apache.hadoop.hbase.mob.MobUtils; 030import org.apache.hadoop.hbase.util.CommonFSUtils; 031import org.apache.yetus.audience.InterfaceAudience; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035/** 036 * HFileLink cleaner that determines if a hfile should be deleted. HFiles can be deleted only if 037 * there're no links to them. When a HFileLink is created a back reference file is created in: 038 * /hbase/archive/table/region/cf/.links-hfile/ref-region.ref-table To check if the hfile can be 039 * deleted the back references folder must be empty. 040 */ 041@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) 042public class HFileLinkCleaner extends BaseHFileCleanerDelegate { 043 private static final Logger LOG = LoggerFactory.getLogger(HFileLinkCleaner.class); 044 045 private FileSystem fs = null; 046 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); 047 048 @Override 049 public boolean isFileDeletable(FileStatus fStat) { 050 lock.readLock().lock(); 051 try { 052 if (this.fs == null) { 053 return false; 054 } 055 Path filePath = fStat.getPath(); 056 // HFile Link is always deletable 057 if (HFileLink.isHFileLink(filePath)) { 058 return true; 059 } 060 061 // If the file is inside a link references directory, means that it is a back ref link. 062 // The back ref can be deleted only if the referenced file doesn't exists. 063 Path parentDir = filePath.getParent(); 064 if (HFileLink.isBackReferencesDir(parentDir)) { 065 Path hfilePath = null; 066 try { 067 // Also check if the HFile is in the HBASE_TEMP_DIRECTORY; this is where the referenced 068 // file gets created when cloning a snapshot. 069 hfilePath = HFileLink.getHFileFromBackReference( 070 new Path(CommonFSUtils.getRootDir(getConf()), HConstants.HBASE_TEMP_DIRECTORY), 071 filePath); 072 if (fs.exists(hfilePath)) { 073 return false; 074 } 075 // check whether the HFileLink still exists in mob dir. 076 hfilePath = HFileLink.getHFileFromBackReference(MobUtils.getMobHome(getConf()), filePath); 077 if (fs.exists(hfilePath)) { 078 return false; 079 } 080 hfilePath = 081 HFileLink.getHFileFromBackReference(CommonFSUtils.getRootDir(getConf()), filePath); 082 return !fs.exists(hfilePath); 083 } catch (IOException e) { 084 if (LOG.isDebugEnabled()) { 085 LOG.debug("Couldn't verify if the referenced file still exists, keep it just in case: " 086 + hfilePath); 087 } 088 return false; 089 } 090 } 091 092 // HFile is deletable only if has no links 093 Path backRefDir = null; 094 try { 095 backRefDir = HFileLink.getBackReferencesDir(parentDir, filePath.getName()); 096 return CommonFSUtils.listStatus(fs, backRefDir) == null; 097 } catch (IOException e) { 098 if (LOG.isDebugEnabled()) { 099 LOG.debug("Couldn't get the references, not deleting file, just in case. filePath=" 100 + filePath + ", backRefDir=" + backRefDir); 101 } 102 return false; 103 } 104 } finally { 105 lock.readLock().unlock(); 106 } 107 } 108 109 @Override 110 public void setConf(Configuration conf) { 111 super.setConf(conf); 112 113 // setup filesystem 114 lock.writeLock().lock(); 115 try { 116 this.fs = FileSystem.get(this.getConf()); 117 } catch (IOException e) { 118 if (LOG.isDebugEnabled()) { 119 LOG.debug("Couldn't instantiate the file system, not deleting file, just in case. " 120 + FileSystem.FS_DEFAULT_NAME_KEY + "=" 121 + getConf().get(FileSystem.FS_DEFAULT_NAME_KEY, FileSystem.DEFAULT_FS)); 122 } 123 } finally { 124 lock.writeLock().unlock(); 125 } 126 } 127}