Skip to content

HDFS-17974. Add pluggable DataNode affinity for tenant isolation in block placement - #8715

Open
rdhabalia wants to merge 1 commit into
apache:trunkfrom
rdhabalia:affinity-tenant-isolation
Open

HDFS-17974. Add pluggable DataNode affinity for tenant isolation in block placement#8715
rdhabalia wants to merge 1 commit into
apache:trunkfrom
rdhabalia:affinity-tenant-isolation

Conversation

@rdhabalia

Copy link
Copy Markdown

Description of PR

Multi-tenant HDFS clusters often need to pin a subset of data, identified by its HDFS path, to a dedicated pool of DataNodes. This prevents noisy or isolation-sensitive tenants from sharing read/write capacity with the rest of the cluster.

The default BlockPlacementPolicy has no notion of path-to-DataNode affinity, so operators typically resort to separate clusters or brittle rack-based workarounds.

Approach

Introduce a pluggable DatanodeAffinityManager abstraction, resolved via reflection from:

dfs.datanode.affinity.manager.classname

An affinity group maps:

  • Source path regexDataNode hostname regex

On refresh, the manager resolves each DataNode hostname regex against the live cluster and builds a restricted NetworkTopology for each group containing only that group's eligible DataNodes.

Components

  • DatanodeManager

    • Instantiates the configured affinity manager.
    • Removes affinity DataNodes from the default NetworkTopology as they register, ensuring the default placement policy cannot select them.
    • Prunes DataNodes from affinity structures when they are decommissioned or removed.
    • Re-triggers an affinity refresh on dfsadmin -refreshNodes.
  • BlockManager

    • Maintains one BlockPlacementPolicy per affinity group.
    • Each policy is backed by the group's restricted topology.
    • Routes initial block placement (chooseTarget4NewBlock) through the matching group's policy.
    • Routes mid-write pipeline recovery (chooseTarget4AdditionalDatanode) through the matching group's policy.
    • Ensures replacement nodes for failed pipeline members remain within the isolated pool.
    • Uses the default placement policy when no affinity group matches.
  • FileDatanodeAffinityManager

    • Built-in implementation that loads affinity groups from a JSON file.

    • Configuration:

      dfs.datanode.affinity.file.path
    • Reloads the configuration on dfsadmin -refreshNodes.

  • hdfs fsck

    • Supports:

      hdfs fsck <path> -favored-nodes
    • Prints the affinity-resolved DataNodes for a path as a dry run.

    • Does not require the path to exist.

Isolation vs. Availability

If an affinity group cannot place all requested replicas because of:

  • an under-provisioned group,
  • all group DataNodes being unavailable, or
  • a datanodesRegex matching no nodes,

the default behavior falls back to the shared pool so the write can still succeed. Spillover is logged at WARN.

Strict isolation can be enabled with:

dfs.namenode.affinity.strict.isolation.enabled=true

In strict mode, initial placement fails closed unless all requested replicas can be placed inside the affinity group.

This is important because placing only minReplication replicas in-group would allow the redundancy monitor to repair the remaining replicas onto shared-pool DataNodes, leaking data outside the isolated group.

Scope and Limitations

Affinity currently governs:

  • Initial block placement.
  • In-pipeline recovery.

Background replication and EC reconstruction still use the default placement policy.

Making these paths affinity-aware would require a reverse block-to-path lookup inside a lock-sensitive hot loop and is intentionally left as follow-up work. This is documented in BlockManager.

DataNode Regex Matching

DataNode regex patterns are matched using find() against each node's:

hostname:port

Therefore, a fully anchored pattern must account for the trailing port.

For example:

^dn-tenant-a[0-9]+\.example\.com(:\d+)?$

Configuration

Property Description Default
dfs.datanode.affinity.manager.classname Configured affinity manager implementation Empty / disabled
dfs.datanode.affinity.file.path JSON configuration file for FileDatanodeAffinityManager -
dfs.namenode.affinity.strict.isolation.enabled Enable strict affinity isolation false

