[jboss-as7-dev] A strategy for mapping a directed dependency graph with transitives and cycles onto a DAG
Scott Marlow
smarlow at redhat.com
Tue Nov 27 22:24:20 EST 2012
On 11/27/2012 11:22 AM, David M. Lloyd wrote:
> The problem: MSC services must form a DAG. However, in several cases,
> the dependency information we are given is potentially cyclic and may
> also include transitive dependency information.
>
> Currently we deal with cyclic dependencies by using a two-phase
> resolution strategy, however this strategy can only ever encompass one
> level of dependencies and cannot accommodate transitive dependencies at all.
>
> This problem has come up in the following contexts:
>
> 1) EJB JNDI resolution where EJB A injects EJB B, but B in turn depends
> on EJB C: A does not receive a dependency on C though it should have.
>
> 2) Module dependency resolution where a dependency has an export from
> another module. In this case the transitive dependency is also lost.
I understand what you said in this email about (1) but I'm not 100% sure
I'm in sync with you about (2). Are you proposing a MCS change to solve
(2) module dependency resolution?
Also, I'm not sure if you meant "from" like you said in the (2) case.
Should that be where a dependency has an export on another module?
>
> The Two-Phase Solution
> ----------------------
> The two-phase solution works like this:
>
> +---------+ +---------+
> | Item A | | Item B |
> | (Create)| | (Create)|
> | | | |
> +---------+ +-+-------+
> ^ ^ ^
> | +--------+ |
> | | |
> +---+--+--+ +-----+---+
> | Item A | | Item B |
> | (Start) | | (Start) |
> | | | |
> +---------+ +---------+
>
> In this example A has a dependency on B. In the create phase, we
> ascertain what the dependencies are for a given item. In the start
> phase we establish dependencies on all of the create-phase services of
> our dependencies.
>
> The problem with this solution has been outlined above.
>
> The Three-Phase Solution
> ------------------------
> Superficially, it would seem that the problems associated with the
> two-phase solution can be resolved by the use of three phases. The
> initial phase would encapsulate the list of dependencies; the second
> phase would depend on the immediate dependencies and would encapsulate
> the set of immediate dependencies plus their immediate dependencies; and
> the third phase would come up only when all these dependencies are up.
>
> For cases where there is no concept of transitivity, this may suffice.
> However it is the case in AS now where both the modules/class-path use
> case and the JNDI @Resource case do indeed include the concept of
> transitivity.
>
> The N-Phase Solution
> --------------------
> The only way to ensure that some arbitrary set of transitive
> dependencies is available is by using a self-configuring N-phase
> mechanism. The way this works is as follows.
>
> 1. We create a Create-phase service as today, which encodes as part of
> its value the set of immediate dependencies. This would include the
> following behavior (pseudo-code):
>
> void start() {
> dependencies = immediate declared deps of this service
> if (dependencies is not empty) {
> create child service "resolver1";
> for each (d in dependencies) {
> add create phase of d to "resolver1" as dependency
> }
> } else {
> create child service "start";
> }
> }
>
> 2. Each resolver service has the following behavior:
>
> void start() {
> dependencies = set of all injected create-phase services
> if (dependencies is not empty) {
> create child service "resolver" + (n + 1);
> for each (d in dependencies) {
> for each (t in d.dependencies) {
> add create phase of t to "resolver" + (n + 1);
> }
> }
> } else {
> create child service "start";
> }
> }
>
> This way, we retain the exact service structure we have today. From an
> outside perspective the *create/*start services act just as they always
> have, except they accommodate transitive dependencies correctly by way
> of the "private" resolver dependencies.
>
> This solution also has the advantage that it only creates as many
> services as necessary to resolve all transitive dependencies.
>
> Optimization
> ------------
> Because the transitive closure of services can be pretty hefty *and* may
> contain cycles, a good optimization would be to maintain a set of
> create-phase services that we've already depended on which we pass from
> resolver to resolver to ensure that we don't bother with redundant or
> cyclic dependencies.
>
> Not Solved
> ----------
> This solution does not address the problem where a dependency actually
> fails to start. Assuming there is no @DependsOn to establish a direct
> acyclic dependency, the service will still start, but any attempt to use
> a failed dependency will in turn result in a failure just like today.
>
More information about the jboss-as7-dev
mailing list