oscerd opened a new pull request, #739:
URL: https://github.com/apache/camel-karaf/pull/739

   Fixes #734
   
   ## 1. `getDelegate()` could build the registry twice
   
   ```java
   if (delegate == null) {
       ensureTrackerOpen();
       delegate = createRegistry();
   }
   return delegate;
   ```
   
   `delegate` is `volatile`, which makes the *read* safe but does not make the
   check and the assignment atomic. Two threads arriving together on first 
access
   each ran `createRegistry()`; one result was returned and the other silently
   discarded, along with anything registered on it in the interim.
   
   Replaced with double-checked locking against the volatile field, so the
   conversion hot path stays lock-free and first access happens exactly once.
   `removedService` and `addingService` now take the same lock, so the delegate
   cannot be stopped and nulled while another thread is in the middle of handing
   it out.
   
   ## 2. Discarding the delegate was silent
   
   Any single `TypeConverterLoader` going away discards the whole delegate.
   `createRegistry()` replays the core converters plus the loaders the tracker
   currently holds — it *cannot* replay converters added via `addTypeConverter` 
or
   by a Blueprint bean implementing `TypeConverters`. Those vanish from a 
running
   context with nothing logged above `trace`.
   
   `removedService` now logs at WARN naming the bundle whose loader went away 
and
   saying what the rebuild cannot restore. This does not fix the loss, but it 
stops
   it being invisible — which was the actual complaint.
   
   ## What is deliberately *not* changed
   
   The asymmetry with `addingService` is intentional and I have left it alone.
   `d54f9a806` (#625, PR #684) specifically *reverted* invalidate-on-add back to
   loading into the existing delegate, precisely to preserve 
programmatically-added
   converters. Making the two paths symmetric would undo that fix.
   
   Genuinely replaying programmatic registrations on rebuild means recording 
them
   as they are added — a larger design change than this issue warrants. Happy to
   open a separate issue if it is worth doing.
   
   ## Tests
   
   `concurrentFirstAccessShouldBuildTheRegistryOnce` releases 16 threads onto
   `getDelegate()` from a single latch and asserts both that every caller sees 
the
   same instance and that `createRegistry()` ran exactly once (counted via a
   subclass override).
   
   I checked it actually catches the bug rather than just passing: against the
   previous `getDelegate()` it fails **3 out of 3 runs** —
   
   ```
   AssertionFailedError: every caller must see the same registry instance
     ==> expected: <...OsgiDefaultTypeConverter@44cffc25>
          but was: <...OsgiDefaultTypeConverter@2a369e14>
   ```
   
   — and passes 3 out of 3 with the fix, so it pins the behaviour rather than
   being a flaky probe.
   
   ```
   Tests run: 13, Failures: 0, Errors: 0, Skipped: 0
   BUILD SUCCESS
   ```
   
   (all 4 pre-existing `OsgiTypeConverterTest` cases, including
   `addingServiceShouldLoadIntoExistingDelegate` which guards the #625 
behaviour,
   still pass.)
   
   ---
   _Claude Code on behalf of Andrea Cosentino_


-- 
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