Concurrency and Correctness Hardening

1. Full-Replica Placement

Both strict and non-strict modes require the affinity group to place all requested replicas before returning in-group targets.

Accepting a partial placement, even when it satisfies minReplication, creates an under-replicated block. The redundancy monitor could then repair the remaining replicas onto shared-pool DataNodes.

Behavior on shortfall:

  • Strict mode: Fail closed.
  • Non-strict mode: Spill the entire block to the shared pool using the default placement policy.

This guarantees that the block is fully replicated at write time and avoids both isolation leaks and silent under-replication windows.

2. Registration/Removal Races During Refresh

Registration and removal races during lock-free configuration refresh are reconciled.

internalRefresh() first takes a live snapshot before publishing the refreshed state. After publishing:

  1. postAffinityRefresh() re-evaluates every live DataNode against the current affinity patterns.

    • A DataNode that registered during the refresh is still moved into its appropriate affinity group.
    • The node cannot leak back into the default topology.
  2. A post-publish purge re-runs onDatanodeRemoved() for any snapshot node that is no longer live.

    • A DataNode removed during refresh cannot remain as a stale entry in the newly published structures.

The isolated-address set is a stable set that is mutated in place rather than replaced. This ensures concurrent registration updates are not lost.

3. DataNode Replacement

A DataNode can re-register with the same host:port but a new descriptor or storage UUID.

Affinity group topologies store descriptor objects while membership is address-keyed. Without reconciliation, a replacement could leave a stale descriptor selectable for placement.

onDatanodeRegistered() now:

  • Detects replacement DataNodes.
  • Swaps stale descriptors for the live descriptor.
  • Uses object identity to guard the replacement.
  • Removes stale descriptors for the same transfer endpoint regardless of which topology path they reside under.
  • Handles replacements that also move to a different rack or IP.

postAffinityRefresh() routes every live DataNode through this reconciliation logic rather than using an address-based short circuit.

4. Per-Group Topology and Storage Types

The per-group restricted topology is intentionally not a storage-type-aware DFSNetworkTopology.

DFSNetworkTopology captures each node's storage-type counts when the node is added and updates them through the descriptor's parent back-pointer.

Affinity DataNodes are removed from the default topology, which nulls their parent back-pointer. Consequently, storage-type counts in a DFSNetworkTopology affinity topology could become stale.

This is particularly problematic because:

  1. A DataNode registers with an empty storage map.
  2. The DataNode is added to its affinity group.
  3. Storage reports arrive later.
  4. A DFSNetworkTopology group would retain a storage count of zero.
  5. Storage-type-gated selection could therefore return no target.

After a NameNode restart, this could cause affinity placement to silently fail until a manual:

dfsadmin -refreshNodes

To avoid this:

  • When the cluster uses the default DFSNetworkTopology, each affinity group uses a plain NetworkTopology.
  • The topology does not maintain storage-type counts.
  • The placement policy selects an eligible leaf and validates the storage type against the live DataNode descriptor.

This ensures storage information remains current.

When:

dfs.use.dfs.network.topology=false

the configured net.topology.impl is honored instead.

For example:

NetworkTopologyWithNodeGroup

can be used for a node-group-based placement policy. Such implementations do not maintain storage counts and therefore do not have the same stale-storage-accounting issue.

The placement policy's initialize() still validates that the supplied cluster map is compatible with the configured topology implementation.

5. Pipeline Recovery

chooseTarget4AdditionalDatanode() routes through the affinity group's policy only when the surviving pipeline replicas actually belong to that group's restricted topology.

Otherwise, it uses the default placement policy.

