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.util;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.hadoop.hbase.Stoppable;
24  import org.apache.hadoop.hbase.classification.InterfaceAudience;
25  
26  /**
27   * Sleeper for current thread.
28   * Sleeps for passed period.  Also checks passed boolean and if interrupted,
29   * will return if the flag is set (rather than go back to sleep until its
30   * sleep time is up).
31   */
32  @InterfaceAudience.Private
33  public class Sleeper {
34    private static final Log LOG = LogFactory.getLog(Sleeper.class);
35    private final int period;
36    private final Stoppable stopper;
37    private static final long MINIMAL_DELTA_FOR_LOGGING = 10000;
38  
39    private final Object sleepLock = new Object();
40    private boolean triggerWake = false;
41  
42    /**
43     * @param sleep sleep time in milliseconds
44     * @param stopper When {@link Stoppable#isStopped()} is true, this thread will
45     *    cleanup and exit cleanly.
46     */
47    public Sleeper(final int sleep, final Stoppable stopper) {
48      this.period = sleep;
49      this.stopper = stopper;
50    }
51  
52    /**
53     * If currently asleep, stops sleeping; if not asleep, will skip the next
54     * sleep cycle.
55     */
56    public void skipSleepCycle() {
57      synchronized (sleepLock) {
58        triggerWake = true;
59        sleepLock.notifyAll();
60      }
61    }
62  
63    /**
64     * Sleep for period.
65     */
66    public void sleep() {
67      sleep(this.period);
68    }
69  
70    public void sleep(long sleepTime) {
71      if (this.stopper.isStopped()) {
72        return;
73      }
74      long now = System.currentTimeMillis();
75      long currentSleepTime = sleepTime;
76      while (currentSleepTime > 0) {
77        long woke = -1;
78        try {
79          synchronized (sleepLock) {
80            if (triggerWake) {
81              break;
82            }
83  
84            sleepLock.wait(currentSleepTime);
85          }
86          woke = System.currentTimeMillis();
87          long slept = woke - now;
88          if (slept - this.period > MINIMAL_DELTA_FOR_LOGGING) {
89            LOG.warn("We slept " + slept + "ms instead of " + this.period +
90              "ms, this is likely due to a long " +
91              "garbage collecting pause and it's usually bad, see " +
92              "http://hbase.apache.org/book.html#trouble.rs.runtime.zkexpired");
93          }
94        } catch(InterruptedException iex) {
95          // We we interrupted because we're meant to stop?  If not, just
96          // continue ignoring the interruption
97          if (this.stopper.isStopped()) {
98            return;
99          }
100       }
101       // Recalculate waitTime.
102       woke = (woke == -1)? System.currentTimeMillis(): woke;
103       currentSleepTime = this.period - (woke - now);
104     }
105     synchronized(sleepLock) {
106       triggerWake = false;
107     }
108   }
109   
110   /**
111    * @return the sleep period in milliseconds
112    */
113   public final int getPeriod() {
114     return period;
115   }
116 }