SOLR-14155: Load all other SolrCore plugins from packages (#1666)

This commit is contained in:
Noble Paul 2021-01-13 22:28:01 +11:00 committed by GitHub
parent 7a301c736c
commit 9466af576a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 403 additions and 112 deletions

View File

@ -249,6 +249,8 @@ Improvements
* SOLR-15040: Improvements to postlogs timestamp handling (Joel Bernstein)
* SOLR-14155: Load all other SolrCore plugins from packages (noble)
Optimizations
---------------------
* SOLR-14975: Optimize CoreContainer.getAllCoreNames, getLoadedCoreNames and getCoreDescriptors. (Bruno Roustant)

View File

@ -419,7 +419,7 @@ public abstract class DirectoryFactory implements NamedListInitializedPlugin,
final DirectoryFactory dirFactory;
if (info != null) {
log.debug(info.className);
dirFactory = config.getResourceLoader().newInstance(info.className, DirectoryFactory.class);
dirFactory = config.getResourceLoader().newInstance (info, DirectoryFactory.class, true);
// allow DirectoryFactory instances to access the CoreContainer
dirFactory.initCoreContainer(cc);
dirFactory.init(info.initArgs);

View File

@ -396,7 +396,6 @@ public class PluginBag<T> implements AutoCloseable {
if (pluginInfo != null) return pluginInfo.className;
return null;
}
public PluginInfo getPluginInfo() {
return pluginInfo;
}

View File

@ -755,7 +755,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
IndexReaderFactory indexReaderFactory;
PluginInfo info = solrConfig.getPluginInfo(IndexReaderFactory.class.getName());
if (info != null) {
indexReaderFactory = resourceLoader.newInstance(info.className, IndexReaderFactory.class);
indexReaderFactory = resourceLoader.newInstance(info, IndexReaderFactory.class, true);
indexReaderFactory.init(info.initArgs);
} else {
indexReaderFactory = new StandardIndexReaderFactory();
@ -955,6 +955,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
this.solrConfig = configSet.getSolrConfig();
this.resourceLoader = configSet.getSolrConfig().getResourceLoader();
this.resourceLoader.initCore(this);
IndexSchema schema = configSet.getIndexSchema();
this.configSetProperties = configSet.getProperties();
@ -1405,7 +1406,7 @@ public final class SolrCore implements SolrInfoBean, Closeable {
final PluginInfo info = solrConfig.getPluginInfo(CodecFactory.class.getName());
final CodecFactory factory;
if (info != null) {
factory = resourceLoader.newInstance(info.className, CodecFactory.class);
factory = resourceLoader.newInstance( info, CodecFactory.class, true);
factory.init(info.initArgs);
} else {
factory = new CodecFactory() {
@ -1443,8 +1444,8 @@ public final class SolrCore implements SolrInfoBean, Closeable {
final StatsCache cache;
PluginInfo pluginInfo = solrConfig.getPluginInfo(StatsCache.class.getName());
if (pluginInfo != null && pluginInfo.className != null && pluginInfo.className.length() > 0) {
cache = createInitInstance(pluginInfo, StatsCache.class, null,
LocalStatsCache.class.getName());
cache = resourceLoader.newInstance( pluginInfo, StatsCache.class, true);
initPlugin(pluginInfo ,cache);
if (log.isDebugEnabled()) {
log.debug("Using statsCache impl: {}", cache.getClass().getName());
}
@ -3280,6 +3281,9 @@ public final class SolrCore implements SolrInfoBean, Closeable {
this.coreName = coreName;
this.coreId = coreId;
}
public void reload() {
coreContainer.reload(coreName, coreId);
}
public void withCore(Consumer<SolrCore> r) {
try(SolrCore core = coreContainer.getCore(coreName, coreId)) {

View File

@ -42,6 +42,7 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -64,6 +65,7 @@ import org.apache.solr.handler.component.SearchComponent;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.logging.DeprecationLog;
import org.apache.solr.pkg.PackageListeningClassLoader;
import org.apache.solr.pkg.PackageLoader;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.rest.RestManager;
@ -100,6 +102,7 @@ public class SolrResourceLoader implements ResourceLoader, Closeable, SolrClassL
private CoreContainer coreContainer;
private PackageListeningClassLoader schemaLoader ;
private PackageListeningClassLoader coreReloadingClassLoader ;
private final List<SolrCoreAware> waitingForCore = Collections.synchronizedList(new ArrayList<SolrCoreAware>());
private final List<SolrInfoBean> infoMBeans = Collections.synchronizedList(new ArrayList<SolrInfoBean>());
private final List<ResourceLoaderAware> waitingForResources = Collections.synchronizedList(new ArrayList<ResourceLoaderAware>());
@ -645,15 +648,29 @@ public class SolrResourceLoader implements ResourceLoader, Closeable, SolrClassL
}
}
void initCore(SolrCore core) {
this.coreName = core.getName();
this.config = core.getSolrConfig();
this.coreId = core.uniqueId;
this.coreContainer = core.getCoreContainer();
SolrCore.Provider coreProvider = core.coreProvider;
this.coreReloadingClassLoader = new PackageListeningClassLoader(core.getCoreContainer(),
this, s -> config.maxPackageVersion(s), null){
@Override
protected void doReloadAction(Ctx ctx) {
log.info("Core reloading classloader issued reload for: {}/{} ", coreName, coreId);
coreProvider.reload();
}
};
core.getPackageListeners().addListener(coreReloadingClassLoader, true);
}
/**
* Tell all {@link SolrCoreAware} instances about the SolrCore
*/
public void inform(SolrCore core) {
this.coreName = core.getName();
this.config = core.getSolrConfig();
this.coreId = core.uniqueId;
this.coreContainer = core.getCoreContainer();
if(getSchemaLoader() != null) core.getPackageListeners().addListener(schemaLoader);
// make a copy to avoid potential deadlock of a callback calling newInstance and trying to
@ -834,6 +851,47 @@ public class SolrResourceLoader implements ResourceLoader, Closeable, SolrClassL
public List<SolrInfoBean> getInfoMBeans() {
return Collections.unmodifiableList(infoMBeans);
}
/**
* Load a class using an appropriate {@link SolrResourceLoader} depending of the package on that class
* @param registerCoreReloadListener register a listener for the package and reload the core if the package is changed.
* Use this sparingly. This will result in core reloads across all the cores in
* all collections using this configset
*/
public <T> Class<? extends T> findClass( PluginInfo info, Class<T> type, boolean registerCoreReloadListener) {
if(info.cName.pkg == null) return findClass(info.className, type);
return _classLookup(info,
(Function<PackageLoader.Package.Version, Class<? extends T>>) ver -> ver.getLoader().findClass(info.cName.className, type), registerCoreReloadListener);
}
private <T> T _classLookup(PluginInfo info, Function<PackageLoader.Package.Version, T> fun, boolean registerCoreReloadListener ) {
PluginInfo.ClassName cName = info.cName;
if (registerCoreReloadListener) {
if (coreReloadingClassLoader == null) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Core not set");
}
return fun.apply(coreReloadingClassLoader.findPackageVersion(cName, true));
} else {
return fun.apply(coreReloadingClassLoader.findPackageVersion(cName, false));
}
}
/**
*Create a n instance of a class using an appropriate {@link SolrResourceLoader} depending on the package of that class
* @param registerCoreReloadListener register a listener for the package and reload the core if the package is changed.
* Use this sparingly. This will result in core reloads across all the cores in
* all collections using this configset
*/
public <T> T newInstance(PluginInfo info, Class<T> type, boolean registerCoreReloadListener) {
if(info.cName.pkg == null) {
return newInstance(info.cName.className == null?
type.getName():
info.cName.className ,
type);
}
return _classLookup( info, version -> version.getLoader().newInstance(info.cName.className, type), registerCoreReloadListener);
}
private PackageListeningClassLoader createSchemaLoader() {
CoreContainer cc = getCoreContainer();

View File

@ -48,6 +48,7 @@ import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.io.stream.expr.Expressible;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.cloud.ZkSolrResourceLoader;
import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
@ -69,6 +70,7 @@ import org.apache.solr.core.RequestParams;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.pkg.PackageAPI;
import org.apache.solr.pkg.PackageListeners;
import org.apache.solr.request.LocalSolrQueryRequest;
import org.apache.solr.request.SolrQueryRequest;
@ -250,25 +252,28 @@ public class SolrConfigHandler extends RequestHandlerBase implements SolrCoreAwa
String componentName = req.getParams().get("componentName");
if (componentName != null) {
@SuppressWarnings({"rawtypes"})
Map map = (Map) val.get(parts.get(1));
if (map != null) {
Object o = map.get(componentName);
val.put(parts.get(1), makeMap(componentName, o));
Map pluginNameVsPluginInfo = (Map) val.get(parts.get(1));
if (pluginNameVsPluginInfo != null) {
@SuppressWarnings({"rawtypes"})
Object o = pluginNameVsPluginInfo instanceof MapSerializable ?
pluginNameVsPluginInfo:
pluginNameVsPluginInfo.get(componentName);
@SuppressWarnings({"rawtypes"})
Map pluginInfo = o instanceof MapSerializable? ((MapSerializable) o).toMap(new LinkedHashMap<>()): (Map) o;
val.put(parts.get(1),pluginNameVsPluginInfo instanceof PluginInfo? pluginInfo : makeMap(componentName, pluginInfo));
if (req.getParams().getBool("meta", false)) {
// meta=true is asking for the package info of the plugin
// We go through all the listeners and see if there is one registered for this plugin
List<PackageListeners.Listener> listeners = req.getCore().getPackageListeners().getListeners();
for (PackageListeners.Listener listener :
listeners) {
PluginInfo info = listener.pluginInfo();
if(info == null) continue;
if (info.type.equals(parts.get(1)) && info.name.equals(componentName)) {
if (o instanceof Map) {
@SuppressWarnings({"rawtypes"})
Map m1 = (Map) o;
m1.put("_packageinfo_", listener.getPackageVersion(info.cName));
}
Map<String, PackageAPI.PkgVersion> infos = listener.packageDetails();
if(infos == null || infos.isEmpty()) continue;
infos.forEach((s, mapWriter) -> {
if(s.equals(pluginInfo.get("class"))) {
(pluginInfo).put("_packageinfo_", mapWriter);
}
});
}
}
}

View File

@ -16,16 +16,6 @@
*/
package org.apache.solr.handler.component;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.index.ExitableDirectoryReader;
import org.apache.lucene.search.TotalHits;
@ -44,6 +34,7 @@ import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.pkg.PackageAPI;
import org.apache.solr.pkg.PackageListeners;
import org.apache.solr.pkg.PackageLoader;
import org.apache.solr.request.SolrQueryRequest;
@ -61,10 +52,13 @@ import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.solr.common.params.CommonParams.DISTRIB;
import static org.apache.solr.common.params.CommonParams.FAILURE;
import static org.apache.solr.common.params.CommonParams.PATH;
import static org.apache.solr.common.params.CommonParams.STATUS;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.invoke.MethodHandles;
import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import static org.apache.solr.common.params.CommonParams.*;
/**
@ -162,8 +156,8 @@ public class SearchHandler extends RequestHandlerBase implements SolrCoreAware,
}
@Override
public PluginInfo pluginInfo() {
return null;
public Map<String , PackageAPI.PkgVersion> packageDetails() {
return Collections.emptyMap();
}
@Override

View File

@ -47,6 +47,14 @@ public class PackageListeners {
public synchronized void addListener(Listener listener) {
listeners.add(new SoftReference<>(listener));
}
public synchronized void addListener(Listener listener, boolean addFirst) {
if(addFirst) {
listeners.add(0, new SoftReference<>(listener));
} else {
addListener(listener);
}
}
@ -71,7 +79,7 @@ public class PackageListeners {
invokeListeners(pkgInfo, ctx);
}
} finally {
ctx.runLaterTasks(core::runAsync);
ctx.runLaterTasks(r -> core.getCoreContainer().runAsync(r));
MDCLoggingContext.clear();
}
}
@ -102,7 +110,10 @@ public class PackageListeners {
/**Name of the package or null to listen to all package changes */
String packageName();
PluginInfo pluginInfo();
/** fetch the package versions of class names
*
*/
Map<String, PackageAPI.PkgVersion> packageDetails();
/**A callback when the package is updated */
void changed(PackageLoader.Package pkg, Ctx ctx);

View File

@ -26,9 +26,8 @@ import org.apache.solr.common.cloud.SolrClassLoader;
import org.apache.solr.core.SolrResourceLoader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
/**
* A {@link SolrClassLoader} that is designed to listen to a set of packages.
@ -37,22 +36,29 @@ import java.util.function.Function;
* */
public class PackageListeningClassLoader implements SolrClassLoader , PackageListeners.Listener {
private final CoreContainer coreContainer;
private final SolrResourceLoader coreResourceLoader;
private final SolrClassLoader fallbackClassLoader;
private final Function<String, String> pkgVersionSupplier;
/** package name and the versions that we are tracking
*/
private Map<String ,PackageAPI.PkgVersion> packageVersions = new HashMap<>(1);
private Map<String ,PackageAPI.PkgVersion> packageVersions = new ConcurrentHashMap<>(1);
private Map<String, String> classNameVsPackageName = new ConcurrentHashMap<>();
private final Runnable onReload;
/**
* @param fallbackClassLoader The {@link SolrClassLoader} to use if no package is specified
* @param pkgVersionSupplier Get the version configured for a given package
* @param onReload The callback function that should be run if a package is updated
*/
public PackageListeningClassLoader(CoreContainer coreContainer,
SolrResourceLoader coreResourceLoader,
SolrClassLoader fallbackClassLoader,
Function<String, String> pkgVersionSupplier,
Runnable onReload) {
this.coreContainer = coreContainer;
this.coreResourceLoader = coreResourceLoader;
this.fallbackClassLoader = fallbackClassLoader;
this.pkgVersionSupplier = pkgVersionSupplier;
this.onReload = () -> {
packageVersions = new HashMap<>();
packageVersions = new ConcurrentHashMap<>();
classNameVsPackageName = new ConcurrentHashMap<>();
onReload.run();
};
}
@ -62,17 +68,27 @@ public class PackageListeningClassLoader implements SolrClassLoader , PackageLis
public <T> T newInstance(String cname, Class<T> expectedType, String... subpackages) {
PluginInfo.ClassName cName = new PluginInfo.ClassName(cname);
if(cName.pkg == null) {
return coreResourceLoader.newInstance(cname, expectedType, subpackages);
return fallbackClassLoader.newInstance(cname, expectedType, subpackages);
} else {
PackageLoader.Package.Version version = findPkgVersion(cName);
return applyResourceLoaderAware(version, version.getLoader().newInstance(cName.className, expectedType, subpackages));
PackageLoader.Package.Version version = findPackageVersion(cName, true);
T obj = version.getLoader().newInstance(cName.className, expectedType, subpackages);
classNameVsPackageName.put(cName.original, cName.pkg);
return applyResourceLoaderAware(version, obj);
}
}
private PackageLoader.Package.Version findPkgVersion(PluginInfo.ClassName cName) {
/**
* This looks up for package and also listens for that package if required
* @param cName The class name
*/
public PackageLoader.Package.Version findPackageVersion(PluginInfo.ClassName cName, boolean registerListener) {
PackageLoader.Package.Version theVersion = coreContainer.getPackageLoader().getPackage(cName.pkg).getLatest(pkgVersionSupplier.apply(cName.pkg));
packageVersions.put(cName.pkg, theVersion.getPkgVersion());
if(registerListener) {
classNameVsPackageName.put(cName.original, cName.pkg);
PackageAPI.PkgVersion pkgVersion = theVersion.getPkgVersion();
if(pkgVersion !=null) packageVersions.put(cName.pkg, pkgVersion);
}
return theVersion;
}
@ -101,10 +117,12 @@ public class PackageListeningClassLoader implements SolrClassLoader , PackageLis
public <T> T newInstance(String cname, Class<T> expectedType, String[] subPackages, Class[] params, Object[] args) {
PluginInfo.ClassName cName = new PluginInfo.ClassName(cname);
if (cName.pkg == null) {
return coreResourceLoader.newInstance(cname, expectedType, subPackages, params, args);
return fallbackClassLoader.newInstance(cname, expectedType, subPackages, params, args);
} else {
PackageLoader.Package.Version version = findPkgVersion(cName);
return applyResourceLoaderAware(version, version.getLoader().newInstance(cName.className, expectedType, subPackages, params, args));
PackageLoader.Package.Version version = findPackageVersion(cName, true);
T obj = version.getLoader().newInstance(cName.className, expectedType, subPackages, params, args);
classNameVsPackageName.put(cName.original, cName.pkg);
return applyResourceLoaderAware(version, obj);
}
}
@ -112,10 +130,12 @@ public class PackageListeningClassLoader implements SolrClassLoader , PackageLis
public <T> Class<? extends T> findClass(String cname, Class<T> expectedType) {
PluginInfo.ClassName cName = new PluginInfo.ClassName(cname);
if (cName.pkg == null) {
return coreResourceLoader.findClass(cname, expectedType);
return fallbackClassLoader.findClass(cname, expectedType);
} else {
PackageLoader.Package.Version version = findPkgVersion(cName);
return version.getLoader().findClass(cName.className, expectedType);
PackageLoader.Package.Version version = findPackageVersion(cName, true);
Class<? extends T> klas = version.getLoader().findClass(cName.className, expectedType);
classNameVsPackageName.put(cName.original, cName.pkg);
return klas;
}
}
@ -126,8 +146,10 @@ public class PackageListeningClassLoader implements SolrClassLoader , PackageLis
}
@Override
public PluginInfo pluginInfo() {
return null;
public Map<String, PackageAPI.PkgVersion> packageDetails() {
Map<String, PackageAPI.PkgVersion> result = new LinkedHashMap<>();
classNameVsPackageName.forEach((k, v) -> result.put(k, packageVersions.get(v)));
return result;
}
@Override
@ -146,6 +168,11 @@ public class PackageListeningClassLoader implements SolrClassLoader , PackageLis
//no need to update
return;
}
doReloadAction(ctx);
}
protected void doReloadAction(Ctx ctx) {
if(onReload == null) return;
ctx.runLater(null, onReload);
}
}

View File

@ -19,6 +19,8 @@ package org.apache.solr.pkg;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Collections;
import java.util.Map;
import org.apache.lucene.util.ResourceLoaderAware;
import org.apache.solr.common.MapWriter;
@ -57,8 +59,8 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
}
@Override
public PluginInfo pluginInfo() {
return info;
public Map<String, PackageAPI.PkgVersion> packageDetails() {
return Collections.singletonMap(info.cName.original, pkgVersion.getPkgVersion());
}
@Override
@ -75,6 +77,12 @@ public class PackagePluginHolder<T> extends PluginBag.PluginHolder<T> {
});
}
public static <T> PluginBag.PluginHolder<T> createHolder(T inst, Class<T> type) {
SolrConfig.SolrPluginInfo plugin = SolrConfig.classVsSolrPluginInfo.get(type.getName());
PluginInfo info = new PluginInfo(plugin.tag, Collections.singletonMap("class", inst.getClass().getName()));
return new PluginBag.PluginHolder<T>(info,inst);
}
public static <T> PluginBag.PluginHolder<T> createHolder(PluginInfo info, SolrCore core, Class<T> type, String msg) {
if(info.cName.pkg == null) {
return new PluginBag.PluginHolder<T>(info, core.createInitInstance(info, type,msg, null));

View File

@ -23,11 +23,15 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.DOMUtil;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrResourceLoader;
import org.slf4j.Logger;
@ -49,8 +53,14 @@ public class CacheConfig implements MapSerializable{
private String nodeName;
/**
* When this object is created, the core is not yet available . So, if the class is to be
* loaded from a package we should have a corresponding core
*
*/
@SuppressWarnings({"rawtypes"})
private Class<? extends SolrCache> clazz;
private Supplier<Class<? extends SolrCache>> clazz;
private Map<String,String> args;
private CacheRegenerator regenerator;
@ -64,9 +74,10 @@ public class CacheConfig implements MapSerializable{
@SuppressWarnings({"rawtypes"})
public CacheConfig(Class<? extends SolrCache> clazz, Map<String,String> args, CacheRegenerator regenerator) {
this.clazz = clazz;
this.clazz = () -> clazz;
this.args = args;
this.regenerator = regenerator;
this.nodeName = args.get(NAME);
}
public CacheRegenerator getRegenerator() {
@ -134,8 +145,20 @@ public class CacheConfig implements MapSerializable{
SolrResourceLoader loader = solrConfig.getResourceLoader();
config.cacheImpl = config.args.get("class");
if (config.cacheImpl == null) config.cacheImpl = "solr.CaffeineCache";
config.clazz = new Supplier<>() {
@SuppressWarnings("rawtypes")
Class<SolrCache> loadedClass;
@Override
@SuppressWarnings("rawtypes")
public Class<? extends SolrCache> get() {
if (loadedClass != null) return loadedClass;
return loadedClass = (Class<SolrCache>) loader.findClass(
new PluginInfo("cache", Collections.singletonMap("class", config.cacheImpl)),
SolrCache.class, true);
}
};
config.regenImpl = config.args.get("regenerator");
config.clazz = loader.findClass(config.cacheImpl, SolrCache.class);
if (config.regenImpl != null) {
config.regenerator = loader.newInstance(config.regenImpl, CacheRegenerator.class);
}
@ -146,7 +169,7 @@ public class CacheConfig implements MapSerializable{
@SuppressWarnings({"rawtypes"})
public SolrCache newInstance() {
try {
SolrCache cache = clazz.getConstructor().newInstance();
SolrCache cache = clazz.get().getConstructor().newInstance();
persistence[0] = cache.init(args, persistence[0], regenerator);
return cache;
} catch (Exception e) {
@ -158,11 +181,8 @@ public class CacheConfig implements MapSerializable{
}
@Override
@SuppressWarnings({"unchecked"})
public Map<String, Object> toMap(Map<String, Object> map) {
@SuppressWarnings({"rawtypes"})
Map result = Collections.unmodifiableMap(args);
return result;
return new HashMap<>(args);
}
public String getNodeName() {

View File

@ -20,12 +20,7 @@ import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Vector;
import org.apache.solr.core.DirectoryFactory;
import org.apache.solr.core.HdfsDirectoryFactory;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrEventListener;
import org.apache.solr.core.SolrInfoBean;
import org.apache.solr.core.*;
import org.apache.solr.metrics.SolrMetricsContext;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.SchemaField;
@ -123,8 +118,8 @@ public abstract class UpdateHandler implements SolrInfoBean {
if (dirFactory instanceof HdfsDirectoryFactory) {
ulog = new HdfsUpdateLog(((HdfsDirectoryFactory)dirFactory).getConfDir());
} else {
String className = ulogPluginInfo.className == null ? UpdateLog.class.getName() : ulogPluginInfo.className;
ulog = core.getResourceLoader().newInstance(className, UpdateLog.class);
ulog = ulogPluginInfo.className == null ? new UpdateLog():
core.getResourceLoader().newInstance(ulogPluginInfo, UpdateLog.class, true);
}
if (!core.isReloaded() && !dirFactory.isPersistent()) {

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<schema name="minimal" version="1.1">
<fieldType name="string" class="solr.StrField"/>
<fieldType name="int" class="${solr.tests.IntegerFieldType}" docValues="${solr.tests.numeric.dv}" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
<fieldType name="long" class="${solr.tests.LongFieldType}" docValues="${solr.tests.numeric.dv}" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
<dynamicField name="*" type="string" indexed="true" stored="true"/>
<!-- for versioning -->
<field name="_version_" type="long" indexed="true" stored="true"/>
<field name="_root_" type="string" indexed="true" stored="true" multiValued="false" required="false"/>
<field name="id" type="string" indexed="true" stored="true"/>
<dynamicField name="*_s" type="string" indexed="true" stored="true" />
<uniqueKey>id</uniqueKey>
<query>
<filterCache
size="0"
initialSize="0"
autowarmCount="0"/>
<queryResultCache
size="0"
initialSize="0"
autowarmCount="0"/>
<documentCache
size="0"
initialSize="0"
autowarmCount="0"/>
</query>
</schema>

View File

@ -0,0 +1,68 @@
<?xml version="1.0" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!-- Minimal solrconfig.xml with /select, /admin and /update only -->
<config>
<dataDir>${solr.data.dir:}</dataDir>
<directoryFactory name="DirectoryFactory"
class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
<schemaFactory class="ClassicIndexSchemaFactory"/>
<luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
<updateHandler class="solr.DirectUpdateHandler2">
<commitWithin>
<softCommit>${solr.commitwithin.softcommit:true}</softCommit>
</commitWithin>
<updateLog class="${solr.ulog:solr.UpdateLog}"></updateLog>
</updateHandler>
<requestHandler name="/select" class="solr.SearchHandler">
<lst name="defaults">
<str name="echoParams">explicit</str>
<str name="indent">true</str>
<str name="df">text</str>
</lst>
</requestHandler>
<query>
<filterCache
class = "mypkg:org.apache.solr.search.CaffeineCache"
size="512"
initialSize="512"
autowarmCount="0" />
<queryResultCache
size="512"
initialSize="512"
autowarmCount="0" />
<documentCache
size="512"
initialSize="512"
autowarmCount="0" />
</query>
<indexConfig>
<mergeScheduler class="${solr.mscheduler:org.apache.lucene.index.ConcurrentMergeScheduler}"/>
</indexConfig>
</config>

View File

@ -17,17 +17,6 @@
package org.apache.solr.pkg;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
import org.apache.lucene.analysis.pattern.PatternReplaceCharFilterFactory;
@ -40,11 +29,7 @@ import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.BaseHttpSolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.GenericSolrRequest;
import org.apache.solr.client.solrj.request.RequestWriter;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.request.V2Request;
import org.apache.solr.client.solrj.request.*;
import org.apache.solr.client.solrj.request.beans.Package;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
@ -75,13 +60,22 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static org.apache.solr.common.cloud.ZkStateReader.SOLR_PKGS_PATH;
import static org.apache.solr.common.params.CommonParams.JAVABIN;
import static org.apache.solr.common.params.CommonParams.WT;
import static org.apache.solr.core.TestSolrConfigHandler.getFileContent;
import static org.apache.solr.filestore.TestDistribPackageStore.checkAllNodesForFile;
import static org.apache.solr.filestore.TestDistribPackageStore.readFile;
import static org.apache.solr.filestore.TestDistribPackageStore.uploadKey;
import static org.apache.solr.filestore.TestDistribPackageStore.*;
@LogLevel("org.apache.solr.pkg.PackageLoader=DEBUG;org.apache.solr.pkg.PackageAPI=DEBUG")
public class TestPackages extends SolrCloudTestCase {
@ -102,6 +96,69 @@ public class TestPackages extends SolrCloudTestCase {
@JsonProperty("class")
public String klass;
}
public void testCoreReloadingPlugin() throws Exception {
MiniSolrCloudCluster cluster =
configureCluster(4)
.withJettyConfig(jetty -> jetty.enableV2(true))
.addConfig("conf", configset("conf2"))
.configure();
try {
String FILE1 = "/mypkg/runtimelibs.jar";
String COLLECTION_NAME = "testCoreReloadingPluginColl";
byte[] derFile = readFile("cryptokeys/pub_key512.der");
uploadKey(derFile, PackageStoreAPI.KEYS_DIR+"/pub_key512.der", cluster);
postFileAndWait(cluster, "runtimecode/runtimelibs.jar.bin", FILE1,
"L3q/qIGs4NaF6JiO0ZkMUFa88j0OmYc+I6O7BOdNuMct/xoZ4h73aZHZGc0+nmI1f/U3bOlMPINlSOM6LK3JpQ==");
Package.AddVersion add = new Package.AddVersion();
add.version = "1.0";
add.pkg = "mypkg";
add.files = Arrays.asList(new String[]{FILE1});
V2Request req = new V2Request.Builder("/cluster/package")
.forceV2(true)
.withMethod(SolrRequest.METHOD.POST)
.withPayload(Collections.singletonMap("add", add))
.build();
req.process(cluster.getSolrClient());
TestDistribPackageStore.assertResponseValues(10,
() -> new V2Request.Builder("/cluster/package").
withMethod(SolrRequest.METHOD.GET)
.build().process(cluster.getSolrClient()),
Utils.makeMap(
":result:packages:mypkg[0]:version", "1.0",
":result:packages:mypkg[0]:files[0]", FILE1
));
CollectionAdminRequest
.createCollection(COLLECTION_NAME, "conf", 2, 2)
.process(cluster.getSolrClient());
cluster.waitForActiveCollection(COLLECTION_NAME, 2, 4);
verifyComponent(cluster.getSolrClient(), COLLECTION_NAME, "query", "filterCache", add.pkg, add.version);
add.version = "2.0";
req.process(cluster.getSolrClient());
TestDistribPackageStore.assertResponseValues(10,
() -> new V2Request.Builder("/cluster/package").
withMethod(SolrRequest.METHOD.GET)
.build().process(cluster.getSolrClient()),
Utils.makeMap(
":result:packages:mypkg[1]:version", "2.0",
":result:packages:mypkg[1]:files[0]", FILE1
));
new UpdateRequest().commit(cluster.getSolrClient(), COLLECTION_NAME);
verifyComponent(cluster.getSolrClient(),
COLLECTION_NAME, "query", "filterCache",
"mypkg", "2.0" );
} finally {
cluster.shutdown();
}
}
@Test
@SuppressWarnings({"unchecked"})
public void testPluginLoading() throws Exception {