SOLR-14975: Optimize CoreContainer.getAllCoreNames and getLoadedCoreNames.

Also optimize getCoreDescriptors.
This commit is contained in:
Bruno Roustant 2020-11-06 17:18:08 +01:00
parent 5897d14fe4
commit 67f9245ce3
No known key found for this signature in database
GPG Key ID: CD28DABB95360525
14 changed files with 216 additions and 153 deletions

View File

@ -29,6 +29,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import org.apache.commons.io.FileUtils;
import org.apache.solr.client.solrj.cloud.SolrCloudManager;
@ -81,7 +82,7 @@ public class CloudUtil {
if (thisCnn != null && thisCnn.equals(cnn)
&& !thisBaseUrl.equals(baseUrl)) {
if (cc.getLoadedCoreNames().contains(desc.getName())) {
if (cc.isLoaded(desc.getName())) {
cc.unload(desc.getName());
}
@ -285,5 +286,15 @@ public class CloudUtil {
};
}
/**
* Builds a string with sorted {@link CoreContainer#getLoadedCoreNames()} while truncating to the first 20 cores.
*/
static String getLoadedCoreNamesAsString(CoreContainer coreContainer) {
List<String> loadedCoreNames = coreContainer.getLoadedCoreNames();
if (loadedCoreNames.size() <= 20) {
loadedCoreNames.sort(null);
}
return loadedCoreNames.stream().limit(20).collect(Collectors.toList())
+ (loadedCoreNames.size() > 20 ? "...(truncated from " + loadedCoreNames.size() + " cores)" : "");
}
}

View File

@ -69,7 +69,8 @@ public class ReplicateFromLeader {
if (cc.isShutDown()) {
return;
} else {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "SolrCore not found:" + coreName + " in " + cc.getLoadedCoreNames());
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "SolrCore not found:" + coreName + " in "
+ CloudUtil.getLoadedCoreNamesAsString(cc));
}
}
SolrConfig.UpdateHandlerInfo uinfo = core.getSolrConfig().getUpdateHandlerInfo();

View File

