Return early when starting/stopping if not in expected state.

This commit is contained in:
akwizgran
2022-06-09 18:01:32 +01:00
parent 85d1addd04
commit de3a87fff5
3 changed files with 115 additions and 63 deletions

View File

@@ -18,7 +18,7 @@ import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Logger;
import javax.annotation.concurrent.ThreadSafe;
@@ -29,10 +29,12 @@ import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.COMPACTING_DATABASE;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.CREATED;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.MIGRATING_DATABASE;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.RUNNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STARTING_SERVICES;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPED;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.ALREADY_RUNNING;
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.StartResult.CLOCK_ERROR;
@@ -60,12 +62,11 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
private final List<Service> services;
private final List<OpenDatabaseHook> openDatabaseHooks;
private final List<ExecutorService> executors;
private final Semaphore startStopSemaphore = new Semaphore(1);
private final CountDownLatch dbLatch = new CountDownLatch(1);
private final CountDownLatch startupLatch = new CountDownLatch(1);
private final CountDownLatch shutdownLatch = new CountDownLatch(1);
private volatile LifecycleState state = STARTING;
private final AtomicReference<LifecycleState> state =
new AtomicReference<>(CREATED);
@Inject
LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus,
@@ -102,8 +103,8 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
@Override
public StartResult startServices(SecretKey dbKey) {
if (!startStopSemaphore.tryAcquire()) {
LOG.info("Already starting or stopping");
if (!state.compareAndSet(CREATED, STARTING)) {
LOG.warning("Already running");
return ALREADY_RUNNING;
}
long now = clock.currentTimeMillis();
@@ -135,7 +136,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
});
LOG.info("Starting services");
state = STARTING_SERVICES;
state.set(STARTING_SERVICES);
dbLatch.countDown();
eventBus.broadcast(new LifecycleEvent(STARTING_SERVICES));
@@ -148,7 +149,7 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
}
}
state = RUNNING;
state.set(RUNNING);
startupLatch.countDown();
eventBus.broadcast(new LifecycleEvent(RUNNING));
return SUCCESS;
@@ -164,69 +165,58 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
} catch (ServiceException e) {
logException(LOG, WARNING, e);
return SERVICE_ERROR;
} finally {
startStopSemaphore.release();
}
}
@Override
public void onDatabaseMigration() {
state = MIGRATING_DATABASE;
state.set(MIGRATING_DATABASE);
eventBus.broadcast(new LifecycleEvent(MIGRATING_DATABASE));
}
@Override
public void onDatabaseCompaction() {
state = COMPACTING_DATABASE;
state.set(COMPACTING_DATABASE);
eventBus.broadcast(new LifecycleEvent(COMPACTING_DATABASE));
}
@Override
public void stopServices() {
try {
startStopSemaphore.acquire();
} catch (InterruptedException e) {
LOG.warning("Interrupted while waiting to stop services");
if (!state.compareAndSet(RUNNING, STOPPING)) {
LOG.warning("Not running");
return;
}
try {
if (state == STOPPING) {
LOG.info("Already stopped");
return;
}
LOG.info("Stopping services");
state = STOPPING;
eventBus.broadcast(new LifecycleEvent(STOPPING));
for (Service s : services) {
try {
long start = now();
s.stopService();
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Stopping service "
+ s.getClass().getSimpleName(), start);
}
} catch (ServiceException e) {
logException(LOG, WARNING, e);
}
}
for (ExecutorService e : executors) {
if (LOG.isLoggable(FINE)) {
LOG.fine("Stopping executor "
+ e.getClass().getSimpleName());
}
e.shutdownNow();
}
LOG.info("Stopping services");
eventBus.broadcast(new LifecycleEvent(STOPPING));
for (Service s : services) {
try {
long start = now();
db.close();
logDuration(LOG, "Closing database", start);
} catch (DbException e) {
s.stopService();
if (LOG.isLoggable(FINE)) {
logDuration(LOG, "Stopping service "
+ s.getClass().getSimpleName(), start);
}
} catch (ServiceException e) {
logException(LOG, WARNING, e);
}
shutdownLatch.countDown();
} finally {
startStopSemaphore.release();
}
for (ExecutorService e : executors) {
if (LOG.isLoggable(FINE)) {
LOG.fine("Stopping executor "
+ e.getClass().getSimpleName());
}
e.shutdownNow();
}
try {
long start = now();
db.close();
logDuration(LOG, "Closing database", start);
} catch (DbException e) {
logException(LOG, WARNING, e);
}
state.set(STOPPED);
shutdownLatch.countDown();
eventBus.broadcast(new LifecycleEvent(STOPPED));
}
@Override
@@ -246,6 +236,6 @@ class LifecycleManagerImpl implements LifecycleManager, MigrationListener {
@Override
public LifecycleState getLifecycleState() {
return state;
return state.get();
}
}