[
https://issues.apache.org/jira/browse/HDDS-17220?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Siyao Meng updated HDDS-17220:
------------------------------
Attachment: TestBugCR2QueuedRecommissionDropsAdminRequest.java
> Decommission or maintenance requested while a recommission is still queued is
> acknowledged and then lost, and the datanode returns to IN_SERVICE
> ------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: HDDS-17220
> URL: https://issues.apache.org/jira/browse/HDDS-17220
> Project: Apache Ozone
> Issue Type: Bug
> Reporter: Siyao Meng
> Priority: Major
> Attachments:
> CR-2-withdraw-queued-recommission-on-new-admin-request.patch,
> TestBugCR2QueuedRecommissionDropsAdminRequest.java
>
>
> h3. Mechanism
> {{NodeDecommissionManager.recommission}} does not change the op state of the
> node. It calls {{DatanodeAdminMonitorImpl.stopMonitoring}}, which queues the
> node in {{cancelledNodes}}, and the next monitor run
> ({{processCancelledNodes}}, every
> {{ozone.scm.datanode.admin.monitor.interval}}, default 30s) puts the node
> back to IN_SERVICE and stops tracking it.
> Until that run the node is still DECOMMISSIONING, DECOMMISSIONED,
> ENTERING_MAINTENANCE or IN_MAINTENANCE. {{startDecommission}} and
> {{startMaintenance}} look only at the op state, so a new request for the same
> kind of state takes the "Nothing to do" branch: no error is returned and
> {{monitor.startMonitoring}}, which removes a queued cancel, is not called.
> The queued recommission then wins.
> h3. Trigger
> # {{ozone admin datanode decommission <dn>}} (or {{maintenance}}), and the
> monitor runs.
> # {{ozone admin datanode recommission <dn>}}.
> # Within the same monitor interval, {{ozone admin datanode decommission
> <dn>}} again (with or without {{--force}}), or {{maintenance}}.
> # The next monitor run puts the node IN_SERVICE and stops tracking it.
> The same happens for a DECOMMISSIONED node and when the recommission is
> queued before the monitor has picked up the node. A recommission followed by
> a request of the other kind (for example maintenance, recommission,
> decommission) is not lost silently: it is rejected with "Cannot decommission
> node ... in state ENTERING_MAINTENANCE", and the node returns to IN_SERVICE.
> h3. Impact
> * The request returns an empty error list, so the CLI reports success, but
> the node ends IN_SERVICE and untracked. No later monitor run, heartbeat or
> leader change brings it back, because it is now IN_SERVICE.
> * An operator who then stops the node believing it is in maintenance gets a
> normal dead node, and SCM re-replicates its containers (argued from code, not
> run). No data is at risk.
> h3. Reproduction
> PASS on the unmodified source, deterministic.
> [^TestBugCR2QueuedRecommissionDropsAdminRequest.java]
> ({{hadoop-hdds/server-scm}}) uses the setup of
> {{TestNodeDecommissionManager}}: a real {{SCMNodeManager}} with registered
> datanodes and a real {{NodeDecommissionManager}} (with a mocked
> {{ReplicationManager}}, so it also runs on master), called through the
> {{decommissionNodes}}, {{startMaintenanceNodes}} and {{recommissionNodes}}
> methods that {{SCMClientProtocolServer}} calls. The scheduled monitor is set
> to 1h and the monitor is run by hand in place of the 30s interval. Output on
> the pin:
> {noformat}
> monitor run after decommission: state=DECOMMISSIONING tracked=true
> recommission (queued): state=DECOMMISSIONING tracked=true
> decommission again, errors=0: state=DECOMMISSIONING tracked=true
> monitor run after the new request: state=IN_SERVICE tracked=false
> monitor run after maintenance: state=ENTERING_MAINTENANCE tracked=true
> recommission (queued): state=ENTERING_MAINTENANCE tracked=true
> maintenance again, errors=0: state=ENTERING_MAINTENANCE tracked=true
> monitor run after the new request: state=IN_SERVICE tracked=false
> {noformat}
> A control with a monitor run between the recommission and the new request
> ends ENTERING_MAINTENANCE and tracked. A passing test means the defect is
> present. With the patch the two defect tests fail, because the node stays
> DECOMMISSIONING or ENTERING_MAINTENANCE and tracked, and the control passes.
> Not run on a cluster with real datanodes.
> h3. Patch
> [^CR-2-withdraw-queued-recommission-on-new-admin-request.patch], against
> b0aa6475b7856d2c7f467dd3db12b9a1dd116f63. It also applies to master at
> 20d95ed37fe.
> {{DatanodeAdminMonitor}} gets {{withdrawStopMonitoring}}, which removes every
> recommission queued for the node under the monitor lock and reports whether
> there was one. More than one can be queued, because the host list of a
> command is not deduplicated and because two commands can arrive in one
> monitor interval. {{startDecommission}} and {{startMaintenance}} call it
> before they read the node status. If a recommission was withdrawn and the
> node is already in the requested kind of admin state, the node keeps its
> state, which is not written, and {{startMonitoring}} is called again unless
> the node is DECOMMISSIONED (that node is not tracked, and keeping it
> DECOMMISSIONED is enough). Keeping the state also keeps a stopped
> IN_MAINTENANCE node in maintenance. A request of the other kind is still
> rejected, and the recommission is queued again, so its outcome does not
> change. Requests without a queued recommission are unchanged.
> Op state and the monitor queues live in the leader SCM's memory and are not
> in the Ratis log, so a failover while the recommission is queued loses the
> recommission, before and after this patch.
> Covered by {{testAdminRequestReplacesQueuedRecommission}} in the existing
> {{TestNodeDecommissionManager}}: decommissioning, entering maintenance and
> dead IN_MAINTENANCE nodes keep their state and stay tracked, a node whose
> recommission was queued before the monitor picked it up is tracked again, a
> DECOMMISSIONED node stays DECOMMISSIONED and untracked whether its
> recommission was queued once or twice, and a decommission of a node in
> maintenance is rejected and the node returns to IN_SERVICE. Without the
> change it fails with {{expected: <DECOMMISSIONING> but was: <IN_SERVICE>}}.
> With it {{TestNodeDecommissionManager}}, {{TestDatanodeAdminMonitor}},
> {{TestNodeDecommissionMetrics}} and {{TestSCMNodeManager}} (113 tests) pass,
> {{TestDecommissionAndMaintenance}} (9 tests, mini cluster) passes with this
> patch alone, and checkstyle is clean.
> Found by code review of the SCM datanode decommission and maintenance admin
> paths, 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. The attached patch
> is a proposal for review. Generated with Specula (Claude Opus 5.5 and Claude
> Opus 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]