[ 
https://issues.apache.org/jira/browse/LUCENE-7870?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16042598#comment-16042598
 ] 

ASF GitHub Bot commented on LUCENE-7870:
----------------------------------------

GitHub user sewe opened a pull request:

    https://github.com/apache/lucene-solr/pull/211

    LUCENE-7870: Use cl.loadClass(...) instead of Class.forName(..., cl)

    Class.forName(..., cl) causes SPIClassIterator to "lock in" the initiating 
class loader, preventing a thread's context class loader from loading different 
classes at different points in time.

You can merge this pull request into a Git repository by running:

    $ git pull https://github.com/sewe/lucene-solr lucene-7870

Alternatively you can review and apply these changes as the patch at:

    https://github.com/apache/lucene-solr/pull/211.patch

To close this pull request, make a commit to your master/trunk branch
with (at least) the following in the commit message:

    This closes #211
    
----
commit 4ef5ee42dfe94771c94ddd6429b5afccd7303ea6
Author: Andreas Sewe <andreas.s...@codetrails.com>
Date:   2017-06-08T12:00:38Z

    LUCENE-7870: Use cl.loadClass(...) instead of Class.forName(..., cl)
    
    Class.forName(..., cl) causes SPIClassIterator to "lock in" the
    initiating class loader, preventing a thread's context class loader from
    loading different classes at different points in time.

----


> Use cl.loadClass(...) instead of Class.forName(..., cl) in SPIClassIterator
> ---------------------------------------------------------------------------
>
>                 Key: LUCENE-7870
>                 URL: https://issues.apache.org/jira/browse/LUCENE-7870
>             Project: Lucene - Core
>          Issue Type: Bug
>    Affects Versions: 5.2.1, 6.1
>         Environment: Eclipse Equinox 4.7
>            Reporter: Andreas Sewe
>
> This issue is initially described in [Eclipse Bug 
> 517935|https://bugs.eclipse.org/bugs/show_bug.cgi?id=517935] and prevents 
> multiple versions of Lucene Core coexisting in an Equinox environment (FYI, 
> Equinox is the OSGi container used by the Eclipse IDE).
> Here’s how the problem manifests: While Equinox cleanly separates two 
> versions of the same Lucene Core bundle (e.g., 
> {{org.apache.lucene.core_5.2.1}} and  {{org.apache.lucene.core_6.1.0}}) using 
> two different bundle class loaders, it uses a single context classloader for 
> all threads: the 
> [{{ContextFinder}}|https://wiki.eclipse.org/Context_Class_Loader_Enhancements#Context_Finder_2].
>  When asked to load a class, the {{ContextFinder}} *initiates* a search 
> through all bundle class loaders currently “on“ the call stack; the class to 
> be loaded is then *defined* by the respective bundle’s class loader.
> And here is where the use of {{Class.forName(..., classLoader)}} rather than 
> {{classLoader.loadClass(...)}} causes problems. Consider the following 
> sequence of events:
> # The {{NamedSPILoader}} of bundle {{o.a.l.core_5.2.1}} (re)loads some 
> service (e.g., the {{Lucene50PostingFormat}}).
> ## It (through {{SPIClassIterator}}) first uses {{Class.forName}} with the 
> bundle class loader of {{o.a.l.core_5.2.1}} (as per LUCENE-4713) to 
> successfully load {{Lucene50PostingFormat}} from the {{o.a.l.core_5.2.1}} 
> bundle.
> ## Then (through another {{SPIClassIterator}}) it uses {{Class.forName}} with 
> the thread’s context class loader (here: {{ContextFinder}}) to load 
> {{Lucene50PostingFormat}}. The {{ContextFinder}} delegates loading to the 
> {{o.a.l.core_5.2.1}} bundle’s class loader, as that bundle is topmost on the 
> call stack. This bundle class loader (again) successfully loads 
> {{Lucene50PostingFormat}} from the {{o.a.l.core_5.2.1}} bundle.
> # Later, the {{NamedSPILoader}} of *another* bundle {{o.a.l.core_6.1.0}} 
> loads the {{Lucene50PostingFormat}} service.
> ## It (through {{SPIClassIterator}}) first uses {{Class.forName}} with the 
> bundle class loader of {{o.a.l.core_6.1.0}} to successfully load 
> {{Lucene50PostingFormat}} from the {{o.a.l.core_6.1.0}} bundle.
> ## Then (through another {{SPIClassIterator}}) it uses {{Class.forName}} with 
> the thread’s context class loader (the same {{ContextFinder}} again) to load 
> {{Lucene50PostingFormat}}. As {{Class.forName}} remembers that the 
> {{ContextFinder}} has successfully initiated the loading of 
> {{Lucene50PostingFormat}} before, it simply returns the {{Class}} instance 
> defined earlier in step _1.2_. But that class was defined by a different 
> bundle class loader, namely that of {{o.a.l.core_5.2.1}}! This cache look up 
> happens in native code; the {{ContextFinder}}‘s {{loadClass}} method isn’t 
> even called, so there’s no way it can load the class from the 
> {{o.a.l.core_6.1.0}} bundle, even though it now is topmost on the stack.
> ## Casting the {{Lucene50PostingFormat}} loading from bundle 
> {{o.a.l.core_5.2.1}} to {{PostingFormat}} from bundle {{o.a.l.core_6.1.0}} 
> then fails, leaving the {{o.a.l.core_6.1.0}} bundle in a broken state.
> It {{SPIClassIterator.next()}} would use {{classLoader.loadClass(...)}} 
> rather than {{Class.forName(..., classLoader}}), then class loading in step 
> _1.2_ wouldn’t *lock in* the {{Lucene50PostingFormat}} class from 
> {{org.apache.lucene.core_5.2.1}}; instead, step _2.2_ would perform a 
> completely independent look up that retrieves the class from the correct 
> bundle. The cast in step _2.3_ would then succeed.
> At Eclipse Orbit, we plan to distribute a [patched 
> version|https://git.eclipse.org/r/98804/] of Lucene Core, but obviously we 
> would like to see the (one-line) change included in the upstream project.
> BTW, if you fear that bypassing {{Class.forName}} “caching” affects 
> performance, then there’s no need to worry: Most {{ClassLoader}} 
> implementations cache as well ({{findLoadedClass}}); it’s only 
> {{ContextFinder}} that [overrides {{loadClass}} 
> wholesale|https://git.eclipse.org/c/equinox/rt.equinox.framework.git/tree/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/framework/ContextFinder.java?h=R4_7_maintenance],
>  as it dynamically (based on the current call stack) delegates to the 
> (caching) bundle class loaders.



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@lucene.apache.org
For additional commands, e-mail: dev-h...@lucene.apache.org

Reply via email to