felix-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Felix Meschberger <fmesc...@adobe.com>
Subject Re: More DS concurrency problems
Date Tue, 05 Jun 2012 12:11:39 GMT

I fear we are getting on the "ever-and-ever-more-complex" track ...

I understand the concurrency issues (how the come into live) but I would love if we could
solve them with simple code without inventing more and more locking and and signaling etc.
behaviour. This really was the "beauty of some sorts" of the previous lock-less approach.

I think under certain circumstances there will always be a situation where one event (service
or configuration) is happening while at the same time another event is being handled. In some
situations -- e.g. a required dependency being unregistered while requiring the component
is being activated -- the ongoing task should probably be aborted and reverted. Which in turn
may be simpler (before service registration) or harder (during service registration).

This can maybe be solved by using checkpoints: Long running tasks (mostly activation) after
each step check the checkpoint while intermittent events (service, configuration) may set
the checkpoint and optionally wait for the checkpoint to be confirmed by the long-running
task (eventually timing out to prevent deadlocks). Such a thing would be "easier" to implement
with an Activating state where just the Activating.deactivate method might be called which
would handle the checkpoint thing.

Do I sound getting complicated ? ;-)


Am 04.06.2012 um 02:40 schrieb David Jencks:

> A colleague suggested using a read-write lock might work.  I may not understand his proposal:
I think he's suggesting a write lock around code that change the state and read lock around
code that doesn't.
> I'm not sure how this would help.  I think we'd need the write lock around the code that
determines that a bind satisfies a component, downgraded to a read lock while the service
is registered.  Then we'd need a write lock on the code that creates the component instance
so we only get one instance.
> In the picture below, thread one will publish the service registration inside a read
lock on C.  Thread 2 will have a write lock on B since it's trying to create the component
instance (B is delayed), blocking thread 1.  In thread 2, B will try to get a write lock on
C to create the instance of C (C is also delayed).  (Note that B knows of C because felix
ds doesn't use the service events to track which services are available, it uses them to trigger
querying for services for binding).
> So here are a couple more lock ideas.
> 1. read-write lock for binding events and state change and a separate plain lock for
creating the component instance object.  All the locks in thread 1 are read-write, all the
locks in thread 2 are plain.  While there's nothing stopping the B service from being unregistered
in a third thread while thread 2 is creating the implementation object, at least A will be
notified in thread 3 that B is no longer available.  Keeping B consistent could be trickier.
> 2. tracking dependent services using events and never querying for services.  This would
mean in thread 2 B would not know about C since the event in thread 1 could not be delivered
until after the lock on B was released.  I'm not sure how to get an accurate initial list
of services with no possibility that we're about to get an event for one of those services.
 I guess this is similar to the problem ServiceTracker is supposed to solve.
> I think one of the effects of the non-blocking model I'm thinking of is that for a given
component, several service registrations and several service instances may briefly be present.
 However the extra ones should disappear quickly as the thread involved discovers it didn't
"win".  This is similar to the situation in the 2-locks scenario in (1) above.
> thanks
> david jencks
> On Jun 3, 2012, at 11:21 AM, David Jencks wrote:
>> We found another DS deadlock with the current locking concurrency solution.
>> When we start, B is registered (its dependencies are optional) but not yet created
(it's delayed)
>> Thread 1 creates and registers D so service registration and bind attempts propagate
right to left <<<<<< starting with D.  Thread 1 obtains the lock on C and
tries to get the lock on B
>>    A  ---- 1..1 -----> B -------0..n -------> C  --------- 1..1 ------->D
>> immediate         delayed                 delayed                       not a ds
>> Thread 2 going left to right >>>>>>> creates A which calls getService
on B (obtaining the B lock) which calls getService on C which is locked by thread 1.
>> I'm considering two possible approaches:
>> 1. dont lock or don't lock as much for events that don't change the state (the C
to B service event: B can't change state as a result)
>> 2. a lock-free implementation using compare-and-set.  The idea is that an event such
as a service event would get processed using a holder.  If at the completion of the processing
the previous holder is the same then we'd compare-and-set the holder, otherwise undo whatever
happened during processing.
>> (2) could result in multiple service registrations for a given component while the
events are getting processed.  It's not completely obvious to me how to assure that all events
will in fact get processed and that e.g the "winning" result will have all the highest-priority
service references and that there won't be infinite update cycles.
>> On the other hand I have no confidence that (1) is possible to implement.  So I'm
going to try for (2).  This is going to reopen the "how does it run on java < 5" debate
since compare-and-set is not available there with the same characteristics of the java 5 implementation.
>> In the interests of making more code paths more consistent and similar I think I
will change the immediate component handling to be as the spec describes, where the service
is registered before the implementation object is created.  This means all the services will
be registered as service factories as the delayed components currently are.
>> In other DS issues:
>> I'd like to separate the felix specific non-spec ComponentFactory behavior (where
it acts like a ManagedServiceFactory) into a separate class so I can understand the spec compliant
behavior more easily.
>> I think that the behavior of ServiceFactory components that are configured by config
admin is wrong.  AFAICT for service factory components we will never call a modify method
but always destroy and recreate the instances.
>> I also have a few cleanup changes such as better javadoc and removing stray references
to no-longer-present *ing transient states that I don't think will be controversial so I plan
to just commit them.
>> thanks
>> david jencks

View raw message