Fix classloading deadlock in analysis factories / AnalysisSPILoader initialization. This closes #11701 (#11718)

This commit is contained in:
Uwe Schindler 2022-08-25 18:16:04 +02:00 committed by GitHub
parent 53b1ce7504
commit 1d54299011
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 72 additions and 18 deletions

View File

@ -124,6 +124,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
---------------------

View File

@ -27,22 +27,39 @@ import java.util.Set;
*/
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 */
@ -65,7 +82,7 @@ public abstract class CharFilterFactory extends AbstractAnalysisFactory {
* given classpath/classloader!</em>
*/
public static void reloadCharFilters(ClassLoader classloader) {
loader.reload(classloader);
Holder.getLoader().reload(classloader);
}
/** Default ctor for compatibility with SPI */

View File

@ -27,22 +27,39 @@ import java.util.Set;
*/
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 */
@ -65,7 +82,7 @@ public abstract class TokenFilterFactory extends AbstractAnalysisFactory {
* given classpath/classloader!</em>
*/
public static void reloadTokenFilters(ClassLoader classloader) {
loader.reload(classloader);
Holder.getLoader().reload(classloader);
}
/** Default ctor for compatibility with SPI */

View File

@ -27,22 +27,39 @@ import org.apache.lucene.util.AttributeFactory;
*/
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 */
@ -65,7 +82,7 @@ public abstract class TokenizerFactory extends AbstractAnalysisFactory {
* given classpath/classloader!</em>
*/
public static void reloadTokenizers(ClassLoader classloader) {
loader.reload(classloader);
Holder.getLoader().reload(classloader);
}
/** Default ctor for compatibility with SPI */