Skip to content

HDFS-17976. HDFS DataNode add configurable inactivity-based timeout for DataNode block transfers - #8718

Open
rdhabalia wants to merge 1 commit into
apache:trunkfrom
rdhabalia:datanode-block-transfer-timeout
Open

HDFS-17976. HDFS DataNode add configurable inactivity-based timeout for DataNode block transfers#8718
rdhabalia wants to merge 1 commit into
apache:trunkfrom
rdhabalia:datanode-block-transfer-timeout

Conversation

@rdhabalia

Copy link
Copy Markdown

Description of PR

A block written to a DataNode remains active until the client sends the final
packet and the block is finalized.

When a client crashes, loses network connectivity, or hangs before sending the
last packet, the DataNode transfer thread can remain blocked indefinitely while
waiting for input. Over time, these stalled transfers can accumulate and cause:

  • Transfer-thread starvation
  • Resource leakage
  • Degraded DataNode responsiveness

Today, there is no built-in inactivity detection to reclaim resources from
stalled transfers. The system relies on client behavior or eventual lease
recovery, which may occur long after the actual failure.

Solution

Introduce a configurable, inactivity-based timeout for block transfers on the
DataNode.

When enabled, the DataNode tracks packet-arrival activity for each ongoing
block write using a monotonic clock. A single scheduled check per transfer
runs every timeout / 2 and compares the time since the last received packet
against timeout / 2.

Transfer Activity Detection

  • If a packet arrived within timeout / 2:

    • The stream is considered active.
    • The check is rescheduled.
    • This provides an automatic reset for healthy streams.
  • Otherwise:

    • The transfer is considered stalled.
    • The transfer is aborted.

Polling every timeout / 2 bounds the detection latency to between
timeout / 2 and timeout after the client stops sending.

Safe Transfer Abort

The abort runs on the shared scheduler thread and deliberately performs no
disk I/O
.

The on-disk streams (out / checksumOut) are written by the receive thread
without holding the BlockReceiver monitor. Flushing these streams from
the scheduler thread could race with those writes and potentially corrupt the
replica.

Instead, the scheduler:

  1. Closes only the client input stream.
  2. This unblocks the receive thread's blocked socket read.
  3. The receive thread unwinds and performs its own single-threaded cleanup.

Data already acknowledged to the client is already durable on disk. The
replica remains in the RBW (Replica Being Written) state, allowing the
NameNode's existing lease-recovery / block-synchronization path to finalize
the block without data loss.

Scheduler Design

The timeout checks use a shared ScheduledThreadPoolExecutor with 2 daemon
threads
.

The scheduler:

  • Is created lazily at DataNode startup only when the timeout is configured.
  • Adds zero threads and zero overhead when the feature is disabled.
  • Uses remove-on-cancel so per-block checks cancelled when a transfer
    completes do not accumulate in the delay queue.
  • Does not execute delayed tasks after shutdown.

The last-packet timestamp is updated only when the timeout feature is enabled,
avoiding unnecessary atomic writes on the hot path when the feature is
disabled.

Client Socket Timeout Considerations

Because a stall is declared after no packet is received for timeout / 2,
the DataNode timeout must be configured comfortably larger than the client
socket read timeout.

A healthy idle hflush / hsync stream still sends heartbeat packets roughly
every half of the socket timeout.

The DataNode logs a warning if the configured transfer timeout is not
sufficiently larger than the client socket timeout.

Configuration

Configuration Default Description
dfs.datanode.last.packet.receive.timeout.ms 0 Last-packet inactivity timeout in milliseconds. 0 disables the feature.

A typical enabled value is:

dfs.datanode.last.packet.receive.timeout.ms=600000

This corresponds to a 10-minute timeout.

The change is fully backward compatible and disabled by default.

Testing

TestBlockReceiverLastPacketTimeout

Verifies the DataNode-side scheduler wiring:

  • The shared scheduler is created only when the timeout is enabled.
  • remove-on-cancel is configured correctly.
  • Delayed tasks do not execute after scheduler shutdown.

TestBlockReceiverTransferTimeout

Runs an end-to-end test using MiniDFSCluster and verifies that a genuinely
stuck client is deterministically aborted.

The test uses a single DataNode with DataNode replacement disabled so that a
broken pipeline cannot be silently recovered.

