You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by no...@apache.org on 2019/08/29 04:07:04 UTC
[lucene-solr] 01/02: SOLR-13723: JettySolrRunner should support
/api/* (the v2 end point)
This is an automated email from the ASF dual-hosted git repository.
noble pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
commit 7d026f803d03467e9152de07381bdc246b26c8ce
Author: Noble Paul <no...@users.noreply.github.com>
AuthorDate: Thu Aug 29 14:01:52 2019 +1000
SOLR-13723: JettySolrRunner should support /api/* (the v2 end point)
---
.../solr/client/solrj/embedded/JettyConfig.java | 14 ++-
.../client/solrj/embedded/JettySolrRunner.java | 109 +++++++++++----------
.../solr/client/solrj/impl/HttpSolrClient.java | 2 +-
.../solr/client/solrj/request/V2Request.java | 17 ++++
.../solr/client/solrj/request/TestV2Request.java | 11 +++
.../apache/solr/cloud/MiniSolrCloudCluster.java | 2 +-
.../org/apache/solr/cloud/SolrCloudTestCase.java | 10 +-
7 files changed, 106 insertions(+), 59 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettyConfig.java b/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettyConfig.java
index bff63e1..e4a0547 100644
--- a/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettyConfig.java
+++ b/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettyConfig.java
@@ -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);
}
}
diff --git a/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java b/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
index ba94104..c98bbb4 100644
--- a/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
+++ b/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
@@ -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);
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
index 75db5a1..7498075 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java
@@ -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";
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/request/V2Request.java b/solr/solrj/src/java/org/apache/solr/client/solrj/request/V2Request.java
index 17e3c9b..4236177 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/request/V2Request.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/request/V2Request.java
@@ -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.
@@ -130,7 +137,16 @@ public class V2Request extends SolrRequest<V2Response> implements MapWriter {
}
/**
+ * 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;
}
}
diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestV2Request.java b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestV2Request.java
index 300b6c5..fa34267 100644
--- a/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestV2Request.java
+++ b/solr/solrj/src/test/org/apache/solr/client/solrj/request/TestV2Request.java
@@ -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 {
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
index eca5235..7c6d120 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/MiniSolrCloudCluster.java
@@ -786,7 +786,7 @@ public class MiniSolrCloudCluster {
if (activeReplicas == expectedReplicas) {
return true;
}
-
+
return false;
};
}
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
index d8d2472..23283cc 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
@@ -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();