Madan Jampani
Committed by Yuta Higuchi

1. Adds a lockAsync method to LockService for async lock acquisition.

2. Fixes a bug where lock() wasn't attempting a tryLock before registering for lock avalilability.
(Note 1 above is needed for LeadershipService which will come later)

Change-Id: I1deaa445f7cdf86416b335df1d7358e17eff19c3
package org.onlab.onos.store.service;
import java.util.concurrent.Future;
/**
* A lock is a tool for controlling access to a shared resource by multiple processes.
* Commonly, a lock provides exclusive access to a resource such as a network device
......@@ -36,6 +38,14 @@ public interface Lock {
void lock(int leaseDurationMillis) throws InterruptedException;
/**
* Acquires the lock asynchronously.
* @param leaseDurationMillis leaseDurationMillis the number of milliseconds the lock
* will be reserved before it becomes available for others.
* @return Future that can be used for blocking until lock is acquired.
*/
Future<Void> lockAsync(int leaseDurationMillis);
/**
* Acquires the lock only if it is free at the time of invocation.
* @param leaseDurationMillis the number of milliseconds the must be
* locked after it is granted, before automatically releasing it if it hasn't
......@@ -57,7 +67,7 @@ public interface Lock {
* elapsed before the lock was acquired
* @throws InterruptedException if the thread is interrupted while waiting
*/
boolean tryLock(long waitTimeMillis, int leaseDurationMillis) throws InterruptedException;
boolean tryLock(int waitTimeMillis, int leaseDurationMillis) throws InterruptedException;
/**
* Returns true if this Lock instance currently holds the lock.
......
......@@ -6,6 +6,7 @@ import java.nio.charset.StandardCharsets;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;
......@@ -53,20 +54,22 @@ public class DistributedLock implements Lock {
@Override
public void lock(int leaseDurationMillis) throws InterruptedException {
if (isLocked() && lockExpirationTime.isAfter(DateTime.now().plusMillis(leaseDurationMillis))) {
return;
} else {
CompletableFuture<DateTime> future =
lockManager.lockIfAvailable(this, leaseDurationMillis);
try {
lockExpirationTime = future.get();
} catch (ExecutionException e) {
throw new DatabaseException(e);
}
try {
lockAsync(leaseDurationMillis).get();
} catch (ExecutionException e) {
throw new DatabaseException(e);
}
}
@Override
public Future<Void> lockAsync(int leaseDurationMillis) {
if (isLocked() || tryLock(leaseDurationMillis)) {
return CompletableFuture.<Void>completedFuture(null);
}
return lockManager.lockIfAvailable(this, leaseDurationMillis);
}
@Override
public boolean tryLock(int leaseDurationMillis) {
if (databaseService.putIfAbsent(
DistributedLockManager.ONOS_LOCK_TABLE_NAME,
......@@ -81,15 +84,16 @@ public class DistributedLock implements Lock {
@Override
public boolean tryLock(
long waitTimeMillis,
int waitTimeMillis,
int leaseDurationMillis) throws InterruptedException {
if (tryLock(leaseDurationMillis)) {
if (isLocked() || tryLock(leaseDurationMillis)) {
return true;
}
CompletableFuture<DateTime> future =
CompletableFuture<Void> future =
lockManager.lockIfAvailable(this, waitTimeMillis, leaseDurationMillis);
try {
lockExpirationTime = future.get(waitTimeMillis, TimeUnit.MILLISECONDS);
future.get(waitTimeMillis, TimeUnit.MILLISECONDS);
return true;
} catch (ExecutionException e) {
throw new DatabaseException(e);
......
......@@ -111,17 +111,17 @@ public class DistributedLockManager implements LockService {
* @param lock lock to acquire.
* @param waitTimeMillis maximum time to wait before giving up.
* @param leaseDurationMillis the duration for which to acquire the lock initially.
* @return Future lease expiration date.
* @return Future that can be blocked on until lock becomes available.
*/
protected CompletableFuture<DateTime> lockIfAvailable(
protected CompletableFuture<Void> lockIfAvailable(
Lock lock,
long waitTimeMillis,
int waitTimeMillis,
int leaseDurationMillis) {
CompletableFuture<DateTime> future = new CompletableFuture<>();
CompletableFuture<Void> future = new CompletableFuture<>();
LockRequest request = new LockRequest(
lock,
leaseDurationMillis,
DateTime.now().plusMillis(leaseDurationMillis),
DateTime.now().plusMillis(waitTimeMillis),
future);
locksToAcquire.put(lock.path(), request);
return future;
......@@ -133,10 +133,10 @@ public class DistributedLockManager implements LockService {
* @param leaseDurationMillis the duration for which to acquire the lock initially.
* @return Future lease expiration date.
*/
protected CompletableFuture<DateTime> lockIfAvailable(
protected CompletableFuture<Void> lockIfAvailable(
Lock lock,
int leaseDurationMillis) {
CompletableFuture<DateTime> future = new CompletableFuture<>();
CompletableFuture<Void> future = new CompletableFuture<>();
LockRequest request = new LockRequest(
lock,
leaseDurationMillis,
......@@ -189,7 +189,7 @@ public class DistributedLockManager implements LockService {
existingRequestIterator.remove();
} else {
if (request.lock().tryLock(request.leaseDurationMillis())) {
request.future().complete(DateTime.now().plusMillis(request.leaseDurationMillis()));
request.future().complete(null);
existingRequestIterator.remove();
}
}
......@@ -203,13 +203,13 @@ public class DistributedLockManager implements LockService {
private final Lock lock;
private final DateTime requestExpirationTime;
private final int leaseDurationMillis;
private final CompletableFuture<DateTime> future;
private final CompletableFuture<Void> future;
public LockRequest(
Lock lock,
int leaseDurationMillis,
DateTime requestExpirationTime,
CompletableFuture<DateTime> future) {
CompletableFuture<Void> future) {
this.lock = lock;
this.requestExpirationTime = requestExpirationTime;
......@@ -229,7 +229,7 @@ public class DistributedLockManager implements LockService {
return leaseDurationMillis;
}
public CompletableFuture<DateTime> future() {
public CompletableFuture<Void> future() {
return future;
}
}
......