It also verifies that healthy streams are never falsely aborted, including:

  • Full transfers
  • Slow-but-steady writers
  • Writers whose packet gaps remain just below the timeout threshold, even
    when the total transfer time exceeds the timeout
  • Disabled timeout configuration
  • Multiple concurrent transfers

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 0m 23s 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 27m 46s trunk passed
+1 💚 compile 1m 1s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 1m 2s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 1m 5s trunk passed
+1 💚 mvnsite 1m 10s trunk passed
+1 💚 javadoc 0m 56s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 0m 57s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 2m 17s trunk passed
+1 💚 shadedclient 17m 41s branch has no errors when building and testing our client artifacts.
_ Patch Compile Tests _
-1 ❌ mvninstall 0m 19s /patch-mvninstall-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ compile 0m 18s /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 18s /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 19s /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 19s /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 The patch has no blanks issues.
-0 ⚠️ checkstyle 0m 41s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 1 new + 309 unchanged - 0 fixed = 310 total (was 309)
-1 ❌ mvnsite 0m 20s /patch-mvnsite-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ javadoc 0m 20s /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 20s /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 20s /patch-spotbugs-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ shadedclient 8m 15s patch has errors when building and testing our client artifacts.
_ Other Tests _
-1 ❌ unit 0m 20s /patch-unit-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
+1 💚 asflicense 0m 21s The patch does not generate ASF License warnings.
63m 36s
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8718/1/artifact/out/Dockerfile
GITHUB PR #8718
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux a96856e65e1a 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 / bfdcbbf
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-8718/1/testReport/
Max. process+thread count 630 (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-8718/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 datanode-block-transfer-timeout branch from bfdcbbf to 37aafe7 Compare September 5, 2026 03:15
…ansfers

Motivation
----------
A block written to a DataNode stays active until the client sends the final
packet and the block is finalized. When a client crashes, loses network
connectivity, or hangs before sending the last packet, the DataNode transfer
thread can remain blocked indefinitely waiting for input. Over time these
stalled transfers accumulate and cause transfer-thread starvation, resource
leakage, and degraded DataNode responsiveness. Today there is no built-in
inactivity detection to reclaim resources from such stalled transfers; the
system relies on client behavior or eventual lease recovery, which may occur
long after the actual failure.

Solution
--------
Introduce a configurable, inactivity-based timeout for block transfers on the
DataNode. When enabled, the DataNode tracks packet-arrival activity for each
ongoing block write using a monotonic clock. A single scheduled check per
transfer polls every timeout/2 and compares the time since the last received
packet against timeout/2:

  * if a packet arrived within timeout/2, the stream is active and the check
    is rescheduled (automatic reset for healthy streams);
  * otherwise the transfer is treated as stalled and is aborted.

Polling every timeout/2 bounds the detection latency to between timeout/2 and
timeout after the client stops sending.

The abort runs on the shared scheduler thread, so it deliberately performs no
disk I/O: the on-disk streams (out/checksumOut) are written by the receive
thread WITHOUT holding the BlockReceiver monitor, so flushing them from the
scheduler thread would race those writes and could corrupt the replica.
Instead the abort only closes the client input stream, which unblocks the
receive thread's blocked socket read so it unwinds and runs its own
single-threaded cleanup. Data already acknowledged to the client is already
durable on disk, and the replica is left in the RBW (Replica Being Written)
state, so the NameNode's existing lease-recovery / block-synchronization path
finalizes the block without data loss.

The checks run on a shared ScheduledThreadPoolExecutor (2 daemon threads) that
is created lazily at DataNode startup only when the timeout is configured, so
the feature adds zero threads and zero overhead when disabled. It is configured
with remove-on-cancel so the per-block checks cancelled when a transfer
completes do not accumulate in the delay queue, and to not run delayed tasks
after shutdown. The last-packet timestamp is only updated when the timeout is
enabled to avoid unnecessary atomic writes on the hot path.

Because a stall is declared after no packet for timeout/2, the timeout must be
configured comfortably larger than the client socket read timeout (a healthy
idle hflush/hsync stream still sends heartbeat packets about every half the
socket timeout); the DataNode logs a warning if it is not.

Configuration
-------------
New key dfs.datanode.last.packet.receive.timeout.ms (default 0 = disabled).
A typical enabled value is 600000 (10 minutes). Fully backward compatible and
disabled by default.

Testing
-------
TestBlockReceiverLastPacketTimeout verifies the DataNode-side wiring: the shared
scheduler is created only when the timeout is enabled and is configured with the
correct lifecycle policies (remove-on-cancel and no delayed execution after
shutdown). TestBlockReceiverTransferTimeout drives MiniDFSCluster end-to-end and
asserts, deterministically, that a genuinely stuck client is aborted (single
DataNode with datanode replacement disabled so the broken pipeline cannot be
silently recovered), while healthy streams are never falsely aborted: full
transfers, a slow-but-steady writer, a writer whose gaps stay just under the
threshold (total time exceeding the timeout), the disabled configuration, and
multiple concurrent transfers all complete successfully.
@hadoop-yetus

Copy link
Copy Markdown

💔 -1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 22s 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 26m 50s trunk passed
+1 💚 compile 0m 59s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 0m 59s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 1m 8s trunk passed
+1 💚 mvnsite 1m 7s trunk passed
+1 💚 javadoc 0m 57s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 0m 57s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 2m 19s trunk passed
+1 💚 shadedclient 18m 22s branch has no errors when building and testing our client artifacts.
-0 ⚠️ patch 18m 41s 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 0m 50s the patch passed
+1 💚 compile 0m 42s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javac 0m 42s the patch passed
+1 💚 compile 0m 47s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 javac 0m 47s the patch passed
+1 💚 blanks 0m 0s The patch has no blanks issues.
-0 ⚠️ checkstyle 0m 42s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 5 new + 309 unchanged - 0 fixed = 314 total (was 309)
+1 💚 mvnsite 0m 50s the patch passed
+1 💚 javadoc 0m 35s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 0m 37s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 2m 5s the patch passed
+1 💚 shadedclient 16m 53s patch has no errors when building and testing our client artifacts.
_ Other Tests _
-1 ❌ unit 185m 55s /patch-unit-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch passed.
+1 💚 asflicense 0m 30s The patch does not generate ASF License warnings.
263m 40s
Reason Tests
Failed junit tests hadoop.hdfs.server.balancer.TestBalancerWithHANameNodes
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8718/2/artifact/out/Dockerfile
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux 1601862756d9 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 / 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-8718/2/testReport/
Max. process+thread count 4375 (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-8718/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.

@rdhabalia
rdhabalia force-pushed the datanode-block-transfer-timeout branch from 37aafe7 to d6d7451 Compare September 5, 2026 07:44
@hadoop-yetus

Copy link
Copy Markdown

🎊 +1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 22s 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 26m 30s trunk passed
+1 💚 compile 0m 57s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 1m 3s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 1m 5s trunk passed
+1 💚 mvnsite 1m 8s trunk passed
+1 💚 javadoc 0m 52s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 0m 57s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 2m 19s trunk passed
+1 💚 shadedclient 17m 25s branch has no errors when building and testing our client artifacts.
-0 ⚠️ patch 17m 43s 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 0m 48s the patch passed
+1 💚 compile 0m 45s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javac 0m 45s the patch passed
+1 💚 compile 0m 43s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 javac 0m 43s the patch passed
+1 💚 blanks 0m 0s The patch has no blanks issues.
-0 ⚠️ checkstyle 0m 44s /results-checkstyle-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs-project/hadoop-hdfs: The patch generated 1 new + 309 unchanged - 0 fixed = 310 total (was 309)
+1 💚 mvnsite 0m 46s the patch passed
+1 💚 javadoc 0m 38s the patch passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 0m 34s the patch passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 spotbugs 2m 3s the patch passed
+1 💚 shadedclient 16m 31s patch has no errors when building and testing our client artifacts.
_ Other Tests _
+1 💚 unit 184m 45s hadoop-hdfs in the patch passed.
+1 💚 asflicense 0m 29s The patch does not generate ASF License warnings.
260m 38s
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8718/3/artifact/out/Dockerfile
Optional Tests dupname asflicense compile javac javadoc mvninstall mvnsite unit shadedclient spotbugs checkstyle codespell detsecrets xmllint
uname Linux 44f3fc410f51 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 / 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-8718/3/testReport/
Max. process+thread count 4135 (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-8718/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.

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