blob: ac83a2c859f6ce76cc3f59eca712e22677673658 [file] [log] [blame]
/*
* 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.activemq.artemis.quorum;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public interface DistributedLock extends AutoCloseable {
String getLockId();
boolean isHeldByCaller() throws UnavailableStateException;
boolean tryLock() throws UnavailableStateException, InterruptedException;
default boolean tryLock(long timeout, TimeUnit unit) throws UnavailableStateException, InterruptedException {
// it doesn't make sense to be super fast
final long TARGET_FIRE_PERIOD_NS = TimeUnit.MILLISECONDS.toNanos(250);
if (timeout < 0) {
throw new IllegalArgumentException("timeout cannot be negative");
}
Objects.requireNonNull(unit);
if (timeout == 0) {
return tryLock();
}
final Thread currentThread = Thread.currentThread();
final long timeoutNs = unit.toNanos(timeout);
final long start = System.nanoTime();
final long deadline = start + timeoutNs;
long expectedNextFireTime = start;
while (!currentThread.isInterrupted()) {
long parkNs = expectedNextFireTime - System.nanoTime();
while (parkNs > 0) {
LockSupport.parkNanos(parkNs);
if (currentThread.isInterrupted()) {
throw new InterruptedException();
}
final long now = System.nanoTime();
parkNs = expectedNextFireTime - now;
}
if (tryLock()) {
return true;
}
final long now = System.nanoTime();
final long remainingTime = deadline - now;
if (remainingTime <= 0) {
return false;
}
if (remainingTime < TARGET_FIRE_PERIOD_NS) {
expectedNextFireTime = now;
} else {
expectedNextFireTime += TARGET_FIRE_PERIOD_NS;
}
}
throw new InterruptedException();
}
void unlock() throws UnavailableStateException;
void addListener(UnavailableLockListener listener);
void removeListener(UnavailableLockListener listener);
@FunctionalInterface
interface UnavailableLockListener {
void onUnavailableLockEvent();
}
@Override
void close();
}