Visitar URL original
[Bug] INSERT OVERWRITE can drop committed rows: crash, swap failure, and uncertain remote/cloud commits · Issue #68679 · apache/doris · GitHub
Skip to content

[Bug] INSERT OVERWRITE can drop committed rows: crash, swap failure, and uncertain remote/cloud commits #68679

Description

@yujun777

Search before asking

  • I searched in the issues and found nothing similar.

Version

master (the two-phase overwrite in InsertOverwriteTableCommand and its publication via ReplacePartitionOperationLog, and the remote/cloud commit paths as of 2026-09).

What's Wrong?

An INSERT OVERWRITE is two-phase: the rows are committed into temporary partitions first (InsertIntoTableCommand hangs the table stream offsets on that transaction; DatabaseTransactionMgr.updateCatalogAfterCommitted applies them on commit and replays them), and a later swap publishes them (Env.replaceTempPartition / ReplacePartitionOperationLog). Two durable facts are therefore split across two journal records, and three remaining paths can leave the offset (and the rows) advanced while nothing is published, with no error:

  1. The FE stops between the two halves (crash, or a master switch, where Env.transferToMaster calls InsertOverwriteManager.allTaskFail() and drops every in-flight task's temporary partitions) or the swap itself fails (replacePartition throwing). The committed rows are gone and the consumed offset stays advanced, so a re-run reads from the advanced position and that range is missing.
  2. A remote commit whose reply is lost. RemoteOlapInsertExecutor.onComplete commits on the owning FE and then waits; if masterCallWithRetry exhausts its retries after the owner committed, this FE sees an error, onFail's abort cannot take a committed remote transaction back, and the overwrite rolls the temporary partitions back, dropping rows that exist.
  3. A cloud transaction that is maybe-committed. FoundationDB can apply a commit and still report an error; after the finite meta-service retries this reaches the FE as KV_TXN_COMMIT_ERR and commitAndPublishTransactionWithRetry throws, so the overwrite rolls back temporary partitions whose rows and stream offsets the meta service may already hold.

The same shape shows up where the decision is the owning FE's: for a remote target, a cancellation that arrives while replacePartitionsImpl waits for the table write lock is not conveyed by the replacement RPC, so an overwrite whose insert committed nothing can still publish an empty result and report success. (The local equivalents of the cancellation cases, and the local error-response case, are fixed by #68662.)

Impact: silent partial data for INSERT OVERWRITE t SELECT * FROM stream(...), and for an IVM/MTMV partition refresh, which resets the stream offsets of exactly the partitions it replaces -- the partition keeps its old rows, the change it read is consumed, and the following refresh reports success. Trace issue for the IVM side: #65418.

What You Expected?

Once a load's rows (or stream offsets) are committed, the overwrite must publish them: committed and published must not be able to disagree, whatever happens to the FE, the RPC or the meta service in between. Where the commit outcome is genuinely unknown, the overwrite must not answer with a rollback that can drop durable rows.

How to Reproduce?

  1. Local, crash or swap failure: run INSERT OVERWRITE t SELECT * FROM stream('db', 'src') (or an IVM partition refresh) and stop the FE (or inject a failure in the swap) between the insert's commit and the swap; the temporary partitions are dropped by allTaskFail/taskFail while the offsets stay advanced.
  2. Remote: overwrite a remote Doris table and drop the commit reply (masterCallWithRetry exhausting retries) after the owning FE committed; the temporary partitions are rolled back on this side.
  3. Cloud: overwrite with a commit that the meta service applies but reports as failed (FDB maybe-committed -> KV_TXN_COMMIT_ERR).

The local cancellation and publication-timeout variants are pinned by the regression suite added in #68662 (insert_overwrite_p0/test_insert_overwrite_cancel), and the local replacePartition-failure and crash windows are pinned by mtmv_p0/ivm/test_ivm_overwrite_failure_between_the_halves.

Anything Else?

Fix directions, in increasing order of cost:

  • Carry the swap as a committed action of the insert transaction, so one journal record decides both the offset advance and the publication (the offsets already ride TransactionState; a "committed catalog action" for the partition swap would ride the same record, and the publish/finish path already re-drives committed transactions after a restart).
  • Or move the consumption position out of the insert transaction and into the swap's record (ReplacePartitionOperationLog), which keeps the transaction path untouched but weakens the read-range exclusivity checkStreamOffset provides during the window, and needs a separate answer for cloud read state.
  • For remote and cloud specifically, the owner side (the owning FE, the meta service) has to be able to answer "did that commit happen"; until then, an uncertain commit has no correct local resolution -- dropping the partitions loses durable rows and keeping them leaves unpublished ones that the next allTaskFail drops anyway.

Are you willing to submit PR?

  • Yes I am willing to submit a PR!

Code of Conduct

Activity

  1. Doris-Breakwater commented on Sep 30, 2026

    @Doris-Breakwater
    Collaborator

    Breakwater-GitHub-Analysis-Slot: slot_9c2dc24ef6e2

    Initial assessment (read-only source review): high-priority correctness risk for stream-consuming INSERT OVERWRITE; no production occurrence or remote/cloud fault-injection result is established by this issue. I checked apache/doris master at 7d231485588 (2026-09-30 08:25 UTC, just before this issue). The issue currently has no labels.

    Confirmed from code

    • The inner insert attaches stream updates to its transaction; the local transaction applies them after committing and on replay (insert setup, commit/replay). InsertOverwriteTableCommand then swaps temporary partitions separately and calls taskFail on a swap exception (overwrite sequence); the swap has its own edit-log record (replacement log). On master transfer, outstanding tasks are failed and their temporary partitions are dropped (recovery, cleanup). Thus a committed offset can outlive an unpublished or dropped temporary partition. A swap exception does surface an error for that attempt; the potentially silent loss is on a later read from the advanced offset.
    • A lost remote commit reply can leave the caller unable to distinguish a committed transaction from a failed one: the RPC has finite retries, and the caller's failure path aborts best-effort while overwrite cleanup can drop the remote temporary partitions (retry, commit/abort). This is a conditional loss window, not proof that the reported remote case has occurred. In particular, the remote commit request does not carry stream updates, so the claimed remote offset impact needs a separate concrete reproduction.
    • Cloud commit requests include stream updates (request). The meta-service maps exhausted KV_TXN_MAYBE_COMMITTED retries to KV_TXN_COMMIT_ERR (retry boundary); FE treats that response as an error (FE response handling). Whether any particular transaction actually committed remains unknown until checked at the owner.

    Important scope correction: current master already journals an IVM partition rebuild requirement before that refresh reads (MTMV task). The checked-in failure-between-halves regression expects the following refresh to rebuild the partition and recover the row. That limits the stated IVM impact on this master revision; it does not close the direct stream-overwrite gap. PR #68662 is open, so its cancellation changes should not yet be assumed present on master. The remote lock-wait cancellation/success scenario also needs its own deterministic test.

    Requested evidence / next steps: Please provide an exact build SHA and mode (local, remote, or cloud), minimal table/stream SQL and partition layout, transaction ID, overwrite task ID, affected partition IDs, stream offset before/after, and row counts before/after retry. For failover, include FE edit-log ordering and leader-transition logs; for remote, caller/owner FE commit and abort RPC logs plus owner transaction status; for cloud, meta-service commit response/actual_code and authoritative transaction status. A direct stream-overwrite fault-injection test at commit-before-swap, plus lost-reply and maybe-committed tests, would establish the remaining outcomes. The fix should make publication recoverable with the committed consumption decision, and reconcile uncertain commits with the owning FE/meta-service before any temporary-partition cleanup; a local error alone cannot determine whether rollback is safe.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions