stronger encapsulation of vault state await/signal mechanism

This commit is contained in:
Sebastian Stenzel
2021-04-15 10:30:29 +02:00
parent 03886f88e8
commit 24baa44e70
2 changed files with 45 additions and 20 deletions

View File

@@ -44,9 +44,6 @@ import java.util.Optional;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static org.cryptomator.common.Constants.MASTERKEY_FILENAME;
@@ -74,8 +71,6 @@ public class Vault {
private final StringBinding accessPoint;
private final BooleanBinding accessPointPresent;
private final BooleanProperty showingStats;
private final Lock lock = new ReentrantLock(); //FIXME: naming
private final Condition isLocked = lock.newCondition(); //FIXME: improve naming
private volatile Volume volume;
@@ -152,13 +147,6 @@ public class Vault {
if (throwable != null) {
LOG.warn("Unexpected unmount and lock of vault " + getDisplayName(), throwable);
}
lock.lock();
try {
isLocked.signal();
} finally {
lock.unlock();
}
});
} catch (Exception e) {
destroyCryptoFileSystem();
@@ -176,20 +164,15 @@ public class Vault {
volume.unmount();
}
destroyCryptoFileSystem();
lock.lock();
try {
while (state.get() != VaultState.Value.LOCKED) {
if (!isLocked.await(3000, TimeUnit.MILLISECONDS)) {
throw new VolumeException("Locking failed"); //FIXME: other exception
}
boolean locked = state.awaitState(VaultState.Value.LOCKED, 3000, TimeUnit.MILLISECONDS);
if (!locked) {
throw new VolumeException("Locking failed"); //FIXME: other exception
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new VolumeException("Lock failed."); //FIXME: other/new exception
} finally {
lock.unlock();
}
}
public void reveal(Volume.Revealer vaultRevealer) throws VolumeException {

View File

@@ -8,7 +8,11 @@ import javax.inject.Inject;
import javafx.application.Platform;
import javafx.beans.value.ObservableObjectValue;
import javafx.beans.value.ObservableValueBase;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
@PerVault
public class VaultState extends ObservableValueBase<VaultState.Value> implements ObservableObjectValue<VaultState.Value> {
@@ -48,6 +52,8 @@ public class VaultState extends ObservableValueBase<VaultState.Value> implements
}
private final AtomicReference<Value> value;
private final Lock lock = new ReentrantLock();
private final Condition valueChanged = lock.newCondition();
@Inject
public VaultState(VaultState.Value initialValue) {
@@ -89,7 +95,43 @@ public class VaultState extends ObservableValueBase<VaultState.Value> implements
}
}
/**
* Waits for the specified time, until the desired state is reached.
*
* @param desiredState what state to wait for
* @param time the maximum time to wait
* @param unit the time unit of the {@code time} argument
* @return {@code false} if the waiting time detectably elapsed before reaching {@code desiredState}
* @throws InterruptedException if the current thread is interrupted
*/
public boolean awaitState(Value desiredState, long time, TimeUnit unit) throws InterruptedException {
lock.lock();
try {
long remaining = unit.convert(time, TimeUnit.NANOSECONDS);
while (value.get() != desiredState) {
if (remaining <= 0L) {
return false;
}
remaining = valueChanged.awaitNanos(remaining);
}
return true;
} finally {
lock.unlock();
}
}
private void signal() {
lock.lock();
try {
valueChanged.signalAll();
} finally {
lock.unlock();
}
}
@Override
protected void fireValueChangedEvent() {
signal();
if (Platform.isFxApplicationThread()) {
super.fireValueChangedEvent();
} else {