Skip to content

Commit 05ea91e

Browse files
committed
[ISSUE #10218] Fix resource leak in DumpCompactionLogCommand
Fixes #10218
1 parent 932588d commit 05ea91e

File tree

2 files changed

+113
-3
lines changed

2 files changed

+113
-3
lines changed

tools/src/main/java/org/apache/rocketmq/tools/command/message/DumpCompactionLogCommand.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,10 @@ public void execute(CommandLine commandLine, Options options, RPCHook rpcHook)
6969
throw new SubCommandException("file " + fileName + " is a directory.");
7070
}
7171

72-
try {
72+
try (RandomAccessFile raf = new RandomAccessFile(fileName, "r");
73+
FileChannel fileChannel = raf.getChannel()) {
7374
long fileSize = Files.size(filePath);
74-
FileChannel fileChannel = new RandomAccessFile(fileName, "rw").getChannel();
75-
ByteBuffer buf = fileChannel.map(MapMode.READ_WRITE, 0, fileSize);
75+
ByteBuffer buf = fileChannel.map(MapMode.READ_ONLY, 0, fileSize);
7676

7777
int current = 0;
7878
while (current < fileSize) {
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.rocketmq.tools.command.message;
18+
19+
import java.io.File;
20+
import java.io.RandomAccessFile;
21+
import java.net.InetSocketAddress;
22+
import java.nio.ByteBuffer;
23+
import java.nio.channels.FileChannel;
24+
import org.apache.commons.cli.CommandLine;
25+
import org.apache.commons.cli.DefaultParser;
26+
import org.apache.commons.cli.Options;
27+
import org.apache.rocketmq.common.message.MessageDecoder;
28+
import org.apache.rocketmq.common.message.MessageExt;
29+
import org.apache.rocketmq.tools.command.SubCommandException;
30+
import org.junit.After;
31+
import org.junit.Assert;
32+
import org.junit.Before;
33+
import org.junit.Test;
34+
35+
public class DumpCompactionLogCommandTest {
36+
37+
private DumpCompactionLogCommand command;
38+
private File tempFile;
39+
40+
@Before
41+
public void setUp() throws Exception {
42+
command = new DumpCompactionLogCommand();
43+
tempFile = File.createTempFile("compaction-log-test", ".log");
44+
}
45+
46+
@After
47+
public void tearDown() {
48+
if (tempFile != null && tempFile.exists()) {
49+
tempFile.delete();
50+
}
51+
}
52+
53+
@Test
54+
public void testExecuteWithValidFile() throws Exception {
55+
// Write a valid message to the temp file
56+
MessageExt msg = new MessageExt();
57+
msg.setBody("test-body".getBytes());
58+
msg.setTopic("test-topic");
59+
msg.setBornHost(new InetSocketAddress("127.0.0.1", 9000));
60+
msg.setStoreHost(new InetSocketAddress("127.0.0.1", 9000));
61+
byte[] encoded = MessageDecoder.encode(msg, false);
62+
63+
try (RandomAccessFile raf = new RandomAccessFile(tempFile, "rw");
64+
FileChannel channel = raf.getChannel()) {
65+
ByteBuffer buffer = ByteBuffer.wrap(encoded);
66+
channel.write(buffer);
67+
}
68+
69+
Options options = command.buildCommandlineOptions(new Options());
70+
String[] args = {"-f", tempFile.getAbsolutePath()};
71+
CommandLine commandLine = new DefaultParser().parse(options, args);
72+
73+
// Should not throw any exception and should not leak file descriptors
74+
command.execute(commandLine, options, null);
75+
76+
// Verify the temp file can still be accessed (not locked by leaked handles)
77+
Assert.assertTrue(tempFile.exists());
78+
Assert.assertTrue(tempFile.canRead());
79+
}
80+
81+
@Test
82+
public void testExecuteWithEmptyFile() throws Exception {
83+
Options options = command.buildCommandlineOptions(new Options());
84+
String[] args = {"-f", tempFile.getAbsolutePath()};
85+
CommandLine commandLine = new DefaultParser().parse(options, args);
86+
87+
// Should handle empty file gracefully without resource leak
88+
command.execute(commandLine, options, null);
89+
Assert.assertTrue(tempFile.exists());
90+
}
91+
92+
@Test(expected = SubCommandException.class)
93+
public void testExecuteWithNonExistentFile() throws Exception {
94+
Options options = command.buildCommandlineOptions(new Options());
95+
String[] args = {"-f", "/non/existent/file.log"};
96+
CommandLine commandLine = new DefaultParser().parse(options, args);
97+
98+
command.execute(commandLine, options, null);
99+
}
100+
101+
@Test
102+
public void testExecuteWithoutFileOption() throws Exception {
103+
Options options = command.buildCommandlineOptions(new Options());
104+
String[] args = {};
105+
CommandLine commandLine = new DefaultParser().parse(options, args);
106+
107+
// Should print error message, not throw
108+
command.execute(commandLine, options, null);
109+
}
110+
}

0 commit comments

Comments
 (0)