From dc73950a783f11b46835862240282b5324e44aa6 Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Wed, 12 Aug 2026 16:36:17 +0900 Subject: [PATCH 1/2] supervisor: reduce memory usage of cleanup_lock_dir with huge number of lock files A long-running multi-worker aggregator with /tmp aging disabled accumulated about 20 million lock files. Dir.glob materializes the whole path list at shutdown, which causes a multi-GB memory spike. Use Dir.each_child to stream directory entries instead. Removing 1,000,000 lock files grows RSS by 884.5 MB with Dir.glob but only by 1.8 MB with Dir.each_child. The elapsed time is unchanged. No behavior change. Signed-off-by: Shizuo Fujita --- lib/fluent/supervisor.rb | 9 ++++++++- test/test_supervisor.rb | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/fluent/supervisor.rb b/lib/fluent/supervisor.rb index bb09cf35a9..248bfddee8 100644 --- a/lib/fluent/supervisor.rb +++ b/lib/fluent/supervisor.rb @@ -100,7 +100,14 @@ def after_run end def cleanup_lock_dir - FileUtils.rm(Dir.glob(File.join(@fluentd_lock_dir, "fluentd-*.lock"))) + begin + Dir.each_child(@fluentd_lock_dir) do |name| + FileUtils.rm(File.join(@fluentd_lock_dir, name)) if File.fnmatch?("fluentd-*.lock", name) + end + rescue Errno::ENOENT + # Directory is already missing. Fall through and let rmdir below + # fail in the same way as the current implementation. + end FileUtils.rmdir(@fluentd_lock_dir) end diff --git a/test/test_supervisor.rb b/test/test_supervisor.rb index 2da25d2b68..5aac3fe09c 100644 --- a/test/test_supervisor.rb +++ b/test/test_supervisor.rb @@ -1003,6 +1003,39 @@ def test_log_result((result, expected_message)) end end + sub_test_case "cleanup_lock_dir" do + def create_server(lock_dir) + server = DummyServer.new + server.instance_variable_set(:@fluentd_lock_dir, lock_dir) + server + end + + def test_remove_lock_dir + lock_dir = File.join(@tmp_dir, "fluentd-lock") + FileUtils.mkdir_p(lock_dir) + FileUtils.touch(File.join(lock_dir, "fluentd-0.lock")) + FileUtils.touch(File.join(lock_dir, "fluentd-1.lock")) + + create_server(lock_dir).cleanup_lock_dir + + assert_false(File.exist?(lock_dir)) + end + + def test_keep_unrelated_file + lock_dir = File.join(@tmp_dir, "fluentd-lock") + FileUtils.mkdir_p(lock_dir) + FileUtils.touch(File.join(lock_dir, "fluentd-0.lock")) + FileUtils.touch(File.join(lock_dir, "unrelated.txt")) + + assert_raise(Errno::ENOTEMPTY) do + create_server(lock_dir).cleanup_lock_dir + end + + assert_false(File.exist?(File.join(lock_dir, "fluentd-0.lock"))) + assert_true(File.exist?(File.join(lock_dir, "unrelated.txt"))) + end + end + sub_test_case "zero_downtime_restart" do setup do omit "Not supported on Windows" if Fluent.windows? From 0e5010e73d4bb8b4867ee0de7e88b9f3b374b3af Mon Sep 17 00:00:00 2001 From: Shizuo Fujita Date: Thu, 13 Aug 2026 12:12:36 +0900 Subject: [PATCH 2/2] supervisor: keep removing lock files if one of them is already gone Co-authored-by: Kentaro Hayashi Signed-off-by: Shizuo Fujita --- lib/fluent/supervisor.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/fluent/supervisor.rb b/lib/fluent/supervisor.rb index 248bfddee8..0b5db1de3d 100644 --- a/lib/fluent/supervisor.rb +++ b/lib/fluent/supervisor.rb @@ -102,7 +102,7 @@ def after_run def cleanup_lock_dir begin Dir.each_child(@fluentd_lock_dir) do |name| - FileUtils.rm(File.join(@fluentd_lock_dir, name)) if File.fnmatch?("fluentd-*.lock", name) + FileUtils.rm_f(File.join(@fluentd_lock_dir, name)) if File.fnmatch?("fluentd-*.lock", name) end rescue Errno::ENOENT # Directory is already missing. Fall through and let rmdir below