Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand Down Expand Up @@ -69,6 +70,7 @@
import org.apache.solr.handler.admin.CoreAdminOperation;
import org.apache.solr.handler.admin.LukeRequestHandler;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.servlet.CoreContainerProvider;
import org.apache.solr.servlet.SolrDispatchFilter;
import org.apache.solr.util.TimeOut;
import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
Expand Down Expand Up @@ -113,7 +115,7 @@ public class JettySolrRunner {
// NOTE: needs to be larger than SolrHttpClient.threadPoolSweeperMaxIdleTime
private static final int THREAD_POOL_MAX_IDLE_TIME_MS = 260000;

Server server;
private Server server;

volatile FilterHolder dispatchFilter;
volatile FilterHolder debugFilter;
Expand Down Expand Up @@ -143,6 +145,8 @@ public class JettySolrRunner {

private volatile boolean started = false;

private CoreContainerProvider coreContainerProvider;

public static class DebugFilter implements Filter {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

Expand Down Expand Up @@ -364,16 +368,17 @@ public void lifeCycleStopping(LifeCycle arg0) {
}

@Override
public void lifeCycleStopped(LifeCycle arg0) {}
public synchronized void lifeCycleStopped(LifeCycle arg0) {
coreContainerProvider.close();
}

@Override
public void lifeCycleStarting(LifeCycle arg0) {

}

@Override
public void lifeCycleStarted(LifeCycle arg0) {

public synchronized void lifeCycleStarted(LifeCycle arg0) {
jettyPort = getFirstConnectorPort();
int port = jettyPort;
if (proxyPort != -1) port = proxyPort;
Expand All @@ -382,7 +387,8 @@ public void lifeCycleStarted(LifeCycle arg0) {

root.getServletContext().setAttribute(SolrDispatchFilter.PROPERTIES_ATTRIBUTE, nodeProperties);
root.getServletContext().setAttribute(SolrDispatchFilter.SOLRHOME_ATTRIBUTE, solrHome);

coreContainerProvider = new CoreContainerProvider();
coreContainerProvider.init(root.getServletContext());
log.info("Jetty properties: {}", nodeProperties);

debugFilter = root.addFilter(DebugFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST) );
Expand Down Expand Up @@ -455,10 +461,16 @@ protected HandlerWrapper injectJettyHandlers(HandlerWrapper chain) {
* @return the {@link CoreContainer} for this node
*/
public CoreContainer getCoreContainer() {
if (getSolrDispatchFilter() == null || getSolrDispatchFilter().getCores() == null) {
return null;
try {
if (getSolrDispatchFilter() == null || getSolrDispatchFilter().getCores() == null) {
return null;
}
return getSolrDispatchFilter().getCores();
} catch (UnavailableException e) {
// Since this is only used in tests, this is just a straight-up failure
// If this is converted for other use something else might be better here
throw new RuntimeException(e);
}
return getSolrDispatchFilter().getCores();
}

public String getNodeName() {
Expand Down Expand Up @@ -500,7 +512,7 @@ public void start() throws Exception {
*
* @throws Exception if an error occurs on startup
*/
public void start(boolean reusePort) throws Exception {
public synchronized void start(boolean reusePort) throws Exception {
// Do not let Jetty/Solr pollute the MDC for this thread
Map<String, String> prevContext = MDC.getCopyOfContextMap();
MDC.clear();
Expand All @@ -527,7 +539,7 @@ public void start(boolean reusePort) throws Exception {
}
synchronized (JettySolrRunner.this) {
int cnt = 0;
while (!waitOnSolr || !dispatchFilter.isRunning() || getCoreContainer() == null) {
while (!waitOnSolr || !dispatchFilter.isRunning() ) {
this.wait(100);
if (cnt++ == 15) {
throw new RuntimeException("Jetty/Solr unresponsive");
Expand Down Expand Up @@ -561,7 +573,7 @@ public void start(boolean reusePort) throws Exception {


private void setProtocolAndHost() {
String protocol = null;
String protocol;

Connector[] conns = server.getConnectors();
if (0 == conns.length) {
Expand All @@ -575,7 +587,7 @@ private void setProtocolAndHost() {
this.host = c.getHost();
}

private void retryOnPortBindFailure(int portRetryTime, int port) throws Exception, InterruptedException {
private void retryOnPortBindFailure(int portRetryTime, int port) throws Exception {
TimeOut timeout = new TimeOut(portRetryTime, TimeUnit.SECONDS, TimeSource.NANO_TIME);
int tryCnt = 1;
while (true) {
Expand Down Expand Up @@ -625,34 +637,12 @@ Exception lookForBindException(IOException ioe) {
*
* @throws Exception if an error occurs on shutdown
*/
public void stop() throws Exception {
public synchronized void stop() throws Exception {
// Do not let Jetty/Solr pollute the MDC for this thread
Map<String,String> prevContext = MDC.getCopyOfContextMap();
MDC.clear();
try {
Filter filter = dispatchFilter.getFilter();

// we want to shutdown outside of jetty cutting us off
SolrDispatchFilter sdf = getSolrDispatchFilter();
ExecutorService customThreadPool = null;
if (sdf != null) {
customThreadPool = ExecutorUtil.newMDCAwareCachedThreadPool(new SolrNamedThreadFactory("jettyShutDown"));

sdf.closeOnDestroy(false);
// customThreadPool.submit(() -> {
// try {
// sdf.close();
// } catch (Throwable t) {
// log.error("Error shutting down Solr", t);
// }
// });
try {
sdf.close();
} catch (Throwable t) {
log.error("Error shutting down Solr", t);
}
}

QueuedThreadPool qtp = (QueuedThreadPool) server.getThreadPool();
ReservedThreadExecutor rte = qtp.getBean(ReservedThreadExecutor.class);

Expand Down Expand Up @@ -687,12 +677,13 @@ public void stop() throws Exception {
rte.stop();

TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, TimeSource.NANO_TIME);
timeout.waitFor("Timeout waiting for reserved executor to stop.", ()
-> rte.isStopped());
timeout.waitFor("Timeout waiting for reserved executor to stop.", rte::isStopped);
}

if (customThreadPool != null) {
ExecutorUtil.shutdownAndAwaitTermination(customThreadPool);
// we want to shutdown outside of jetty cutting us off
SolrDispatchFilter sdf = getSolrDispatchFilter();
if (sdf != null) {
ExecutorUtil.shutdownAndAwaitTermination(getJettyShutDownThreadPool());
}

do {
Expand All @@ -716,6 +707,10 @@ public void stop() throws Exception {
}
}

private ExecutorService getJettyShutDownThreadPool() {
return ExecutorUtil.newMDCAwareCachedThreadPool(new SolrNamedThreadFactory("jettyShutDown"));
}

public void outputMetrics(File outputDirectory, String fileName) throws IOException {
if (getCoreContainer() != null) {

Expand Down Expand Up @@ -750,12 +745,11 @@ public void dumpCoresInfo(PrintStream pw) throws IOException {
NamedList<Object> coreStatus = CoreAdminOperation.getCoreStatus(getCoreContainer(), core.getName(), false);
core.withSearcher(solrIndexSearcher -> {
SimpleOrderedMap<Object> lukeIndexInfo = LukeRequestHandler.getIndexInfo(solrIndexSearcher.getIndexReader());
@SuppressWarnings({"unchecked", "rawtypes"})
Map<String,Object> indexInfoMap = coreStatus.toMap(new LinkedHashMap<>());
indexInfoMap.putAll(lukeIndexInfo.toMap(new LinkedHashMap<>()));
pw.println(JSONUtil.toJSON(indexInfoMap, 2));

pw.println("");
pw.println();
return null;
});
}
Expand Down Expand Up @@ -897,7 +891,12 @@ public Properties getNodeProperties() {
private void waitForLoadingCoresToFinish(long timeoutMs) {
if (dispatchFilter != null) {
SolrDispatchFilter solrFilter = (SolrDispatchFilter) dispatchFilter.getFilter();
CoreContainer cores = solrFilter.getCores();
CoreContainer cores;
try {
cores = solrFilter.getCores();
} catch (UnavailableException e) {
throw new IllegalStateException("The CoreContainer is unavailable!");
}
if (cores != null) {
cores.waitForLoadingCoresToFinish(timeoutMs);
} else {
Expand Down
39 changes: 39 additions & 0 deletions solr/core/src/java/org/apache/solr/core/NodeConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@
*/
package org.apache.solr.core;

import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.search.IndexSearcher;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.logging.LogWatcherConfig;

import org.apache.solr.update.UpdateShardHandlerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.lang.invoke.MethodHandles;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -31,6 +39,8 @@


public class NodeConfig {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

// all Path fields here are absolute and normalized.

private final String nodeName;
Expand Down Expand Up @@ -149,6 +159,35 @@ private NodeConfig(String nodeName, Path coreRootDirectory, Path solrDataHome, I
if (null == this.loader) throw new NullPointerException("loader");
}

/**
* Get the NodeConfig whether stored on disk, in ZooKeeper, etc.
* This may also be used by custom filters to load relevant configuration.
* @return the NodeConfig
*/
public static NodeConfig loadNodeConfig(Path solrHome, Properties nodeProperties) {
if (!StringUtils.isEmpty(System.getProperty("solr.solrxml.location"))) {
log.warn("Solr property solr.solrxml.location is no longer supported. Will automatically load solr.xml from ZooKeeper if it exists");
}
nodeProperties = SolrXmlConfig.wrapAndSetZkHostFromSysPropIfNeeded(nodeProperties);
String zkHost = nodeProperties.getProperty(SolrXmlConfig.ZK_HOST);
if (!StringUtils.isEmpty(zkHost)) {
int startUpZkTimeOut = Integer.getInteger("waitForZk", 30);
startUpZkTimeOut *= 1000;
try (SolrZkClient zkClient = new SolrZkClient(zkHost, startUpZkTimeOut, startUpZkTimeOut)) {
if (zkClient.exists("/solr.xml", true)) {
log.info("solr.xml found in ZooKeeper. Loading...");
byte[] data = zkClient.getData("/solr.xml", null, null, true);
return SolrXmlConfig.fromInputStream(solrHome, new ByteArrayInputStream(data), nodeProperties, true);
}
} catch (Exception e) {
throw new SolrException(ErrorCode.SERVER_ERROR, "Error occurred while loading solr.xml from zookeeper", e);
}
log.info("Loading solr.xml from SolrHome (not found in ZooKeeper)");
}

return SolrXmlConfig.fromSolrHome(solrHome, nodeProperties);
}

public String getConfigSetServiceClass() {
return this.configSetServiceClass;
}
Expand Down
Loading