You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2025/05/01 09:31:57 UTC
(aries-typedevent) branch maint/1.0.x created (now cceb0d8)
This is an automated email from the ASF dual-hosted git repository.
timothyjward pushed a change to branch maint/1.0.x
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git
at cceb0d8 BACKPORT - Improve conversion performance for Record to Map
This branch includes the following new commits:
new 3ff27a2 BACKPORT - Correctly handle mapping records with null components to Maps
new 6417347 BACKPORT - Use trace statements for main-path event conversion and monitoring
new cceb0d8 BACKPORT - Improve conversion performance for Record to Map
The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
(aries-typedevent) 03/03: BACKPORT - Improve conversion performance for Record to Map
Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
timothyjward pushed a commit to branch maint/1.0.x
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git
commit cceb0d877426456dd0a4ed04189369352c49548c
Author: Tim Ward <ti...@apache.org>
AuthorDate: Thu May 1 10:09:23 2025 +0100
BACKPORT - Improve conversion performance for Record to Map
This is a common transformation as all events are converted to Maps for monitoring. Records will typically have a small number of components and we can reduce the overhead of each Map by setting the capacity and load factor properly.
Signed-off-by: Tim Ward <ti...@apache.org>
---
.../java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java b/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java
index fd7756f..4eadc0d 100644
--- a/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java
+++ b/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java
@@ -61,7 +61,8 @@ public class RecordConverter {
}
return createRecord(clz, args, argTypes);
} else {
- Map<String, Object> converted = new HashMap<>(sourceComponents.length);
+ // Avoid rehashing on insertion and reduce the iteration overhead of empty buckets
+ Map<String, Object> converted = new HashMap<>((int) (sourceComponents.length / 0.9f + 1.0f), 0.9f);
for(RecordComponent rc : sourceComponents) {
converted.put(rc.getName(), getComponentValue(rc, o));
}
(aries-typedevent) 02/03: BACKPORT - Use trace statements for main-path event conversion and monitoring
Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
timothyjward pushed a commit to branch maint/1.0.x
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git
commit 64173479843be7ce780be42e65b218ae2a3796ea
Author: Tim Ward <ti...@apache.org>
AuthorDate: Mon Apr 7 16:42:54 2025 +0100
BACKPORT - Use trace statements for main-path event conversion and monitoring
The main path through the event bus is heavily used and results in huge amounts of logging. This is too much even for debug level, and so we are moving these log messages to TRACE so that they aren't written unless a user really needs them.
Signed-off-by: Tim Ward <ti...@apache.org>
---
.../java/org/apache/aries/typedevent/bus/impl/EventConverter.java | 4 ++--
.../java/org/apache/aries/typedevent/bus/impl/MonitorEventTask.java | 6 +++---
2 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/EventConverter.java b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/EventConverter.java
index 5add133..ef8a9e3 100644
--- a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/EventConverter.java
+++ b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/EventConverter.java
@@ -286,8 +286,8 @@ public class EventConverter {
return untypedEventDataForFiltering;
}
} else {
- if(_log.isDebugEnabled()) {
- _log.debug("Converting {} to untyped data", originalEvent);
+ if(_log.isTraceEnabled()) {
+ _log.trace("Converting {} to untyped data", originalEvent);
}
untypedEventDataForFiltering = eventConverter.convert(originalEvent).sourceAsDTO().to(MAP_WITH_STRING_KEYS);
}
diff --git a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/MonitorEventTask.java b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/MonitorEventTask.java
index 93e0dc2..3ea41db 100644
--- a/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/MonitorEventTask.java
+++ b/org.apache.aries.typedevent.bus/src/main/java/org/apache/aries/typedevent/bus/impl/MonitorEventTask.java
@@ -36,9 +36,9 @@ class MonitorEventTask extends EventTask {
}
@Override
- protected void unsafeNotify() {
- if(_log.isDebugEnabled()) {
- _log.debug("Distributing event to the event monitor");
+ protected void unsafeNotify() throws Exception {
+ if(_log.isTraceEnabled()) {
+ _log.trace("Distributing event to the event monitor");
}
monitorImpl.event(eventType, eventData.toUntypedEvent());
}
(aries-typedevent) 01/03: BACKPORT - Correctly handle mapping records with null components to Maps
Posted by ti...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
timothyjward pushed a commit to branch maint/1.0.x
in repository https://gitbox.apache.org/repos/asf/aries-typedevent.git
commit 3ff27a24a84a4bbec1bed098e0f0684a35c19022
Author: Tim Ward <ti...@apache.org>
AuthorDate: Mon Apr 7 16:40:56 2025 +0100
BACKPORT - Correctly handle mapping records with null components to Maps
Simply streaming the record components into a Map would throw an NPE when the record component's value was null. This is something that is permitted in a record and so we must use a null-safe way of populating the Map.
Signed-off-by: Tim Ward <ti...@apache.org>
---
.../aries/typedevent/bus/impl/RecordConverter.java | 7 +-
.../bus/osgi/AbstractIntegrationTest.java | 7 +-
.../typedevent/bus/osgi/RecordIntegrationTest.java | 77 ++++++++++++++++++++++
3 files changed, 86 insertions(+), 5 deletions(-)
diff --git a/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java b/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java
index 1e32c3c..fd7756f 100644
--- a/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java
+++ b/org.apache.aries.typedevent.bus/src/main/java16/org/apache/aries/typedevent/bus/impl/RecordConverter.java
@@ -22,6 +22,7 @@ import static java.util.stream.Collectors.toMap;
import java.lang.reflect.RecordComponent;
import java.lang.reflect.Type;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Map;
import org.osgi.util.converter.ConversionException;
@@ -60,8 +61,10 @@ public class RecordConverter {
}
return createRecord(clz, args, argTypes);
} else {
- Map<String, Object> converted = Arrays.stream(sourceComponents)
- .collect(toMap(RecordComponent::getName, rc -> getComponentValue(rc, o)));
+ Map<String, Object> converted = new HashMap<>(sourceComponents.length);
+ for(RecordComponent rc : sourceComponents) {
+ converted.put(rc.getName(), getComponentValue(rc, o));
+ }
return converter.convert(converted).to(target);
}
diff --git a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/AbstractIntegrationTest.java b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/AbstractIntegrationTest.java
index 81cd6d2..f624d46 100644
--- a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/AbstractIntegrationTest.java
+++ b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/AbstractIntegrationTest.java
@@ -19,6 +19,7 @@ package org.apache.aries.typedevent.bus.osgi;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import org.apache.aries.typedevent.bus.common.TestEvent;
import org.apache.aries.typedevent.bus.common.TestEvent2;
@@ -55,7 +56,7 @@ public abstract class AbstractIntegrationTest {
@Override
public boolean matches(TestEvent argument) {
- return message.equals(argument.message);
+ return argument != null && Objects.equals(message, argument.message);
}
};
}
@@ -65,7 +66,7 @@ public abstract class AbstractIntegrationTest {
@Override
public boolean matches(TestEvent2 argument) {
- return message.equals(argument.subEvent.message);
+ return argument != null && Objects.equals(message, argument.subEvent.message);
}
};
}
@@ -75,7 +76,7 @@ public abstract class AbstractIntegrationTest {
@Override
public boolean matches(Map<String, Object> argument) {
- return argument != null && message.equals(argument.get("message"));
+ return argument != null && Objects.equals(message, argument.get("message"));
}
};
}
diff --git a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/RecordIntegrationTest.java b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/RecordIntegrationTest.java
index 8b5d69d..32d493c 100644
--- a/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/RecordIntegrationTest.java
+++ b/org.apache.aries.typedevent.bus/src/test/java/org/apache/aries/typedevent/bus/osgi/RecordIntegrationTest.java
@@ -33,6 +33,7 @@ import org.mockito.junit.jupiter.MockitoExtension;
import org.osgi.framework.BundleContext;
import org.osgi.service.typedevent.TypedEventBus;
import org.osgi.service.typedevent.TypedEventHandler;
+import org.osgi.service.typedevent.UntypedEventHandler;
import org.osgi.test.common.annotation.InjectBundleContext;
import org.osgi.test.common.annotation.InjectService;
import org.osgi.test.junit5.context.BundleContextExtension;
@@ -64,6 +65,9 @@ public class RecordIntegrationTest extends AbstractIntegrationTest {
@Mock
TestRecordListener recordEventHandler;
+ @Mock
+ UntypedEventHandler untypedEventHandler;
+
@Test
public void testUnFilteredListenerEventToRecord() throws Exception {
Dictionary<String, Object> props = new Hashtable<>();
@@ -140,6 +144,42 @@ public class RecordIntegrationTest extends AbstractIntegrationTest {
}
+ @Test
+ public void testUnFilteredListenerRecordToMap() throws Exception {
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put(TYPED_EVENT_TOPICS, TOPIC);
+
+ regs.add(context.registerService(TypedEventHandler.class, typedEventHandler, props));
+
+ props = new Hashtable<>();
+ props.put(TYPED_EVENT_TOPICS, TOPIC);
+
+ regs.add(context.registerService(UntypedEventHandler.class, untypedEventHandler, props));
+
+ // Record to Map
+ TestRecord2 testRecord2 = new TestRecord2("foobar", 5);
+
+ eventBus.deliver(TOPIC, testRecord2);
+
+ Mockito.verify(typedEventHandler, Mockito.timeout(1000))
+ .notify(Mockito.eq(TOPIC), Mockito.argThat(isTestEventWithMessage("foobar")));
+
+ Mockito.verify(untypedEventHandler, Mockito.timeout(1000))
+ .notifyUntyped(Mockito.eq(TOPIC), Mockito.argThat(isUntypedTestEventWithMessage("foobar")));
+
+ // Record to Map with null
+ testRecord2 = new TestRecord2(null, 5);
+
+ eventBus.deliver(TOPIC, testRecord2);
+
+ Mockito.verify(typedEventHandler, Mockito.timeout(1000))
+ .notify(Mockito.eq(TOPIC), Mockito.argThat(isTestEventWithMessage(null)));
+
+ Mockito.verify(untypedEventHandler, Mockito.timeout(1000))
+ .notifyUntyped(Mockito.eq(TOPIC), Mockito.argThat(isUntypedTestEventWithMessage(null)));
+
+ }
+
@Test
public void testFilteredListenerEventToRecord() throws Exception {
Dictionary<String, Object> props = new Hashtable<>();
@@ -253,6 +293,43 @@ public class RecordIntegrationTest extends AbstractIntegrationTest {
Mockito.verify(typedEventHandler, Mockito.after(1000).never())
.notify(Mockito.eq(TOPIC), Mockito.argThat(isTestEventWithMessage("bar")));
}
+
+ @Test
+ public void testFilteredListenerRecordToMap() throws Exception {
+ Dictionary<String, Object> props = new Hashtable<>();
+ props.put(TYPED_EVENT_FILTER, "(message=foo)");
+ props.put(TYPED_EVENT_TOPICS, TOPIC);
+
+ regs.add(context.registerService(TypedEventHandler.class, typedEventHandler, props));
+
+ props = new Hashtable<>();
+ props.put(TYPED_EVENT_FILTER, "(message=bar)");
+ props.put(TYPED_EVENT_TOPICS, TOPIC);
+
+ regs.add(context.registerService(UntypedEventHandler.class, untypedEventHandler, props));
+
+ // Record to Record
+ TestRecord2 testRecord2 = new TestRecord2("foo", 5);
+
+ eventBus.deliver(TOPIC, testRecord2);
+
+ Mockito.verify(typedEventHandler, Mockito.timeout(1000))
+ .notify(Mockito.eq(TOPIC), Mockito.argThat(isTestEventWithMessage("foo")));
+
+ Mockito.verify(untypedEventHandler, Mockito.after(1000).never())
+ .notifyUntyped(Mockito.eq(TOPIC), Mockito.argThat(isUntypedTestEventWithMessage("foo")));
+
+
+ testRecord2 = new TestRecord2("bar", 5);
+
+ eventBus.deliver(TOPIC, testRecord2);
+
+ Mockito.verify(untypedEventHandler, Mockito.timeout(1000))
+ .notifyUntyped(Mockito.eq(TOPIC), Mockito.argThat(isUntypedTestEventWithMessage("bar")));
+
+ Mockito.verify(typedEventHandler, Mockito.after(1000).never())
+ .notify(Mockito.eq(TOPIC), Mockito.argThat(isTestEventWithMessage("bar")));
+ }
public interface TestRecordListener extends TypedEventHandler<TestRecord> {}