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.mob;
020
021import java.io.IOException;
022
023import org.apache.hadoop.conf.Configuration;
024import org.apache.hadoop.conf.Configured;
025import org.apache.hadoop.fs.FileSystem;
026import org.apache.hadoop.hbase.HBaseConfiguration;
027import org.apache.hadoop.hbase.HConstants;
028import org.apache.hadoop.hbase.TableName;
029import org.apache.yetus.audience.InterfaceAudience;
030import org.slf4j.Logger;
031import org.slf4j.LoggerFactory;
032import org.apache.hadoop.hbase.client.Admin;
033import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
034import org.apache.hadoop.hbase.client.Connection;
035import org.apache.hadoop.hbase.client.ConnectionFactory;
036import org.apache.hadoop.hbase.client.HBaseAdmin;
037import org.apache.hadoop.hbase.client.TableDescriptor;
038import org.apache.hadoop.hbase.io.hfile.CacheConfig;
039import org.apache.hadoop.hbase.util.Bytes;
040import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
041import org.apache.hadoop.util.Tool;
042import org.apache.hadoop.util.ToolRunner;
043
044/**
045 * The cleaner to delete the expired MOB files.
046 */
047@InterfaceAudience.Private
048public class ExpiredMobFileCleaner extends Configured implements Tool {
049
050  private static final Logger LOG = LoggerFactory.getLogger(ExpiredMobFileCleaner.class);
051  /**
052   * Cleans the MOB files when they're expired and their min versions are 0.
053   * If the latest timestamp of Cells in a MOB file is older than the TTL in the column family,
054   * it's regarded as expired. This cleaner deletes them.
055   * At a time T0, the cells in a mob file M0 are expired. If a user starts a scan before T0, those
056   * mob cells are visible, this scan still runs after T0. At that time T1, this mob file M0
057   * is expired, meanwhile a cleaner starts, the M0 is archived and can be read in the archive
058   * directory.
059   * @param tableName The current table name.
060   * @param family The current family.
061   */
062  public void cleanExpiredMobFiles(String tableName, ColumnFamilyDescriptor family) throws IOException {
063    Configuration conf = getConf();
064    TableName tn = TableName.valueOf(tableName);
065    FileSystem fs = FileSystem.get(conf);
066    LOG.info("Cleaning the expired MOB files of " + family.getNameAsString() + " in " + tableName);
067    // disable the block cache.
068    Configuration copyOfConf = new Configuration(conf);
069    copyOfConf.setFloat(HConstants.HFILE_BLOCK_CACHE_SIZE_KEY, 0f);
070    CacheConfig cacheConfig = new CacheConfig(copyOfConf);
071    MobUtils.cleanExpiredMobFiles(fs, conf, tn, family, cacheConfig,
072        EnvironmentEdgeManager.currentTime());
073  }
074
075  public static void main(String[] args) throws Exception {
076    Configuration conf = HBaseConfiguration.create();
077    ToolRunner.run(conf, new ExpiredMobFileCleaner(), args);
078  }
079
080  private void printUsage() {
081    System.err.println("Usage:\n" + "--------------------------\n"
082        + ExpiredMobFileCleaner.class.getName() + " tableName familyName");
083    System.err.println(" tableName        The table name");
084    System.err.println(" familyName       The column family name");
085  }
086
087  @edu.umd.cs.findbugs.annotations.SuppressWarnings(value="REC_CATCH_EXCEPTION",
088      justification="Intentional")
089  @Override
090  public int run(String[] args) throws Exception {
091    if (args.length != 2) {
092      printUsage();
093      return 1;
094    }
095    String tableName = args[0];
096    String familyName = args[1];
097    TableName tn = TableName.valueOf(tableName);
098    HBaseAdmin.available(getConf());
099    Connection connection = ConnectionFactory.createConnection(getConf());
100    Admin admin = connection.getAdmin();
101    try {
102      TableDescriptor htd = admin.getDescriptor(tn);
103      ColumnFamilyDescriptor family = htd.getColumnFamily(Bytes.toBytes(familyName));
104      if (family == null || !family.isMobEnabled()) {
105        throw new IOException("Column family " + familyName + " is not a MOB column family");
106      }
107      if (family.getMinVersions() > 0) {
108        throw new IOException(
109            "The minVersions of the column family is not 0, could not be handled by this cleaner");
110      }
111      cleanExpiredMobFiles(tableName, family);
112      return 0;
113    } finally {
114      try {
115        admin.close();
116      } catch (IOException e) {
117        LOG.error("Failed to close the HBaseAdmin.", e);
118      }
119      try {
120        connection.close();
121      } catch (IOException e) {
122        LOG.error("Failed to close the connection.", e);
123      }
124    }
125  }
126}