@ -288,7 +288,7 @@ final class ShardLeaderElectionContext extends ShardLeaderElectionContextBase {
if (core == null) {
if (log.isDebugEnabled()) {
log.debug("SolrCore not found: {} in {}", coreName, cc.getLoadedCoreNames());
log.debug("SolrCore not found: {} in {}", coreName, CloudUtil.getLoadedCoreNamesAsString(cc));
}
return;
}

View File

@ -26,7 +26,6 @@ import java.security.spec.InvalidKeySpecException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
@ -784,18 +783,18 @@ public class CoreContainer {
// initialize gauges for reporting the number of cores and disk total/free
solrMetricsContext.gauge(() -> solrCores.getCores().size(),
solrMetricsContext.gauge(solrCores::getNumLoadedPermanentCores,
true, "loaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
solrMetricsContext.gauge(() -> solrCores.getLoadedCoreNames().size() - solrCores.getCores().size(),
solrMetricsContext.gauge(solrCores::getNumLoadedTransientCores,
true, "lazy", SolrInfoBean.Category.CONTAINER.toString(), "cores");
solrMetricsContext.gauge(() -> solrCores.getAllCoreNames().size() - solrCores.getLoadedCoreNames().size(),
solrMetricsContext.gauge(solrCores::getNumUnloadedCores,
true, "unloaded", SolrInfoBean.Category.CONTAINER.toString(), "cores");
Path dataHome = cfg.getSolrDataHome() != null ? cfg.getSolrDataHome() : cfg.getCoreRootDirectory();
solrMetricsContext.gauge(() -> dataHome.toFile().getTotalSpace(),
true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
solrMetricsContext.gauge(() -> dataHome.toFile().getUsableSpace(),
true, "usableSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs");
solrMetricsContext.gauge(() -> dataHome.toString(),
solrMetricsContext.gauge(dataHome::toString,
true, "path", SolrInfoBean.Category.CONTAINER.toString(), "fs");
solrMetricsContext.gauge(() -> cfg.getCoreRootDirectory().toFile().getTotalSpace(),
true, "totalSpace", SolrInfoBean.Category.CONTAINER.toString(), "fs", "coreRoot");
@ -1286,7 +1285,7 @@ public class CoreContainer {
CoreDescriptor cd = new CoreDescriptor(coreName, instancePath, parameters, getContainerProperties(), getZkController());
// Since the core descriptor is removed when a core is unloaded, it should never be anywhere when a core is created.
if (getAllCoreNames().contains(coreName)) {
if (getCoreDescriptor(coreName) != null) {
log.warn("Creating a core with existing name is not allowed: '{}'", coreName);
// TODO: Shouldn't this be a BAD_REQUEST?
throw new SolrException(ErrorCode.SERVER_ERROR, "Core with name '" + coreName + "' already exists.");
@ -1568,33 +1567,49 @@ public class CoreContainer {
}
/**
* @return a Collection of registered SolrCores
* Gets the permanent (non-transient) cores that are currently loaded.
*
* @return An unsorted list. This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*/
public Collection<SolrCore> getCores() {
public List<SolrCore> getCores() {
return solrCores.getCores();
}
/**
* Gets the cores that are currently loaded, i.e. cores that have
* Gets the permanent and transient cores that are currently loaded, i.e. cores that have
* 1: loadOnStartup=true and are either not-transient or, if transient, have been loaded and have not been aged out
* 2: loadOnStartup=false and have been loaded but are either non-transient or have not been aged out.
* <p>
* Put another way, this will not return any names of cores that are lazily loaded but have not been called for yet
* or are transient and either not loaded or have been swapped out.
* <p>
* For efficiency, prefer to check {@link #isLoaded(String)} instead of {@link #getLoadedCoreNames()}.contains(coreName).
*
* @return An unsorted list. This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*/
public Collection<String> getLoadedCoreNames() {
public List<String> getLoadedCoreNames() {
return solrCores.getLoadedCoreNames();
}
/**
* get a list of all the cores that are currently known, whether currently loaded or not
* Gets a collection of all the cores, permanent and transient, that are currently known, whether they are loaded or not.
* <p>
* For efficiency, prefer to check {@link #getCoreDescriptor(String)} != null instead of {@link #getAllCoreNames()}.contains(coreName).
*
* @return a list of all the available core names in either permanent or transient cores
* @return An unsorted list. This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*/
public Collection<String> getAllCoreNames() {
public List<String> getAllCoreNames() {
return solrCores.getAllCoreNames();
}
/**
* Gets the total number of cores, including permanent and transient cores, loaded and unloaded cores.
* Faster equivalent for {@link #getAllCoreNames()}.size().
*/
public int getNumAllCores() {
return solrCores.getNumAllCores();
}
/**
* Returns an immutable Map of Exceptions that occurred when initializing
* SolrCores (either at startup, or do to runtime requests to create cores)

View File

@ -16,37 +16,26 @@
*/
package org.apache.solr.core;
import com.google.common.collect.Lists;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.common.util.SolrNamedThreadFactory;
import org.apache.solr.logging.MDCLoggingContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
class SolrCores {
private static Object modifyLock = new Object(); // for locking around manipulating any of the core maps.
private final Map<String, SolrCore> cores = new LinkedHashMap<>(); // For "permanent" cores
// These descriptors, once loaded, will _not_ be unloaded, i.e. they are not "transient".
private final Map<String, CoreDescriptor> residentDesciptors = new LinkedHashMap<>();
private final Map<String, CoreDescriptor> residentDescriptors = new LinkedHashMap<>();
private final CoreContainer container;
@ -62,9 +51,7 @@ class SolrCores {
// to essentially queue them up to be handled via pendingCoreOps.
private static final List<SolrCore> pendingCloses = new ArrayList<>();
private TransientSolrCoreCacheFactory transientCoreCache;
private TransientSolrCoreCache transientSolrCoreCache = null;
private TransientSolrCoreCacheFactory transientSolrCoreCacheFactory;
SolrCores(CoreContainer container) {
this.container = container;
@ -73,13 +60,9 @@ class SolrCores {
protected void addCoreDescriptor(CoreDescriptor p) {
synchronized (modifyLock) {
if (p.isTransient()) {
if (getTransientCacheHandler() != null) {
getTransientCacheHandler().addTransientDescriptor(p.getName(), p);
} else {
log.warn("We encountered a core marked as transient, but there is no transient handler defined. This core will be inaccessible");
}
} else {
residentDesciptors.put(p.getName(), p);
residentDescriptors.put(p.getName(), p);
}
}
}
@ -87,29 +70,30 @@ class SolrCores {
protected void removeCoreDescriptor(CoreDescriptor p) {
synchronized (modifyLock) {
if (p.isTransient()) {
if (getTransientCacheHandler() != null) {
getTransientCacheHandler().removeTransientDescriptor(p.getName());
}
} else {
residentDesciptors.remove(p.getName());
residentDescriptors.remove(p.getName());
}
}
}
public void load(SolrResourceLoader loader) {
transientCoreCache = TransientSolrCoreCacheFactory.newInstance(loader, container);
synchronized (modifyLock) {
transientSolrCoreCacheFactory = TransientSolrCoreCacheFactory.newInstance(loader, container);
}
}
// We are shutting down. You can't hold the lock on the various lists of cores while they shut down, so we need to
// make a temporary copy of the names and shut them down outside the lock.
protected void close() {
waitForLoadingCoresToFinish(30*1000);
Collection<SolrCore> coreList = new ArrayList<>();
TransientSolrCoreCache transientSolrCoreCache = getTransientCacheHandler();
// Release observer
if (transientSolrCoreCache != null) {
transientSolrCoreCache.close();
// Release transient core cache.
synchronized (modifyLock) {
if (transientSolrCoreCacheFactory != null) {
getTransientCacheHandler().close();
}
}
// It might be possible for one of the cores to move from one list to another while we're closing them. So
@ -121,8 +105,8 @@ class SolrCores {
// make a copy of the cores then clear the map so the core isn't handed out to a request again
coreList.addAll(cores.values());
cores.clear();
if (transientSolrCoreCache != null) {
coreList.addAll(transientSolrCoreCache.prepareForShutdown());
if (transientSolrCoreCacheFactory != null) {
coreList.addAll(getTransientCacheHandler().prepareForShutdown());
}
coreList.addAll(pendingCloses);
@ -162,32 +146,28 @@ class SolrCores {
addCoreDescriptor(cd); // cd must always be registered if we register a core
if (cd.isTransient()) {
if (getTransientCacheHandler() != null) {
return getTransientCacheHandler().addCore(cd.getName(), core);
}
} else {
return cores.put(cd.getName(), core);
}
}
return null;
}
/**
*
* @return A list of "permanent" cores, i.e. cores that may not be swapped out and are currently loaded.
*
* A core may be non-transient but still lazily loaded. If it is "permanent" and lazy-load _and_
* not yet loaded it will _not_ be returned by this call.
*
* This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*
* Note: This is one of the places where SolrCloud is incompatible with Transient Cores. This call is used in
* cancelRecoveries, transient cores don't participate.
*/
List<SolrCore> getCores() {
synchronized (modifyLock) {
List<SolrCore> lst = new ArrayList<>(cores.values());
return lst;
return new ArrayList<>(cores.values());
}
}
@ -199,34 +179,85 @@ class SolrCores {
* Put another way, this will not return any names of cores that are lazily loaded but have not been called for yet
* or are transient and either not loaded or have been swapped out.
*
* @return List of currently loaded cores.
* @return An unsorted list. This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*/
Set<String> getLoadedCoreNames() {
Set<String> set;
List<String> getLoadedCoreNames() {
synchronized (modifyLock) {
return distinctSetsUnion(cores.keySet(), getTransientCacheHandler().getLoadedCoreNames());
}
}
synchronized (modifyLock) {
set = new TreeSet<>(cores.keySet());
if (getTransientCacheHandler() != null) {
set.addAll(getTransientCacheHandler().getLoadedCoreNames());
}
}
return set;
}
/**
* Gets a list of all cores, loaded and unloaded
* Gets a collection of all cores names, loaded and unloaded.
* For efficiency, prefer to check {@link #getCoreDescriptor(String)} != null instead of {@link #getAllCoreNames()}.contains(String)
*
* @return all cores names, whether loaded or unloaded, transient or permanent.
* @return An unsorted list. This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*/
public Collection<String> getAllCoreNames() {
Set<String> set;
public List<String> getAllCoreNames() {
synchronized (modifyLock) {
set = new TreeSet<>(cores.keySet());
if (getTransientCacheHandler() != null) {
set.addAll(getTransientCacheHandler().getAllCoreNames());
return distinctSetsUnion(residentDescriptors.keySet(), getTransientCacheHandler().getAllCoreNames());
}
set.addAll(residentDesciptors.keySet());
}
return set;
/**
* Makes the union of two distinct sets.
*
* @return An unsorted list. This list is a new copy, it can be modified by the caller (e.g. it can be sorted).
*/
private static <T> List<T> distinctSetsUnion(Set<T> set1, Set<T> set2) {
assert areSetsDistinct(set1, set2);
List<T> union = new ArrayList<>(set1.size() + set2.size());
union.addAll(set1);
union.addAll(set2);
return union;
}
/**
* Indicates whether two sets are distinct (intersection is empty).
*/
private static <T> boolean areSetsDistinct(Set<T> set1, Set<T> set2) {
return set1.stream().noneMatch(set2::contains);
}
/**
* Gets the number of currently loaded permanent (non transient) cores.
* Faster equivalent for {@link #getCores()}.size().
*/
int getNumLoadedPermanentCores() {
synchronized (modifyLock) {
return cores.size();
}
}
/**
* Gets the number of currently loaded transient cores.
*/
int getNumLoadedTransientCores() {
synchronized (modifyLock) {
return getTransientCacheHandler().getLoadedCoreNames().size();
}
}
/**
* Gets the number of unloaded cores, including permanent and transient cores.
*/
int getNumUnloadedCores() {
synchronized (modifyLock) {
assert areSetsDistinct(residentDescriptors.keySet(), getTransientCacheHandler().getAllCoreNames());
return getTransientCacheHandler().getAllCoreNames().size() - getTransientCacheHandler().getLoadedCoreNames().size()
+ residentDescriptors.size() - cores.size();
}
}
/**
* Gets the total number of cores, including permanent and transient cores, loaded and unloaded cores.
* Faster equivalent for {@link #getAllCoreNames()}.size().
*/
public int getNumAllCores() {
synchronized (modifyLock) {
assert areSetsDistinct(residentDescriptors.keySet(), getTransientCacheHandler().getAllCoreNames());
return residentDescriptors.size() + getTransientCacheHandler().getAllCoreNames().size();
}
}
SolrCore getCore(String name) {
@ -276,9 +307,8 @@ class SolrCores {
SolrCore ret = cores.remove(name);
// It could have been a newly-created core. It could have been a transient core. The newly-created cores
// in particular should be checked. It could have been a dynamic core.
TransientSolrCoreCache transientHandler = getTransientCacheHandler();
if (ret == null && transientHandler != null) {
ret = transientHandler.removeCore(name);
if (ret == null) {
ret = getTransientCacheHandler().removeCore(name);
}
return ret;
}
@ -292,7 +322,7 @@ class SolrCores {
synchronized (modifyLock) {
SolrCore core = cores.get(name);
if (core == null && getTransientCacheHandler() != null) {
if (core == null) {
core = getTransientCacheHandler().getCore(name);
}
if(core != null && coreId != null && coreId != core.uniqueId) return null;
@ -314,7 +344,7 @@ class SolrCores {
if (cores.containsKey(name)) {
return true;
}
if (getTransientCacheHandler() != null && getTransientCacheHandler().containsCore(name)) {
if (getTransientCacheHandler().containsCore(name)) {
// Check pending
for (SolrCore core : pendingCloses) {
if (core.getName().equals(name)) {
@ -330,22 +360,14 @@ class SolrCores {
protected boolean isLoaded(String name) {
synchronized (modifyLock) {
if (cores.containsKey(name)) {
return true;
return cores.containsKey(name) || getTransientCacheHandler().containsCore(name);
}
if (getTransientCacheHandler() != null && getTransientCacheHandler().containsCore(name)) {
return true;
}
}
return false;
}
protected CoreDescriptor getUnloadedCoreDescriptor(String cname) {
synchronized (modifyLock) {
CoreDescriptor desc = residentDesciptors.get(cname);
CoreDescriptor desc = residentDescriptors.get(cname);
if (desc == null) {
if (getTransientCacheHandler() == null) return null;
desc = getTransientCacheHandler().getTransientDescriptor(cname);
if (desc == null) {
return null;
@ -432,29 +454,28 @@ class SolrCores {
*/
public CoreDescriptor getCoreDescriptor(String coreName) {
synchronized (modifyLock) {
if (residentDesciptors.containsKey(coreName))
return residentDesciptors.get(coreName);
CoreDescriptor coreDescriptor = residentDescriptors.get(coreName);
if (coreDescriptor != null) {
return coreDescriptor;
}
return getTransientCacheHandler().getTransientDescriptor(coreName);
}
}
/**
* Get the CoreDescriptors for every SolrCore managed here
* @return a List of CoreDescriptors
* Get the CoreDescriptors for every {@link SolrCore} managed here (permanent and transient, loaded and unloaded).
*
* @return An unordered list copy. This list can be modified by the caller (e.g. sorted).
*/
public List<CoreDescriptor> getCoreDescriptors() {
List<CoreDescriptor> cds = Lists.newArrayList();
synchronized (modifyLock) {
for (String coreName : getAllCoreNames()) {
// TODO: This null check is a bit suspicious - it seems that
// getAllCoreNames might return deleted cores as well?
CoreDescriptor cd = getCoreDescriptor(coreName);
if (cd != null)
cds.add(cd);
Collection<CoreDescriptor> transientCoreDescriptors = getTransientCacheHandler().getTransientDescriptors();
List<CoreDescriptor> coreDescriptors = new ArrayList<>(residentDescriptors.size() + transientCoreDescriptors.size());
coreDescriptors.addAll(residentDescriptors.values());
coreDescriptors.addAll(transientCoreDescriptors);
return coreDescriptors;
}
}
return cds;
}
// cores marked as loading will block on getCore
public void markCoreAsLoading(CoreDescriptor cd) {
@ -509,10 +530,7 @@ class SolrCores {
}
public boolean isCoreLoading(String name) {
if (currentlyLoadingCores.contains(name)) {
return true;
}
return false;
return currentlyLoadingCores.contains(name);
}
public void queueCoreToClose(SolrCore coreToClose) {
@ -522,14 +540,16 @@ class SolrCores {
}
}
/**
* @return the cache holding the transient cores; never null.
*/
public TransientSolrCoreCache getTransientCacheHandler() {
if (transientCoreCache == null) {
log.error("No transient handler has been defined. Check solr.xml to see if an attempt to provide a custom {}"
, "TransientSolrCoreCacheFactory was done incorrectly since the default should have been used otherwise.");
return null;
synchronized (modifyLock) {
if (transientSolrCoreCacheFactory == null) {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, getClass().getName() + " not loaded; call load() before using it");
}
return transientSolrCoreCacheFactory.getTransientSolrCoreCache();
}
return transientCoreCache.getTransientSolrCoreCache();
}
}

View File

@ -97,6 +97,10 @@ public abstract class TransientSolrCoreCache {
// method and return the current core descriptor.
public abstract CoreDescriptor getTransientDescriptor(String name);
/**
* Gets the {@link CoreDescriptor} for all transient cores (loaded and unloaded).
*/
public abstract Collection<CoreDescriptor> getTransientDescriptors();
// Remove the core descriptor from your list of transient descriptors.
public abstract CoreDescriptor removeTransientDescriptor(String name);

View File

@ -18,12 +18,7 @@
package org.apache.solr.core;
import java.lang.invoke.MethodHandles;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.*;
import org.apache.solr.common.util.NamedList;
import org.slf4j.Logger;
@ -124,12 +119,12 @@ public class TransientSolrCoreCacheDefault extends TransientSolrCoreCache {
@Override
public Set<String> getAllCoreNames() {
return transientDescriptors.keySet();
return Collections.unmodifiableSet(transientDescriptors.keySet());
}
@Override
public Set<String> getLoadedCoreNames() {
return transientCores.keySet();
return Collections.unmodifiableSet(transientCores.keySet());
}
// Remove a core from the internal structures, presumably it
@ -166,6 +161,11 @@ public class TransientSolrCoreCacheDefault extends TransientSolrCoreCache {
return transientDescriptors.get(name);
}
@Override
public Collection<CoreDescriptor> getTransientDescriptors() {
return Collections.unmodifiableCollection(transientDescriptors.values());
}
@Override
public CoreDescriptor removeTransientDescriptor(String name) {
return transientDescriptors.remove(name);

View File

@ -20,6 +20,7 @@ import java.lang.invoke.MethodHandles;
import java.util.Collections;
import com.google.common.collect.ImmutableMap;
import org.apache.solr.common.SolrException;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -32,6 +33,9 @@ public abstract class TransientSolrCoreCacheFactory {
private volatile CoreContainer coreContainer = null;
/**
* @return the cache holding the transient cores; never null.
*/
public abstract TransientSolrCoreCache getTransientSolrCoreCache();
/**
* Create a new TransientSolrCoreCacheFactory instance
@ -51,19 +55,19 @@ public abstract class TransientSolrCoreCacheFactory {
// According to the docs, this returns a TransientSolrCoreCacheFactory with the default c'tor
TransientSolrCoreCacheFactory tccf = loader.findClass(info.className, TransientSolrCoreCacheFactory.class).getConstructor().newInstance();
// OK, now we call it's init method.
// OK, now we call its init method.
if (PluginInfoInitialized.class.isAssignableFrom(tccf.getClass()))
PluginInfoInitialized.class.cast(tccf).init(info);
tccf.setCoreContainer(coreContainer);
return tccf;
} catch (Exception e) {
// Many things could cause this, bad solrconfig, mis-typed class name, whatever. However, this should not
// keep the enclosing coreContainer from instantiating, so log an error and continue.
log.error("Error instantiating TransientSolrCoreCacheFactory class [{}]: ", info.className, e);
return null;
// Many things could cause this, bad solrconfig, mis-typed class name, whatever.
// Throw an exception to stop loading here; never return null.
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Error instantiating "
+ TransientSolrCoreCacheFactory.class.getName() + " class [" + info.className + "]", e);
}
}
}
public static final PluginInfo DEFAULT_TRANSIENT_SOLR_CACHE_INFO =
new PluginInfo("transientSolrCoreCacheFactory",
ImmutableMap.of("class", TransientSolrCoreCacheFactoryDefault.class.getName(),

View File

@ -22,13 +22,12 @@ import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.apache.commons.lang3.StringUtils;
import org.apache.solr.cloud.SolrZkServer;
@ -125,14 +124,8 @@ public class ZkContainer {
"A chroot was specified in ZkHost but the znode doesn't exist. " + zookeeperHost);
}
Supplier<List<CoreDescriptor>> descriptorsSupplier = () -> {
List<CoreDescriptor> descriptors = new ArrayList<>(cc.getLoadedCoreNames().size());
Collection<SolrCore> cores = cc.getCores();
for (SolrCore core : cores) {
descriptors.add(core.getCoreDescriptor());
}
return descriptors;
};
Supplier<List<CoreDescriptor>> descriptorsSupplier = () ->
cc.getCores().stream().map(SolrCore::getCoreDescriptor).collect(Collectors.toList());
ZkController zkController = new ZkController(cc, zookeeperHost, zkClientConnectTimeout, config, descriptorsSupplier);

View File

@ -126,7 +126,7 @@ public class HealthCheckHandler extends RequestHandlerBase {
rsp.add(STATUS, FAILURE);
rsp.add("num_cores_unhealthy", unhealthyCores);
rsp.setException(new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE, unhealthyCores + " out of "
+ cores.getAllCoreNames().size() + " replicas are currently initializing or recovering"));
+ cores.getNumAllCores() + " replicas are currently initializing or recovering"));
return;
}
rsp.add("message", "All cores are healthy");

View File

@ -19,6 +19,7 @@ package org.apache.solr.handler.admin;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.solr.common.params.CoreAdminParams;
@ -42,7 +43,9 @@ class StatusOp implements CoreAdminHandler.CoreAdminOp {
failures.put(failure.getKey(), failure.getValue().exception);
}
if (cname == null) {
for (String name : it.handler.coreContainer.getAllCoreNames()) {
List<String> nameList = it.handler.coreContainer.getAllCoreNames();
nameList.sort(null);
for (String name : nameList) {
status.add(name, CoreAdminOperation.getCoreStatus(it.handler.coreContainer, name, isIndexInfoNeeded));
}
it.rsp.add("initFailures", failures);

View File

@ -670,6 +670,7 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
// check that we get null accessing a non-existent core
assertNull(cc.getCore("does_not_exist"));
assertFalse(cc.isLoaded("does_not_exist"));
// check that we get a 500 accessing the core with an init failure
SolrException thrown = expectThrows(SolrException.class, () -> {
SolrCore c = cc.getCore("col_bad");
@ -691,7 +692,9 @@ public class TestCoreContainer extends SolrTestCaseJ4 {
assertNotNull("core names is null", cores);
assertEquals("wrong number of cores", 2, cores.size());
assertTrue("col_ok not found", cores.contains("col_ok"));
assertTrue(cc.isLoaded("col_ok"));
assertTrue("col_bad not found", cores.contains("col_bad"));
assertTrue(cc.isLoaded("col_bad"));
// check that we have the failures we expect
failures = cc.getCoreInitFailures();

View File

@ -668,6 +668,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
Collection<String> loadedNames = cc.getLoadedCoreNames();
for (String name : nameCheck) {
assertFalse("core " + name + " was found in the list of cores", loadedNames.contains(name));
assertFalse(cc.isLoaded(name));
}
// There was a problem at one point exacerbated by the poor naming conventions. So parallel to loaded cores, there
@ -681,26 +682,33 @@ public class TestLazyCores extends SolrTestCaseJ4 {
List<CoreDescriptor> descriptors = cc.getCoreDescriptors();
assertEquals("There should be as many coreDescriptors as coreNames", allNames.size(), descriptors.size());
assertEquals(allNames.size(), cc.getNumAllCores());
for (CoreDescriptor desc : descriptors) {
assertTrue("Name should have a corresponding descriptor", allNames.contains(desc.getName()));
assertNotNull(cc.getCoreDescriptor(desc.getName()));
}
// First check that all loaded cores are in allNames.
for (String name : loadedNames) {
assertTrue("Loaded core " + name + " should have been found in the list of all possible core names",
allNames.contains(name));
assertNotNull(cc.getCoreDescriptor(name));
assertTrue(cc.isLoaded(name));
}
// failed cores should have had their descriptors removed.
// Unloaded cores should be in allNames.
for (String name : nameCheck) {
assertTrue("Not-currently-loaded core " + name + " should have been found in the list of all possible core names",
allNames.contains(name));
assertNotNull(cc.getCoreDescriptor(name));
}
// Failed cores should not be in coreDescriptors.
for (String name : namesBad) {
assertFalse("Failed core " + name + " should have been found in the list of all possible core names",
allNames.contains(name));
assertNull(cc.getCoreDescriptor(name));
assertFalse(cc.isLoaded(name));
}
}

View File

@ -193,6 +193,7 @@ public class TestCoreAdmin extends AbstractEmbeddedSolrServerTestCase {
names = cores.getAllCoreNames();
assertFalse(names.toString(), names.contains("coreRenamed"));
assertTrue(names.toString(), names.contains("core1"));
assertEquals(names.size(), cores.getNumAllCores());
}
@Test