mirror of https://github.com/apache/lucene.git
SOLR-7259: fix thread safety of lazy loaded plugins
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1667431 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
ce472961c9
commit
bf00c1a0a7
|
@ -235,7 +235,7 @@ public class PluginBag<T> implements AutoCloseable {
|
||||||
* subclasses may choose to lazily load the plugin
|
* subclasses may choose to lazily load the plugin
|
||||||
*/
|
*/
|
||||||
public static class PluginHolder<T> implements AutoCloseable {
|
public static class PluginHolder<T> implements AutoCloseable {
|
||||||
protected T inst;
|
private T inst;
|
||||||
protected final PluginInfo pluginInfo;
|
protected final PluginInfo pluginInfo;
|
||||||
|
|
||||||
public PluginHolder(PluginInfo info) {
|
public PluginHolder(PluginInfo info) {
|
||||||
|
@ -257,8 +257,14 @@ public class PluginBag<T> implements AutoCloseable {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws Exception {
|
public void close() throws Exception {
|
||||||
if (inst != null && inst instanceof AutoCloseable) ((AutoCloseable) inst).close();
|
// TODO: there may be a race here. One thread can be creating a plugin
|
||||||
|
// and another thread can come along and close everything (missing the plugin
|
||||||
|
// that is in the state of being created and will probably never have close() called on it).
|
||||||
|
// can close() be called concurrently with other methods?
|
||||||
|
if (isLoaded()) {
|
||||||
|
T myInst = get();
|
||||||
|
if (myInst != null && myInst instanceof AutoCloseable) ((AutoCloseable) myInst).close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getClassName() {
|
public String getClassName() {
|
||||||
|
@ -273,6 +279,7 @@ public class PluginBag<T> implements AutoCloseable {
|
||||||
* the Plugin is initialized and returned.
|
* the Plugin is initialized and returned.
|
||||||
*/
|
*/
|
||||||
public static class LazyPluginHolder<T> extends PluginHolder<T> {
|
public static class LazyPluginHolder<T> extends PluginHolder<T> {
|
||||||
|
private volatile T lazyInst;
|
||||||
private final SolrConfig.SolrPluginInfo pluginMeta;
|
private final SolrConfig.SolrPluginInfo pluginMeta;
|
||||||
protected SolrException solrException;
|
protected SolrException solrException;
|
||||||
private final SolrCore core;
|
private final SolrCore core;
|
||||||
|
@ -294,36 +301,45 @@ public class PluginBag<T> implements AutoCloseable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T get() {
|
public boolean isLoaded() {
|
||||||
if (inst != null) return inst;
|
return lazyInst != null;
|
||||||
if (solrException != null) throw solrException;
|
|
||||||
createInst();
|
|
||||||
registerMBean(inst, core, pluginInfo.name);
|
|
||||||
return inst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized void createInst() {
|
@Override
|
||||||
if (inst != null) return;
|
public T get() {
|
||||||
|
if (lazyInst != null) return lazyInst;
|
||||||
|
if (solrException != null) throw solrException;
|
||||||
|
if (createInst()) {
|
||||||
|
// check if we created the instance to avoid registering it again
|
||||||
|
registerMBean(lazyInst, core, pluginInfo.name);
|
||||||
|
}
|
||||||
|
return lazyInst;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized boolean createInst() {
|
||||||
|
if (lazyInst != null) return false;
|
||||||
log.info("Going to create a new {} with {} ", pluginMeta.tag, pluginInfo.toString());
|
log.info("Going to create a new {} with {} ", pluginMeta.tag, pluginInfo.toString());
|
||||||
if (resourceLoader instanceof MemClassLoader) {
|
if (resourceLoader instanceof MemClassLoader) {
|
||||||
MemClassLoader loader = (MemClassLoader) resourceLoader;
|
MemClassLoader loader = (MemClassLoader) resourceLoader;
|
||||||
loader.loadJars();
|
loader.loadJars();
|
||||||
}
|
}
|
||||||
Class<T> clazz = (Class<T>) pluginMeta.clazz;
|
Class<T> clazz = (Class<T>) pluginMeta.clazz;
|
||||||
inst = core.createInstance(pluginInfo.className, clazz, pluginMeta.tag, null, resourceLoader);
|
T localInst = core.createInstance(pluginInfo.className, clazz, pluginMeta.tag, null, resourceLoader);
|
||||||
initInstance(inst, pluginInfo, core);
|
initInstance(localInst, pluginInfo, core);
|
||||||
if (inst instanceof SolrCoreAware) {
|
if (localInst instanceof SolrCoreAware) {
|
||||||
SolrResourceLoader.assertAwareCompatibility(SolrCoreAware.class, inst);
|
SolrResourceLoader.assertAwareCompatibility(SolrCoreAware.class, localInst);
|
||||||
((SolrCoreAware) inst).inform(core);
|
((SolrCoreAware) localInst).inform(core);
|
||||||
}
|
}
|
||||||
if (inst instanceof ResourceLoaderAware) {
|
if (localInst instanceof ResourceLoaderAware) {
|
||||||
SolrResourceLoader.assertAwareCompatibility(ResourceLoaderAware.class, inst);
|
SolrResourceLoader.assertAwareCompatibility(ResourceLoaderAware.class, localInst);
|
||||||
try {
|
try {
|
||||||
((ResourceLoaderAware) inst).inform(core.getResourceLoader());
|
((ResourceLoaderAware) localInst).inform(core.getResourceLoader());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "error initializing component", e);
|
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "error initializing component", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lazyInst = localInst; // only assign the volatile until after the plugin is completely ready to use
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue