Skip to content

Commit

Permalink
Fix classloading deadlock in analysis factories / AnalysisSPILoader i…
Browse files Browse the repository at this point in the history
…nitialization. This closes #11701 (#11718)
  • Loading branch information
uschindler committed Aug 25, 2022
1 parent 7d824b1 commit 61a8fd6
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 18 deletions.
3 changes: 3 additions & 0 deletions lucene/CHANGES.txt
Expand Up @@ -49,6 +49,9 @@ Bug Fixes

* LUCENE-10644: Facets#getAllChildren testing should ignore child order. (Yuting Gan)

* LUCENE-10665, GITHUB#11701: Fix classloading deadlock in analysis factories / AnalysisSPILoader
initialization. (Uwe Schindler)

Build
---------------------

Expand Down
Expand Up @@ -27,22 +27,39 @@
*/
public abstract class CharFilterFactory extends AbstractAnalysisFactory {

private static final AnalysisSPILoader<CharFilterFactory> loader =
new AnalysisSPILoader<>(CharFilterFactory.class);
/**
* This static holder class prevents classloading deadlock by delaying init of factories until
* needed.
*/
private static final class Holder {
private static final AnalysisSPILoader<CharFilterFactory> LOADER =
new AnalysisSPILoader<>(CharFilterFactory.class);

private Holder() {}

static AnalysisSPILoader<CharFilterFactory> getLoader() {
if (LOADER == null) {
throw new IllegalStateException(
"You tried to lookup a CharFilterFactory by name before all factories could be initialized. "
+ "This likely happens if you call CharFilterFactory#forName from a CharFilterFactory's ctor.");
}
return LOADER;
}
}

/** looks up a charfilter by name from context classpath */
public static CharFilterFactory forName(String name, Map<String, String> args) {
return loader.newInstance(name, args);
return Holder.getLoader().newInstance(name, args);
}

/** looks up a charfilter class by name from context classpath */
public static Class<? extends CharFilterFactory> lookupClass(String name) {
return loader.lookupClass(name);
return Holder.getLoader().lookupClass(name);
}

/** returns a list of all available charfilter names */
public static Set<String> availableCharFilters() {
return loader.availableServices();
return Holder.getLoader().availableServices();
}

/** looks up a SPI name for the specified char filter factory */
Expand All @@ -65,7 +82,7 @@ public static String findSPIName(Class<? extends CharFilterFactory> serviceClass
* given classpath/classloader!</em>
*/
public static void reloadCharFilters(ClassLoader classloader) {
loader.reload(classloader);
Holder.getLoader().reload(classloader);
}

/** Default ctor for compatibility with SPI */
Expand Down
Expand Up @@ -27,22 +27,39 @@
*/
public abstract class TokenFilterFactory extends AbstractAnalysisFactory {

private static final AnalysisSPILoader<TokenFilterFactory> loader =
new AnalysisSPILoader<>(TokenFilterFactory.class);
/**
* This static holder class prevents classloading deadlock by delaying init of factories until
* needed.
*/
private static final class Holder {
private static final AnalysisSPILoader<TokenFilterFactory> LOADER =
new AnalysisSPILoader<>(TokenFilterFactory.class);

private Holder() {}

static AnalysisSPILoader<TokenFilterFactory> getLoader() {
if (LOADER == null) {
throw new IllegalStateException(
"You tried to lookup a TokenFilterFactory by name before all factories could be initialized. "
+ "This likely happens if you call TokenFilterFactory#forName from a TokenFilterFactory's ctor.");
}
return LOADER;
}
}

/** looks up a tokenfilter by name from context classpath */
public static TokenFilterFactory forName(String name, Map<String, String> args) {
return loader.newInstance(name, args);
return Holder.getLoader().newInstance(name, args);
}

/** looks up a tokenfilter class by name from context classpath */
public static Class<? extends TokenFilterFactory> lookupClass(String name) {
return loader.lookupClass(name);
return Holder.getLoader().lookupClass(name);
}

/** returns a list of all available tokenfilter names from context classpath */
public static Set<String> availableTokenFilters() {
return loader.availableServices();
return Holder.getLoader().availableServices();
}

/** looks up a SPI name for the specified token filter factory */
Expand All @@ -65,7 +82,7 @@ public static String findSPIName(Class<? extends TokenFilterFactory> serviceClas
* given classpath/classloader!</em>
*/
public static void reloadTokenFilters(ClassLoader classloader) {
loader.reload(classloader);
Holder.getLoader().reload(classloader);
}

/** Default ctor for compatibility with SPI */
Expand Down
Expand Up @@ -27,22 +27,39 @@
*/
public abstract class TokenizerFactory extends AbstractAnalysisFactory {

private static final AnalysisSPILoader<TokenizerFactory> loader =
new AnalysisSPILoader<>(TokenizerFactory.class);
/**
* This static holder class prevents classloading deadlock by delaying init of factories until
* needed.
*/
private static final class Holder {
private static final AnalysisSPILoader<TokenizerFactory> LOADER =
new AnalysisSPILoader<>(TokenizerFactory.class);

private Holder() {}

static AnalysisSPILoader<TokenizerFactory> getLoader() {
if (LOADER == null) {
throw new IllegalStateException(
"You tried to lookup a TokenizerFactory by name before all factories could be initialized. "
+ "This likely happens if you call TokenizerFactory#forName from a TokenizerFactory ctor.");
}
return LOADER;
}
}

/** looks up a tokenizer by name from context classpath */
public static TokenizerFactory forName(String name, Map<String, String> args) {
return loader.newInstance(name, args);
return Holder.getLoader().newInstance(name, args);
}

/** looks up a tokenizer class by name from context classpath */
public static Class<? extends TokenizerFactory> lookupClass(String name) {
return loader.lookupClass(name);
return Holder.getLoader().lookupClass(name);
}

/** returns a list of all available tokenizer names from context classpath */
public static Set<String> availableTokenizers() {
return loader.availableServices();
return Holder.getLoader().availableServices();
}

/** looks up a SPI name for the specified tokenizer factory */
Expand All @@ -65,7 +82,7 @@ public static String findSPIName(Class<? extends TokenizerFactory> serviceClass)
* given classpath/classloader!</em>
*/
public static void reloadTokenizers(ClassLoader classloader) {
loader.reload(classloader);
Holder.getLoader().reload(classloader);
}

/** Default ctor for compatibility with SPI */
Expand Down

0 comments on commit 61a8fd6

Please sign in to comment.