forked from apache/activemq-artemis
-
Notifications
You must be signed in to change notification settings - Fork 1
/
DistributedLock.java
87 lines (75 loc) · 2.97 KB
/
DistributedLock.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/*
* 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();
}