This distinction is required for non-strict availability mode:

  1. An under-provisioned affinity group spills the whole block to the shared pool.
  2. The surviving pipeline replicas are therefore shared-pool DataNodes.
  3. Those DataNodes are not present in the affinity group's restricted topology.
  4. Forcing the affinity policy would count out-of-topology survivors against the group's getMaxNodesPerRack() calculation.
  5. numChosen + numAdditional could exceed the group's leaf count.
  6. The additional target count could become zero.
  7. No replacement DataNode would be returned.
  8. With the client default best-effort=false, the write could fail.

Using the default policy for a spilled block avoids this failure.

It also does not introduce an isolation leak because:

  • The block is already entirely in the shared pool.
  • Affinity DataNodes are excluded from the default topology.

Testing

TestDatanodeAffinityBlockPlacement contains 14 tests covering:

  • All replicas for an affinity path landing only on the group's DataNodes.

  • Non-affinity paths using the full cluster.

  • Isolation surviving DataNode re-registration.

  • Stale-node pruning on DataNode removal.

  • Strict isolation failing for:

    • Unsatisfiable placement.
    • Partially provisioned groups.
  • Non-strict fallback succeeding through the shared pool for:

    • Empty groups.
    • Partially provisioned groups.
  • Whole-block spillover with no replica remaining on the under-provisioned affinity group.

  • Pipeline recovery of a spilled shared-pool block succeeding through the default policy.

  • In-group pipeline recovery remaining within the affinity group.

  • Malformed records with null regex values being skipped without aborting refresh.

  • DataNodes registering during configuration refresh being reconciled into their affinity group instead of leaking into the default topology.

  • Replaced DataNodes with the same address but a new UUID being reconciled to the live descriptor.

  • DataNode replacement working both:

    • In place.
    • When the replacement moves to a different rack/path.
  • Per-group topology being a plain NetworkTopology rather than a storage-type-aware DFSNetworkTopology.

  • Storage accounting remaining current for affinity DataNodes.

The removal-race purge reuses onDatanodeRemoved(), whose pruning behavior is covered by the removal test.

The exact mid-refresh interleaving is not unit-tested because reproducing it deterministically would require intrusive production test hooks.

Results

The implementation enables strict tenant isolation of write and read traffic onto a dedicated DataNode pool while keeping the rest of the cluster on the default placement policy.

Affinity configuration can be refreshed at runtime without requiring a NameNode restart.

How was this patch tested?

Tested by newly added unit test

For code changes:

  • Does the title of this PR start with the corresponding JIRA issue id (e.g. 'HADOOP-17799. Your PR title ...')?
  • Object storage: Have the integration tests been executed and the endpoint
    declared according to the connector-specific documentation? Note: Automated CI
    testing doesn't cover all cases so manual testing with cloud storage is still
    required.
  • If adding new dependencies to the code, are these dependencies licensed in a way that is compatible for inclusion under ASF 2.0?
  • If applicable, have you updated the LICENSE, LICENSE-binary, NOTICE-binary files?

AI Tooling

If an AI tool was used:

@hadoop-yetus

Copy link
Copy Markdown

