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 */
018package org.apache.hadoop.hbase.procedure2.util;
019
020import java.util.Objects;
021import java.util.concurrent.DelayQueue;
022import java.util.concurrent.Delayed;
023import java.util.concurrent.TimeUnit;
024import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
025import org.apache.yetus.audience.InterfaceAudience;
026import org.apache.yetus.audience.InterfaceStability;
027
028// FIX namings. TODO.
029@InterfaceAudience.Private
030@InterfaceStability.Evolving
031public final class DelayedUtil {
032  private DelayedUtil() {
033  }
034
035  /**
036   * Add a timeout to a Delay
037   */
038  public interface DelayedWithTimeout extends Delayed {
039    long getTimeout();
040  }
041
042  /**
043   * POISON implementation; used to mark special state: e.g. shutdown.
044   */
045  public static final DelayedWithTimeout DELAYED_POISON = new DelayedWithTimeout() {
046    @Override
047    public long getTimeout() {
048      return 0;
049    }
050
051    @Override
052    public long getDelay(final TimeUnit unit) {
053      return 0;
054    }
055
056    @Override
057    public int compareTo(final Delayed o) {
058      return Long.compare(0, DelayedUtil.getTimeout(o));
059    }
060
061    @Override
062    public boolean equals(final Object other) {
063      return this == other;
064    }
065
066    @Override
067    public int hashCode() {
068      return Objects.hash(this);
069    }
070
071    @Override
072    public String toString() {
073      return getClass().getSimpleName() + "(POISON)";
074    }
075  };
076
077  /** Returns null (if an interrupt) or an instance of E; resets interrupt on calling thread. */
078  public static <E extends Delayed> E takeWithoutInterrupt(final DelayQueue<E> queue,
079    final long timeout, final TimeUnit timeUnit) {
080    try {
081      return queue.poll(timeout, timeUnit);
082    } catch (InterruptedException e) {
083      Thread.currentThread().interrupt();
084      return null;
085    }
086  }
087
088  /** Returns Time remaining as milliseconds. */
089  public static long getRemainingTime(final TimeUnit resultUnit, final long timeout) {
090    final long currentTime = EnvironmentEdgeManager.currentTime();
091    if (currentTime >= timeout) {
092      return 0;
093    }
094    return resultUnit.convert(timeout - currentTime, TimeUnit.MILLISECONDS);
095  }
096
097  public static int compareDelayed(final Delayed o1, final Delayed o2) {
098    return Long.compare(getTimeout(o1), getTimeout(o2));
099  }
100
101  private static long getTimeout(final Delayed o) {
102    assert o instanceof DelayedWithTimeout : "expected DelayedWithTimeout instance, got " + o;
103    return ((DelayedWithTimeout) o).getTimeout();
104  }
105
106  public static abstract class DelayedObject implements DelayedWithTimeout {
107    @Override
108    public long getDelay(final TimeUnit unit) {
109      return DelayedUtil.getRemainingTime(unit, getTimeout());
110    }
111
112    @Override
113    public int compareTo(final Delayed other) {
114      return DelayedUtil.compareDelayed(this, other);
115    }
116
117    @Override
118    public String toString() {
119      long timeout = getTimeout();
120      return "timeout=" + timeout + ", delay=" + getDelay(TimeUnit.MILLISECONDS);
121    }
122  }
123
124  public static abstract class DelayedContainer<T> extends DelayedObject {
125    private final T object;
126
127    public DelayedContainer(final T object) {
128      this.object = object;
129    }
130
131    public T getObject() {
132      return this.object;
133    }
134
135    @Override
136    public boolean equals(final Object other) {
137      if (other == this) {
138        return true;
139      }
140
141      if (!(other instanceof DelayedContainer)) {
142        return false;
143      }
144
145      return Objects.equals(getObject(), ((DelayedContainer) other).getObject());
146    }
147
148    @Override
149    public int hashCode() {
150      return object != null ? object.hashCode() : 0;
151    }
152
153    @Override
154    public String toString() {
155      return "containedObject=" + getObject() + ", " + super.toString();
156    }
157  }
158
159  /**
160   * Has a timeout.
161   */
162  public static class DelayedContainerWithTimestamp<T> extends DelayedContainer<T> {
163    private long timeout;
164
165    public DelayedContainerWithTimestamp(final T object, final long timeout) {
166      super(object);
167      setTimeout(timeout);
168    }
169
170    @Override
171    public long getTimeout() {
172      return timeout;
173    }
174
175    public void setTimeout(final long timeout) {
176      this.timeout = timeout;
177    }
178  }
179}