View Javadoc

1   /**
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *     http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  package org.apache.hadoop.hbase.regionserver.compactions;
20  
21  import java.util.ArrayList;
22  import java.util.Collection;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.apache.hadoop.classification.InterfaceAudience;
27  import org.apache.hadoop.classification.InterfaceStability;
28  import org.apache.hadoop.hbase.regionserver.Store;
29  import org.apache.hadoop.hbase.regionserver.StoreFile;
30  import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
31  import org.apache.hadoop.util.StringUtils;
32  
33  import com.google.common.base.Function;
34  import com.google.common.base.Joiner;
35  import com.google.common.base.Preconditions;
36  import com.google.common.base.Predicate;
37  import com.google.common.collect.Collections2;
38  
39  /**
40   * This class holds all logical details necessary to run a compaction.
41   */
42  @InterfaceAudience.LimitedPrivate({ "coprocessor" })
43  @InterfaceStability.Evolving
44  public class CompactionRequest implements Comparable<CompactionRequest> {
45    static final Log LOG = LogFactory.getLog(CompactionRequest.class);
46    // was this compaction promoted to an off-peak
47    private boolean isOffPeak = false;
48    private enum DisplayCompactionType { MINOR, ALL_FILES, MAJOR }
49    private DisplayCompactionType isMajor = DisplayCompactionType.MINOR;
50    private int priority = Store.NO_PRIORITY;
51    private Collection<StoreFile> filesToCompact;
52  
53    // CompactRequest object creation time.
54    private long selectionTime;
55    // System time used to compare objects in FIFO order. TODO: maybe use selectionTime?
56    private Long timeInNanos;
57    private String regionName = "";
58    private String storeName = "";
59    private long totalSize = -1L;
60  
61    /**
62     * This ctor should be used by coprocessors that want to subclass CompactionRequest.
63     */
64    public CompactionRequest() {
65      this.selectionTime = EnvironmentEdgeManager.currentTimeMillis();
66      this.timeInNanos = System.nanoTime();
67    }
68  
69    public CompactionRequest(Collection<StoreFile> files) {
70      this();
71      Preconditions.checkNotNull(files);
72      this.filesToCompact = files;
73      recalculateSize();
74    }
75  
76    /**
77     * Called before compaction is executed by CompactSplitThread; for use by coproc subclasses.
78     */
79    public void beforeExecute() {}
80  
81    /**
82     * Called after compaction is executed by CompactSplitThread; for use by coproc subclasses.
83     */
84    public void afterExecute() {}
85  
86    /**
87     * Combines the request with other request. Coprocessors subclassing CR may override
88     * this if they want to do clever things based on CompactionPolicy selection that
89     * is passed to this method via "other". The default implementation just does a copy.
90     * @param other Request to combine with.
91     * @return The result (may be "this" or "other").
92     */
93    public CompactionRequest combineWith(CompactionRequest other) {
94      this.filesToCompact = new ArrayList<StoreFile>(other.getFiles());
95      this.isOffPeak = other.isOffPeak;
96      this.isMajor = other.isMajor;
97      this.priority = other.priority;
98      this.selectionTime = other.selectionTime;
99      this.timeInNanos = other.timeInNanos;
100     this.regionName = other.regionName;
101     this.storeName = other.storeName;
102     this.totalSize = other.totalSize;
103     return this;
104   }
105 
106   /**
107    * This function will define where in the priority queue the request will
108    * end up.  Those with the highest priorities will be first.  When the
109    * priorities are the same it will first compare priority then date
110    * to maintain a FIFO functionality.
111    *
112    * <p>Note: The enqueue timestamp is accurate to the nanosecond. if two
113    * requests have same timestamp then this function will break the tie
114    * arbitrarily with hashCode() comparing.
115    */
116   @Override
117   public int compareTo(CompactionRequest request) {
118     //NOTE: The head of the priority queue is the least element
119     if (this.equals(request)) {
120       return 0; //they are the same request
121     }
122     int compareVal;
123 
124     compareVal = priority - request.priority; //compare priority
125     if (compareVal != 0) {
126       return compareVal;
127     }
128 
129     compareVal = timeInNanos.compareTo(request.timeInNanos);
130     if (compareVal != 0) {
131       return compareVal;
132     }
133 
134     // break the tie based on hash code
135     return this.hashCode() - request.hashCode();
136   }
137 
138   @Override
139   public boolean equals(Object obj) {
140     return (this == obj);
141   }
142 
143   public Collection<StoreFile> getFiles() {
144     return this.filesToCompact;
145   }
146 
147   /**
148    * Sets the region/store name, for logging.
149    */
150   public void setDescription(String regionName, String storeName) {
151     this.regionName = regionName;
152     this.storeName = storeName;
153   }
154 
155   /** Gets the total size of all StoreFiles in compaction */
156   public long getSize() {
157     return totalSize;
158   }
159 
160   public boolean isAllFiles() {
161     return this.isMajor == DisplayCompactionType.MAJOR
162         || this.isMajor == DisplayCompactionType.ALL_FILES;
163   }
164 
165   public boolean isMajor() {
166     return this.isMajor == DisplayCompactionType.MAJOR;
167   }
168 
169   /** Gets the priority for the request */
170   public int getPriority() {
171     return priority;
172   }
173 
174   /** Sets the priority for the request */
175   public void setPriority(int p) {
176     this.priority = p;
177   }
178 
179   public boolean isOffPeak() {
180     return this.isOffPeak;
181   }
182 
183   public void setOffPeak(boolean value) {
184     this.isOffPeak = value;
185   }
186 
187   public long getSelectionTime() {
188     return this.selectionTime;
189   }
190 
191   /**
192    * Specify if this compaction should be a major compaction based on the state of the store
193    * @param isMajor <tt>true</tt> if the system determines that this compaction should be a major
194    *          compaction
195    */
196   public void setIsMajor(boolean isMajor, boolean isAllFiles) {
197     assert isAllFiles || !isMajor;
198     this.isMajor = !isAllFiles ? DisplayCompactionType.MINOR
199         : (isMajor ? DisplayCompactionType.MAJOR : DisplayCompactionType.ALL_FILES);
200   }
201 
202   @Override
203   public String toString() {
204     String fsList = Joiner.on(", ").join(
205         Collections2.transform(Collections2.filter(
206             this.getFiles(),
207             new Predicate<StoreFile>() {
208               public boolean apply(StoreFile sf) {
209                 return sf.getReader() != null;
210               }
211           }), new Function<StoreFile, String>() {
212             public String apply(StoreFile sf) {
213               return StringUtils.humanReadableInt(sf.getReader().length());
214             }
215           }));
216 
217     return "regionName=" + regionName + ", storeName=" + storeName +
218       ", fileCount=" + this.getFiles().size() +
219       ", fileSize=" + StringUtils.humanReadableInt(totalSize) +
220         ((fsList.isEmpty()) ? "" : " (" + fsList + ")") +
221       ", priority=" + priority + ", time=" + timeInNanos;
222   }
223 
224   /**
225    * Recalculate the size of the compaction based on current files.
226    * @param files files that should be included in the compaction
227    */
228   private void recalculateSize() {
229     long sz = 0;
230     for (StoreFile sf : this.filesToCompact) {
231       sz += sf.getReader().length();
232     }
233     this.totalSize = sz;
234   }
235 }
236