💔 -1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 21m 51s Docker mode activated.
_ Prechecks _
+1 💚 dupname 0m 0s No case conflicting files found.
+0 🆗 codespell 0m 0s codespell was not available.
+0 🆗 detsecrets 0m 0s detect-secrets was not available.
+0 🆗 xmllint 0m 0s xmllint was not available.
+1 💚 @author 0m 0s The patch does not contain any @author tags.
+1 💚 test4tests 0m 0s The patch appears to include 2 new or modified test files.
_ trunk Compile Tests _
+1 💚 mvninstall 49m 53s trunk passed
+1 💚 compile 1m 48s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 1m 49s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 1m 53s trunk passed
+1 💚 mvnsite 2m 0s trunk passed
+1 💚 javadoc 1m 29s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 1m 32s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 4m 27s trunk passed
+1 💚 shadedclient 38m 38s branch has no errors when building and testing our client artifacts.
_ Patch Compile Tests _
-1 ❌ mvninstall 0m 28s /patch-mvninstall-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ compile 0m 30s /patch-compile-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javac 0m 30s /patch-compile-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ compile 0m 29s /patch-compile-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
-1 ❌ javac 0m 29s /patch-compile-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
-1 ❌ blanks 0m 0s /blanks-eol.txt The patch has 1 line(s) that end in blanks. Use git apply --whitespace=fix <<patch_file>>. Refer https://git-scm.com/docs/git-apply
-0 ⚠️ checkstyle 1m 24s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 31 new + 385 unchanged - 0 fixed = 416 total (was 385)
-1 ❌ mvnsite 0m 30s /patch-mvnsite-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ javadoc 0m 29s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javadoc 0m 28s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
-1 ❌ spotbugs 0m 28s /patch-spotbugs-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ shadedclient 14m 32s patch has errors when building and testing our client artifacts.
_ Other Tests _
-1 ❌ unit 0m 31s /patch-unit-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
+1 💚 asflicense 0m 32s The patch does not generate ASF License warnings.
141m 2s
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/1/artifact/out/Dockerfile
GITHUB PR #8715
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux 50e280e9c285 5.15.0-185-generic #195-Ubuntu SMP Fri Jun 19 17:11:50 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/bin/hadoop.sh
git revision trunk / 67ff6fa
Default Java Ubuntu-17.0.20+8-1-24.04-Ubuntu
Multi-JDK versions /usr/lib/jvm/java-21-openjdk-amd64:Ubuntu-21.0.12+8-1-24.04-Ubuntu /usr/lib/jvm/java-17-openjdk-amd64:Ubuntu-17.0.20+8-1-24.04-Ubuntu
Test Results https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/1/testReport/
Max. process+thread count 569 (vs. ulimit of 10000)
modules C: hadoop-hdfs-project/hadoop-hdfs U: hadoop-hdfs-project/hadoop-hdfs
Console output https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/1/console
versions git=2.43.0 maven=3.9.15 spotbugs=4.9.7
Powered by Apache Yetus 0.14.1 https://yetus.apache.org

This message was automatically generated.

@rdhabalia
rdhabalia force-pushed the affinity-tenant-isolation branch 2 times, most recently from a42c953 to f2c52f6 Compare September 5, 2026 05:03
…lacement

Motivation:
Multi-tenant HDFS clusters often need to pin a subset of data (identified by
its HDFS path) to a dedicated pool of DataNodes so that a noisy or
isolation-sensitive tenant does not share write/read capacity with the rest
of the cluster. The default BlockPlacementPolicy has no notion of such
path-to-DataNode affinity, so operators resort to separate clusters or
brittle rack hacks.

Approach:
Introduce a pluggable DatanodeAffinityManager abstraction resolved by
reflection from `dfs.datanode.affinity.manager.classname`. An affinity group
maps a source-path regex to a DataNode-hostname regex. On refresh the manager
resolves each DataNode-hostname regex against the live cluster and builds, per
group, a restricted NetworkTopology containing only that group's eligible
DataNodes.

- DatanodeManager instantiates the configured manager, removes affinity
  DataNodes from the default NetworkTopology as they register (so the default
  policy can never select them), prunes them from the affinity structures when
  they are decommissioned/removed, and re-triggers a refresh on
  `dfsadmin -refreshNodes`.
- BlockManager keeps one BlockPlacementPolicies per affinity group, each backed
  by the group's restricted topology. Both initial block placement
  (chooseTarget4NewBlock) and mid-write pipeline recovery
  (chooseTarget4AdditionalDatanode) route through the matching group's policy
  so a replacement node for a failed pipeline member stays inside the isolated
  pool. When no group matches, the default policy is used.
- A built-in FileDatanodeAffinityManager loads affinity groups from a JSON file
  (`dfs.datanode.affinity.file.path`), reloaded on `dfsadmin -refreshNodes`.
- `hdfs fsck <path> -favored-nodes` prints the affinity-resolved DataNodes for a
  path as a dry-run, without requiring the path to exist.

