jbonofre commented on code in PR #739:
URL: https://github.com/apache/camel-karaf/pull/739#discussion_r3872608047


##########
core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/OsgiTypeConverter.java:
##########
@@ -238,10 +314,13 @@ public TypeConverterExists getTypeConverterExists() {
 
     @Override
     public void setTypeConverterExists(TypeConverterExists 
typeConverterExists) {
-        getDelegate().setTypeConverterExists(typeConverterExists);
+        register(TYPE_CONVERTER_EXISTS_KEY, registry -> 
registry.setTypeConverterExists(typeConverterExists));
     }
 
-    public DefaultTypeConverter getDelegate() {
+    // fully synchronized rather than double checked: the delegate is not 
immutable after publication -
+    // removedService stops and replaces it - so a lock free read of the field 
buys a race for no real gain,
+    // conversion work dwarfing an uncontended monitor either way
+    public synchronized DefaultTypeConverter getDelegate() {

Review Comment:
   **Making `getDelegate()` fully synchronized turns the conversion hot path 
into a global serialization point, and blocks every conversion in the container 
for the full duration of a rebuild.**
   
   `convertTo`, `tryConvertTo`, `mandatoryConvertTo`, `lookup`, `allowNull`, 
`size`, `getStatistics` and `getInjector` all funnel through here. Previously 
`delegate` was `volatile` and read without a lock, so the hot path was 
contention-free; now every conversion on every route thread contends one 
monitor (and biased locking is gone as of JDK 15, so it inflates).
   
   The rebuild case is the sharper one: when a single `TypeConverterLoader` 
unregisters, the next `getDelegate()` holds this monitor across `init()` + 
`loadCoreAndFastTypeConverters()` (bundle resource scanning) + `loader.load()` 
for every tracked loader + the replay. Every conversion in the container blocks 
for that whole span. `registrationCannotInterleaveWithARebuild` demonstrates 
precisely this with its 2 s stall.
   
   The comment's "conversion work dwarfing an uncontended monitor" only holds 
while uncontended. Keeping a volatile fast-path read and synchronizing only the 
build gives the same build-once guarantee at no hot-path cost:
   
   ```java
   DefaultTypeConverter d = delegate;
   if (d != null) {
       return d;
   }
   synchronized (this) { ... }
   ```



##########
core/camel-core-osgi/src/main/java/org/apache/camel/karaf/core/OsgiTypeConverter.java:
##########
@@ -238,10 +314,13 @@ public TypeConverterExists getTypeConverterExists() {
 
     @Override
     public void setTypeConverterExists(TypeConverterExists 
typeConverterExists) {
-        getDelegate().setTypeConverterExists(typeConverterExists);
+        register(TYPE_CONVERTER_EXISTS_KEY, registry -> 
registry.setTypeConverterExists(typeConverterExists));
     }
 
-    public DefaultTypeConverter getDelegate() {
+    // fully synchronized rather than double checked: the delegate is not 
immutable after publication -
+    // removedService stops and replaces it - so a lock free read of the field 
buys a race for no real gain,
+    // conversion work dwarfing an uncontended monitor either way
+    public synchronized DefaultTypeConverter getDelegate() {

Review Comment:
   **Making `getDelegate()` fully synchronized turns the conversion hot path 
into a global serialization point, and blocks every conversion in the container 
for the full duration of a rebuild.**
   
   `convertTo`, `tryConvertTo`, `mandatoryConvertTo`, `lookup`, `allowNull`, 
`size`, `getStatistics` and `getInjector` all funnel through here. Previously 
`delegate` was `volatile` and read without a lock, so the hot path was 
contention-free; now every conversion on every route thread contends one 
monitor (and biased locking is gone as of JDK 15, so it inflates).
   
   The rebuild case is the sharper one: when a single `TypeConverterLoader` 
unregisters, the next `getDelegate()` holds this monitor across `init()` + 
`loadCoreAndFastTypeConverters()` (bundle resource scanning) + `loader.load()` 
for every tracked loader + the replay. Every conversion in the container blocks 
for that whole span. `registrationCannotInterleaveWithARebuild` demonstrates 
precisely this with its 2 s stall.
   
   The comment's "conversion work dwarfing an uncontended monitor" only holds 
while uncontended. Keeping a volatile fast-path read and synchronizing only the 
build gives the same build-once guarantee at no hot-path cost:
   
   ```java
   DefaultTypeConverter d = delegate;
   if (d != null) {
       return d;
   }
   synchronized (this) { ... }
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to