Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 27 additions & 26 deletions common/main/java/com/couchbase/lite/AbstractDatabase.java
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,13 @@ abstract class AbstractDatabase extends BaseDatabase

private static final LogDomain DOMAIN = LogDomain.DATABASE;

private static final int DB_CLOSE_WAIT_SECS = 6; // > Core replicator timeout
private static final int DB_CLOSE_MAX_RETRIES = 5; // random choice: wait for 5 replicators
// Max time to wait for active processes to finish.
private static final int DB_CLOSE_PROCESS_TIMEOUT_SECS = 10;
// Backoff between BUSY retries on close.
private static final int DB_CLOSE_RETRY_DELAY_SECS = 2;
// Max number of BUSY retries before giving up.
private static final int DB_CLOSE_MAX_RETRIES = 5;
// Max time to wait for executors to drain.
private static final int EXECUTOR_CLOSE_MAX_WAIT_SECS = 5;

static class ActiveProcess<T> {
Expand Down Expand Up @@ -1224,7 +1229,6 @@ private void verifyActiveProcesses() {
for (ActiveProcess<?> process: processes) { Log.d(DOMAIN, " processes: %s", process); }
}

@SuppressWarnings("PMD.NPathComplexity")
private void shutdown(boolean failIfClosed, Fn.ConsumerThrows<C4Database, LiteCoreException> onShut)
throws CouchbaseLiteException {
final C4Database c4Db;
Expand All @@ -1251,33 +1255,30 @@ private void shutdown(boolean failIfClosed, Fn.ConsumerThrows<C4Database, LiteCo
}

try {
for (int i = 0; ; i++) {
verifyActiveProcesses();
verifyActiveProcesses();
if (!closeLatch.await(DB_CLOSE_PROCESS_TIMEOUT_SECS, TimeUnit.SECONDS)) {
throw new CouchbaseLiteException("Shutdown failed", CBLError.Domain.CBLITE, CBLError.Code.BUSY);
}

if ((i >= DB_CLOSE_MAX_RETRIES) && (closeLatch.getCount() > 0)) {
throw new CouchbaseLiteException("Shutdown failed", CBLError.Domain.CBLITE, CBLError.Code.BUSY);
for (int i = 0; ; i++) {
try {
synchronized (getDbLock()) { onShut.accept(c4Db); }
break;
}

if (closeLatch.await(DB_CLOSE_WAIT_SECS, TimeUnit.SECONDS)) {
try {
synchronized (getDbLock()) { onShut.accept(c4Db); }
break;
}
catch (LiteCoreException e) {
if ((e.getDomain() != C4Constants.ErrorDomain.LITE_CORE)
|| (e.getCode() != C4Constants.LiteCoreError.BUSY)) {
throw CouchbaseLiteException.convertException(e);
}
catch (LiteCoreException e) {
if (i >= DB_CLOSE_MAX_RETRIES
|| e.getDomain() != C4Constants.ErrorDomain.LITE_CORE
|| e.getCode() != C4Constants.LiteCoreError.BUSY) {
throw CouchbaseLiteException.convertException(e);
}
Log.i(
DOMAIN,
"Database close returned BUSY, retrying in %d secs (retry %d/%d)",
DB_CLOSE_RETRY_DELAY_SECS,
i + 1,
DB_CLOSE_MAX_RETRIES);
Thread.sleep(TimeUnit.SECONDS.toMillis(DB_CLOSE_RETRY_DELAY_SECS));
}

// If we get here then, despite the fact that it appears to us that all
// active processes have been stopped, LiteCore has other ideas.
// We have no way of finding out what LiteCore thinks, other than waiting
// a bit and trying the again. Since verifyActiveProcess will count down
// the latch, we need a new one with a count of at least 2 in order to force
// a wait
closeLatch = new CountDownLatch(2);
}
}
catch (InterruptedException ignore) { }
Expand Down
Loading