Proposal: #NonHierarchicalLayers (+ #LayerPrimitives)

Thomas Watson tjwatson at us.ibm.com
Mon Mar 6 16:08:19 UTC 2017


> From: mark.reinhold at oracle.com
> > The addPackage method would be beneficial for other reasons when 
adhering 
> > an existing module system into a JPMS Layer.
> > 
> >  - addPackage would allow existing module systems to avoid aggressive 
> > discovery of all private packages for its own modules when building a 
JPMS 
> > ModuleDescriptor.  For the existing module systems I know about the 
class 
> > loader is used extensively as the module primitive.  Requirements wire 
up 
> > the class loaders for proper class loader delegation and typically the 

> > APIs are declared capabilities to indicate what the modular class 
loaders 
> > can load and expose to another module class loader.  But nowhere was 
it 
> > required to aggressively discover all private packages and resources 
up 
> > front.  Having an addPackage would allow such module systems to grow 
the 
> > list of private packages lazily as it is defining classes in the 
packages 
> > that are private to the module.
> 
> Understood, but for context: I previously suggested that you could use
> the `Private-Package` manifest header added by bndtools, when present,
> in order to avoid scanning a bundle for private packages [1].  In reply
> you wrote that you planned to use that approach for bundles built by
> bndtools, and that "even for the bundles where we have to scan for all
> packages the framework can easily cache the private-package information
> so that upon restart the scan is not needed again" [2].  So, I see how 
an
> `addPackage` method could help OSGi interoperation, but it doesn't 
appear
> to be a hard requirement.
> 
> (As a side note, scanning a JAR file to determine its private packages
>  is pretty fast these days, even without caching.  That's what we do for
>  automatic modules in the JPMS implementation, and so far it hasn't been
>  a significant performance problem.)

The Private-Package cannot be relied on from BND.  A very large number of 
existing bundles are not built with BND.  The option to have 
Private-Package header in BND can be turned off.  In many cases the 
exhaustive scan of the jars will be needed.  As a data point, to scan my 
current Eclipse installation (~360 bundles at well over 310 MB of jars) it 
is taking over 1000 ms to do the full scan (on a pretty new MacBook Pro).

Some optimization may speed this up.  In OSGi the artifact the bundle is 
stored in on disk is abstracted away.  There is no independent way to get 
hold of the jar file directly.  I am using OSGi APIs to do the scanning of 
the bundle wiring.  It is possible this is not as speedy as it can be, but 
the cost will always be measurable and it will linear O(n) with the number 
of bundles installed.  Without caching the results this also pays an 
upfront cost of having to open each and every jar file.  In Equinox we 
delay the opening of the jars until a class or resource is actually going 
to be loaded from the bundle.  This upfront scanning forces us to open all 
installed bundle jars every startup even though no classes or resources 
may be loaded from the jar.

The caching comes with its own price in code complication and performance 
cost to load.  Doing this lazily would greatly simplify this and should 
result in better performance for really large installations.  We have 
common cases with 1000s of bundles installed.


> 
> > - In my prototype I also have a boot strapping issue that addPackage 
would 
> > be helpful for.  In my prototype I have a launcher that assembles a 
module 
> > Layer which then holds the OSGi framework implementation.  In this 
case 
> > the launcher is using Java 9 Layer API and then is loading up a 
standard 
> > OSGi framework implementation using only OSGi standard API.  The 
launcher 
> > then assigns the framework implementation a ModuleDescriptor to 
represent 
> > the OSGi framework.  In OSGi the framework is represented by an OSGi 
> > bundle called the "system.bundle".  So in this case the 
ModuleDescriptor 
> > also has a name "system.bundle".  And the ModuleDescriptor has a well 
> > known list of OSGi APIs it exports.  But the launcher does not know 
the 
> > private implementation packages of the framework implementation.  In 
my 
> > prototype I just hack in the list of private package for the equinox 
> > framework, but this is far from ideal.
> 
> Aren't the solutions for the previous problem also applicable here?  If
> such a launcher must be able to launch an arbitrary OSGi framework
> implementation then can't it use the `Private-Package` manifest header,
> when available, or else scan the framework's bundle for private packages
> and cache that result for later use?

Perhaps, but there is still a complication with system bundle fragments. I 
mentioned this in a past thread about how important it is to support 
dynamic fragment attachment.  In general I don't think there is a large 
number of OSGi users depending on dynamic fragment attachment to normal 
host bundles.  But system bundle fragments are a different story.  These 
are dynamically attached to the framework implementation class loader. 
These require special support by the launcher in order to provide the 
framework the ability to add content to its own class loader.