Isolation vs. availability:
When an affinity group cannot place all requested replicas (under-provisioned
group, all group DataNodes down, or a datanodesRegex that matched no nodes),
the default behaviour falls back to the shared pool so the write still succeeds,
logging the spillover at WARN. Setting
`dfs.namenode.affinity.strict.isolation.enabled=true` makes initial placement
fail closed unless ALL requested replicas fit inside the group -- placing only
minReplication in-group would let the redundancy monitor repair the remainder
on shared-pool nodes and leak data out of the group.

Scope / limitations:
Affinity governs initial block placement and in-pipeline recovery. Background
replication / EC reconstruction still uses the default placement policy: making
it affinity-aware requires a reverse block->path lookup inside a lock-sensitive
hot loop and is intentionally left as follow-up work (documented in
BlockManager). DataNode-regex patterns are matched (via find()) against each
node's "hostname:port" address, so a fully anchored pattern must allow the
trailing ":port" (e.g. `^dn-tenant-a[0-9]+\.example\.com(:\d+)?$`).

Configuration:
- dfs.datanode.affinity.manager.classname (empty/disabled by default)
- dfs.datanode.affinity.file.path (JSON file for FileDatanodeAffinityManager)
- dfs.namenode.affinity.strict.isolation.enabled (default false)

Concurrency and correctness hardening:
- Both the strict and non-strict modes now require the affinity group to place
  ALL requested replicas before returning in-group targets. Accepting a partial
  placement (only >= minReplication) would create the block under-replicated and
  let the redundancy monitor "repair" the remainder onto shared-pool nodes --
  leaking data out of the isolated group (strict) or leaving a silent
  under-replication window (non-strict). On a shortfall strict fails closed and
  non-strict spills the WHOLE block to the shared pool via the default policy, so
  it is fully replicated at write time.
- Symmetric registration/removal races during a lock-free config refresh are
  reconciled: internalRefresh() takes a live snapshot before publishing, then
  (a) postAffinityRefresh() re-evaluates every live DataNode against the current
  patterns so a node that registered mid-refresh stays isolated instead of
  leaking back into the default topology, and (b) a post-publish purge re-runs
  onDatanodeRemoved() for any snapshot node no longer live so a node removed
  mid-refresh cannot linger as a dead entry in the freshly published structures.
  The isolated-address set is a stable final set mutated in place (never swapped)
  so concurrent registration adds are not lost.
- DataNode replacement (same host:port re-registering with a new descriptor /
  storage UUID) is reconciled in the per-group topology: because that topology
  stores descriptor OBJECTS but membership is address-keyed, a replacement could
  otherwise leave a STALE, dead descriptor selectable for placement.
  onDatanodeRegistered() now swaps the stale descriptor for the live one
  (object-identity guarded), removing every stale descriptor for the same
  transfer endpoint regardless of the topology path it sits under (so a
  replacement that also changes rack/IP cannot leave a dead leaf behind), and
  postAffinityRefresh() routes every live node through it (no address
  short-circuit) so the reconciliation always runs.
