/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.procedure2.util;
import java.util.Objects;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import org.apache.hadoop.hbase.classification.InterfaceAudience;
import org.apache.hadoop.hbase.classification.InterfaceStability;
import org.apache.hadoop.hbase.util.EnvironmentEdgeManager;
@InterfaceAudience.Private
@InterfaceStability.Evolving
public final class DelayedUtil {
private DelayedUtil() { }
/**
* Add a timeout to a Delay
*/
public interface DelayedWithTimeout extends Delayed {
long getTimeout();
}
/**
* POISON implementation; used to mark special state: e.g. shutdown.
*/
public static final DelayedWithTimeout DELAYED_POISON = new DelayedWithTimeout() {
@Override
public long getTimeout() {
return 0;
}
@Override
public long getDelay(final TimeUnit unit) {
return 0;
}
@Override
public int compareTo(final Delayed o) {
return Long.compare(0, DelayedUtil.getTimeout(o));
}
@Override
public boolean equals(final Object other) {
return this == other;
}
@Override
public String toString() {
return getClass().getSimpleName() + "(POISON)";
}
};
/**
* @return null (if an interrupt) or an instance of E; resets interrupt on calling thread.
*/
public static <E extends Delayed> E takeWithoutInterrupt(final DelayQueue<E> queue) {
try {
return queue.take();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
/**
* @return Time remaining as milliseconds.
*/
public static long getRemainingTime(final TimeUnit resultUnit, final long timeout) {
final long currentTime = EnvironmentEdgeManager.currentTime();
if (currentTime >= timeout) {
return 0;
}
return resultUnit.convert(timeout - currentTime, TimeUnit.MILLISECONDS);
}
public static int compareDelayed(final Delayed o1, final Delayed o2) {
return Long.compare(getTimeout(o1), getTimeout(o2));
}
private static long getTimeout(final Delayed o) {
assert o instanceof DelayedWithTimeout : "expected DelayedWithTimeout instance, got " + o;
return ((DelayedWithTimeout)o).getTimeout();
}
public static abstract class DelayedObject implements DelayedWithTimeout {
@Override
public long getDelay(final TimeUnit unit) {
return DelayedUtil.getRemainingTime(unit, getTimeout());
}
@Override
public int compareTo(final Delayed other) {
return DelayedUtil.compareDelayed(this, other);
}
@Override
public String toString() {
long timeout = getTimeout();
return "timeout=" + timeout + ", delay=" + getDelay(TimeUnit.MILLISECONDS);
}
}
public static abstract class DelayedContainer<T> extends DelayedObject {
private final T object;
public DelayedContainer(final T object) {
this.object = object;
}
public T getObject() {
return this.object;
}
@Override
public boolean equals(final Object other) {
if (other == this) return true;
if (!(other instanceof DelayedContainer)) return false;
return Objects.equals(getObject(), ((DelayedContainer)other).getObject());
}
@Override
public int hashCode() {
return object != null ? object.hashCode() : 0;
}
@Override
public String toString() {
return "containedObject=" + getObject() + ", " + super.toString();
}
}
public static class DelayedContainerWithTimestamp<T> extends DelayedContainer<T> {
private long timeout;
public DelayedContainerWithTimestamp(final T object, final long timeout) {
super(object);
setTimeout(timeout);
}
@Override
public long getTimeout() {
return timeout;
}
public void setTimeout(final long timeout) {
this.timeout = timeout;
}
}
}