View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.util.compaction;
20  
21  import com.google.common.base.Optional;
22  import com.google.common.collect.Sets;
23  
24  import java.io.IOException;
25  import java.util.Arrays;
26  import java.util.Set;
27  import java.util.concurrent.Executors;
28  
29  import org.apache.commons.cli.BasicParser;
30  import org.apache.commons.cli.CommandLine;
31  import org.apache.commons.cli.CommandLineParser;
32  import org.apache.commons.cli.Option;
33  import org.apache.commons.cli.Options;
34  import org.apache.commons.cli.ParseException;
35  import org.apache.hadoop.conf.Configuration;
36  import org.apache.hadoop.hbase.HBaseConfiguration;
37  import org.apache.hadoop.hbase.HBaseInterfaceAudience;
38  import org.apache.hadoop.hbase.HColumnDescriptor;
39  import org.apache.hadoop.hbase.HConstants;
40  import org.apache.hadoop.hbase.HRegionInfo;
41  import org.apache.hadoop.hbase.HTableDescriptor;
42  import org.apache.hadoop.hbase.TableName;
43  import org.apache.hadoop.hbase.classification.InterfaceAudience;
44  import org.apache.hadoop.hbase.client.Connection;
45  import org.apache.hadoop.hbase.client.ConnectionFactory;
46  import org.apache.hadoop.util.ToolRunner;
47  import org.slf4j.Logger;
48  import org.slf4j.LoggerFactory;
49  
50  /**
51   * This tool compacts a table's regions that are beyond it's TTL. It helps to save disk space and
52   * regions become empty as a result of compaction.
53   */
54  @InterfaceAudience.LimitedPrivate(HBaseInterfaceAudience.TOOLS)
55  public class MajorCompactorTTL extends MajorCompactor {
56  
57    private static final Logger LOG = LoggerFactory.getLogger(MajorCompactorTTL .class);
58  
59    private HTableDescriptor htd;
60  
61    @InterfaceAudience.Private
62    public MajorCompactorTTL(Configuration conf, HTableDescriptor htd, int concurrency,
63        long sleepForMs) throws IOException {
64      this.connection = ConnectionFactory.createConnection(conf);
65      this.htd = htd;
66      this.tableName = htd.getTableName();
67      this.storesToCompact = Sets.newHashSet(); // Empty set so all stores will be compacted
68      this.sleepForMs = sleepForMs;
69      this.executor = Executors.newFixedThreadPool(concurrency);
70      this.clusterCompactionQueues = new ClusterCompactionQueues(concurrency);
71    }
72  
73    protected MajorCompactorTTL() {
74      super();
75    }
76  
77    @Override
78    protected Optional<MajorCompactionRequest> getMajorCompactionRequest(HRegionInfo hri)
79        throws IOException {
80      return MajorCompactionTTLRequest.newRequest(connection.getConfiguration(), hri, htd);
81    }
82  
83    @Override
84    protected Set<String> getStoresRequiringCompaction(MajorCompactionRequest request)
85        throws IOException {
86      return ((MajorCompactionTTLRequest)request).getStoresRequiringCompaction(htd).keySet();
87    }
88  
89    public int compactRegionsTTLOnTable(Configuration conf, String table, int concurrency,
90        long sleep, int numServers, int numRegions, boolean dryRun, boolean skipWait)
91        throws Exception {
92  
93      Connection conn = ConnectionFactory.createConnection(conf);
94      TableName tableName = TableName.valueOf(table);
95  
96      HTableDescriptor htd = conn.getAdmin().getTableDescriptor(tableName);
97      if (!doesAnyColFamilyHaveTTL(htd)) {
98        LOG.info("No TTL present for CF of table: " + tableName + ", skipping compaction");
99        return 0;
100     }
101 
102     LOG.info("Major compacting table " + tableName + " based on TTL");
103     MajorCompactor compactor = new MajorCompactorTTL(conf, htd, concurrency, sleep);
104     compactor.setNumServers(numServers);
105     compactor.setNumRegions(numRegions);
106     compactor.setSkipWait(skipWait);
107 
108     compactor.initializeWorkQueues();
109     if (!dryRun) {
110       compactor.compactAllRegions();
111     }
112     compactor.shutdown();
113     return ERRORS.size();
114   }
115 
116   private boolean doesAnyColFamilyHaveTTL(HTableDescriptor htd) {
117     for (HColumnDescriptor descriptor : htd.getColumnFamilies()) {
118       if (descriptor.getTimeToLive() != HConstants.FOREVER) {
119         return true;
120       }
121     }
122     return false;
123   }
124 
125   private Options getOptions() {
126     Options options = getCommonOptions();
127 
128     Option tableOption = new Option("table", true, "Table to be compacted");
129     tableOption.setRequired(true);
130     options.addOption(tableOption);
131 
132     return options;
133   }
134 
135   @Override
136   public int run(String[] args) throws Exception {
137     Options options = getOptions();
138 
139     final CommandLineParser cmdLineParser =  new BasicParser();
140     CommandLine commandLine;
141     try {
142       commandLine = cmdLineParser.parse(options, args);
143     } catch (ParseException parseException) {
144       System.err.println("ERROR: Unable to parse command-line arguments " + Arrays.toString(args)
145           + " due to: " + parseException);
146       printUsage(options);
147       throw parseException;
148     }
149 
150     String table = commandLine.getOptionValue("table");
151     int numServers = Integer.parseInt(commandLine.getOptionValue("numservers", "-1"));
152     int numRegions = Integer.parseInt(commandLine.getOptionValue("numregions", "-1"));
153     int concurrency = Integer.parseInt(commandLine.getOptionValue("servers", "1"));
154     long sleep = Long.parseLong(commandLine.getOptionValue("sleep", "30000"));
155     boolean dryRun = commandLine.hasOption("dryRun");
156     boolean skipWait = commandLine.hasOption("skipWait");
157 
158     return compactRegionsTTLOnTable(HBaseConfiguration.create(), table, concurrency, sleep,
159         numServers, numRegions, dryRun, skipWait);
160   }
161 
162   public static void main(String[] args) throws Exception {
163     ToolRunner.run(HBaseConfiguration.create(), new MajorCompactorTTL(), args);
164   }
165 }