- The per-group restricted topology is never a storage-type-aware
  DFSNetworkTopology. A DFSNetworkTopology captures each node's storage-type
  counts at add() time and updates them only through the descriptor's parent
  back-pointer; but an affinity node's shared descriptor has its parent nulled
  when it is removed from the default topology, so those counts could never
  update from later storage reports. Because a DataNode registers (and is added
  to its group) with an EMPTY storage map -- storage reports arrive afterwards --
  a DFSNetworkTopology group would freeze the count at ZERO and, via
  storage-type-gated selection, return no target: group placement would silently
  break after every NameNode restart (all affinity nodes re-register fresh)
  until a manual `dfsadmin -refreshNodes`. So when the cluster uses
  DFSNetworkTopology (the default) the group topology is built as a plain
  NetworkTopology, which tracks no storage counts; the placement policy instead
  selects a random eligible leaf and validates the storage type against the LIVE
  descriptor, which is always current. When dfs.use.dfs.network.topology=false
  the configured net.topology.impl is honored instead (e.g.
  NetworkTopologyWithNodeGroup for a node-group replicator, whose placement
  policy's initialize() rejects any other clusterMap type) -- those impls track
  no storage counts, so they are immune to the staleness problem while keeping
  the isolation feature from silently failing open under a node-group topology.
- Pipeline recovery (chooseTarget4AdditionalDatanode) now routes through the
  affinity group's policy ONLY when the surviving pipeline replicas actually
  live inside that group's restricted topology; otherwise it uses the default
  policy. In non-strict availability mode an under-provisioned group spills the
  WHOLE block to the shared pool, so the survivors are shared-pool nodes absent
  from the tiny group topology. Forcing the group policy would then count those
  out-of-topology survivors against the group in getMaxNodesPerRack (numChosen +
  numAdditional exceeds the group's leaf count), drive the additional count to 0,
  return no replacement, and -- with the client default best-effort=false --
  fail the write. Recovering a spilled block through the default policy keeps
  the write alive and never leaks isolation (the block already lives in the
  shared pool, and affinity nodes are absent from the default topology).

Testing:
TestDatanodeAffinityBlockPlacement (14 tests) covers: all replicas of an
affinity path landing only on the group's DataNodes; non-affinity paths using
the full cluster; isolation surviving DataNode re-registration; stale-node
pruning on removal; strict isolation failing both an unsatisfiable and a
partially-provisioned write; non-strict fallback succeeding via the shared
pool for both an empty group and a partially-provisioned group (whole block
spilled, no replica left on the under-provisioned group); pipeline recovery of
a spilled (shared-pool) block succeeding via the default policy while in-group
recovery stays in-group; malformed (null-regex) records being skipped without
aborting refresh; a DataNode that registers during a config refresh being
reconciled into its group instead of leaking back into the default topology; a
replaced DataNode (same address, new UUID) having its group topology reconciled
to the live descriptor, both in place and when the replacement moves to a
different rack/path; and the per-group topology being a plain NetworkTopology
(not a storage-type-aware DFSNetworkTopology) so its node storage accounting
cannot go stale for affinity nodes. The removal-race purge reuses
onDatanodeRemoved(), whose pruning of the published structures is covered by the
removal test; the exact mid-refresh interleaving is not unit-tested because it
cannot be made deterministic without intrusive production test hooks.

Results:
Enables strict tenant isolation of write and read traffic onto a dedicated
DataNode pool while leaving the rest of the cluster on the default placement
policy, refreshable at runtime without a NameNode restart.
@rdhabalia
rdhabalia force-pushed the affinity-tenant-isolation branch from f2c52f6 to 2ae7b9d Compare September 5, 2026 06:06
@hadoop-yetus

Copy link
Copy Markdown

💔 -1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 55s Docker mode activated.
_ Prechecks _
+1 💚 dupname 0m 0s No case conflicting files found.
+0 🆗 codespell 0m 0s codespell was not available.
+0 🆗 detsecrets 0m 0s detect-secrets was not available.
+0 🆗 xmllint 0m 0s xmllint was not available.
+1 💚 @author 0m 1s The patch does not contain any @author tags.
+1 💚 test4tests 0m 0s The patch appears to include 1 new or modified test files.
_ trunk Compile Tests _
+1 💚 mvninstall 48m 18s trunk passed
+1 💚 compile 1m 46s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 1m 49s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 1m 55s trunk passed
+1 💚 mvnsite 1m 56s trunk passed
+1 💚 javadoc 1m 32s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 1m 30s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 4m 27s trunk passed
+1 💚 shadedclient 38m 21s branch has no errors when building and testing our client artifacts.
-0 ⚠️ patch 38m 55s Used diff version of patch file. Binary files and potentially other changes not applied. Please rebase and squash commits if necessary.
_ Patch Compile Tests _
+1 💚 mvninstall 1m 26s the patch passed
+1 💚 compile 1m 15s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javac 1m 15s the patch passed
+1 💚 compile 1m 21s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 javac 1m 21s the patch passed
+1 💚 blanks 0m 0s The patch has no blanks issues.
-0 ⚠️ checkstyle 1m 24s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 60 new + 382 unchanged - 0 fixed = 442 total (was 382)
+1 💚 mvnsite 1m 36s the patch passed
-1 ❌ javadoc 1m 5s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javadoc 1m 4s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
+1 💚 spotbugs 4m 20s the patch passed
+1 💚 shadedclient 39m 16s patch has no errors when building and testing our client artifacts.
_ Other Tests _
+1 💚 unit 284m 1s hadoop-hdfs in the patch passed.
+1 💚 asflicense 0m 57s The patch does not generate ASF License warnings.
437m 50s
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/2/artifact/out/Dockerfile
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux 57828c13da31 5.15.0-185-generic #195-Ubuntu SMP Fri Jun 19 17:11:50 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/bin/hadoop.sh
git revision trunk / 706d4dc
Default Java Ubuntu-17.0.20+8-1-24.04-Ubuntu
Multi-JDK versions /usr/lib/jvm/java-21-openjdk-amd64:Ubuntu-21.0.12+8-1-24.04-Ubuntu /usr/lib/jvm/java-17-openjdk-amd64:Ubuntu-17.0.20+8-1-24.04-Ubuntu
Test Results https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/2/testReport/
Max. process+thread count 3328 (vs. ulimit of 10000)
modules C: hadoop-hdfs-project/hadoop-hdfs U: hadoop-hdfs-project/hadoop-hdfs
Console output https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/2/console
versions git=2.43.0 maven=3.9.15 spotbugs=4.9.7
Powered by Apache Yetus 0.14.1 https://yetus.apache.org

This message was automatically generated.

@hadoop-yetus

Copy link
Copy Markdown

💔 -1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 58s Docker mode activated.
_ Prechecks _
+1 💚 dupname 0m 0s No case conflicting files found.
+0 🆗 codespell 0m 0s codespell was not available.
+0 🆗 detsecrets 0m 0s detect-secrets was not available.
+0 🆗 xmllint 0m 0s xmllint was not available.
+1 💚 @author 0m 0s The patch does not contain any @author tags.
+1 💚 test4tests 0m 0s The patch appears to include 1 new or modified test files.
_ trunk Compile Tests _
+1 💚 mvninstall 49m 58s trunk passed
+1 💚 compile 2m 11s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 2m 9s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 2m 2s trunk passed
+1 💚 mvnsite 2m 13s trunk passed
+1 💚 javadoc 1m 35s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 1m 37s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 5m 7s trunk passed
+1 💚 shadedclient 42m 32s branch has no errors when building and testing our client artifacts.
_ Patch Compile Tests _
+1 💚 mvninstall 1m 30s the patch passed
+1 💚 compile 1m 28s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javac 1m 28s the patch passed
+1 💚 compile 1m 36s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 javac 1m 36s the patch passed
+1 💚 blanks 0m 0s The patch has no blanks issues.
-0 ⚠️ checkstyle 1m 32s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 60 new + 382 unchanged - 0 fixed = 442 total (was 382)
+1 💚 mvnsite 1m 51s the patch passed
-1 ❌ javadoc 1m 13s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javadoc 1m 17s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
+1 💚 spotbugs 4m 31s the patch passed
+1 💚 shadedclient 41m 19s patch has no errors when building and testing our client artifacts.
_ Other Tests _
-1 ❌ unit 279m 30s /patch-unit-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch passed.
+1 💚 asflicense 0m 57s The patch does not generate ASF License warnings.
444m 48s
Reason Tests
Failed junit tests hadoop.hdfs.server.namenode.ha.TestStandbyCheckpoints
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/3/artifact/out/Dockerfile
GITHUB PR #8715
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux d51629d53ba0 5.15.0-185-generic #195-Ubuntu SMP Fri Jun 19 17:11:50 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/bin/hadoop.sh
git revision trunk / f2c52f6
Default Java Ubuntu-17.0.20+8-1-24.04-Ubuntu
Multi-JDK versions /usr/lib/jvm/java-21-openjdk-amd64:Ubuntu-21.0.12+8-1-24.04-Ubuntu /usr/lib/jvm/java-17-openjdk-amd64:Ubuntu-17.0.20+8-1-24.04-Ubuntu
Test Results https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/3/testReport/
Max. process+thread count 3313 (vs. ulimit of 10000)
modules C: hadoop-hdfs-project/hadoop-hdfs U: hadoop-hdfs-project/hadoop-hdfs
Console output https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/3/console
versions git=2.43.0 maven=3.9.15 spotbugs=4.9.7
Powered by Apache Yetus 0.14.1 https://yetus.apache.org

This message was automatically generated.

@hadoop-yetus

Copy link
Copy Markdown

💔 -1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 56s Docker mode activated.
_ Prechecks _
+1 💚 dupname 0m 0s No case conflicting files found.
+0 🆗 codespell 0m 0s codespell was not available.
+0 🆗 detsecrets 0m 0s detect-secrets was not available.
+0 🆗 xmllint 0m 0s xmllint was not available.
+1 💚 @author 0m 0s The patch does not contain any @author tags.
+1 💚 test4tests 0m 0s The patch appears to include 1 new or modified test files.
_ trunk Compile Tests _
+1 💚 mvninstall 47m 58s trunk passed
+1 💚 compile 1m 47s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 1m 47s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 1m 50s trunk passed
+1 💚 mvnsite 1m 57s trunk passed
+1 💚 javadoc 1m 28s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 1m 30s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 4m 25s trunk passed
+1 💚 shadedclient 38m 29s branch has no errors when building and testing our client artifacts.
_ Patch Compile Tests _
+1 💚 mvninstall 1m 25s the patch passed
+1 💚 compile 1m 16s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javac 1m 16s the patch passed
+1 💚 compile 1m 21s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 javac 1m 21s the patch passed
+1 💚 blanks 0m 0s The patch has no blanks issues.
-0 ⚠️ checkstyle 1m 23s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 27 new + 383 unchanged - 0 fixed = 410 total (was 383)
+1 💚 mvnsite 1m 29s the patch passed
-1 ❌ javadoc 1m 1s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javadoc 1m 3s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
+1 💚 spotbugs 4m 1s the patch passed
+1 💚 shadedclient 36m 24s patch has no errors when building and testing our client artifacts.
_ Other Tests _
+1 💚 unit 257m 28s hadoop-hdfs in the patch passed.
+1 💚 asflicense 0m 48s The patch does not generate ASF License warnings.
407m 37s
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/4/artifact/out/Dockerfile
GITHUB PR #8715
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux b3654eb52727 5.15.0-190-generic #200-Ubuntu SMP Fri Aug 7 15:06:04 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/bin/hadoop.sh
git revision trunk / 2ae7b9d
Default Java Ubuntu-17.0.20+8-1-24.04-Ubuntu
Multi-JDK versions /usr/lib/jvm/java-21-openjdk-amd64:Ubuntu-21.0.12+8-1-24.04-Ubuntu /usr/lib/jvm/java-17-openjdk-amd64:Ubuntu-17.0.20+8-1-24.04-Ubuntu
Test Results https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/4/testReport/
Max. process+thread count 2184 (vs. ulimit of 10000)
modules C: hadoop-hdfs-project/hadoop-hdfs U: hadoop-hdfs-project/hadoop-hdfs
Console output https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8715/4/console
versions git=2.43.0 maven=3.9.15 spotbugs=4.9.7
Powered by Apache Yetus 0.14.1 https://yetus.apache.org

This message was automatically generated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants