1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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
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 }