This is an automated email from the ASF dual-hosted git repository.
gus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new 4153aa83955 SOLR-18046 RateLimitFilter, rename
EssentialSolrRequestFilter (#4065)
4153aa83955 is described below
commit 4153aa839556f8397673c40691ede46af16437ed
Author: Gus Heck <[email protected]>
AuthorDate: Fri Jan 23 22:44:40 2026 -0500
SOLR-18046 RateLimitFilter, rename EssentialSolrRequestFilter (#4065)
---
changelog/unreleased/SOLR-18046.yml | 8 +++
.../org/apache/solr/core/RateLimiterConfig.java | 6 +-
.../solr/servlet/CoreContainerAwareHttpFilter.java | 10 ---
.../apache/solr/servlet/CoreContainerProvider.java | 30 ---------
.../apache/solr/servlet/LoadAdminUiServlet.java | 2 +-
.../org/apache/solr/servlet/RateLimitFilter.java | 76 ++++++++++++++++++++++
.../org/apache/solr/servlet/RateLimitManager.java | 23 ++++---
...tFilter.java => RequiredSolrRequestFilter.java} | 23 +++----
.../java/org/apache/solr/servlet/ServletUtils.java | 36 +---------
.../apache/solr/servlet/SolrDispatchFilter.java | 42 ++++++------
.../org/apache/solr/util/tracing/TraceUtils.java | 12 ++--
.../solr/servlet/TestRequestRateLimiter.java | 25 +++----
.../org/apache/solr/embedded/JettySolrRunner.java | 26 ++++++--
solr/webapp/web/WEB-INF/web.xml | 12 +++-
14 files changed, 179 insertions(+), 152 deletions(-)
diff --git a/changelog/unreleased/SOLR-18046.yml
b/changelog/unreleased/SOLR-18046.yml
new file mode 100644
index 00000000000..6c03a3b395a
--- /dev/null
+++ b/changelog/unreleased/SOLR-18046.yml
@@ -0,0 +1,8 @@
+# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
+title: Ratelimiting now exists in it's own Servlet filter which can be
customized or removed.
+type: other # added, changed, fixed, deprecated, removed, dependency_update,
security, other
+authors:
+ - name: Gus Heck
+links:
+ - name: SOLR-18046
+ url: https://issues.apache.org/jira/browse/SOLR-18046
diff --git a/solr/core/src/java/org/apache/solr/core/RateLimiterConfig.java
b/solr/core/src/java/org/apache/solr/core/RateLimiterConfig.java
index b3c00cf4cf0..e0444df4375 100644
--- a/solr/core/src/java/org/apache/solr/core/RateLimiterConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/RateLimiterConfig.java
@@ -17,14 +17,14 @@
package org.apache.solr.core;
-import static
org.apache.solr.servlet.RateLimitManager.DEFAULT_CONCURRENT_REQUESTS;
-import static
org.apache.solr.servlet.RateLimitManager.DEFAULT_SLOT_ACQUISITION_TIMEOUT_MS;
-
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.request.beans.RateLimiterPayload;
public class RateLimiterConfig {
public static final String RL_CONFIG_KEY = "rate-limiters";
+ public static final int DEFAULT_CONCURRENT_REQUESTS =
+ (Runtime.getRuntime().availableProcessors()) * 3;
+ public static final long DEFAULT_SLOT_ACQUISITION_TIMEOUT_MS = -1;
public final SolrRequest.SolrRequestType requestType;
public final boolean isEnabled;
diff --git
a/solr/core/src/java/org/apache/solr/servlet/CoreContainerAwareHttpFilter.java
b/solr/core/src/java/org/apache/solr/servlet/CoreContainerAwareHttpFilter.java
index bfddf0357b7..36226ccb001 100644
---
a/solr/core/src/java/org/apache/solr/servlet/CoreContainerAwareHttpFilter.java
+++
b/solr/core/src/java/org/apache/solr/servlet/CoreContainerAwareHttpFilter.java
@@ -33,7 +33,6 @@ public abstract class CoreContainerAwareHttpFilter extends
HttpFilter {
@Override
public void init(FilterConfig config) throws ServletException {
- super.init(config);
containerProvider =
CoreContainerProvider.serviceForContext(config.getServletContext());
if (log.isTraceEnabled()) {
log.trace("{}.init(): {}", this.getClass().getName(),
this.getClass().getClassLoader());
@@ -47,13 +46,4 @@ public abstract class CoreContainerAwareHttpFilter extends
HttpFilter {
public CoreContainer getCores() throws UnavailableException {
return containerProvider.getCoreContainer();
}
-
- // TODO: not fond of having these here, but RateLimiter initialization can
be sorted out later
- RateLimitManager getRateLimitManager() {
- return containerProvider.getRateLimitManager();
- }
-
- void replaceRateLimitManager(RateLimitManager rlm) {
- containerProvider.setRateLimitManager(rlm);
- }
}
diff --git
a/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
b/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
index d7e6adad942..c718ef0e569 100644
--- a/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
+++ b/solr/core/src/java/org/apache/solr/servlet/CoreContainerProvider.java
@@ -23,7 +23,6 @@ import static
org.apache.solr.servlet.SolrDispatchFilter.SOLR_INSTALL_DIR_ATTRIB
import static org.apache.solr.servlet.SolrDispatchFilter.SOLR_LOG_LEVEL;
import static org.apache.solr.servlet.SolrDispatchFilter.SOLR_LOG_MUTECONSOLE;
-import com.google.common.annotations.VisibleForTesting;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
@@ -45,16 +44,13 @@ import javax.naming.NoInitialContextException;
import org.apache.lucene.store.MMapDirectory;
import org.apache.lucene.util.VectorUtil;
import org.apache.solr.client.api.util.SolrVersion;
-import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
-import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.util.EnvUtils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.NodeConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrXmlConfig;
-import org.apache.solr.servlet.RateLimitManager.Builder;
import org.apache.solr.util.StartupLoggingUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -67,8 +63,6 @@ import org.slf4j.LoggerFactory;
public class CoreContainerProvider implements ServletContextListener {
private static final Logger log =
LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private CoreContainer cores;
- // TODO: this probably should not live here...
- private RateLimitManager rateLimitManager;
/**
* Acquires an instance from the context. Never null.
@@ -187,21 +181,6 @@ public class CoreContainerProvider implements
ServletContextListener {
coresInit = createCoreContainer(computeSolrHome(servletContext),
extraProperties);
- SolrZkClient zkClient = null;
- ZkController zkController = coresInit.getZkController();
-
- if (zkController != null) {
- zkClient = zkController.getZkClient();
- }
-
- Builder builder = new Builder(zkClient);
-
- this.rateLimitManager = builder.build();
-
- if (zkController != null) {
-
zkController.zkStateReader.registerClusterPropertiesListener(this.rateLimitManager);
- }
-
if (log.isDebugEnabled()) {
log.debug("user.dir={}", System.getProperty("user.dir"));
}
@@ -364,13 +343,4 @@ public class CoreContainerProvider implements
ServletContextListener {
coreContainer.load();
return coreContainer;
}
-
- public RateLimitManager getRateLimitManager() {
- return rateLimitManager;
- }
-
- @VisibleForTesting
- void setRateLimitManager(RateLimitManager rateLimitManager) {
- this.rateLimitManager = rateLimitManager;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
b/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
index 24b0d6e1063..1c381f06f8c 100644
--- a/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
+++ b/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
@@ -16,7 +16,7 @@
*/
package org.apache.solr.servlet;
-import static
org.apache.solr.servlet.EssentialSolrRequestFilter.CORE_CONTAINER_REQUEST_ATTRIBUTE;
+import static
org.apache.solr.servlet.RequiredSolrRequestFilter.CORE_CONTAINER_REQUEST_ATTRIBUTE;
import com.google.common.net.HttpHeaders;
import jakarta.servlet.http.HttpServlet;
diff --git a/solr/core/src/java/org/apache/solr/servlet/RateLimitFilter.java
b/solr/core/src/java/org/apache/solr/servlet/RateLimitFilter.java
new file mode 100644
index 00000000000..6f0d301e086
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/servlet/RateLimitFilter.java
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+package org.apache.solr.servlet;
+
+import com.google.common.annotations.VisibleForTesting;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import org.apache.solr.common.SolrException;
+
+public class RateLimitFilter extends CoreContainerAwareHttpFilter {
+ private RateLimitManager rateLimitManager;
+
+ @Override
+ public void init(FilterConfig config) throws ServletException {
+ super.init(config);
+ RateLimitManager.Builder builder = new RateLimitManager.Builder();
+ builder.withZk(getCores().getZkController());
+ this.rateLimitManager = builder.build();
+ }
+
+ @Override
+ protected void doFilter(HttpServletRequest req, HttpServletResponse res,
FilterChain chain)
+ throws IOException, ServletException {
+ RateLimitManager rateLimitManager = getRateLimitManager();
+ try (RequestRateLimiter.SlotReservation accepted =
rateLimitManager.handleRequest(req)) {
+ if (accepted == null) {
+ res.sendError(
+ SolrException.ErrorCode.TOO_MANY_REQUESTS.code,
RateLimitManager.ERROR_MESSAGE);
+ return;
+ }
+ // todo: this shouldn't be required, tracing and rate limiting should be
independently
+ // composable
+ ServletUtils.traceHttpRequestExecution2(
+ req,
+ res,
+ () -> {
+ try {
+ chain.doFilter(req, res);
+ } catch (Exception e) {
+ throw new ExceptionWhileTracing(e);
+ }
+ });
+ } catch (InterruptedException e1) {
+ Thread.currentThread().interrupt();
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
e1.getMessage());
+ }
+ }
+
+ public RateLimitManager getRateLimitManager() {
+ return rateLimitManager;
+ }
+
+ @VisibleForTesting
+ void setRateLimitManager(RateLimitManager rateLimitManager) {
+ this.rateLimitManager = rateLimitManager;
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/servlet/RateLimitManager.java
b/solr/core/src/java/org/apache/solr/servlet/RateLimitManager.java
index 3a5da1f39e9..8ca04c086a3 100644
--- a/solr/core/src/java/org/apache/solr/servlet/RateLimitManager.java
+++ b/solr/core/src/java/org/apache/solr/servlet/RateLimitManager.java
@@ -28,8 +28,8 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import net.jcip.annotations.ThreadSafe;
import org.apache.solr.client.solrj.SolrRequest;
+import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.cloud.ClusterPropertiesListener;
-import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.core.RateLimiterConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -49,9 +49,6 @@ public class RateLimitManager implements
ClusterPropertiesListener {
public static final String ERROR_MESSAGE =
"Too many requests for this request type. Please try after some time or
increase the quota for this request type";
- public static final int DEFAULT_CONCURRENT_REQUESTS =
- (Runtime.getRuntime().availableProcessors()) * 3;
- public static final long DEFAULT_SLOT_ACQUISITION_TIMEOUT_MS = -1;
private final ConcurrentHashMap<String, RequestRateLimiter>
requestRateLimiterMap;
public RateLimitManager() {
@@ -175,18 +172,24 @@ public class RateLimitManager implements
ClusterPropertiesListener {
}
public static class Builder {
- protected SolrZkClient solrZkClient;
+ protected ZkController solrZk;
- public Builder(SolrZkClient solrZkClient) {
- this.solrZkClient = solrZkClient;
+ public Builder() {}
+
+ @SuppressWarnings("UnusedReturnValue")
+ public Builder withZk(ZkController zkClient) {
+ solrZk = zkClient;
+ return this;
}
public RateLimitManager build() {
RateLimitManager rateLimitManager = new RateLimitManager();
-
rateLimitManager.registerRequestRateLimiter(
- new QueryRateLimiter(solrZkClient),
SolrRequest.SolrRequestType.QUERY);
-
+ new QueryRateLimiter(solrZk == null ? null : solrZk.getZkClient()),
+ SolrRequest.SolrRequestType.QUERY);
+ if (solrZk != null) {
+
solrZk.zkStateReader.registerClusterPropertiesListener(rateLimitManager);
+ }
return rateLimitManager;
}
}
diff --git
a/solr/core/src/java/org/apache/solr/servlet/EssentialSolrRequestFilter.java
b/solr/core/src/java/org/apache/solr/servlet/RequiredSolrRequestFilter.java
similarity index 78%
rename from
solr/core/src/java/org/apache/solr/servlet/EssentialSolrRequestFilter.java
rename to
solr/core/src/java/org/apache/solr/servlet/RequiredSolrRequestFilter.java
index 076d7caae6c..50ec9decdc9 100644
--- a/solr/core/src/java/org/apache/solr/servlet/EssentialSolrRequestFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/RequiredSolrRequestFilter.java
@@ -35,10 +35,10 @@ import org.slf4j.LoggerFactory;
* It is expected that solr will fail to function as intended without the
conditions initialized in
* this filter. Before adding anything to this filter ask yourself if a user
could run without the
* feature you are adding (either with an alternative implementation or
without it at all to reduce
- * cpu/memory/dependencies). If it is not essential, it should have its own
separate filter. Also,
- * please include a comment indicating why the thing added is essential.
+ * cpu/memory/dependencies). If it is not required, it should have its own
separate filter. Also,
+ * please include a comment indicating why the thing added here is required.
*/
-public class EssentialSolrRequestFilter extends CoreContainerAwareHttpFilter {
+public class RequiredSolrRequestFilter extends CoreContainerAwareHttpFilter {
// Best to put constant here because solr is not supposed to be functional
(or compile)
// without this filter.
@@ -55,25 +55,22 @@ public class EssentialSolrRequestFilter extends
CoreContainerAwareHttpFilter {
// this autocloseable is here to invoke MDCSnapshot.close() which restores
captured state
try (var mdcSnapshot = MDCSnapshot.create()) {
- // MDC logging *shouldn't* be essential but currently is, see SOLR-18050.
- // Our use of SLF4J indicates that we intend logging to be pluggable, and
- // some implementations won't have an MDC, so having it as essential
limits
- // logging implementations.
+ // MDC logging *shouldn't* be required but currently is, see SOLR-18050.
log.trace("MDC snapshot recorded {}", mdcSnapshot); // avoid both
compiler and ide warning.
MDCLoggingContext.reset();
MDCLoggingContext.setNode(getCores());
- // This is essential to accommodate libraries that (annoyingly) use
+ // This is required to accommodate libraries that (annoyingly) use
// Thread.currentThread().getContextClassLoader()
Thread.currentThread().setContextClassLoader(getCores().getResourceLoader().getClassLoader());
// set a request timer which can be reused by requests if needed
- // Request Timer is essential for QueryLimits functionality as well as
+ // Request Timer is required for QueryLimits functionality as well as
// timing our requests.
req.setAttribute(SolrRequestParsers.REQUEST_TIMER_SERVLET_ATTRIBUTE, new
RTimerTree());
// put the core container in request attribute
- // This is essential for the LoadAdminUiServlet class. Removing it will
cause 404
+ // This is required for the LoadAdminUiServlet class. Removing it will
cause 404
req.setAttribute(CORE_CONTAINER_REQUEST_ATTRIBUTE, getCores());
chain.doFilter(req, res);
} finally {
@@ -81,15 +78,15 @@ public class EssentialSolrRequestFilter extends
CoreContainerAwareHttpFilter {
MDCLoggingContext.reset();
Thread.currentThread().setContextClassLoader(contextClassLoader);
- // This is an essential safety valve to ensure we don't accidentally
bleed information
+ // This is a required safety valve to ensure we don't accidentally bleed
information
// between requests.
SolrRequestInfo.reset();
if (!req.isAsyncStarted()) { // jetty's proxy uses this
- // essential to avoid SOLR-8453 and SOLR-8683
+ // required to avoid SOLR-8453 and SOLR-8683
ServletUtils.consumeInputFully(req, res);
- // essential to remove temporary files created during multipart
requests.
+ // required to remove temporary files created during multipart
requests.
SolrRequestParsers.cleanupMultipartFiles(req);
}
}
diff --git a/solr/core/src/java/org/apache/solr/servlet/ServletUtils.java
b/solr/core/src/java/org/apache/solr/servlet/ServletUtils.java
index f63a16187d2..97af38d8b27 100644
--- a/solr/core/src/java/org/apache/solr/servlet/ServletUtils.java
+++ b/solr/core/src/java/org/apache/solr/servlet/ServletUtils.java
@@ -32,8 +32,6 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.invoke.MethodHandles;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.util.Utils;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.util.tracing.TraceUtils;
@@ -126,34 +124,6 @@ public abstract class ServletUtils {
};
}
- /**
- * Enforces rate limiting for a request. Should be converted to a servlet
filter at some point.
- * Currently, this is tightly coupled with request tracing which is not
ideal either.
- *
- * @param request The request to limit
- * @param response The associated response
- * @param limitedExecution code that will be traced
- */
- static void rateLimitRequest(
- RateLimitManager rateLimitManager,
- HttpServletRequest request,
- HttpServletResponse response,
- Runnable limitedExecution)
- throws ServletException, IOException {
- try (RequestRateLimiter.SlotReservation accepted =
rateLimitManager.handleRequest(request)) {
- if (accepted == null) {
- response.sendError(ErrorCode.TOO_MANY_REQUESTS.code,
RateLimitManager.ERROR_MESSAGE);
- return;
- }
- // todo: this shouldn't be required, tracing and rate limiting should be
independently
- // composable
- traceHttpRequestExecution2(request, response, limitedExecution);
- } catch (InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new SolrException(ErrorCode.SERVER_ERROR, e.getMessage());
- }
- }
-
/**
* Sets up tracing for an HTTP request. Perhaps should be converted to a
servlet filter at some
* point.
@@ -162,7 +132,7 @@ public abstract class ServletUtils {
* @param response The associated response
* @param tracedExecution the executed code
*/
- private static void traceHttpRequestExecution2(
+ static void traceHttpRequestExecution2(
HttpServletRequest request, HttpServletResponse response, Runnable
tracedExecution)
throws ServletException, IOException {
Context context = TraceUtils.extractContext(request);
@@ -181,10 +151,6 @@ public abstract class ServletUtils {
}
tracedExecution.run();
} catch (ExceptionWhileTracing e) {
- if (e.e instanceof SolrAuthenticationException) {
- // done, the response and status code have already been sent
- return;
- }
if (e.e instanceof ServletException) {
throw (ServletException) e.e;
}
diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
index 43de6e2bd07..0d0bef9b6ce 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -18,7 +18,6 @@ package org.apache.solr.servlet;
import static org.apache.solr.servlet.ServletUtils.closeShield;
import static org.apache.solr.util.tracing.TraceUtils.getSpan;
-import static org.apache.solr.util.tracing.TraceUtils.setTracer;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
@@ -125,7 +124,8 @@ public class SolrDispatchFilter extends
CoreContainerAwareHttpFilter {
public void doFilter(HttpServletRequest request, HttpServletResponse
response, FilterChain chain)
throws IOException, ServletException {
// internal version of doFilter that tracks if we are in a retry
- doFilterRetry(closeShield(request), closeShield(response), chain, false);
+
+ dispatch(chain, closeShield(request), closeShield(response), false);
}
/*
@@ -140,30 +140,25 @@ public class SolrDispatchFilter extends
CoreContainerAwareHttpFilter {
before adding anything else to it.
*/
- private void doFilterRetry(
- HttpServletRequest request, HttpServletResponse response, FilterChain
chain, boolean retry)
- throws IOException, ServletException {
- setTracer(request, getCores().getTracer());
- RateLimitManager rateLimitManager = getRateLimitManager();
- ServletUtils.rateLimitRequest(
- rateLimitManager,
- request,
- response,
- () -> {
- try {
- dispatch(chain, request, response, retry);
- } catch (IOException | ServletException |
SolrAuthenticationException e) {
- throw new ExceptionWhileTracing(e);
- }
- });
- }
-
private void dispatch(
FilterChain chain, HttpServletRequest request, HttpServletResponse
response, boolean retry)
- throws IOException, ServletException, SolrAuthenticationException {
+ throws IOException, ServletException {
AtomicReference<HttpServletRequest> wrappedRequest = new
AtomicReference<>();
- authenticateRequest(request, response, wrappedRequest);
+ try {
+ authenticateRequest(request, response, wrappedRequest);
+ } catch (SolrAuthenticationException e) {
+ // it seems our auth system expects the plugin to set the status on the
request.
+ // If this hasn't happened make sure it does happen now rather than
throwing an
+ // exception, that formerly went on to be ignored in
+ // org.apache.solr.servlet.ServletUtils.traceHttpRequestExecution2
+ if (response.getStatus() < 400) {
+ log.error(
+ "Authentication Plugin threw SolrAuthenticationException without
setting request status >= 400");
+ response.sendError(401, "Authentication Plugin rejected credentials.");
+ }
+ return; // Nothing more to do, chain.doFilter(req,res) doesn't get
called.
+ }
if (wrappedRequest.get() != null) {
request = wrappedRequest.get();
}
@@ -193,7 +188,8 @@ public class SolrDispatchFilter extends
CoreContainerAwareHttpFilter {
break;
case RETRY:
span.addEvent("SolrDispatchFilter RETRY");
- doFilterRetry(request, response, chain, true); // RECURSION
+ // RECURSION
+ dispatch(chain, request, response, true);
break;
case FORWARD:
span.addEvent("SolrDispatchFilter FORWARD");
diff --git a/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java
b/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java
index 645a412f6c1..9936dfbb232 100644
--- a/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java
+++ b/solr/core/src/java/org/apache/solr/util/tracing/TraceUtils.java
@@ -30,7 +30,9 @@ import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
+import org.apache.solr.core.CoreContainer;
import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.servlet.RequiredSolrRequestFilter;
import org.eclipse.jetty.client.Request;
/** Utilities for distributed tracing. */
@@ -134,12 +136,12 @@ public class TraceUtils {
return (Span) req.getAttribute(REQ_ATTR_TRACING_SPAN);
}
- public static void setTracer(HttpServletRequest req, Tracer t) {
- req.setAttribute(REQ_ATTR_TRACING_TRACER, t);
- }
-
public static Tracer getTracer(HttpServletRequest req) {
- return (Tracer) req.getAttribute(REQ_ATTR_TRACING_TRACER);
+ // This attribute is required to be not null, this method should only be
called after
+ // requiredSolrRequestFilter has invoked chain.doFilter(req, res)
+ return ((CoreContainer)
+
req.getAttribute(RequiredSolrRequestFilter.CORE_CONTAINER_REQUEST_ATTRIBUTE))
+ .getTracer();
}
public static Context extractContext(HttpServletRequest req) {
diff --git
a/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
b/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
index fd29c164b02..1c7c49b1c41 100644
--- a/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
+++ b/solr/core/src/test/org/apache/solr/servlet/TestRequestRateLimiter.java
@@ -19,7 +19,7 @@ package org.apache.solr.servlet;
import static
org.apache.solr.common.params.CommonParams.SOLR_REQUEST_CONTEXT_PARAM;
import static
org.apache.solr.common.params.CommonParams.SOLR_REQUEST_TYPE_PARAM;
-import static
org.apache.solr.servlet.RateLimitManager.DEFAULT_SLOT_ACQUISITION_TIMEOUT_MS;
+import static
org.apache.solr.core.RateLimiterConfig.DEFAULT_SLOT_ACQUISITION_TIMEOUT_MS;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -49,7 +49,6 @@ import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.cloud.SolrCloudTestCase;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
-import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.util.ExecutorUtil;
import org.apache.solr.core.RateLimiterConfig;
import org.junit.BeforeClass;
@@ -74,7 +73,7 @@ public class TestRequestRateLimiter extends SolrCloudTestCase
{
CollectionAdminRequest.createCollection(FIRST_COLLECTION, 1,
1).process(client);
cluster.waitForActiveCollection(FIRST_COLLECTION, 1, 1);
- SolrDispatchFilter solrDispatchFilter =
cluster.getJettySolrRunner(0).getSolrDispatchFilter();
+ RateLimitFilter rateLimitFilter =
cluster.getJettySolrRunner(0).getSolrRateLimitFilter();
RateLimiterConfig rateLimiterConfig =
new RateLimiterConfig(
@@ -87,11 +86,10 @@ public class TestRequestRateLimiter extends
SolrCloudTestCase {
// We are fine with a null FilterConfig here since we ensure that
MockBuilder never invokes
// its parent here
RateLimitManager.Builder builder =
- new MockBuilder(
- null /* dummy SolrZkClient */, new
MockRequestRateLimiter(rateLimiterConfig));
+ new MockBuilder(new MockRequestRateLimiter(rateLimiterConfig));
RateLimitManager rateLimitManager = builder.build();
- solrDispatchFilter.replaceRateLimitManager(rateLimitManager);
+ rateLimitFilter.setRateLimitManager(rateLimitManager);
int numDocs = TEST_NIGHTLY ? 10000 : 100;
@@ -295,7 +293,7 @@ public class TestRequestRateLimiter extends
SolrCloudTestCase {
CollectionAdminRequest.createCollection(SECOND_COLLECTION, 1,
1).process(client);
cluster.waitForActiveCollection(SECOND_COLLECTION, 1, 1);
- SolrDispatchFilter solrDispatchFilter =
cluster.getJettySolrRunner(0).getSolrDispatchFilter();
+ RateLimitFilter rateLimitFilter =
cluster.getJettySolrRunner(0).getSolrRateLimitFilter();
RateLimiterConfig queryRateLimiterConfig =
new RateLimiterConfig(
@@ -317,12 +315,11 @@ public class TestRequestRateLimiter extends
SolrCloudTestCase {
// its parent
RateLimitManager.Builder builder =
new MockBuilder(
- null /*dummy SolrZkClient */,
new MockRequestRateLimiter(queryRateLimiterConfig),
new MockRequestRateLimiter(indexRateLimiterConfig));
RateLimitManager rateLimitManager = builder.build();
- solrDispatchFilter.replaceRateLimitManager(rateLimitManager);
+ rateLimitFilter.setRateLimitManager(rateLimitManager);
int numDocs = 10000;
@@ -435,18 +432,16 @@ public class TestRequestRateLimiter extends
SolrCloudTestCase {
private final RequestRateLimiter queryRequestRateLimiter;
private final RequestRateLimiter indexRequestRateLimiter;
- public MockBuilder(SolrZkClient zkClient, RequestRateLimiter
queryRequestRateLimiter) {
- super(zkClient);
+ public MockBuilder(RequestRateLimiter queryRequestRateLimiter) {
+ super();
this.queryRequestRateLimiter = queryRequestRateLimiter;
this.indexRequestRateLimiter = null;
}
public MockBuilder(
- SolrZkClient zkClient,
- RequestRateLimiter queryRequestRateLimiter,
- RequestRateLimiter indexRequestRateLimiter) {
- super(zkClient);
+ RequestRateLimiter queryRequestRateLimiter, RequestRateLimiter
indexRequestRateLimiter) {
+ super();
this.queryRequestRateLimiter = queryRequestRateLimiter;
this.indexRequestRateLimiter = indexRequestRateLimiter;
diff --git
a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
index 99ebe39fe67..2530ed7acd4 100644
--- a/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
+++ b/solr/test-framework/src/java/org/apache/solr/embedded/JettySolrRunner.java
@@ -61,8 +61,9 @@ import org.apache.solr.common.util.Utils;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.metrics.SolrMetricManager;
import org.apache.solr.servlet.CoreContainerProvider;
-import org.apache.solr.servlet.EssentialSolrRequestFilter;
import org.apache.solr.servlet.PathExclusionFilter;
+import org.apache.solr.servlet.RateLimitFilter;
+import org.apache.solr.servlet.RequiredSolrRequestFilter;
import org.apache.solr.servlet.SolrDispatchFilter;
import org.apache.solr.util.SocketProxy;
import org.apache.solr.util.TimeOut;
@@ -113,7 +114,8 @@ public class JettySolrRunner {
volatile FilterHolder debugFilter;
volatile FilterHolder pathExcludeFilter;
- volatile FilterHolder essentialFilter;
+ volatile FilterHolder requiredFilter;
+ volatile FilterHolder rateLimitFilter;
volatile FilterHolder dispatchFilter;
private int jettyPort = -1;
@@ -411,9 +413,13 @@ public class JettySolrRunner {
pathExcludeFilter.setHeldClass(PathExclusionFilter.class);
pathExcludeFilter.setInitParameter("excludePatterns", excludePatterns);
- // logging context setup
- essentialFilter =
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
- essentialFilter.setHeldClass(EssentialSolrRequestFilter.class);
+ // required request setup
+ requiredFilter =
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
+ requiredFilter.setHeldClass(RequiredSolrRequestFilter.class);
+
+ // Ratelimit Requests
+ rateLimitFilter =
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
+ rateLimitFilter.setHeldClass(RateLimitFilter.class);
// This is our main workhorse
dispatchFilter =
root.getServletHandler().newFilterHolder(Source.EMBEDDED);
@@ -421,7 +427,8 @@ public class JettySolrRunner {
// Map dispatchFilter in same path as in web.xml
root.addFilter(pathExcludeFilter, "/*",
EnumSet.of(DispatcherType.REQUEST));
- root.addFilter(essentialFilter, "/*",
EnumSet.of(DispatcherType.REQUEST));
+ root.addFilter(requiredFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
+ root.addFilter(rateLimitFilter, "/*",
EnumSet.of(DispatcherType.REQUEST));
root.addFilter(dispatchFilter, "/*", EnumSet.of(DispatcherType.REQUEST));
// Default servlet as a fall-through
@@ -478,6 +485,13 @@ public class JettySolrRunner {
return (SolrDispatchFilter) dispatchFilter.getFilter();
}
+ /**
+ * @return the {@link SolrDispatchFilter} for this node
+ */
+ public RateLimitFilter getSolrRateLimitFilter() {
+ return (RateLimitFilter) rateLimitFilter.getFilter();
+ }
+
/**
* @return the {@link CoreContainer} for this node
*/
diff --git a/solr/webapp/web/WEB-INF/web.xml b/solr/webapp/web/WEB-INF/web.xml
index af5e733526c..e383133ea6d 100644
--- a/solr/webapp/web/WEB-INF/web.xml
+++ b/solr/webapp/web/WEB-INF/web.xml
@@ -46,7 +46,7 @@
<filter>
<filter-name>MDCLoggingFilter</filter-name>
-
<filter-class>org.apache.solr.servlet.EssentialSolrRequestFilter</filter-class>
+
<filter-class>org.apache.solr.servlet.RequiredSolrRequestFilter</filter-class>
</filter>
<filter-mapping>
@@ -54,6 +54,16 @@
<url-pattern>/*</url-pattern>
</filter-mapping>
+ <filter>
+ <filter-name>RateLimitFilter</filter-name>
+ <filter-class>org.apache.solr.servlet.RateLimitFilter</filter-class>
+ </filter>
+
+ <filter-mapping>
+ <filter-name>RateLimitFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+
<filter>
<filter-name>SolrRequestFilter</filter-name>
<filter-class>org.apache.solr.servlet.SolrDispatchFilter</filter-class>