Skip to content

fix(kv-server): complete the restore session future on synchronous start failure — fixes #303 - #310

Open
ImDanXie wants to merge 1 commit into
apache:mainfrom
ImDanXie:fix/kv-server-restore-future
Open

ImDanXie wants to merge 1 commit into
apache:mainfrom
ImDanXie:fix/kv-server-restore-future

Conversation

@ImDanXie

Copy link
Copy Markdown
Contributor

Summary

KVRangeRestorer.restoreFrom() wraps snapshot-install setup in try { … } catch (Throwable t) { log.error(…) } and returns the session's doneFuture. If startRestore() — or the subsequent messenger.send() — throws synchronously, the future is never completed.

Root cause & impact

  • There is no timeout on this path (the receiver-driven path has an idle timeout; the synchronous-throw path has nothing), so the caller waits forever.
  • Worse: the session stays cached in currentSession. A retry with the same snapshot from the same leader hits the reuse branch — existingSession.snapshot.equals(rangeSnapshot) && !doneFuture.isDone() && same leader — and returns the same dead future. The range is permanently stuck: it never applies anything and never retries.

Snapshot install is mandatory on expansion/rebalance, so any transient synchronous failure here is a hard wedge.

Fix

Complete the future exceptionally in the catch block; the caller observes the failure and a retry starts a fresh session:

} catch (Throwable t) {
    log.error("Unexpected error", t);
    onDone.completeExceptionally(new KVRangeStoreException("Snapshot restore failed to start", t));
}

Test evidence

New restoreFromStartFailureCompletesFutureExceptionally: startRestore throws → the future must be completed exceptionally, and a retry with the same snapshot must start a fresh session (not reuse the dead one).

  • Control experiment: fails on the unfixed code (future never completes), passes with the fix.
  • Existing restore expectations unchanged (9/9).

Production validation

Deployed in a rolling 6-node cluster (wholesale lib/ replacement, one node at a time, zero rollbacks); cluster mesh, all 13 live client connections and cross-node delivery verified post-deploy. No wedged range (a range stuck in snapshot restore) observed before or after; the fix closes the permanent-wedge path should a synchronous start failure ever occur.

Fixes #303

…art failure

restoreFrom() swallows any Throwable from startRestore()/messenger.send() with
just a log line, leaving the session's doneFuture pending forever. There is no
timeout on this path, and because the session remains cached and un-done, a
retry with the same snapshot (same leader) hits the reuse branch and returns
the same dead future - the range is permanently stuck after a failed snapshot
install.

Complete the future exceptionally in the catch block, so callers observe the
failure and a retry starts a fresh session.

Control experiment: restoreFromStartFailureCompletesFutureExceptionally fails
on the old code and passes with the fix; existing restore expectations
unchanged (9/9).

Fixes apache#303
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] KVRangeRestorer leaves the restore future uncompleted when startRestore() throws, permanently wedging the range

1 participant