Doris-Breakwater commented on issue #66051:
URL: https://github.com/apache/doris/issues/66051#issuecomment-5081414105

   Breakwater-GitHub-Analysis-Slot: slot_a77e50f6a370
   
   ## Initial maintainer assessment
   
   **Current judgment: the reported data-loss chain is not established, and the 
two proposed fixes do not follow from the current code.** The issue points at 
safety-critical code and should receive a deterministic reproducer or incident 
evidence, but source inspection contradicts both asserted defects. I would not 
mark the listed branches as confirmed affected or merge the proposed changes on 
the present evidence.
   
   The issue is open and currently has no labels, assignee, type, milestone, or 
linked development. I inspected the cited code on the live branch heads:
   
   - `branch-2.1`: `a3052de2e5cbc397d67b9cd9d5cd9701aaa6426c`
   - `branch-3.1`: `7f5ba43de6c7f148e1dacdb7cb838394d2ec1537`
   - `branch-4.1`: `1ac74c857454c7dc59005fdc688eeeb4ad58cf75`
   - `master`: `b9c561a03849a78d3cb41294cce8c0ae610257a0`
   
   ### Why the proposed root cause does not hold
   
   1. **A non-cooldown full clone preserves a consistent pair: clone-source 
remote rowsets plus clone-source `cooldown_meta_id`.**
   
      A full snapshot copies the source tablet metadata, explicitly selects all 
remote rowsets, and records those selected rowset metas in the snapshot. During 
rowset-ID conversion, remote rowset metadata and IDs are copied unchanged; only 
local rowsets receive new IDs. `_finish_full_clone()` then installs those 
cloned rowsets and, for a non-cooldown destination, installs the same source 
`cooldown_meta_id`.
   
      Therefore, the `else` branch does not by itself create the issue's 
required state of “same `cooldown_meta_id`, different remote rowset IDs.” It 
keeps the identifier and the remote rowset set from the same snapshot together. 
See 
[`SnapshotManager`](https://github.com/apache/doris/blob/b9c561a03849a78d3cb41294cce8c0ae610257a0/be/src/storage/snapshot/snapshot_manager.cpp#L642-L766),
 
[`convert_rowset_ids`](https://github.com/apache/doris/blob/b9c561a03849a78d3cb41294cce8c0ae610257a0/be/src/storage/snapshot/snapshot_manager.cpp#L177-L242),
 and 
[`_finish_full_clone`](https://github.com/apache/doris/blob/b9c561a03849a78d3cb41294cce8c0ae610257a0/be/src/storage/task/engine_clone_task.cpp#L962-L1035).
   
      The special-case fresh ID for the **current cooldown replica** was 
deliberately introduced by 
[#17644](https://github.com/apache/doris/pull/17644): that replica owns the 
current term's remote `.meta` path, so replacing its rowsets from another 
replica while reusing the source ID could make its local state disagree with 
the already-written remote meta. That is the exact scenario described by the 
in-code comment. A non-cooldown replica does not own/write that term meta and 
will follow the owner when its ID differs.
   
      Changing every non-cooldown clone to a fresh ID would deliberately create 
an ID mismatch and force an extra follower synchronization. It does **not** 
force the cooldown replica to rewrite remote meta, contrary to the proposed 
explanation.
   
   2. **The FE request-side null guard already exists on all four cited 
branches.**
   
      `confirmUnusedRemoteFiles()` starts each entry with:
   
      ```java
      if (!info.isSetCooldownMetaId()) {
          LOG.warn("cooldown_meta_id is null");
          return;
      }
      ```
   
      The BE collector also only processes tablets with an initialized ID and 
explicitly sets the request field. For a replica whose `getCooldownMetaId()` is 
null, `info.cooldown_meta_id.equals(null)` is false, so the existing negated 
condition returns without confirming deletion. The suggested explicit 
replica-null test may improve readability, but it does not change the decision. 
See 
[`confirmUnusedRemoteFiles`](https://github.com/apache/doris/blob/b9c561a03849a78d3cb41294cce8c0ae610257a0/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java#L401-L483).
   
   3. **The deletion path is fail-closed for the state described in the issue.**
   
      The current cooldown replica collects its live remote rowset IDs and its 
`cooldown_meta_id` under the tablet header lock. FE confirms only when the 
configured cooldown replica matches, there are enough live replicas, every 
replica reports the current cooldown term, and every reported meta ID equals 
the request ID. Any missing or different ID blocks deletion. See 
[`collect_tablet_unused_remote_files`](https://github.com/apache/doris/blob/b9c561a03849a78d3cb41294cce8c0ae610257a0/be/src/storage/olap_server.cpp#L1320-L1364).
   
      Consequently, differing `CooldownMetaId` values are a 
synchronization-in-progress signal that prevents reclamation, not evidence that 
deletion has been approved. An empty ID is also not sufficient evidence of loss 
(for example, a tablet may not yet have cooled data), and it prevents 
confirmation rather than permitting it.
   
   ### Missing evidence needed to validate a real bug
   
   The reproduction section is currently an outline, not an executed 
reproducer. The decisive proof would be a non-cooldown full clone producing 
**two replicas with the same non-null `cooldown_meta_id` but different remote 
`rowset_id_v2` lists**. Please provide:
   
   - Exact Doris commit/version, table and storage-policy DDL, replica count, 
and the exact command/fault used to force a **full** clone.
   - Tablet ID plus the clone source replica, destination replica, current 
cooldown replica, and cooldown term.
   - A timeline before clone, immediately after clone, after tablet report, at 
FE confirmation, and after deletion. At each point include every replica's 
`CooldownReplicaId`, `CooldownTerm`, `CooldownMetaId`, and remote rowset IDs.
   - BE logs covering `begin to finish full clone`, cooldown-meta write/follow 
activity, `begin to confirm unused remote files`, and every `delete unused 
file` line; FE logs covering the corresponding tablet report and 
`confirmUnusedRemoteFiles` decision.
   - The current term's remote `.meta` decoded to its 
`rs_metas[*].rowset_id_v2`, an object listing or object-store audit event 
proving the exact delete, and the subsequent query's full `[NOT_FOUND]` error.
   - If this came from an incident, the relevant tablet headers/metas before 
any repair or restart. Bucket version history is especially useful to 
distinguish Doris deletion from lifecycle rules or an external deleter.
   
   ### Recommended next steps
   
   1. Keep this as **needs reproduction / needs information**, not confirmed 
data loss. Apply the repository's applicable triage label; none is currently 
present.
   2. Add a focused BE test that full-clones both (a) a non-cooldown 
destination and (b) the current cooldown destination, asserting the 
`(cooldown_meta_id, remote rowset-ID list)` invariant in each case.
   3. Add an FE unit test for unset request IDs and null replica IDs to 
document that both paths reject confirmation.
   4. If a deterministic reproducer demonstrates the required 
same-ID/different-rowset state, investigate the first operation that broke that 
invariant; changing clone ID generation alone should not be assumed to be the 
correct fix.
   5. For an active incident only, preserve object versions/audit logs and 
pause or substantially delay remote-file reclamation while collecting evidence. 
The broad topology freeze proposed in the issue is not justified as a general 
mitigation until the causal chain is reproduced.
   
   No code changes were made during this assessment.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to