[
https://issues.apache.org/jira/browse/FELIX-4913?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14572508#comment-14572508
]
Pierre De Rop commented on FELIX-4913:
--------------------------------------
Commited the patch in 1683504.
Now, a hashtable is used to keep track of all invoked callbacks. An
IdentityHashMap is used to make sure that a "change" event will be different
from an "add" event (in case both may refer to the same ServiceReference
instance).
When we invoke a component dependency callback in ComponentImpl, we are now
using the invokeCallbackSafe which won't invoke the same callback twice.
When handleEvent is called, the clearInvokeCallbackCache() method is called at
the end of the method, but this method will only clear the cache of invoked
callbacks if the handleChange is not currently running.
Also added some comments and did some code cleanup.
Removed the handleChange() method call from the startDependencies() method
(this is useless).
> DM Optional callbacks may sometimes be invoked twice
> ----------------------------------------------------
>
> Key: FELIX-4913
> URL: https://issues.apache.org/jira/browse/FELIX-4913
> Project: Felix
> Issue Type: Bug
> Components: Dependency Manager
> Affects Versions: org.apache.felix.dependencymanager-r3
> Reporter: Pierre De Rop
> Assignee: Pierre De Rop
> Fix For: org.apache.felix.dependencymanager-r4
>
>
> The following use case is not currently supported by the DM state machine,
> which suffers from a bug where sometimes, when the use case happens, the same
> optional callback may be invoked twice.
> The following case is supported by DS, so DM should support it, regardless of
> the fact that the design of this use case is arguable/questionable:
> - there is a component B
> - there is a component BFactory (registered in the OSGI registry). And
> BFactory.createB() creates a B instance and simply registers it in the OSGi
> registry.
> - there is a A component that has two OPTIONAL dependencies:
> {code}
> A.bind(BFactory)
> A.bind(B b)
> {code}
> - Then A is created and is starting. Since BFactory is available, the DM
> state machine for A transits from the INSTANTIATED_AND_WAITING_FOR_REQUIRED
> into the TRACKING_OPTIONAL state:
> {code}
> if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED
> && newState == ComponentState.TRACKING_OPTIONAL) {
> invokeAutoConfigInstanceBoundDependencies();
> invokeAddRequiredInstanceBoundDependencies();
> invoke(m_callbackStart);
> invokeAddOptionalDependencies();
> registerService();
> notifyListeners(newState);
> return true;
> }
> {code}
> - then, when the invokeAddOptionalDependencies() is running, it is invoking
> A.bind(BFactory b). At this exact point, the A.bind(BFactory) method calls
> bf.createB():
> {code}
> A.bind(BFactory bf) {
> bf.createB();
> }
> {code}
> - this has the following side effect: a B service is synchronously registered
> in the OSGI service registry. So ComponentImpl.handleAdded() is called, and
> since we are in the
> TRACKING_OPTIONAL state (we are entering into this state), then the A.bindB(B
> b) callback is invoked.
> - BUT ... we are still running in the invokeAddOptionalDependencies() method.
> So when that method is about to iterate on the available services of the B
> dependency, then it calls a
> second time the "A.bind(B)" callback.
> I have a patch for this use case, which I have extensively tested since two
> days.
> To preserve my soul, the patch is simple and conservative: I use the same
> technique that was done in the ConfigurationDependencyImpl class: I'm using a
> cache of callbacks that ensures that the same callback won't be invoked more
> than one time. The advantage of this patch is that it does not make too much
> polutions in the state machine which is not altered too much.
> I will also commit a test case which demonstrates the issue.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)