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