apache / apache/lucene

Problem with SPI components (e.g., AnalysisSPILoader) when refreshing from different classloader and closing previous classloader

Open
#13,101 4 comments 0 reactions 1 assignee Claimed by @uschindler View on GitHub
type:bug
Dominant language
Java
Stars
3.6k
Forks
1.4k
Avg merge
2d 11h
Merged PRs (30d)
88

Description

### Description

Applications like Solr allow users to reference token filters, tokenizers, etc. by their SPI names - and Lucene provides utility methods to discover and load these services.

The discovery relies on `AnalysisSPILoader#reload(ClassLoader)` method which scans the provided classloader's classpath, and loads and caches available services.

However, if this method is called again (with a different classloader), it makes no attempt to invalidate the cache of available services.

**This means that if:**
- the cache already contains a mapping `"myservice" -> org.example.MyServiceFactory`, where MyServiceFactory class was defined by classloader1,
- the `reload` method is called again with classloader2, so that
- `"myservice"` is discovered again
- `MyServiceFactory` class is defined again (but by classloader2)

**then:**
- the `AnalysisSPILoader` cache will retain the `MyServiceFactory` class defined by classloader1 (and not classloader2).

This behavior places restrictions on how the applications can reload the SPI - and it does not work well with how Solr manages the lifecycle of its classloaders.

### Specific example

Basically, whenever Solr adds jars to classpath at runtime, it replaces its current classloader with a new instance of URLClassLoader, closes the old classloader, and reloads the SPI.

So this may lead to a situation where the AnalysisSPILoader cache keeps a reference to `MyServiceFactory` class that was defined by classloader1 (which is now closed because Solr closed it and switched to classloader2).

As a result, when the application code retrieves `MyServiceFactory` by its SPI name, and the factory executes code which requires loading some other class from classloader1's classpath - the loading fails because Solr already invoked `((URLClassLoader) classloader1).close()`.

And from users's perspective, this issue manifests in rather cryptic `ClassNotFoundException`.

### Version and environment details

Lucene 9.8.0

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.