yandrey321 opened a new pull request, #11353:
URL: https://github.com/apache/ozone/pull/11353
## What changes were proposed in this pull request?
`SCMNodeManager.register()` handles the re-registration of an already known
datanode in three
branches, but only one of them keeps the network topology in step with the
node state:
| re-registration | `clusterMap.update` | `nodeStateManager.updateNode` |
| --------------- | ------------------- | ----------------------------- |
| ip or hostname changed | yes | yes |
| version changed | **no** | yes |
| port set changed | **no** | yes |
The order in the first branch is load-bearing. `NetworkTopologyImpl.update`
ends in
`clusterTree.add(newNode)`, which sets the parent on the new node object, and
`NodeStateManager.updateNode` then builds the stored `DatanodeInfo` from
that same object, whose copy
constructor carries the parent across. A branch that updates the node state
alone therefore leaves
three problems behind:
1. The topology keeps the stale record, with the old port set and the old
version. Anything that reads
a datanode back out of the topology — placement, topology-aware read
ordering — sees the ports the
datanode no longer exposes.
2. The freshly stored `DatanodeInfo` has no parent, so
`NetworkTopologyImpl.containsNode` walks to
`null` and `clusterMap.contains(nodeManager.getNode(id))` returns false
for a node that is,
as far as SCM is concerned, registered and healthy.
3. A datanode that `DeadNodeHandler` had already removed from the topology
never re-enters it. This
one does not heal. `NodeStateManager.updateNode` recomputes the status
straight to `HEALTHY` and
`nodeStateMap.updateNode` publishes no state-change event, so the DEAD ->
HEALTHY_READONLY
transition that `HealthyReadOnlyNodeHandler` re-adds the node on never
happens. A datanode that
restarts with a new version or a new port set after being marked dead
stays absent from the
topology for the lifetime of the SCM.
Both missing branches are reachable in normal operation: the version branch
on any datanode upgrade,
and the port branch whenever a datanode restarts with a different port set,
for example when Ratis
DataStream is enabled and `RATIS_DATASTREAM` appears.
### Approach
The body of the first branch already does the right thing in the right
order, so this patch extracts
it into a private `updateNodeAndTopology(oldNode, datanodeDetails,
layoutInfo)` and calls it from all
three branches, rather than duplicating `clusterMap.update` plus the parent
assertion twice more. The
helper's javadoc records why the topology has to be updated before the node
state, so the ordering is
not silently reversed later.
Re-entry into the topology needs no special case. When `oldNode` is absent
from the tree,
`containsNode(oldNode)` is false, `NetworkTopologyImpl.update` skips the
removal, and
`clusterTree.add(newNode)` inserts the node again.
Couple things to consider:
* A DEAD datanode that re-registers with nothing at all changed still fires
no branch, so this patch
does not add it back to the topology on registration. That case does heal
on its own: the next
heartbeat drives DEAD -> HEALTHY_READONLY and `HealthyReadOnlyNodeHandler`
re-adds the node.
Forcing a topology write on every no-op re-registration would be wider
than the bug.
* `NetworkTopologyImpl.update` throws `InvalidTopologyException` (a
`RuntimeException`) on a
network-location depth mismatch, and `register` only catches
`NodeNotFoundException`. The version
and port branches now inherit that exposure from the ip/hostname branch.
It appears unreachable,
because `clusterMap.add` on the initial-registration path applies the same
depth check, so a node
with a mismatched depth could not have registered in the first place.
Generated-by: Claude Code (Claude Opus 5)
## What is the link to the Apache JIRA
https://issues.apache.org/jira/browse/HDDS-16630
## How was this patch tested?
Unit tests in `TestSCMNodeManager`, extending the existing suite.
`portsChanged` had no
`SCMNodeManager`-level coverage before this patch; it was only unit-tested
in `TestDatanodeDetails`.
* `testRegisterRefreshesPortsOnPortChange` (added in HDDS-15799) gains
topology assertions: the leaf
count, `clusterMap.contains(stored)`, and that the object held *in* the
topology exposes the new
`RATIS_DATASTREAM` port rather than being the stale one.
* `testRegisterUpdatesTopologyOnVersionChange` is new. It covers a
version-only re-registration, then
removes the node from the topology the way `DeadNodeHandler` does for a
dead node and asserts that
re-registration puts it back.
Results:
* `TestSCMNodeManager` 51/51 and `TestDeadNodeHandler` 4/4 — 55 tests, 0
failures.
* Negative control: with only the version and port branches reverted to the
previous
`nodeStateManager.updateNode` call, both tests fail with
`refreshed node should still be in the network topology ==> expected:
<true> but was: <false>`.
Line coverage alone would not have caught this regression, since the old
call sites were covered
too, so the assertions were verified to actually bite.
* JaCoCo on the new code: `updateNodeAndTopology` is `LINE 5/5`,
`INSTRUCTION 23/24`, `BRANCH 1/2`,
and all three call sites are executed. The single uncovered instruction
and branch is the throwing
side of `Preconditions.checkState(dn.getParent() != null)`, an invariant
assertion that is
unreachable unless `NetworkTopology.update` returns without parenting the
node. The ip/hostname
branch this was lifted from has the same uncovered throw.
* `mvn clean install -DskipTests -DskipShade -DskipRecon -DskipDocs` — BUILD
SUCCESS.
* `./hadoop-ozone/dev-support/checks/checkstyle.sh` — 0 violations across 58
modules.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]