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  package org.apache.hadoop.hbase.util.compaction;
19  
20  import com.google.common.base.Optional;
21  import com.google.common.collect.Sets;
22  import java.io.IOException;
23  import java.util.Collection;
24  import java.util.List;
25  import java.util.Set;
26  import org.apache.hadoop.conf.Configuration;
27  import org.apache.hadoop.fs.FileStatus;
28  import org.apache.hadoop.fs.FileSystem;
29  import org.apache.hadoop.fs.Path;
30  import org.apache.hadoop.hbase.HRegionInfo;
31  import org.apache.hadoop.hbase.classification.InterfaceAudience;
32  import org.apache.hadoop.hbase.client.Admin;
33  import org.apache.hadoop.hbase.client.Connection;
34  import org.apache.hadoop.hbase.client.ConnectionFactory;
35  import org.apache.hadoop.hbase.regionserver.HRegionFileSystem;
36  import org.apache.hadoop.hbase.regionserver.StoreFileInfo;
37  import org.apache.hadoop.hbase.util.FSUtils;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  @InterfaceAudience.Private
42  class MajorCompactionRequest {
43  
44    private static final Logger LOG = LoggerFactory.getLogger(MajorCompactionRequest.class);
45  
46    protected final Configuration configuration;
47    protected final HRegionInfo region;
48    private Set<String> stores;
49  
50    MajorCompactionRequest(Configuration configuration, HRegionInfo region) {
51      this.configuration = configuration;
52      this.region = region;
53    }
54  
55    MajorCompactionRequest(Configuration configuration, HRegionInfo region,
56        Set<String> stores) {
57      this(configuration, region);
58      this.stores = stores;
59    }
60  
61    static Optional<MajorCompactionRequest> newRequest(Configuration configuration, HRegionInfo info,
62        Set<String> stores, long timestamp) throws IOException {
63      MajorCompactionRequest request =
64          new MajorCompactionRequest(configuration, info, stores);
65      return request.createRequest(configuration, stores, timestamp);
66    }
67  
68    HRegionInfo getRegion() {
69      return region;
70    }
71  
72    Set<String> getStores() {
73      return stores;
74    }
75  
76    void setStores(Set<String> stores) {
77      this.stores = stores;
78    }
79  
80    Optional<MajorCompactionRequest> createRequest(Configuration configuration,
81        Set<String> stores, long timestamp) throws IOException {
82      Set<String> familiesToCompact = getStoresRequiringCompaction(stores, timestamp);
83      MajorCompactionRequest request = null;
84      if (!familiesToCompact.isEmpty()) {
85        request = new MajorCompactionRequest(configuration, region, familiesToCompact);
86      }
87      return Optional.fromNullable(request);
88    }
89  
90    Set<String> getStoresRequiringCompaction(Set<String> requestedStores, long timestamp)
91        throws IOException {
92      try(Connection connection = getConnection(configuration)) {
93        HRegionFileSystem fileSystem = getFileSystem(connection);
94        Set<String> familiesToCompact = Sets.newHashSet();
95        for (String family : requestedStores) {
96          if (shouldCFBeCompacted(fileSystem, family, timestamp)) {
97            familiesToCompact.add(family);
98          }
99        }
100       return familiesToCompact;
101     }
102   }
103 
104   boolean shouldCFBeCompacted(HRegionFileSystem fileSystem, String family, long ts)
105       throws IOException {
106 
107     // do we have any store files?
108     Collection<StoreFileInfo> storeFiles = fileSystem.getStoreFiles(family);
109     if (storeFiles == null) {
110       LOG.info("Excluding store: " + family + " for compaction for region:  " + fileSystem
111           .getRegionInfo().getEncodedName(), " has no store files");
112       return false;
113     }
114     // check for reference files
115     if (fileSystem.hasReferences(family) && familyHasReferenceFile(fileSystem, family, ts)) {
116       LOG.info("Including store: " + family + " with: " + storeFiles.size()
117           + " files for compaction for region: " + fileSystem.getRegionInfo().getEncodedName());
118       return true;
119     }
120     // check store file timestamps
121     boolean includeStore = this.shouldIncludeStore(fileSystem, family, storeFiles, ts);
122     if (!includeStore) {
123       LOG.info("Excluding store: " + family + " for compaction for region:  " + fileSystem
124           .getRegionInfo().getEncodedName() + " already compacted");
125     }
126     return includeStore;
127   }
128 
129   protected boolean shouldIncludeStore(HRegionFileSystem fileSystem, String family,
130       Collection<StoreFileInfo> storeFiles, long ts) throws IOException {
131 
132     for (StoreFileInfo storeFile : storeFiles) {
133       if (storeFile.getModificationTime() < ts) {
134         LOG.info("Including store: " + family + " with: " + storeFiles.size()
135             + " files for compaction for region: "
136             + fileSystem.getRegionInfo().getEncodedName());
137         return true;
138       }
139     }
140     return false;
141   }
142 
143   Connection getConnection(Configuration configuration) throws IOException {
144     return ConnectionFactory.createConnection(configuration);
145   }
146 
147   protected boolean familyHasReferenceFile(HRegionFileSystem fileSystem, String family, long ts)
148       throws IOException {
149     List<Path> referenceFiles =
150         getReferenceFilePaths(fileSystem.getFileSystem(), fileSystem.getStoreDir(family));
151     for (Path referenceFile : referenceFiles) {
152       FileStatus status = fileSystem.getFileSystem().getFileLinkStatus(referenceFile);
153       if (status.getModificationTime() < ts) {
154         LOG.info("Including store: " + family + " for compaction for region:  " + fileSystem
155             .getRegionInfo().getEncodedName() + " (reference store files)");
156         return true;
157       }
158     }
159     return false;
160 
161   }
162 
163   List<Path> getReferenceFilePaths(FileSystem fileSystem, Path familyDir)
164       throws IOException {
165     return FSUtils.getReferenceFilePaths(fileSystem, familyDir);
166   }
167 
168   HRegionFileSystem getFileSystem(Connection connection) throws IOException {
169     Admin admin = connection.getAdmin();
170     return HRegionFileSystem.openRegionFromFileSystem(admin.getConfiguration(),
171         FSUtils.getCurrentFileSystem(admin.getConfiguration()),
172         FSUtils.getTableDir(FSUtils.getRootDir(admin.getConfiguration()), region.getTable()),
173         region, true);
174   }
175 
176   @Override
177   public String toString() {
178     return "region: " + region.getEncodedName() + " store(s): " + stores;
179   }
180 }