felix-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From David Jencks <david_jen...@yahoo.com>
Subject Re: More DS concurrency problems
Date Mon, 04 Jun 2012 00:40:48 GMT
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.

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