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 */
018
019package org.apache.hadoop.hbase.util.compaction;
020
021import java.io.IOException;
022import java.util.Collection;
023import java.util.Map;
024import java.util.Optional;
025import org.apache.hadoop.conf.Configuration;
026import org.apache.hadoop.hbase.HConstants;
027import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
028import org.apache.hadoop.hbase.client.Connection;
029import org.apache.hadoop.hbase.client.RegionInfo;
030import org.apache.hadoop.hbase.client.TableDescriptor;
031import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
032import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
033import org.apache.yetus.audience.InterfaceAudience;
034import org.slf4j.Logger;
035import org.slf4j.LoggerFactory;
036
037import org.apache.hbase.thirdparty.com.google.common.collect.Maps;
038
039/**
040 * This request helps determine if a region has to be compacted based on table's TTL.
041 */
042@InterfaceAudience.Private
043public class MajorCompactionTTLRequest extends MajorCompactionRequest {
044
045  private static final Logger LOG = LoggerFactory.getLogger(MajorCompactionTTLRequest.class);
046
047  MajorCompactionTTLRequest(Configuration conf, RegionInfo region) {
048    super(conf, region);
049  }
050
051  static Optional<MajorCompactionRequest> newRequest(Configuration conf, RegionInfo info,
052      TableDescriptor htd) throws IOException {
053    MajorCompactionTTLRequest request = new MajorCompactionTTLRequest(conf, info);
054    return request.createRequest(conf, htd);
055  }
056
057  private Optional<MajorCompactionRequest> createRequest(Configuration conf, TableDescriptor htd)
058      throws IOException {
059    Map<String, Long> familiesToCompact = getStoresRequiringCompaction(htd);
060    MajorCompactionRequest request = null;
061    if (!familiesToCompact.isEmpty()) {
062      LOG.debug("Compaction families for region: " + region + " CF: " + familiesToCompact.keySet());
063      request = new MajorCompactionTTLRequest(conf, region);
064    }
065    return Optional.ofNullable(request);
066  }
067
068  Map<String, Long> getStoresRequiringCompaction(TableDescriptor htd) throws IOException {
069    try(Connection connection = getConnection(configuration)) {
070      HRegionFileSystem fileSystem = getFileSystem(connection);
071      Map<String, Long> familyTTLMap = Maps.newHashMap();
072      for (ColumnFamilyDescriptor descriptor : htd.getColumnFamilies()) {
073        long ts = getColFamilyCutoffTime(descriptor);
074        // If the table's TTL is forever, lets not compact any of the regions.
075        if (ts > 0 && shouldCFBeCompacted(fileSystem, descriptor.getNameAsString(), ts)) {
076          familyTTLMap.put(descriptor.getNameAsString(), ts);
077        }
078      }
079      return familyTTLMap;
080    }
081  }
082
083  // If the CF has no TTL, return -1, else return the current time - TTL.
084  private long getColFamilyCutoffTime(ColumnFamilyDescriptor colDesc) {
085    if (colDesc.getTimeToLive() == HConstants.FOREVER) {
086      return -1;
087    }
088    return System.currentTimeMillis() - (colDesc.getTimeToLive() * 1000L);
089  }
090
091  @Override
092  protected boolean shouldIncludeStore(HRegionFileSystem fileSystem, String family,
093      Collection<StoreFileInfo> storeFiles, long ts) throws IOException {
094
095    for (StoreFileInfo storeFile : storeFiles) {
096      // Lets only compact when all files are older than TTL
097      if (storeFile.getModificationTime() >= ts) {
098        LOG.info("There is atleast one file in store: " + family + " file: " + storeFile.getPath()
099            + " with timestamp " + storeFile.getModificationTime()
100            + " for region: " + fileSystem.getRegionInfo().getEncodedName()
101            + " older than TTL: " + ts);
102        return false;
103      }
104    }
105    return true;
106  }
107}