[ 
https://issues.apache.org/jira/browse/HDDS-16896?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Siyao Meng updated HDDS-16896:
------------------------------
    Attachment: TestBugMC2BootstrappedScmSafeMode.java

> Bootstrapped SCM builds its container safe mode rules from its empty DB and 
> leaves safe mode before datanodes report its containers
> -----------------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HDDS-16896
>                 URL: https://issues.apache.org/jira/browse/HDDS-16896
>             Project: Apache Ozone
>          Issue Type: Bug
>            Reporter: Siyao Meng
>            Priority: Major
>         Attachments: 
> MC-2-reload-container-safemode-rules-after-catch-up.patch, 
> TestBugMC2BootstrappedScmSafeMode.java
>
>
> h3. Mechanism
> {{RatisContainerSafeModeRule}} and {{ECContainerSafeModeRule}} read the 
> CLOSED and QUASI_CLOSED containers with keys from the container DB once, in 
> the SCM constructor ({{AbstractContainerSafeModeRule.initializeRule}}). That 
> is before {{StorageContainerManager.start}} replays the Ratis log or installs 
> a snapshot. Afterwards the periodic refresh ({{reinitializeRule}}) only 
> removes DELETED containers, by design since HDDS-15238, and 
> {{SCMSafeModeManager.refreshAndValidate}} does nothing when the periodic 
> refresh is enabled (the default).
> On a newly bootstrapped SCM the DB is still empty when the rules are built, 
> so both rules see 0 of 0 containers and {{getCurrentContainerThreshold}} 
> returns 1. Both are marked validated on the next safe mode refresh (every 
> 5s), usually before the state machine has caught up. Nothing reloads them, so 
> even when catch-up is faster, they are validated at 0 of 0. A validated rule 
> is never revalidated, so as soon as the datanode, pipeline and state machine 
> rules pass, the SCM leaves safe mode, however few of the containers in the 
> installed snapshot the datanodes have reported.
> h3. Trigger
> # An HA cluster with CLOSED containers that have keys.
> # A new SCM is bootstrapped and catches up from the leader (in every run, by 
> installing a checkpoint of the leader DB, with the default Ratis settings).
> # Only some datanodes report to the new SCM, as during a rolling update of 
> {{ozone.scm.nodes}} on the datanodes, or when datanodes register unevenly.
> # The new SCM leaves safe mode once the minimum number of datanodes and the 
> pipeline rules are satisfied.
> h3. Impact
> * The new SCM leaves safe mode with only part of its closed containers 
> reported. In the reproduction this was 6 of 10 containers, with a cutoff of 
> 99%.
> * If it becomes leader before the remaining datanodes report to it 
> (leadership transfer, or failover during the rollout), ReplicationManager 
> runs on that partial view after {{hdds.scm.wait.time.after.safemode.exit}} (5 
> minutes by default, 3 seconds in the mini cluster). In the reproduction it 
> classified the 4 unreported single replica containers as MISSING. MISSING is 
> only a classification: no command is sent for it.
> * Containers with at least one reported replica are handled as on any SCM 
> that leaves safe mode before all datanodes have reported. What this defect 
> adds is that containers with no reported replica no longer keep the SCM in 
> safe mode, so the container check of safe mode does nothing on a bootstrapped 
> SCM. I found no path to data loss.
> * The effect ends when the remaining datanodes register with the new SCM.
> h3. Reproduction
> PASS on the unmodified source. [^TestBugMC2BootstrappedScmSafeMode.java] 
> ({{hadoop-ozone/integration-test}}) runs a mini cluster with 3 SCMs, 1 OM and 
> 5 datanodes, and uses the client, {{closeContainer}}, {{bootstrapSCM}}, 
> {{transferLeadership}} and the datanode reconfiguration handler, as an 
> operator adding an SCM would. It writes RATIS/ONE keys, closes their 
> containers, bootstraps a fourth SCM with the default Ratis settings and 
> points only the three datanodes of one RATIS/THREE pipeline at it. Before any 
> datanode registers, the new SCM reports {{RatisContainerSafeModeRule 
> validate=true: ... Containers(0 / 0)}} although it holds 10 closed containers 
> with keys. After the three datanodes register, it leaves safe mode within 
> about 1s with 6 of 10 containers reported. After leadership is transferred to 
> it, ReplicationManager runs and reports MISSING=4. A passing test means the 
> defect is present.
> With the patch the same test fails at its first assertion. The new SCM logs 
> "Initialized RATIS Containers threshold count to 10" once it has caught up, 
> stays in safe mode at {{Containers(6 / 10)}}, and ReplicationManager does not 
> run after the leadership transfer.
> Not run: the restart variant (a restarted SCM whose replayed log closes 
> containers). Containers closed while that SCM was down are replayed with the 
> key count it had persisted, which is usually 0 for a container that was open 
> when it stopped, so the rule mostly skips them anyway.
> h3. Suggested fix
> Rebuilding the rules after every snapshot install is not safe. After the 
> datanode server has started, a rebuild would refill the list from the DB 
> without resetting the reported count. Containers that registered datanodes 
> have already reported would be back in the list and could be counted a second 
> time. Containers closed since registration would raise the total, but 
> datanodes report containers to these rules only when they register, so SCM 
> could stay in safe mode indefinitely (the concern behind HDDS-15238). 
> Clearing an already validated rule from {{validatedRules}} at readiness would 
> race with the refresh thread. The patch instead keeps the rules from 
> validating until the data they count is current.
> h3. Patch
> [^MC-2-reload-container-safemode-rules-after-catch-up.patch], against 
> b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at 
> 6818707698c.
> When the SCM has a Ratis state machine, {{SafeModeRuleFactory}} passes it to 
> the two container rules. Until the state machine is ready, 
> {{AbstractContainerSafeModeRule.validate}} returns false. On its first call 
> after that, it reads the containers again with {{initializeRule}}. Datanode 
> reports only reach the rules after the state machine is ready, because the 
> datanode server is started in 
> {{SCMStateMachine.tryStartDNServerAndRefreshSafeMode}}, and each report goes 
> through {{validate}} before it is processed. So the reload always runs before 
> any container is counted, and no report is lost. Rules without a state 
> machine ({{SCMHAManagerStub}}, unit tests) behave as before. An SCM whose DB 
> is still empty after catch-up still validates the rules at once.
> The fix relies on the datanode server starting only after the state machine 
> is ready, which came with HDDS-14989 (2.3.0). Released versions (2.2.0 and 
> 2.2.1) build the rules the same way and start the datanode server in 
> {{StorageContainerManager.start}} unconditionally, so they are also affected 
> (argued from the code, not run). They need HDDS-14989 together with this fix: 
> without it, reports processed before readiness stay counted, because 
> {{initializeRule}} does not reset the reported count or the EC replica map, 
> so the reload could over count.
> Covered by {{testContainerRulesCountContainersLoadedBeforeStateMachineReady}} 
> in the existing {{TestSCMSafeModeManager}}. The rules are built from an empty 
> DB, 10 closed containers are then added and the state machine becomes ready, 
> and a datanode reports half of them. Without the change SCM leaves safe mode 
> at that point. With it, SCM stays in safe mode until the remaining containers 
> are reported, and with 0 containers it leaves safe mode on the first 
> registration as before. With the patch, the safe mode unit suites (76 tests) 
> and the mini cluster suites {{TestSCMFollowerCatchupWithContainerReport}}, 
> {{TestDatanodeSCMNodesReconfiguration}}, {{TestSafeModeCheckSubcommandHA}}, 
> {{TestSCMInstallSnapshot}}, {{TestStorageContainerManagerHA}}, 
> {{TestSCMSnapshot}} and {{TestFailoverWithSCMHA}} pass, and checkstyle is 
> clean.
> Not changed: the same cause makes {{OneReplicaPipelineSafeModeRule}} pass 
> with a threshold of 0 on a bootstrapped SCM. It is built from the empty 
> pipeline DB, validated on the first refresh, and its refresh only rebuilds it 
> while it is not validated, so the threshold is never corrected. What is lost 
> is the check that 90% of the open RATIS/THREE pipelines have a reported 
> datanode before exit. Its effect is limited, because 
> {{HealthyPipelineSafeModeRule}} is rebuilt on every refresh until it passes 
> and still waits for at least one healthy pipeline (with the default 
> {{hdds.scm.safemode.min.datanode}} of 3). It is left for a follow up.
> Found by TLA+ model checking and code review of the SCM safe mode rules under 
> HDDS-15926, on commit b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. Checked 
> against HDDS issues and apache/ozone pull requests for duplicates before 
> filing. 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