This is an automated email from the ASF dual-hosted git repository.

jinrongtong pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/rocketmq.git


The following commit(s) were added to refs/heads/develop by this push:
     new 7a1a9501ca [ISSUE# 9841] Improve Resource Management in TimerWheel to 
Prevent File Handle Leaks (#9842)
7a1a9501ca is described below

commit 7a1a9501cab8ff74b1a4aaecb2f22235eef66616
Author: guyinyou <[email protected]>
AuthorDate: Wed Nov 12 15:22:59 2025 +0800

    [ISSUE# 9841] Improve Resource Management in TimerWheel to Prevent File 
Handle Leaks (#9842)
    
    * fix: fix file handle leak in TimerWheel
    
    - Move RandomAccessFile and FileChannel to instance variables
    - Close FileChannel in shutdown() method instead of constructor finally 
block
    - This ensures proper resource cleanup and prevents file handle leaks
    
    Change-Id: If6f0bdd555e5f6fdd5c44ca8404f7918b45cf67b
    Co-developed-by: Cursor <[email protected]>
    
    * fix
    
    Change-Id: Icf8f6c316208f8e38421013f2d7b7028f56d5259
    
    * fix
    
    Change-Id: I9ed022b94fca31f005e71afe92a0374265f6ea11
    
    * fix
    
    Change-Id: Ibfd499652378710ccc7b5632370a77ab5dc4b8f3
    
    ---------
    
    Co-authored-by: guyinyou <[email protected]>
---
 .../apache/rocketmq/store/timer/TimerWheel.java    | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git 
a/store/src/main/java/org/apache/rocketmq/store/timer/TimerWheel.java 
b/store/src/main/java/org/apache/rocketmq/store/timer/TimerWheel.java
index 261d8f6a3d..2d5ce38201 100644
--- a/store/src/main/java/org/apache/rocketmq/store/timer/TimerWheel.java
+++ b/store/src/main/java/org/apache/rocketmq/store/timer/TimerWheel.java
@@ -43,7 +43,9 @@ public class TimerWheel {
     public final int slotsTotal;
     public final int precisionMs;
     private final String fileName;
-    private MappedByteBuffer mappedByteBuffer;
+    private final MappedByteBuffer mappedByteBuffer;
+    private final RandomAccessFile randomAccessFile;
+    private final FileChannel fileChannel;
     private final ByteBuffer byteBuffer;
     private final ThreadLocal<ByteBuffer> localBuffer = new 
ThreadLocal<ByteBuffer>() {
         @Override
@@ -69,7 +71,6 @@ public class TimerWheel {
         File file = new File(finalFileName);
         UtilAll.ensureDirOK(file.getParent());
 
-        RandomAccessFile randomAccessFile = null;
         try {
             randomAccessFile = new RandomAccessFile(finalFileName, "rw");
             if (file.exists() && randomAccessFile.length() != 0 &&
@@ -79,8 +80,13 @@ public class TimerWheel {
             }
             randomAccessFile.setLength(wheelLength);
             if (snapOffset < 0) {
-                mappedByteBuffer = 
randomAccessFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 
wheelLength);
+                fileChannel = randomAccessFile.getChannel();
+                mappedByteBuffer = 
fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, wheelLength);
                 assert wheelLength == mappedByteBuffer.remaining();
+            } else {
+                fileChannel = null;
+                mappedByteBuffer = null;
+                randomAccessFile.close();
             }
             this.byteBuffer = ByteBuffer.allocateDirect(wheelLength);
             this.byteBuffer.put(Files.readAllBytes(file.toPath()));
@@ -90,10 +96,6 @@ public class TimerWheel {
         } catch (IOException e) {
             log.error("map file " + finalFileName + " Failed. ", e);
             throw e;
-        } finally {
-            if (randomAccessFile != null) {
-                randomAccessFile.close();
-            }
         }
     }
 
@@ -114,6 +116,12 @@ public class TimerWheel {
         UtilAll.cleanBuffer(this.mappedByteBuffer);
         UtilAll.cleanBuffer(this.byteBuffer);
         localBuffer.remove();
+
+        try {
+            this.fileChannel.close();
+        } catch (Throwable t) {
+            log.error("Shutdown error in timer wheel", t);
+        }
     }
 
     public void flush() {

Reply via email to