Siyao Meng created HDDS-16904:
---------------------------------

             Summary: HealthyPipelineSafeModeRule keeps pipelines closed during 
safe mode in its threshold, so a running SCM can stay in safe mode
                 Key: HDDS-16904
                 URL: https://issues.apache.org/jira/browse/HDDS-16904
             Project: Apache Ozone
          Issue Type: Bug
            Reporter: Siyao Meng
         Attachments: 
CR-4-drop-closed-pipelines-from-healthy-pipeline-threshold.patch, 
TestBugCR4ClosedPipelinesKeepSafeModeThreshold.java

h3. Mechanism
{{HealthyPipelineSafeModeRule.initializeRule}} runs at startup and on every 
refresh while the rule is unmet. It adds the IDs of the OPEN RATIS/THREE 
pipelines to {{unProcessedPipelineSet}} and sets the threshold to 
{{max(minHealthyPipelines, ceil(pct * set size))}}. IDs leave the set only when 
the pipeline is counted as healthy, or in {{cleanup()}} after the rule has 
passed. A pipeline that was OPEN when SCM started and is closed during safe 
mode, before it was reported healthy, therefore stays in the threshold until 
the rule passes or SCM restarts. The same holds for a pipeline added by an 
earlier refresh, and in HA for a pipeline loaded from the DB as OPEN that the 
Ratis log replay then closes (argued from the code). A closed pipeline cannot 
become healthy, so the threshold can stay above what the remaining OPEN 
pipelines can reach.

HDDS-5263 (1.2.0) added this refresh so that the pipeline thresholds follow the 
pipelines that are OPEN now, for example after the Ratis log replay closes 
pipelines that the DB still listed as OPEN. HDDS-9478 (2.0.0) introduced the 
set to show sample pipelines in the status output, and the set undid that for 
this rule. {{OneReplicaPipelineSafeModeRule}} and the report free path of the 
same rule still compute the threshold from the current number of OPEN pipelines.

h3. Trigger
* Either {{hdds.scm.safemode.pipeline.creation=false}}, or fewer than three 
healthy datanodes left, so that the background pipeline creator cannot build a 
RATIS/THREE pipeline (for example a three datanode cluster with 
{{hdds.scm.safemode.min.datanode}} of 1 or 2 and one datanode down; Ozone's 
docker compose clusters default to 1). Otherwise the creator builds new 
pipelines on the surviving datanodes during safe mode (closed pipelines do not 
count against the datanode pipeline limit), which rescues the rule (argued, not 
run).
* RATIS/THREE pipelines that are still OPEN when SCM starts, and whose members 
are then partly down. The surviving members ask SCM to close them (pipeline 
action) after their Ratis timeouts, which is after the one shot pipeline 
creation run at the end of the precheck. That run created nothing, because 
fewer than three healthy datanodes were left or the datanodes were at their 
pipeline limit.
* Either no pipeline survives and {{hdds.scm.safemode.min.datanode}} is 2 or 
less (with the default of 3 the rule requires one healthy pipeline anyway), or 
fewer than 10% of the pipelines that were OPEN at startup survive and at least 
one does. The three datanode cluster above is an example of the first case. 
With {{hdds.scm.safemode.pipeline.creation=false}}, so is losing one of two 
racks with rack aware placement: every pipeline loses a member, and every 
container keeps a replica, so the container rules pass.

h3. Impact
SCM stays in safe mode while every other rule passes, and a fresh SCM on the 
same state (a restart) would leave it. Block allocation is refused, and 
{{ReplicationManager}} does not start, so the containers left under-replicated 
by the lost datanodes are not repaired (argued from the code, not run). It ends 
with a restart, with the lost datanodes returning or a new datanode registering 
(both trigger a one shot pipeline creation run), or with {{ozone admin safemode 
exit}}. No data is lost. Present since 2.0.0 (HDDS-9478).

h3. Reproduction
[^TestBugCR4ClosedPipelinesKeepSafeModeThreshold.java] 
({{hadoop-hdds/server-scm}}) uses the real {{PipelineManagerImpl}} with its 
background pipeline creator, {{PipelineReportHandler}}, 
{{PipelineActionHandler}} and {{SCMSafeModeManager}} with all its rules. Three 
datanodes hold two OPEN RATIS/THREE pipelines, which fills their pipeline 
limit, with one closed container with keys per pipeline. One datanode is down 
at startup. The other two register with their replicas, so the container rules 
pass, and the one shot creation run after the precheck creates nothing. Then 
they send close actions for both pipelines, and the rules are refreshed. 
Configuration: {{hdds.scm.safemode.min.datanode=1}}, with 
{{hdds.scm.safemode.pipeline.creation}} left at its default and the SCM leader 
ready, so the creator runs in safe mode. Output on unmodified source: 0 OPEN 
pipelines, a new RATIS/THREE pipeline cannot be created, threshold 1, 
{{HealthyPipelineSafeModeRule}} the only rule not met, SCM in safe mode. A new 
safe mode manager on the same state computes threshold 0 and leaves safe mode. 
The test passes on unmodified source, which means the defect is present. With 
the patch, the refresh lowers the threshold to 0 and SCM leaves safe mode, so 
the test fails.

h3. Patch
[^CR-4-drop-closed-pipelines-from-healthy-pipeline-threshold.patch], against 
b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at 
a5aeb764d80. It and the patch on HDDS-16903 add the same two imports to 
{{TestHealthyPipelineSafeModeRule}}, so whichever lands second needs a trivial 
rebase.

{{initializeRule}} clears {{unProcessedPipelineSet}} before adding the 
pipelines that are OPEN now, so the threshold is again based on the current 
OPEN RATIS/THREE count, as it was from HDDS-5263 until HDDS-9478, and the 
refresh thread lowers it on the running SCM. If no pipeline closes or is 
deactivated during safe mode, the threshold is the same as before: the old set 
already re-added the counted OPEN pipelines on every refresh.

Covered by {{testClosedPipelinesAreDroppedFromThresholdOnRefresh}} in the 
existing {{TestHealthyPipelineSafeModeRule}}, with default thresholds: 11 OPEN 
pipelines (threshold 2), 10 closed before they are reported, then 
{{SCMSafeModeManager.refreshAndValidate}}. The rule must then require 1, and 
pass on the remaining healthy pipeline. Without the change it fails 
({{expected: 1 but was: 2}}). With it, the 
{{org.apache.hadoop.hdds.scm.safemode}} unit tests together with 
{{TestPipelineManagerImpl}} and {{TestPipelineActionHandler}} (108 tests) pass, 
as do {{TestSCMSafeModeWithPipelineRules}} and 
{{TestSafeModeCheckSubcommandHA}} on a mini cluster (8 tests), and checkstyle 
is clean.

Found by code review of the SCM safe mode rules, as part of the TLA+ 
verification effort under HDDS-15926, on commit 
b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. Checked against HDDS issues and 
apache/ozone pull requests for duplicates before filing. Related but not 
duplicates: HDDS-16903 (the same rule counts DORMANT and CLOSED pipelines, a 
separate defect in {{process}}), HDDS-9478 (introduced the set), HDDS-5263 
(added the refresh so that pipeline thresholds follow the current OPEN 
pipelines, for example after Ratis log replay; HDDS-9478 undid that for this 
rule) and HDDS-11844 (open, proposes not waiting for all pipelines). 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