In fact, this is how my JPMS POC is implemented, in its own system bundle 
framework fragment.  To make this work the list of equinox framework 
packages and the list of packages for framework fragment must be specified 
for the framework module descriptor by the launcher.  For my POC I just 
hardcoded these packages directly into the launcher.  In the general case 
the launcher will not know what framework fragments will be installed 
during the lifetime of the framework instance.  The addPackage and 
addExports method would allow such a launcher to handle when new packages 
are added from a framework fragment.

> 
> A higher-level question is, how important is it for an OSGi-on-JPMS
> launcher to be completely independent of the OSGi framework that it's
> launching?  If every framework provides its own such launcher then, in
> each one, a little bit of build logic could be used to embed a list of
> the system bundle's private packages in the launcher itself, so that
> there's no need to duplicate that list manually.

There are framework independent launchers that only use OSGi APIs (BND 
tools has one such example).  It would be beneficial if these launchers 
could do the right thing when running on JPMS.  The addPackage and 
addExportToAll method would make this possible.

> 
> > I did say that I could live without supporting dynamic attachment of 
> > fragments which provided additional packages.  But I do not want that 
> > compromise from me to justify not adding the method addPackage to the 
> > controller.  I think it would be beneficial to existing module systems 

> > that need to live within a proper JPMS Layer. 
> 
> Understood.
> 
> > It would help to understand what complications addPackage bring to 
JPMS 
> > above the other dynamic add methods already on the Module API and the 
> > others being proposed for the Controller API here.
> 
> My concern is less about how these additional methods would complicate
> JPMS -- although they would -- than about the constraints they would
> place on the future evolution of JPMS, the rest of the platform, and its
> implementations.
> 
> The `addReads` and `addOpens` methods that we've already added to the
> `Layer.Controller` class require essentially the same support from the
> run-time library and the JVM as the corresponding methods in the 
`Module`
> class.  Those methods in the `Module` class are essential to the design,
> so adding them to the `Controller` class presented little risk.
> 
> The same argument can be made for the qualified `addExports` method and
> the `addUses` method, though whether adding just these two methods to 
the
> `Controller` API would benefit anyone is unclear.
> 
> The main problem with the remainder of the proposed methods is that they
> vastly increase the space of situations in which the run-time system 
must
> be prepared to update the definitions of modules.  That can, in turn,
> limit both the space of potential implementations and the bounds of
> practical performance.

I obviously don't know the internal details of the java implementation, I 
can understand your potential concerns.  I do wonder if the performance 
improvements you speak of can still be done in the vast majority of cases 
where the controller is not exposed at all.  The controller is only made 
available when using one of the static defineModule methods on the Layer 
API.  The static defineModule methods are useful for cases where an 
existing module system is trying to adhere their modules into JPMS and the 
additional dynamics are needed by the controller.  But for the typical 
case where it is JPMS only there is no need for the controller at all, so 
you should be able to count on things remaining static.

I say this knowing it does not simplify the spec or RI for the controller 
case, but it should allow for you to optimize the common case more at some 
point.

> 
> The current, internal versions of these methods are used only in limited
> circumstances.  Some are invoked only in the process of instantiating a
> module, and never thereafter.  Others exist only to support white-box
> testing, and are never invoked during normal run-time operations.  These
> limitations on use simplify both the specification and the 
implementation
> of the rest of the system, which can be written under the assumption 
that
> module definitions change in these ways only rarely, if ever.
> 
> To generalize these methods and expose them for use at arbitrary times
> would add complexity to both the specification and the RI, and would 
very
> likely degrade performance.  To make these methods part of the Java SE
> API would -- more importantly -- mandate that all future specifications
> and implementations support such updates to module definitions at
> arbitrary times.
> 
> It is not necessary to expose these methods in order to achieve the goal
> of this JSR.  Designing such low-level primitives via which different
> module systems can interoperate on an intimate basis was never a goal
> of this JSR.  To avoid adding complexity to the specification and its
> implementations in the short term, and to impose as few constraints as
> possible on the evolution of the specification and its implementations
> in the long term, these methods should remain internal.
> 
> - Mark
> 
> 
> [1] http://mail.openjdk.java.net/pipermail/jpms-spec-experts/2016-
> October/000409.html
> [2] http://mail.openjdk.java.net/pipermail/jpms-spec-comments/2016-
> October/000070.html
> 




More information about the jpms-spec-observers mailing list