Siyao Meng created HDDS-17050:
---------------------------------

             Summary: Recon task cursor advances past a batch that failed both 
attempts, so a restart soon after the failure can lose that batch
                 Key: HDDS-17050
                 URL: https://issues.apache.org/jira/browse/HDDS-17050
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: MC-7-skip-batches-behind-failed-batch-until-reinit.patch, 
TestBugMC7FailedBatchLostAcrossRestart.java

h3. Mechanism
When a delta batch fails both attempts in 
{{ReconTaskControllerImpl.processOMUpdateBatch}}, the controller only sets the 
in memory {{tasksFailed}} flag; the next sync iteration turns it into a 
reinitialization. Batches that are already in the event buffer behind the 
failed one are still processed, and for each task that succeeds 
{{processTasks}} saves {{lastUpdatedSeqNumber}} to the task status table. The 
cursor of the failed task therefore reaches the cursor of {{OmDeltaRequest}}. 
If Recon restarts before the reinitialization has finished and before the sync 
has fetched any new OM update, the flag and the queued reinitialization are 
gone, and the startup check in {{OzoneManagerServiceProviderImpl.start}}, which 
rebuilds only tasks whose cursor is below that of {{OmDeltaRequest}}, finds 
nothing to do. The failed batch is never applied.

The same happens when a manual rebuild drains a buffered batch and the 
rebuild's reprocess step then fails, because that failure also only sets 
{{tasksFailed}} (code reading, not run). A rebuild that fails in its DB swap 
sets no flag at all, because {{reInitializeTasks}} still reports success; 
HDDS-17047 makes it report the failure.

h3. Trigger
# The sync buffers two batches before the event thread gets to the first, as 
when it fetches several deltas in one run.
# A task fails the first batch on both attempts and succeeds on the second 
batch. The failure has to be tied to the first batch; a Recon RocksDB I/O error 
closes the DB, so the second batch would fail too. One such failure is 
HDDS-17048: {{NSSummaryTask}} fails with a NullPointerException, on both 
attempts, on a key event whose bucket was deleted later in the same delta, 
while a later batch about other buckets succeeds (code reading).
# Recon restarts after the event thread has processed the buffered batches and 
before the sync fetches any new OM update. A non empty fetch after the failure 
moves the {{OmDeltaRequest}} cursor past the task cursors, because the batch is 
refused or drained, and the startup check then rebuilds. On a cluster with 
ongoing writes this leaves about one sync interval (5s by default). Without new 
writes, it lasts until the queued reinitialization has completed.

h3. Impact
The changes of the failed batch are missing from that task's derived data for 
good: for NSSummary the namespace summary and du APIs report too few files and 
bytes. Later syncs and restarts do not notice it; a manual rebuild repairs it. 
Without a restart the reinitialization repairs it as designed.

h3. Reproduction
PASS, deterministic, unmodified source. 
[^TestBugMC7FailedBatchLostAcrossRestart.java] ({{hadoop-ozone/recon}}) uses a 
real OM RocksDB that serves its write ahead log through a mocked 
{{getDBUpdates}}, and the real {{OzoneManagerServiceProviderImpl}}, 
{{ReconTaskControllerImpl}}, {{NSSummaryTask}} and task status table. 
{{NSSummaryTask.process}} returns a failed result for one batch on both 
attempts, and its first attempt is held until the next batch is buffered. The 
restart stops the provider and controller and starts new ones on the same 
databases. Output before the restart: {{tasksFailed}} true, NSSummaryTask 
cursor 5, OmDeltaRequest cursor 5, OM has 3 files under the bucket and 
NSSummary 2. After the restart and a sync NSSummary still reports 2; a rebuild 
gives 3. A passing test means the defect is present.

h3. Patch
[^MC-7-skip-batches-behind-failed-batch-until-reinit.patch], against 
0665932dd35da4d05087e02748af0a64eb846ad5. It also applies to master at 
2264d4d48ac.

{{processOMUpdateBatch}} does not run the tasks while {{tasksFailed}} is set. 
In that state {{consumeOMEvents}} already refuses new batches, and queueing the 
reinitialization drains the buffer, clears the flag and takes the checkpoint 
the rebuild uses, which contains every batch applied to the Recon OM DB, so the 
skipped batches would be discarded by it anyway. Not processing them keeps the 
failed task's cursor behind, and the existing startup check rebuilds after a 
restart. Without a restart nothing changes, except that until the 
reinitialization is queued (normally the next sync iteration) the tasks that 
did not fail also stop applying buffered batches, which the reinitialization 
rebuilds.

Covered by {{testBatchesBehindFailedBatchDoNotAdvanceTaskCursor}} in the 
existing {{TestReconTaskControllerImpl}}, which fails without the change 
({{expected: 0L but was: 200L}}). With the change the Recon tasks suites and 
{{TestOzoneManagerServiceProviderImpl}} (155 tests) pass and checkstyle is 
clean. With the patch the reproduction fails at its undercount assertion: the 
NSSummaryTask cursor stays at 3, the restart rebuilds the tasks and NSSummary 
reports 3.

A related case, a task whose {{process}} throws instead of returning a failed 
result and so never sets {{tasksFailed}}, is HDDS-17040.

Found by TLA+ model checking and code review of the Recon namespace summary and 
task sync paths under HDDS-15926, on commit 
0665932dd35da4d05087e02748af0a64eb846ad5. Checked against HDDS issues and 
apache/ozone pull requests for duplicates before filing. Related but not 
duplicates: HDDS-5146 (a failure between the Recon OM DB update and the task 
hand off loses the batch) and HDDS-16463 (sync the Recon DB before the cursor 
advances). The attached patch is a proposal for review. Generated with Specula 
(Claude Opus 5.5).



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

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

Reply via email to