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.backup.example; 019 020import java.io.IOException; 021import org.apache.hadoop.conf.Configuration; 022import org.apache.hadoop.fs.FileStatus; 023import org.apache.hadoop.fs.FileSystem; 024import org.apache.hadoop.fs.Path; 025import org.apache.hadoop.hbase.HBaseInterfaceAudience; 026import org.apache.hadoop.hbase.master.cleaner.BaseHFileCleanerDelegate; 027import org.apache.hadoop.hbase.util.CommonFSUtils; 028import org.apache.yetus.audience.InterfaceAudience; 029import org.apache.zookeeper.KeeperException; 030import org.slf4j.Logger; 031import org.slf4j.LoggerFactory; 032 033/** 034 * {@link BaseHFileCleanerDelegate} that only cleans HFiles that don't belong to a table that is 035 * currently being archived. 036 * <p> 037 * This only works properly if the 038 * {@link org.apache.hadoop.hbase.master.cleaner.TimeToLiveHFileCleaner} 039 * is also enabled (it always should be), since it may take a little time 040 * for the ZK notification to propagate, in which case we may accidentally 041 * delete some files. 042 */ 043@InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.CONFIG) 044public class LongTermArchivingHFileCleaner extends BaseHFileCleanerDelegate { 045 046 private static final Logger LOG = LoggerFactory.getLogger(LongTermArchivingHFileCleaner.class); 047 048 TableHFileArchiveTracker archiveTracker; 049 private FileSystem fs; 050 051 @Override 052 public boolean isFileDeletable(FileStatus fStat) { 053 try { 054 // if its a directory, then it can be deleted 055 if (fStat.isDirectory()) { 056 return true; 057 } 058 059 Path file = fStat.getPath(); 060 // check to see if 061 FileStatus[] deleteStatus = CommonFSUtils.listStatus(this.fs, file, null); 062 // if the file doesn't exist, then it can be deleted (but should never 063 // happen since deleted files shouldn't get passed in) 064 if (deleteStatus == null) { 065 return true; 066 } 067 068 // otherwise, we need to check the file's table and see its being archived 069 Path family = file.getParent(); 070 Path region = family.getParent(); 071 Path table = region.getParent(); 072 073 String tableName = table.getName(); 074 boolean ret = !archiveTracker.keepHFiles(tableName); 075 LOG.debug("Archiver says to [" + (ret ? "delete" : "keep") + "] files for table:" + 076 tableName); 077 return ret; 078 } catch (IOException e) { 079 LOG.error("Failed to lookup status of:" + fStat.getPath() + ", keeping it just incase.", e); 080 return false; 081 } 082 } 083 084 @Override 085 public void setConf(Configuration config) { 086 // setup our own zookeeper connection 087 // Make my own Configuration. Then I'll have my own connection to zk that 088 // I can close myself when comes time. 089 Configuration conf = new Configuration(config); 090 super.setConf(conf); 091 try { 092 this.fs = FileSystem.get(conf); 093 this.archiveTracker = TableHFileArchiveTracker.create(conf); 094 this.archiveTracker.start(); 095 } catch (KeeperException e) { 096 LOG.error("Error while configuring " + this.getClass().getName(), e); 097 } catch (IOException e) { 098 LOG.error("Error while configuring " + this.getClass().getName(), e); 099 } 100 } 101 102 @Override 103 public void stop(String reason) { 104 if (this.isStopped()) { 105 return; 106 } 107 108 super.stop(reason); 109 if (this.archiveTracker != null) { 110 LOG.info("Stopping " + this.archiveTracker); 111 this.archiveTracker.stop(); 112 } 113 } 114}