Siyao Meng created HDDS-16145:
---------------------------------

             Summary: Checkpoint flush during delete transaction removal can 
double count the SCM deleted block summary
                 Key: HDDS-16145
                 URL: https://issues.apache.org/jira/browse/HDDS-16145
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng


A checkpoint or leader-transfer flush that interposes in the middle of 
{{DeletedBlockLogStateManagerImpl.removeTransactionsFromDB}} can re-expose a 
delete-transaction row that is still durable, causing the block-deletion 
scanner to select it again and decrement the volatile summary a second time, to 
a permanent and impossible negative value.

h3. Steps to reproduce

# The block-deletion scanner drives terminal cleanup, which calls 
{{removeTransactionsFromDB(txIDs, summary)}}. That method first marks the ids 
in {{deletingTxIDs}} (the scanner-hide set), then removes each row from the 
transaction buffer, then buffers the updated summary, as separate steps.
# A checkpoint download ({{InterSCMGrpcService}}) or leader-transfer flush runs 
{{transactionBuffer.flush()}} between the mark and the buffered removal. 
{{onFlush}} then resets {{deletingTxIDs}} to a fresh empty set, clearing the 
hide marker while the row is still durable (its {{removeFromBuffer}} had not 
been flushed).
# The next scan no longer sees the row as hidden, re-selects it, and terminal 
cleanup decrements the summary again for the same transaction.

The summary is driven to a negative value (for a single transaction it reaches 
-1), which is persisted durably and reloaded verbatim on restart and leader 
transfer.

h3. Root cause

{{removeTransactionsFromDB}} performs the hide marking 
({{deletingTxIDs.addAll}}), the row removal ({{removeFromBuffer}}), and the 
summary update as separate, non-atomic steps. 
{{SCMHADBTransactionBufferImpl.flush()}} takes only the write lock and does not 
consult the in-progress apply/removal state, and {{onFlush}} resets 
{{deletingTxIDs}}. A flush interposed mid-removal therefore clears the hide 
marker for a row that is still durable, so the scanner re-selects it and 
double-decrements the summary. A negative deleted-block count is an impossible 
undercount.

h3. Impact

The deleted-block transaction summary is observability only. It is surfaced by 
the SCM client protocol {{getDeletedBlockSummary}}, {{ozone admin scm}}, Recon 
{{PendingDeletionEndpoint}}, and JMX metrics, and does not affect deletion 
correctness. The consequence is a persistent, operator visible accounting 
corruption (a negative pending-deletion count) that survives restart and leader 
transfer. There is no data loss and no premature deletion.

h3. Relation to HDDS-15665

HDDS-15665 stabilizes an already-open deleted-block iterator against concurrent 
modification, but does not make {{removeTransactionsFromDB}} atomic with 
respect to {{flush()}}, nor does it protect a new iterator opened after a 
mid-removal flush clears the hide marker. No filed issue reports this 
checkpoint-flush re-exposure and summary double decrement.

h3. Suggested fix

Make the hide marking, row removal, and summary update in 
{{removeTransactionsFromDB}} atomic with respect to flush, or have 
{{flush()}}/{{onFlush}} preserve the {{deletingTxIDs}} hide markers for rows 
whose removal has not yet been flushed, so a flush cannot re-expose a 
still-durable row that is being removed. Recomputing the summary from the 
durable rows on reload would also prevent a negative value from being persisted.



--
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