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.Calendar;
22  import java.util.GregorianCalendar;
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.conf.Configuration;
28  
29  /**
30   * The class used to track off-peak hours and compactions. Off-peak compaction counter
31   * is global for the entire server, hours can be different per instance of this class,
32   * based on the configuration of the corresponding store.
33   */
34  @InterfaceAudience.Private
35  public class OffPeakCompactions {
36    private static final Log LOG = LogFactory.getLog(OffPeakCompactions.class);
37    private final static Calendar calendar = new GregorianCalendar();
38    private int offPeakStartHour;
39    private int offPeakEndHour;
40  
41    // TODO: replace with AtomicLong, see HBASE-7437.
42    /**
43     * Number of off peak compactions either in the compaction queue or
44     * happening now. Please lock compactionCountLock before modifying.
45     */
46    private static long numOutstanding = 0;
47  
48    /**
49     * Lock object for numOutstandingOffPeakCompactions
50     */
51    private static final Object compactionCountLock = new Object();
52  
53    public OffPeakCompactions(Configuration conf) {
54      offPeakStartHour = conf.getInt("hbase.offpeak.start.hour", -1);
55      offPeakEndHour = conf.getInt("hbase.offpeak.end.hour", -1);
56      if (!isValidHour(offPeakStartHour) || !isValidHour(offPeakEndHour)) {
57        if (!(offPeakStartHour == -1 && offPeakEndHour == -1)) {
58          LOG.warn("Ignoring invalid start/end hour for peak hour : start = " +
59              this.offPeakStartHour + " end = " + this.offPeakEndHour +
60              ". Valid numbers are [0-23]");
61        }
62        this.offPeakStartHour = this.offPeakEndHour = -1;
63      }
64    }
65  
66    /**
67     * Tries making the compaction off-peak.
68     * @return Whether the compaction can be made off-peak.
69     */
70    public boolean tryStartOffPeakRequest() {
71      if (!isOffPeakHour()) return false;
72      synchronized(compactionCountLock) {
73        if (numOutstanding == 0) {
74           numOutstanding++;
75           return true;
76        }
77      }
78      return false;
79    }
80  
81    /**
82     * The current compaction finished, so reset the off peak compactions count
83     * if this was an off peak compaction.
84     */
85    public void endOffPeakRequest() {
86      long newValueToLog = -1;
87      synchronized(compactionCountLock) {
88        newValueToLog = --numOutstanding;
89      }
90      LOG.info("Compaction done, numOutstandingOffPeakCompactions is now " +  newValueToLog);
91    }
92  
93    /**
94     * @return whether this is off-peak hour
95     */
96    private boolean isOffPeakHour() {
97      int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
98      // If offpeak time checking is disabled just return false.
99      if (this.offPeakStartHour == this.offPeakEndHour) {
100       return false;
101     }
102     if (this.offPeakStartHour < this.offPeakEndHour) {
103       return (currentHour >= this.offPeakStartHour && currentHour < this.offPeakEndHour);
104     }
105     return (currentHour >= this.offPeakStartHour || currentHour < this.offPeakEndHour);
106   }
107 
108   private static boolean isValidHour(int hour) {
109     return (hour >= 0 && hour <= 23);
110   }
111 }