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

piotr pushed a commit to branch fix_segment_leak
in repository https://gitbox.apache.org/repos/asf/iggy.git

commit 4adf0e00e9435fc0870f7ec9a0aa4e7f2118be59
Author: spetz <[email protected]>
AuthorDate: Thu Feb 5 14:32:21 2026 +0100

    fix(server): memory leak in segment rotation, clear indexes and close 
writers
---
 core/server/src/shard/system/segments.rs | 20 ++++++++++++++++++--
 1 file changed, 18 insertions(+), 2 deletions(-)

diff --git a/core/server/src/shard/system/segments.rs 
b/core/server/src/shard/system/segments.rs
index 38e91fd2d..b805f3da1 100644
--- a/core/server/src/shard/system/segments.rs
+++ b/core/server/src/shard/system/segments.rs
@@ -15,6 +15,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
+use crate::configs::cache_indexes::CacheIndexesConfig;
 use crate::shard::IggyShard;
 use crate::streaming::segments::Segment;
 use iggy_common::IggyError;
@@ -162,14 +163,15 @@ impl IggyShard {
     ) -> Result<(), IggyError> {
         use crate::streaming::segments::storage::create_segment_storage;
 
-        let start_offset = {
+        let (start_offset, old_segment_index) = {
             let mut partitions = self.local_partitions.borrow_mut();
             let partition = partitions
                 .get_mut(namespace)
                 .expect("rotate_segment: partition must exist");
+            let old_segment_index = partition.log.segments().len() - 1;
             let active_segment = partition.log.active_segment_mut();
             active_segment.sealed = true;
-            active_segment.end_offset + 1
+            (active_segment.end_offset + 1, old_segment_index)
         };
 
         let segment = Segment::new(start_offset, 
self.config.system.segment.size);
@@ -187,6 +189,20 @@ impl IggyShard {
 
         let mut partitions = self.local_partitions.borrow_mut();
         if let Some(partition) = partitions.get_mut(namespace) {
+            // Clear old segment's indexes if cache_indexes is not set to All.
+            // This prevents memory accumulation from keeping index buffers 
for sealed segments.
+            if !matches!(
+                self.config.system.segment.cache_indexes,
+                CacheIndexesConfig::All
+            ) {
+                partition.log.indexes_mut()[old_segment_index] = None;
+            }
+
+            // Close writers for the sealed segment - they're never needed 
after sealing.
+            // This releases file handles and associated kernel/io_uring 
resources.
+            let old_storage = &mut 
partition.log.storages_mut()[old_segment_index];
+            let _ = old_storage.shutdown();
+
             partition.log.add_persisted_segment(segment, storage);
             partition.stats.increment_segments_count(1);
             tracing::info!(

Reply via email to