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

timothyjward pushed a commit to branch fix-jira-2195
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git

commit 2c4946240f414b3dac044eb6c7acf08b9613e540
Author: Tim Ward <[email protected]>
AuthorDate: Thu Dec 4 11:02:27 2025 +0100

    [aries-typedevent] Fix for ARIES-2195 - Avoid OOM in history configuration
    
    This commit adds tests contributed by Guido Grune and fixes the issue where 
policies with a defined minimum and large maximum could trigger an OOM. The 
simple fix is to limit the maximum storage using the overall maximum number of 
events that the history is permitted to store. This may still waste memory if 
there are many different policies set with large maximums and a large total 
history capacity, but this can be managed by users selecting appropriate 
policies and overall capacities.
    
    Signed-off-by: Tim Ward <[email protected]>
---
 .../typedevent/bus/impl/TypedEventMonitorImpl.java |  2 +-
 .../bus/impl/TypedEventMonitorImplTest.java        | 75 ++++++++++++++++++++++
 2 files changed, 76 insertions(+), 1 deletion(-)

diff --git 
a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImpl.java
 
b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImpl.java
index 71762c8..8a245ff 100644
--- 
a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImpl.java
+++ 
b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImpl.java
@@ -370,7 +370,7 @@ public class TypedEventMonitorImpl implements 
TypedEventMonitor {
        }
 
        private void updateRestrictedHistory(String topicFilter, int 
minRequired, int maxRequired) {
-               TopicHistory newHistory = new TopicHistory(minRequired, 
maxRequired);
+               TopicHistory newHistory = new TopicHistory(minRequired, 
Math.min(historySize, maxRequired));
                TopicHistory oldHistory = 
topicsWithRestrictedHistories.put(topicFilter, newHistory);
                if(oldHistory != null) {
                        List<MonitorEvent> toRemove = 
newHistory.copyFrom(oldHistory);
diff --git 
a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImplTest.java
 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImplTest.java
new file mode 100644
index 0000000..65ae3c4
--- /dev/null
+++ 
b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/impl/TypedEventMonitorImplTest.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.aries.typedevent.bus.impl;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Collections;
+import java.util.Map;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.osgi.service.typedevent.monitor.RangePolicy;
+
+@ExtendWith(MockitoExtension.class)
+public class TypedEventMonitorImplTest {
+
+    private static final String TOPIC = "a/b/c";
+       TypedEventMonitorImpl monitorImpl;
+
+    @BeforeEach
+    public void start() throws ClassNotFoundException {
+        Map<String, Object> config = Collections.emptyMap();
+        
+        monitorImpl = new TypedEventMonitorImpl(config);
+    }
+    
+    @AfterEach
+    public void stop() throws Exception {
+        monitorImpl.destroy();
+    }
+
+    /**
+     * Tests that events are delivered to Smart Behaviours based on type
+     * 
+     * @throws InterruptedException
+     */
+    @Test
+    public void testConfigureHistoryStorage() throws InterruptedException {
+        checkRangeConfiguration(RangePolicy.unlimited());
+        checkRangeConfiguration(RangePolicy.atLeast(0));
+        checkRangeConfiguration(RangePolicy.range(0,Integer.MAX_VALUE));
+        checkRangeConfiguration(RangePolicy.atLeast(10));
+        checkRangeConfiguration(RangePolicy.range(1,Integer.MAX_VALUE));
+
+    }
+
+       private void checkRangeConfiguration(final RangePolicy policy) {
+               monitorImpl.configureHistoryStorage(TOPIC, policy);
+               RangePolicy configured = 
monitorImpl.getConfiguredHistoryStorage(TOPIC);
+               assertEquals(policy.getMinimum(), configured.getMinimum());
+               assertEquals(policy.getMaximum(), configured.getMaximum());
+               RangePolicy effective = 
monitorImpl.getConfiguredHistoryStorage(TOPIC);
+               assertEquals(effective.getMinimum(), effective.getMinimum());
+               assertEquals(policy.getMaximum(), effective.getMaximum());
+       }
+
+}

Reply via email to