001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.hbase.procedure2.util;
020
021import java.util.Objects;
022import java.util.concurrent.DelayQueue;
023import java.util.concurrent.Delayed;
024import java.util.concurrent.TimeUnit;
025
026import org.apache.yetus.audience.InterfaceAudience;
027import org.apache.yetus.audience.InterfaceStability;
028import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
029
030// FIX namings. TODO.
031@InterfaceAudience.Private
032@InterfaceStability.Evolving
033public final class DelayedUtil {
034  private DelayedUtil() { }
035
036  /**
037   * Add a timeout to a Delay
038   */
039  public interface DelayedWithTimeout extends Delayed {
040    long getTimeout();
041  }
042
043  /**
044   * POISON implementation; used to mark special state: e.g. shutdown.
045   */
046  public static final DelayedWithTimeout DELAYED_POISON = new DelayedWithTimeout() {
047    @Override
048    public long getTimeout() {
049      return 0;
050    }
051
052    @Override
053    public long getDelay(final TimeUnit unit) {
054      return 0;
055    }
056
057    @Override
058    public int compareTo(final Delayed o) {
059      return Long.compare(0, DelayedUtil.getTimeout(o));
060    }
061
062    @Override
063    public boolean equals(final Object other) {
064      return this == other;
065    }
066
067    @Override
068    public String toString() {
069      return getClass().getSimpleName() + "(POISON)";
070    }
071  };
072
073  /**
074   * @return null (if an interrupt) or an instance of E; resets interrupt on calling thread.
075   */
076  public static <E extends Delayed> E takeWithoutInterrupt(final DelayQueue<E> queue) {
077    try {
078      return queue.take();
079    } catch (InterruptedException e) {
080      Thread.currentThread().interrupt();
081      return null;
082    }
083  }
084
085  /**
086   * @return Time remaining as milliseconds.
087   */
088  public static long getRemainingTime(final TimeUnit resultUnit, final long timeout) {
089    final long currentTime = EnvironmentEdgeManager.currentTime();
090    if (currentTime >= timeout) {
091      return 0;
092    }
093    return resultUnit.convert(timeout - currentTime, TimeUnit.MILLISECONDS);
094  }
095
096  public static int compareDelayed(final Delayed o1, final Delayed o2) {
097    return Long.compare(getTimeout(o1), getTimeout(o2));
098  }
099
100  private static long getTimeout(final Delayed o) {
101    assert o instanceof DelayedWithTimeout : "expected DelayedWithTimeout instance, got " + o;
102    return ((DelayedWithTimeout)o).getTimeout();
103  }
104
105  public static abstract class DelayedObject implements DelayedWithTimeout {
106    @Override
107    public long getDelay(final TimeUnit unit) {
108      return DelayedUtil.getRemainingTime(unit, getTimeout());
109    }
110
111    @Override
112    public int compareTo(final Delayed other) {
113      return DelayedUtil.compareDelayed(this, other);
114    }
115
116    @Override
117    public String toString() {
118      long timeout = getTimeout();
119      return "timeout=" + timeout + ", delay=" + getDelay(TimeUnit.MILLISECONDS);
120    }
121  }
122
123  public static abstract class DelayedContainer<T> extends DelayedObject {
124    private final T object;
125
126    public DelayedContainer(final T object) {
127      this.object = object;
128    }
129
130    public T getObject() {
131      return this.object;
132    }
133
134    @Override
135    public boolean equals(final Object other) {
136      if (other == this) return true;
137      if (!(other instanceof DelayedContainer)) return false;
138      return Objects.equals(getObject(), ((DelayedContainer)other).getObject());
139    }
140
141    @Override
142    public int hashCode() {
143      return object != null ? object.hashCode() : 0;
144    }
145
146    @Override
147    public String toString() {
148      return "containedObject=" + getObject() + ", " + super.toString();
149    }
150  }
151
152  /**
153   * Has a timeout.
154   */
155  public static class DelayedContainerWithTimestamp<T> extends DelayedContainer<T> {
156    private long timeout;
157
158    public DelayedContainerWithTimestamp(final T object, final long timeout) {
159      super(object);
160      setTimeout(timeout);
161    }
162
163    @Override
164    public long getTimeout() {
165      return timeout;
166    }
167
168    public void setTimeout(final long timeout) {
169      this.timeout = timeout;
170    }
171  }
172}