mirror of https://github.com/apache/lucene.git
SOLR-13723: JettySolrRunner should support /api/* (the v2 end point)
This commit is contained in:
parent
7c101fba4a
commit
7d026f803d
|
@ -32,6 +32,9 @@ public class JettyConfig {
|
|||
|
||||
public final String context;
|
||||
|
||||
public final boolean enableV2;
|
||||
|
||||
|
||||
public final boolean stopAtShutdown;
|
||||
|
||||
public final Long waitForLoadingCoresToFinishMs;
|
||||
|
@ -46,7 +49,7 @@ public class JettyConfig {
|
|||
|
||||
private JettyConfig(boolean onlyHttp1, int port, int portRetryTime , String context, boolean stopAtShutdown,
|
||||
Long waitForLoadingCoresToFinishMs, Map<ServletHolder, String> extraServlets,
|
||||
Map<Class<? extends Filter>, String> extraFilters, SSLConfig sslConfig) {
|
||||
Map<Class<? extends Filter>, String> extraFilters, SSLConfig sslConfig, boolean enableV2) {
|
||||
this.onlyHttp1 = onlyHttp1;
|
||||
this.port = port;
|
||||
this.context = context;
|
||||
|
@ -56,6 +59,7 @@ public class JettyConfig {
|
|||
this.extraFilters = extraFilters;
|
||||
this.sslConfig = sslConfig;
|
||||
this.portRetryTime = portRetryTime;
|
||||
this.enableV2 = enableV2;
|
||||
}
|
||||
|
||||
public static Builder builder() {
|
||||
|
@ -78,6 +82,7 @@ public class JettyConfig {
|
|||
boolean onlyHttp1 = false;
|
||||
int port = 0;
|
||||
String context = "/solr";
|
||||
boolean enableV2 = true;
|
||||
boolean stopAtShutdown = true;
|
||||
Long waitForLoadingCoresToFinishMs = 300000L;
|
||||
Map<ServletHolder, String> extraServlets = new TreeMap<>();
|
||||
|
@ -89,6 +94,10 @@ public class JettyConfig {
|
|||
this.onlyHttp1 = useOnlyHttp1;
|
||||
return this;
|
||||
}
|
||||
public Builder enableV2(boolean flag){
|
||||
this.enableV2 = flag;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPort(int port) {
|
||||
this.port = port;
|
||||
|
@ -144,7 +153,8 @@ public class JettyConfig {
|
|||
|
||||
|
||||
public JettyConfig build() {
|
||||
return new JettyConfig(onlyHttp1, port, portRetryTime, context, stopAtShutdown, waitForLoadingCoresToFinishMs, extraServlets, extraFilters, sslConfig);
|
||||
return new JettyConfig(onlyHttp1, port, portRetryTime, context, stopAtShutdown,
|
||||
waitForLoadingCoresToFinishMs, extraServlets, extraFilters, sslConfig, enableV2);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,6 +59,8 @@ import org.eclipse.jetty.alpn.server.ALPNServerConnectionFactory;
|
|||
import org.eclipse.jetty.http2.HTTP2Cipher;
|
||||
import org.eclipse.jetty.http2.server.HTTP2CServerConnectionFactory;
|
||||
import org.eclipse.jetty.http2.server.HTTP2ServerConnectionFactory;
|
||||
import org.eclipse.jetty.rewrite.handler.RewriteHandler;
|
||||
import org.eclipse.jetty.rewrite.handler.RewritePatternRule;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConfiguration;
|
||||
import org.eclipse.jetty.server.HttpConnectionFactory;
|
||||
|
@ -83,7 +85,7 @@ import org.slf4j.MDC;
|
|||
|
||||
/**
|
||||
* Run solr using jetty
|
||||
*
|
||||
*
|
||||
* @since solr 1.3
|
||||
*/
|
||||
public class JettySolrRunner {
|
||||
|
@ -93,7 +95,7 @@ public class JettySolrRunner {
|
|||
private static final int THREAD_POOL_MAX_THREADS = 10000;
|
||||
// NOTE: needs to be larger than SolrHttpClient.threadPoolSweeperMaxIdleTime
|
||||
private static final int THREAD_POOL_MAX_IDLE_TIME_MS = 260000;
|
||||
|
||||
|
||||
Server server;
|
||||
|
||||
volatile FilterHolder dispatchFilter;
|
||||
|
@ -128,14 +130,14 @@ public class JettySolrRunner {
|
|||
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
private AtomicLong nRequests = new AtomicLong();
|
||||
|
||||
|
||||
List<Delay> delays = new ArrayList<>();
|
||||
|
||||
public long getTotalRequests() {
|
||||
return nRequests.get();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Introduce a delay of specified milliseconds for the specified request.
|
||||
*
|
||||
|
@ -146,7 +148,7 @@ public class JettySolrRunner {
|
|||
public void addDelay(String reason, int count, int delay) {
|
||||
delays.add(new Delay(reason, count, delay));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove any delay introduced before.
|
||||
*/
|
||||
|
@ -167,14 +169,14 @@ public class JettySolrRunner {
|
|||
|
||||
@Override
|
||||
public void destroy() { }
|
||||
|
||||
|
||||
private void executeDelay() {
|
||||
int delayMs = 0;
|
||||
for (Delay delay: delays) {
|
||||
this.log.info("Delaying "+delay.delayValue+", for reason: "+delay.reason);
|
||||
if (delay.counter.decrementAndGet() == 0) {
|
||||
delayMs += delay.delayValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delayMs > 0) {
|
||||
|
@ -215,7 +217,7 @@ public class JettySolrRunner {
|
|||
public JettySolrRunner(String solrHome, JettyConfig config) {
|
||||
this(solrHome, new Properties(), config);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a JettySolrRunner
|
||||
*
|
||||
|
@ -244,7 +246,7 @@ public class JettySolrRunner {
|
|||
this.solrHome = solrHome;
|
||||
this.config = config;
|
||||
this.nodeProperties = nodeProperties;
|
||||
|
||||
|
||||
if (enableProxy) {
|
||||
try {
|
||||
proxy = new SocketProxy(0, config.sslConfig != null && config.sslConfig.isSSLMode());
|
||||
|
@ -256,7 +258,7 @@ public class JettySolrRunner {
|
|||
|
||||
this.init(this.config.port);
|
||||
}
|
||||
|
||||
|
||||
private void init(int port) {
|
||||
|
||||
QueuedThreadPool qtp = new QueuedThreadPool();
|
||||
|
@ -275,7 +277,7 @@ public class JettySolrRunner {
|
|||
//
|
||||
// This means we will use the same truststore, keystore (and keys) for
|
||||
// the server as well as any client actions taken by this JVM in
|
||||
// talking to that server, but for the purposes of testing that should
|
||||
// talking to that server, but for the purposes of testing that should
|
||||
// be good enough
|
||||
final SslContextFactory sslcontext = SSLConfig.createContextFactory(config.sslConfig);
|
||||
|
||||
|
@ -382,7 +384,7 @@ public class JettySolrRunner {
|
|||
dispatchFilter.setHeldClass(SolrDispatchFilter.class);
|
||||
dispatchFilter.setInitParameter("excludePatterns", excludePatterns);
|
||||
root.addFilter(dispatchFilter, "*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
|
||||
synchronized (JettySolrRunner.this) {
|
||||
waitOnSolr = true;
|
||||
JettySolrRunner.this.notify();
|
||||
|
@ -400,7 +402,16 @@ public class JettySolrRunner {
|
|||
}
|
||||
|
||||
chain = injectJettyHandlers(chain);
|
||||
|
||||
|
||||
if(config.enableV2) {
|
||||
RewriteHandler rwh = new RewriteHandler();
|
||||
rwh.setHandler(chain);
|
||||
rwh.setRewriteRequestURI(true);
|
||||
rwh.setRewritePathInfo(false);
|
||||
rwh.setOriginalPathAttribute("requestedPath");
|
||||
rwh.addRule(new RewritePatternRule("/api/*", "/solr/____v2"));
|
||||
chain = rwh;
|
||||
}
|
||||
GzipHandler gzipHandler = new GzipHandler();
|
||||
gzipHandler.setHandler(chain);
|
||||
|
||||
|
@ -413,7 +424,7 @@ public class JettySolrRunner {
|
|||
server.setHandler(gzipHandler);
|
||||
}
|
||||
|
||||
/** descendants may inject own handler chaining it to the given root
|
||||
/** descendants may inject own handler chaining it to the given root
|
||||
* and then returning that own one*/
|
||||
protected HandlerWrapper injectJettyHandlers(HandlerWrapper chain) {
|
||||
return chain;
|
||||
|
@ -445,7 +456,7 @@ public class JettySolrRunner {
|
|||
public boolean isRunning() {
|
||||
return server.isRunning() && dispatchFilter != null && dispatchFilter.isRunning();
|
||||
}
|
||||
|
||||
|
||||
public boolean isStopped() {
|
||||
return (server.isStopped() && dispatchFilter == null) || (server.isStopped() && dispatchFilter.isStopped()
|
||||
&& ((QueuedThreadPool) server.getThreadPool()).isStopped());
|
||||
|
@ -478,12 +489,12 @@ public class JettySolrRunner {
|
|||
// Do not let Jetty/Solr pollute the MDC for this thread
|
||||
Map<String, String> prevContext = MDC.getCopyOfContextMap();
|
||||
MDC.clear();
|
||||
|
||||
|
||||
log.info("Start Jetty (original configured port={})", this.config.port);
|
||||
|
||||
|
||||
try {
|
||||
int port = reusePort && jettyPort != -1 ? jettyPort : this.config.port;
|
||||
|
||||
|
||||
// if started before, make a new server
|
||||
if (startedBefore) {
|
||||
waitOnSolr = false;
|
||||
|
@ -508,21 +519,21 @@ public class JettySolrRunner {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (config.waitForLoadingCoresToFinishMs != null && config.waitForLoadingCoresToFinishMs > 0L) {
|
||||
waitForLoadingCoresToFinish(config.waitForLoadingCoresToFinishMs);
|
||||
}
|
||||
|
||||
|
||||
setProtocolAndHost();
|
||||
|
||||
|
||||
if (enableProxy) {
|
||||
if (started) {
|
||||
proxy.reopen();
|
||||
} else {
|
||||
proxy.open(getBaseUrl().toURI());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} finally {
|
||||
started = true;
|
||||
if (prevContext != null) {
|
||||
|
@ -548,7 +559,7 @@ public class JettySolrRunner {
|
|||
this.protocol = protocol;
|
||||
this.host = c.getHost();
|
||||
}
|
||||
|
||||
|
||||
private void retryOnPortBindFailure(int portRetryTime, int port) throws Exception, InterruptedException {
|
||||
TimeOut timeout = new TimeOut(portRetryTime, TimeUnit.SECONDS, TimeSource.NANO_TIME);
|
||||
int tryCnt = 1;
|
||||
|
@ -567,7 +578,7 @@ public class JettySolrRunner {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
@ -628,7 +639,7 @@ public class JettySolrRunner {
|
|||
|
||||
QueuedThreadPool qtp = (QueuedThreadPool) server.getThreadPool();
|
||||
ReservedThreadExecutor rte = qtp.getBean(ReservedThreadExecutor.class);
|
||||
|
||||
|
||||
server.stop();
|
||||
|
||||
if (server.getState().equals(Server.FAILED)) {
|
||||
|
@ -647,18 +658,18 @@ public class JettySolrRunner {
|
|||
Thread.sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// we tried to kill everything, now we wait for executor to stop
|
||||
qtp.setStopTimeout(Integer.MAX_VALUE);
|
||||
qtp.stop();
|
||||
qtp.join();
|
||||
|
||||
|
||||
if (rte != null) {
|
||||
// we try and wait for the reserved thread executor, but it doesn't always seem to work
|
||||
// so we actually set 0 reserved threads at creation
|
||||
|
||||
|
||||
rte.stop();
|
||||
|
||||
|
||||
TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, TimeSource.NANO_TIME);
|
||||
timeout.waitFor("Timeout waiting for reserved executor to stop.", ()
|
||||
-> rte.isStopped());
|
||||
|
@ -675,12 +686,12 @@ public class JettySolrRunner {
|
|||
// ignore
|
||||
}
|
||||
} while (!server.isStopped());
|
||||
|
||||
|
||||
} finally {
|
||||
if (enableProxy) {
|
||||
proxy.close();
|
||||
}
|
||||
|
||||
|
||||
if (prevContext != null) {
|
||||
MDC.setContextMap(prevContext);
|
||||
} else {
|
||||
|
@ -691,7 +702,7 @@ public class JettySolrRunner {
|
|||
|
||||
/**
|
||||
* Returns the Local Port of the jetty Server.
|
||||
*
|
||||
*
|
||||
* @exception RuntimeException if there is no Connector
|
||||
*/
|
||||
private int getFirstConnectorPort() {
|
||||
|
@ -701,22 +712,22 @@ public class JettySolrRunner {
|
|||
}
|
||||
return ((ServerConnector) conns[0]).getLocalPort();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Local Port of the jetty Server.
|
||||
*
|
||||
*
|
||||
* @exception RuntimeException if there is no Connector
|
||||
*/
|
||||
public int getLocalPort() {
|
||||
return getLocalPort(false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the Local Port of the jetty Server.
|
||||
*
|
||||
*
|
||||
* @param internalPort pass true to get the true jetty port rather than the proxy port if configured
|
||||
*
|
||||
*
|
||||
* @exception RuntimeException if there is no Connector
|
||||
*/
|
||||
public int getLocalPort(boolean internalPort) {
|
||||
|
@ -728,7 +739,7 @@ public class JettySolrRunner {
|
|||
}
|
||||
return (proxyPort != -1) ? proxyPort : jettyPort;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the port of a local socket proxy that sits infront of this server; if set
|
||||
* then all client traffic will flow through the proxy, giving us the ability to
|
||||
|
@ -737,7 +748,7 @@ public class JettySolrRunner {
|
|||
public void setProxyPort(int proxyPort) {
|
||||
this.proxyPort = proxyPort;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a base URL consisting of the protocol, host, and port for a
|
||||
* Connector in use by the Jetty Server contained in this runner.
|
||||
|
@ -764,7 +775,7 @@ public class JettySolrRunner {
|
|||
public SolrClient newClient() {
|
||||
return new HttpSolrClient.Builder(getBaseUrl().toString()).build();
|
||||
}
|
||||
|
||||
|
||||
public SolrClient newClient(int connectionTimeoutMillis, int socketTimeoutMillis) {
|
||||
return new HttpSolrClient.Builder(getBaseUrl().toString())
|
||||
.withConnectionTimeout(connectionTimeoutMillis)
|
||||
|
@ -793,13 +804,9 @@ public class JettySolrRunner {
|
|||
/**
|
||||
* A main class that starts jetty+solr This is useful for debugging
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
JettySolrRunner jetty = new JettySolrRunner(".", "/solr", 8983);
|
||||
jetty.start();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
public static void main(String[] args) throws Exception {
|
||||
JettySolrRunner jetty = new JettySolrRunner(".", "/solr", 8983);
|
||||
jetty.start();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -829,12 +836,12 @@ public class JettySolrRunner {
|
|||
throw new IllegalStateException("The dispatchFilter is not set!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class Delay {
|
||||
final AtomicInteger counter;
|
||||
final int delayValue;
|
||||
final String reason;
|
||||
|
||||
|
||||
public Delay(String reason, int counter, int delay) {
|
||||
this.reason = reason;
|
||||
this.counter = new AtomicInteger(counter);
|
||||
|
|
|
@ -364,7 +364,7 @@ public class HttpSolrClient extends BaseHttpSolrClient {
|
|||
basePath += "/" + collection;
|
||||
|
||||
if (request instanceof V2Request) {
|
||||
if (System.getProperty("solr.v2RealPath") == null) {
|
||||
if (System.getProperty("solr.v2RealPath") == null || ((V2Request) request).isForceV2()) {
|
||||
basePath = baseUrl.replace("/solr", "/api");
|
||||
} else {
|
||||
basePath = baseUrl + "/____v2";
|
||||
|
|
|
@ -42,6 +42,7 @@ public class V2Request extends SolrRequest<V2Response> implements MapWriter {
|
|||
private SolrParams solrParams;
|
||||
public final boolean useBinary;
|
||||
private String collection;
|
||||
private boolean forceV2 = false;
|
||||
private boolean isPerCollectionRequest = false;
|
||||
|
||||
private V2Request(METHOD m, String resource, boolean useBinary) {
|
||||
|
@ -55,6 +56,10 @@ public class V2Request extends SolrRequest<V2Response> implements MapWriter {
|
|||
|
||||
}
|
||||
|
||||
public boolean isForceV2(){
|
||||
return forceV2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SolrParams getParams() {
|
||||
return solrParams;
|
||||
|
@ -113,6 +118,8 @@ public class V2Request extends SolrRequest<V2Response> implements MapWriter {
|
|||
private SolrParams params;
|
||||
private boolean useBinary = false;
|
||||
|
||||
private boolean forceV2EndPoint = false;
|
||||
|
||||
/**
|
||||
* Create a Builder object based on the provided resource.
|
||||
* The default method is GET.
|
||||
|
@ -129,8 +136,17 @@ public class V2Request extends SolrRequest<V2Response> implements MapWriter {
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only for testing. It's always true otherwise
|
||||
*/
|
||||
public Builder forceV2(boolean flag) {
|
||||
forceV2EndPoint = flag;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set payload for request.
|
||||
*
|
||||
* @param payload as UTF-8 String
|
||||
* @return builder object
|
||||
*/
|
||||
|
@ -161,6 +177,7 @@ public class V2Request extends SolrRequest<V2Response> implements MapWriter {
|
|||
V2Request v2Request = new V2Request(method, resource, useBinary);
|
||||
v2Request.solrParams = params;
|
||||
v2Request.payload = payload;
|
||||
v2Request.forceV2 = forceV2EndPoint;
|
||||
return v2Request;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,9 +42,20 @@ public class TestV2Request extends SolrCloudTestCase {
|
|||
@Before
|
||||
public void setupCluster() throws Exception {
|
||||
configureCluster(4)
|
||||
.withJettyConfig(jettyCfg -> jettyCfg.enableV2(true))
|
||||
.addConfig("config", getFile("solrj/solr/collection1/conf").toPath())
|
||||
.configure();
|
||||
}
|
||||
|
||||
public void testApiPathAvailability() throws Exception {
|
||||
V2Response rsp = new V2Request.Builder("/cluster/nodes")
|
||||
.forceV2(true)
|
||||
.withMethod(SolrRequest.METHOD.GET).build()
|
||||
.process(cluster.getSolrClient());
|
||||
List l = (List) rsp._get("nodes",null);
|
||||
assertNotNull(l);
|
||||
assertFalse(l.isEmpty());
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterTest() throws Exception {
|
||||
|
|
|
@ -786,7 +786,7 @@ public class MiniSolrCloudCluster {
|
|||
if (activeReplicas == expectedReplicas) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Optional;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.solr.SolrTestCaseJ4;
|
||||
|
@ -106,7 +107,7 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
|
|||
private final int nodeCount;
|
||||
private final Path baseDir;
|
||||
private String solrxml = MiniSolrCloudCluster.DEFAULT_CLOUD_SOLR_XML;
|
||||
private JettyConfig jettyConfig = buildJettyConfig("/solr");
|
||||
private JettyConfig.Builder jettyConfigBuilder = JettyConfig.builder().setContext("/solr").withSSLConfig(sslConfig.buildServerSSLConfig());
|
||||
private Optional<String> securityJson = Optional.empty();
|
||||
|
||||
private List<Config> configs = new ArrayList<>();
|
||||
|
@ -126,10 +127,10 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
|
|||
}
|
||||
|
||||
/**
|
||||
* Use a {@link JettyConfig} to configure the cluster's jetty servers
|
||||
* Use a JettyConfig.Builder to configure the cluster's jetty servers
|
||||
*/
|
||||
public Builder withJettyConfig(JettyConfig jettyConfig) {
|
||||
this.jettyConfig = jettyConfig;
|
||||
public Builder withJettyConfig(Consumer<JettyConfig.Builder> fun) {
|
||||
fun.accept(jettyConfigBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -226,6 +227,7 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
|
|||
* @throws Exception if an error occurs on startup
|
||||
*/
|
||||
public MiniSolrCloudCluster build() throws Exception {
|
||||
JettyConfig jettyConfig = jettyConfigBuilder.build();
|
||||
MiniSolrCloudCluster cluster = new MiniSolrCloudCluster(nodeCount, baseDir, solrxml, jettyConfig,
|
||||
null, securityJson, trackJettyMetrics);
|
||||
CloudSolrClient client = cluster.getSolrClient();
|
||||
|
|
Loading…
Reference in New Issue