You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ge...@apache.org on 2023/01/23 19:33:31 UTC
[solr] branch branch_9x updated: SOLR-16615: Revert Jersey app reuse
This is an automated email from the ASF dual-hosted git repository.
gerlowskija pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9x by this push:
new 4069f9b33cf SOLR-16615: Revert Jersey app reuse
4069f9b33cf is described below
commit 4069f9b33cfe649a4e04c21cb33148a443389786
Author: Jason Gerlowski <ge...@apache.org>
AuthorDate: Mon Jan 23 14:31:40 2023 -0500
SOLR-16615: Revert Jersey app reuse
This reverts commit c21719ee2245bceebe124e3d39def9deabd2430c.
---
.../src/java/org/apache/solr/api/V2HttpCall.java | 31 ++-----
.../java/org/apache/solr/core/ConfigOverlay.java | 29 +++----
.../java/org/apache/solr/core/CoreContainer.java | 8 --
.../src/java/org/apache/solr/core/PluginBag.java | 29 ++-----
.../src/java/org/apache/solr/core/SolrConfig.java | 25 +-----
.../src/java/org/apache/solr/core/SolrCore.java | 33 ++------
.../org/apache/solr/core/SolrResourceLoader.java | 46 +---------
.../org/apache/solr/handler/SolrConfigHandler.java | 7 +-
.../designer/SchemaDesignerSettingsDAO.java | 2 +-
.../org/apache/solr/jersey/InjectionFactories.java | 22 -----
.../apache/solr/jersey/JerseyAppHandlerCache.java | 98 ---------------------
.../org/apache/solr/jersey/JerseyApplications.java | 21 +++--
.../org/apache/solr/jersey/MetricBeanFactory.java | 55 ++++++++++++
.../org/apache/solr/jersey/RequestContextKeys.java | 2 -
.../apache/solr/jersey/RequestMetricHandling.java | 34 +++-----
.../solr/jersey/JerseyApplicationSharingTest.java | 99 ----------------------
16 files changed, 126 insertions(+), 415 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
index b2512efcb07..41d3c11417e 100644
--- a/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
+++ b/solr/core/src/java/org/apache/solr/api/V2HttpCall.java
@@ -337,19 +337,14 @@ public class V2HttpCall extends HttpSolrCall {
}
private boolean invokeJerseyRequest(
- CoreContainer cores,
- SolrCore core,
- ApplicationHandler jerseyHandler,
- PluginBag<SolrRequestHandler> requestHandlers,
- SolrQueryResponse rsp) {
- return invokeJerseyRequest(cores, core, jerseyHandler, requestHandlers, rsp, Map.of());
+ CoreContainer cores, SolrCore core, ApplicationHandler primary, SolrQueryResponse rsp) {
+ return invokeJerseyRequest(cores, core, primary, rsp, Map.of());
}
private boolean invokeJerseyRequest(
CoreContainer cores,
SolrCore core,
ApplicationHandler jerseyHandler,
- PluginBag<SolrRequestHandler> requestHandlers,
SolrQueryResponse rsp,
Map<String, String> additionalProperties) {
final ContainerRequest containerRequest =
@@ -360,8 +355,6 @@ public class V2HttpCall extends HttpSolrCall {
containerRequest.setProperty(RequestContextKeys.SOLR_QUERY_REQUEST, solrReq);
containerRequest.setProperty(RequestContextKeys.SOLR_QUERY_RESPONSE, rsp);
containerRequest.setProperty(RequestContextKeys.CORE_CONTAINER, cores);
- containerRequest.setProperty(
- RequestContextKeys.RESOURCE_TO_RH_MAPPING, requestHandlers.getJaxrsRegistry());
containerRequest.setProperty(RequestContextKeys.HTTP_SERVLET_REQ, req);
containerRequest.setProperty(RequestContextKeys.REQUEST_TYPE, requestType);
containerRequest.setProperty(RequestContextKeys.SOLR_PARAMS, queryParams);
@@ -408,12 +401,7 @@ public class V2HttpCall extends HttpSolrCall {
SolrQueryResponse solrResp = new SolrQueryResponse();
final boolean jerseyResourceFound =
invokeJerseyRequest(
- cores,
- null,
- cores.getJerseyApplicationHandler(),
- cores.getRequestHandlers(),
- solrResp,
- suppressNotFoundProp);
+ cores, null, cores.getJerseyApplicationHandler(), solrResp, suppressNotFoundProp);
if (jerseyResourceFound) {
logAndFlushAdminRequest(solrResp);
return;
@@ -427,8 +415,7 @@ public class V2HttpCall extends HttpSolrCall {
@Override
protected void handleAdmin(SolrQueryResponse solrResp) {
if (api == null) {
- invokeJerseyRequest(
- cores, null, cores.getJerseyApplicationHandler(), cores.getRequestHandlers(), solrResp);
+ invokeJerseyRequest(cores, null, cores.getJerseyApplicationHandler(), solrResp);
} else {
SolrCore.preDecorateResponse(solrReq, solrResp);
try {
@@ -462,16 +449,10 @@ public class V2HttpCall extends HttpSolrCall {
Map.of(RequestContextKeys.SUPPRESS_ERROR_ON_NOT_FOUND_EXCEPTION, "true");
final boolean resourceFound =
invokeJerseyRequest(
- cores,
- core,
- core.getJerseyApplicationHandler(),
- core.getRequestHandlers(),
- rsp,
- suppressNotFoundProp);
+ cores, core, core.getJerseyApplicationHandler(), rsp, suppressNotFoundProp);
if (!resourceFound) {
response.getHeaderNames().stream().forEach(name -> response.setHeader(name, null));
- invokeJerseyRequest(
- cores, null, cores.getJerseyApplicationHandler(), cores.getRequestHandlers(), rsp);
+ invokeJerseyRequest(cores, null, cores.getJerseyApplicationHandler(), rsp);
}
} else {
SolrCore.preDecorateResponse(solrReq, rsp);
diff --git a/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java b/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
index 56a01afec14..acfa64941e1 100644
--- a/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
+++ b/solr/core/src/java/org/apache/solr/core/ConfigOverlay.java
@@ -34,15 +34,15 @@ import org.apache.solr.common.util.Utils;
* performed on tbhis gives a new copy of the object with the changed value
*/
public class ConfigOverlay implements MapSerializable {
- private final int version;
+ private final int znodeVersion;
private final Map<String, Object> data;
private Map<String, Object> props;
private Map<String, Object> userProps;
@SuppressWarnings({"unchecked"})
- public ConfigOverlay(Map<String, Object> jsonObj, int version) {
+ public ConfigOverlay(Map<String, Object> jsonObj, int znodeVersion) {
if (jsonObj == null) jsonObj = Collections.emptyMap();
- this.version = version;
+ this.znodeVersion = znodeVersion;
data = Collections.unmodifiableMap(jsonObj);
props = (Map<String, Object>) data.get("props");
if (props == null) props = Collections.emptyMap();
@@ -71,7 +71,7 @@ public class ConfigOverlay implements MapSerializable {
copy.put(key, val);
Map<String, Object> jsonObj = new LinkedHashMap<>(this.data);
jsonObj.put("userProps", copy);
- return new ConfigOverlay(jsonObj, version);
+ return new ConfigOverlay(jsonObj, znodeVersion);
}
public ConfigOverlay unsetUserProperty(String key) {
@@ -80,7 +80,7 @@ public class ConfigOverlay implements MapSerializable {
copy.remove(key);
Map<String, Object> jsonObj = new LinkedHashMap<>(this.data);
jsonObj.put("userProps", copy);
- return new ConfigOverlay(jsonObj, version);
+ return new ConfigOverlay(jsonObj, znodeVersion);
}
@SuppressWarnings({"unchecked", "rawtypes"})
@@ -103,7 +103,7 @@ public class ConfigOverlay implements MapSerializable {
Map<String, Object> jsonObj = new LinkedHashMap<>(this.data);
jsonObj.put("props", deepCopy);
- return new ConfigOverlay(jsonObj, version);
+ return new ConfigOverlay(jsonObj, znodeVersion);
}
public static final String NOT_EDITABLE = "''{0}'' is not an editable property";
@@ -139,15 +139,15 @@ public class ConfigOverlay implements MapSerializable {
Map<String, Object> jsonObj = new LinkedHashMap<>(this.data);
jsonObj.put("props", deepCopy);
- return new ConfigOverlay(jsonObj, version);
+ return new ConfigOverlay(jsonObj, znodeVersion);
}
public byte[] toByteArray() {
return Utils.toJSON(data);
}
- public int getVersion() {
- return version;
+ public int getZnodeVersion() {
+ return znodeVersion;
}
@Override
@@ -236,7 +236,7 @@ public class ConfigOverlay implements MapSerializable {
@Override
public Map<String, Object> toMap(Map<String, Object> map) {
- map.put(ZNODEVER, version);
+ map.put(ZNODEVER, znodeVersion);
map.putAll(data);
return map;
}
@@ -258,7 +258,7 @@ public class ConfigOverlay implements MapSerializable {
Map<String, Object> existing = (Map<String, Object>) dataCopy.get(typ);
if (existing == null) dataCopy.put(typ, existing = new LinkedHashMap<>());
existing.put(info.get(CoreAdminParams.NAME).toString(), info);
- return new ConfigOverlay(dataCopy, this.version);
+ return new ConfigOverlay(dataCopy, this.znodeVersion);
}
@SuppressWarnings({"unchecked"})
@@ -267,14 +267,9 @@ public class ConfigOverlay implements MapSerializable {
Map<?, ?> reqHandler = (Map<?, ?>) dataCopy.get(typ);
if (reqHandler == null) return this;
reqHandler.remove(name);
- return new ConfigOverlay(dataCopy, this.version);
+ return new ConfigOverlay(dataCopy, this.znodeVersion);
}
public static final String ZNODEVER = "znodeVersion";
public static final String NAME = "overlay";
-
- @Override
- public int hashCode() {
- return data.hashCode();
- }
}
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index ce4b0cc2573..666536abc72 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -129,7 +129,6 @@ import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.handler.component.ShardHandlerFactory;
import org.apache.solr.handler.designer.SchemaDesignerAPI;
import org.apache.solr.jersey.InjectionFactories;
-import org.apache.solr.jersey.JerseyAppHandlerCache;
import org.apache.solr.logging.LogWatcher;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.metrics.SolrCoreMetricManager;
@@ -193,16 +192,11 @@ public class CoreContainer {
new PluginBag<>(SolrRequestHandler.class, null);
private volatile ApplicationHandler jerseyAppHandler;
- private volatile JerseyAppHandlerCache appHandlersByConfigSetId;
public ApplicationHandler getJerseyApplicationHandler() {
return jerseyAppHandler;
}
- public JerseyAppHandlerCache getAppHandlerCache() {
- return appHandlersByConfigSetId;
- }
-
/** Minimize exposure to CoreContainer. Mostly only ZK interface is required */
public final Supplier<SolrZkClient> zkClientSupplier = () -> getZkController().getZkClient();
@@ -1098,8 +1092,6 @@ public class CoreContainer {
jerseyAppHandler = new ApplicationHandler(containerHandlers.getJerseyEndpoints());
}
- appHandlersByConfigSetId = new JerseyAppHandlerCache();
-
// Do Node setup logic after all handlers have been registered.
if (isZooKeeperAware()) {
clusterSingletons.setReady();
diff --git a/solr/core/src/java/org/apache/solr/core/PluginBag.java b/solr/core/src/java/org/apache/solr/core/PluginBag.java
index 7e06449ca5a..3711e2c0f17 100644
--- a/solr/core/src/java/org/apache/solr/core/PluginBag.java
+++ b/solr/core/src/java/org/apache/solr/core/PluginBag.java
@@ -69,38 +69,26 @@ public class PluginBag<T> implements AutoCloseable {
private final ApiBag apiBag;
private final ResourceConfig jerseyResources;
- /**
- * Allows JAX-RS 'filters' to find the requestHandler (if any) associated particular JAX-RS
- * resource classes
- *
- * <p>Used primarily by JAX-RS when recording per-request metrics, which requires a {@link
- * org.apache.solr.handler.RequestHandlerBase.HandlerMetrics} object from the relevant
- * requestHandler.
- */
- public static class JaxrsResourceToHandlerMappings
+ public static class JerseyMetricsLookupRegistry
extends HashMap<Class<? extends JerseyResource>, RequestHandlerBase> {}
- private final JaxrsResourceToHandlerMappings jaxrsResourceRegistry;
-
- public JaxrsResourceToHandlerMappings getJaxrsRegistry() {
- return jaxrsResourceRegistry;
- }
+ private final JerseyMetricsLookupRegistry infoBeanByResource;
/** Pass needThreadSafety=true if plugins can be added and removed concurrently with lookups. */
public PluginBag(Class<T> klass, SolrCore core, boolean needThreadSafety) {
if (klass == SolrRequestHandler.class && V2ApiUtils.isEnabled()) {
this.loadV2ApisIfPresent = true;
this.apiBag = new ApiBag(core != null);
- this.jaxrsResourceRegistry = new JaxrsResourceToHandlerMappings();
+ this.infoBeanByResource = new JerseyMetricsLookupRegistry();
this.jerseyResources =
(core == null)
- ? new JerseyApplications.CoreContainerApp()
- : new JerseyApplications.SolrCoreApp();
+ ? new JerseyApplications.CoreContainerApp(infoBeanByResource)
+ : new JerseyApplications.SolrCoreApp(core, infoBeanByResource);
} else {
this.loadV2ApisIfPresent = false;
this.apiBag = null;
this.jerseyResources = null;
- this.jaxrsResourceRegistry = null;
+ this.infoBeanByResource = null;
}
this.core = core;
this.klass = klass;
@@ -262,11 +250,10 @@ public class PluginBag<T> implements AutoCloseable {
log.debug("Registering jersey resource class: {}", jerseyClazz.getName());
}
jerseyResources.register(jerseyClazz);
- // See RequestMetricHandling javadocs for a better understanding of this
- // resource->RH
+ // See MetricsBeanFactory javadocs for a better understanding of this resource->RH
// mapping
if (inst instanceof RequestHandlerBase) {
- jaxrsResourceRegistry.put(jerseyClazz, (RequestHandlerBase) inst);
+ infoBeanByResource.put(jerseyClazz, (RequestHandlerBase) inst);
}
}
}
diff --git a/solr/core/src/java/org/apache/solr/core/SolrConfig.java b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
index 522ee33a357..a3be18156c5 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
@@ -108,7 +108,6 @@ public class SolrConfig implements MapSerializable {
private int znodeVersion;
ConfigNode root;
- int hashCode;
private final SolrResourceLoader resourceLoader;
private Properties substituteProperties;
@@ -179,14 +178,9 @@ public class SolrConfig implements MapSerializable {
ZkSolrResourceLoader.ZkByteArrayInputStream zkin =
(ZkSolrResourceLoader.ZkByteArrayInputStream) in;
zkVersion = zkin.getStat().getVersion();
- hash = Objects.hash(zkin.getStat().getCtime(), zkVersion, overlay.getVersion());
+ hash = Objects.hash(zkin.getStat().getCtime(), zkVersion, overlay.getZnodeVersion());
this.fileName = zkin.fileName;
}
- if (in instanceof SolrResourceLoader.SolrFileInputStream) {
- SolrResourceLoader.SolrFileInputStream sfin = (SolrResourceLoader.SolrFileInputStream) in;
- zkVersion = (int) sfin.getLastModified();
- hash = Objects.hash(sfin.getLastModified(), overlay.getVersion());
- }
}
@Override
@@ -241,10 +235,6 @@ public class SolrConfig implements MapSerializable {
}
});
try {
- // This will hash the solrconfig.xml, user properties and overlay (all possible ways of
- // modifying the resulting SolrConfig)
- hashCode = Objects.hash(this.root.txt(), overlay.getVersion());
-
getRequestParams();
initLibs(loader, isConfigsetTrusted);
String val =
@@ -586,17 +576,11 @@ public class SolrConfig implements MapSerializable {
return new ConfigOverlay(Collections.emptyMap(), -1);
}
- int version = 0;
+ int version = 0; // will be always 0 for file based resourceLoader
if (in instanceof ZkSolrResourceLoader.ZkByteArrayInputStream) {
version = ((ZkSolrResourceLoader.ZkByteArrayInputStream) in).getStat().getVersion();
log.debug("Config overlay loaded. version : {} ", version);
}
- if (in instanceof SolrResourceLoader.SolrFileInputStream) {
- // We should be ok, it is unlikely that a configOverlay is loaded decades apart and has the
- // same version after casting to an int
- version = (int) ((SolrResourceLoader.SolrFileInputStream) in).getLastModified();
- log.debug("Config overlay loaded. version : {} ", version);
- }
@SuppressWarnings("unchecked")
Map<String, Object> m = (Map<String, Object>) Utils.fromJSON(in);
return new ConfigOverlay(m, version);
@@ -1178,9 +1162,4 @@ public class SolrConfig implements MapSerializable {
public ConfigNode get(String name, Predicate<ConfigNode> test) {
return root.get(name, test);
}
-
- @Override
- public int hashCode() {
- return hashCode;
- }
}
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 4f06a96c156..75cb384d4fd 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -110,7 +110,6 @@ import org.apache.solr.handler.SolrConfigHandler;
import org.apache.solr.handler.api.V2ApiUtils;
import org.apache.solr.handler.component.HighlightComponent;
import org.apache.solr.handler.component.SearchComponent;
-import org.apache.solr.jersey.JerseyAppHandlerCache;
import org.apache.solr.logging.MDCLoggingContext;
import org.apache.solr.metrics.SolrCoreMetricManager;
import org.apache.solr.metrics.SolrMetricProducer;
@@ -226,7 +225,7 @@ public class SolrCore implements SolrInfoBean, Closeable {
private final Date startTime = new Date();
private final long startNanoTime = System.nanoTime();
private final RequestHandlers reqHandlers;
- private final RefCounted<ApplicationHandler> appHandlerForConfigSet;
+ private final ApplicationHandler jerseyAppHandler;
private final PluginBag<SearchComponent> searchComponents =
new PluginBag<>(SearchComponent.class, this);
private final PluginBag<UpdateRequestProcessorFactory> updateProcessors =
@@ -1137,23 +1136,10 @@ public class SolrCore implements SolrInfoBean, Closeable {
updateProcessorChains = loadUpdateProcessorChains();
reqHandlers = new RequestHandlers(this);
reqHandlers.initHandlersFromConfig(solrConfig);
- if (V2ApiUtils.isEnabled()) {
- final String effectiveConfigsetId = JerseyAppHandlerCache.generateIdForConfigSet(configSet);
- appHandlerForConfigSet =
- coreContainer
- .getAppHandlerCache()
- .computeIfAbsent(
- effectiveConfigsetId,
- () -> {
- log.debug(
- "Creating Jersey ApplicationHandler for 'effective configset' [{}]",
- effectiveConfigsetId);
- return new ApplicationHandler(
- reqHandlers.getRequestHandlers().getJerseyEndpoints());
- });
- } else {
- appHandlerForConfigSet = null;
- }
+ jerseyAppHandler =
+ (V2ApiUtils.isEnabled())
+ ? new ApplicationHandler(reqHandlers.getRequestHandlers().getJerseyEndpoints())
+ : null;
// cause the executor to stall so firstSearcher events won't fire
// until after inform() has been called for all components.
@@ -1789,9 +1775,6 @@ public class SolrCore implements SolrInfoBean, Closeable {
}
if (reqHandlers != null) reqHandlers.close();
- if (V2ApiUtils.isEnabled()) {
- appHandlerForConfigSet.decref();
- }
responseWriters.close();
searchComponents.close();
qParserPlugins.close();
@@ -1979,7 +1962,7 @@ public class SolrCore implements SolrInfoBean, Closeable {
}
public ApplicationHandler getJerseyApplicationHandler() {
- return appHandlerForConfigSet.get();
+ return jerseyAppHandler;
}
/**
@@ -3407,8 +3390,8 @@ public class SolrCore implements SolrInfoBean, Closeable {
if (solrCore == null || solrCore.isClosed() || solrCore.getCoreContainer().isShutDown())
return;
cfg = solrCore.getSolrConfig();
- solrConfigversion = solrCore.getSolrConfig().getZnodeVersion();
- overlayVersion = solrCore.getSolrConfig().getOverlay().getVersion();
+ solrConfigversion = solrCore.getSolrConfig().getOverlay().getZnodeVersion();
+ overlayVersion = solrCore.getSolrConfig().getZnodeVersion();
if (managedSchmaResourcePath != null) {
managedSchemaVersion =
((ManagedIndexSchema) solrCore.getLatestSchema()).getSchemaZkVersion();
diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
index f01f74ce580..59641b6b912 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
@@ -359,14 +359,11 @@ public class SolrResourceLoader
// The resource is either inside instance dir or we allow unsafe loading, so allow testing if
// file exists
if (Files.exists(inConfigDir) && Files.isReadable(inConfigDir)) {
- return new SolrFileInputStream(
- Files.newInputStream(inConfigDir), Files.getLastModifiedTime(inConfigDir).toMillis());
+ return Files.newInputStream(inConfigDir);
}
if (Files.exists(inInstanceDir) && Files.isReadable(inInstanceDir)) {
- return new SolrFileInputStream(
- Files.newInputStream(inInstanceDir),
- Files.getLastModifiedTime(inInstanceDir).toMillis());
+ return Files.newInputStream(inInstanceDir);
}
}
@@ -988,43 +985,4 @@ public class SolrResourceLoader
// This is to verify if this requires to use the schema classloader for classes loaded from
// packages
private static final ThreadLocal<ResourceLoaderAware> CURRENT_AWARE = new ThreadLocal<>();
-
- public static class SolrFileInputStream extends InputStream {
- private final InputStream delegate;
- private final long lastModified;
-
- public SolrFileInputStream(InputStream delegate, long lastModified) {
- this.delegate = delegate;
- this.lastModified = lastModified;
- }
-
- public long getLastModified() {
- return lastModified;
- }
-
- @Override
- public synchronized int read() throws IOException {
- return delegate.read();
- }
-
- @Override
- public synchronized int read(byte[] bs, int off, int len) throws IOException {
- return delegate.read(bs, off, len);
- }
-
- @Override
- public int available() throws IOException {
- return delegate.available();
- }
-
- @Override
- public synchronized long skip(long n) throws IOException {
- return delegate.skip(n);
- }
-
- @Override
- public void close() throws IOException {
- delegate.close();
- }
- }
}
diff --git a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
index aeb17522b8d..b83fdb57839 100644
--- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
+++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java
@@ -213,12 +213,13 @@ public class SolrConfigHandler extends RequestHandlerBase
resp.add(
ZNODEVER,
Map.of(
- ConfigOverlay.NAME, req.getCore().getSolrConfig().getOverlay().getVersion(),
+ ConfigOverlay.NAME,
+ req.getCore().getSolrConfig().getOverlay().getZnodeVersion(),
RequestParams.NAME,
req.getCore().getSolrConfig().getRequestParams().getZnodeVersion()));
boolean isStale = false;
int expectedVersion = req.getParams().getInt(ConfigOverlay.NAME, -1);
- int actualVersion = req.getCore().getSolrConfig().getOverlay().getVersion();
+ int actualVersion = req.getCore().getSolrConfig().getOverlay().getZnodeVersion();
if (expectedVersion > actualVersion) {
log.info(
"expecting overlay version {} but my version is {}",
@@ -588,7 +589,7 @@ public class SolrConfigHandler extends RequestHandlerBase
int latestVersion =
ZkController.persistConfigResourceToZooKeeper(
(ZkSolrResourceLoader) loader,
- overlay.getVersion(),
+ overlay.getZnodeVersion(),
ConfigOverlay.RESOURCE_NAME,
overlay.toByteArray(),
true);
diff --git a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java
index eea151dc69d..63e11ea4f5d 100644
--- a/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java
+++ b/solr/core/src/java/org/apache/solr/handler/designer/SchemaDesignerSettingsDAO.java
@@ -99,7 +99,7 @@ class SchemaDesignerSettingsDAO implements SchemaDesignerConstants {
if (changed) {
ZkController.persistConfigResourceToZooKeeper(
zkLoaderForConfigSet(configSet),
- overlay.getVersion(),
+ overlay.getZnodeVersion(),
ConfigOverlay.RESOURCE_NAME,
overlay.toByteArray(),
true);
diff --git a/solr/core/src/java/org/apache/solr/jersey/InjectionFactories.java b/solr/core/src/java/org/apache/solr/jersey/InjectionFactories.java
index e794ea30237..ee430c86258 100644
--- a/solr/core/src/java/org/apache/solr/jersey/InjectionFactories.java
+++ b/solr/core/src/java/org/apache/solr/jersey/InjectionFactories.java
@@ -17,11 +17,8 @@
package org.apache.solr.jersey;
-import static org.apache.solr.jersey.RequestContextKeys.SOLR_CORE;
-
import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
-import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
import org.glassfish.hk2.api.Factory;
@@ -65,25 +62,6 @@ public class InjectionFactories {
public void dispose(SolrQueryResponse instance) {}
}
- /** Fetch the (existing) SolrCore from the request context */
- public static class SolrCoreFactory implements Factory<SolrCore> {
-
- private final ContainerRequestContext containerRequestContext;
-
- @Inject
- public SolrCoreFactory(ContainerRequestContext containerRequestContext) {
- this.containerRequestContext = containerRequestContext;
- }
-
- @Override
- public SolrCore provide() {
- return (SolrCore) containerRequestContext.getProperty(SOLR_CORE);
- }
-
- @Override
- public void dispose(SolrCore instance) {}
- }
-
public static class SingletonFactory<T> implements Factory<T> {
private final T singletonVal;
diff --git a/solr/core/src/java/org/apache/solr/jersey/JerseyAppHandlerCache.java b/solr/core/src/java/org/apache/solr/jersey/JerseyAppHandlerCache.java
deleted file mode 100644
index 49b317ef185..00000000000
--- a/solr/core/src/java/org/apache/solr/jersey/JerseyAppHandlerCache.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.jersey;
-
-import java.lang.invoke.MethodHandles;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-import java.util.function.Supplier;
-import org.apache.solr.core.ConfigSet;
-import org.apache.solr.core.SolrConfig;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.util.RefCounted;
-import org.glassfish.jersey.server.ApplicationHandler;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * Stores Jersey 'ApplicationHandler' instances by an ID or hash derived from their {@link
- * ConfigSet}.
- *
- * <p>ApplicationHandler creation is expensive; caching these objects allows them to be shared by
- * multiple cores with the same configuration.
- */
-public class JerseyAppHandlerCache {
-
- private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
-
- private final Map<String, RefCounted<ApplicationHandler>> applicationByConfigSetId;
-
- public JerseyAppHandlerCache() {
- this.applicationByConfigSetId = new ConcurrentHashMap<>();
- }
-
- /**
- * Return the 'ApplicationHandler' associated with the provided ID, creating it first if
- * necessary.
- *
- * <p>This method is thread-safe by virtue of its delegation to {@link
- * ConcurrentHashMap#computeIfAbsent(Object, Function)} internally.
- *
- * @param effectiveConfigSetId an ID to associate the ApplicationHandler with. Usually created via
- * {@link #generateIdForConfigSet(ConfigSet)}.
- * @param createApplicationHandler a Supplier producing an ApplicationHandler
- */
- public RefCounted<ApplicationHandler> computeIfAbsent(
- String effectiveConfigSetId, Supplier<ApplicationHandler> createApplicationHandler) {
- final Function<String, RefCounted<ApplicationHandler>> wrapper =
- s -> {
- return new RefCounted<>(createApplicationHandler.get()) {
- @Override
- public void close() {
- log.info(
- "Removing AppHandler from cache for 'effective configset' [{}]",
- effectiveConfigSetId);
- applicationByConfigSetId.remove(effectiveConfigSetId);
- }
- };
- };
-
- final RefCounted<ApplicationHandler> fetched =
- applicationByConfigSetId.computeIfAbsent(effectiveConfigSetId, wrapper);
- fetched.incref();
- return fetched;
- }
-
- public int size() {
- return applicationByConfigSetId.size();
- }
-
- /**
- * Generates a String ID to represent the provided {@link ConfigSet}
- *
- * <p>Relies on {@link SolrConfig#hashCode()} to generate a different ID for each "unique"
- * configset (where "uniqueness" considers various overlays that get applied to the {@link
- * ConfigSet})
- *
- * @see SolrCore#hashCode()
- */
- public static String generateIdForConfigSet(ConfigSet configSet) {
- return configSet.getName() + "-" + configSet.getSolrConfig().hashCode();
- }
-}
diff --git a/solr/core/src/java/org/apache/solr/jersey/JerseyApplications.java b/solr/core/src/java/org/apache/solr/jersey/JerseyApplications.java
index d3670accfce..7a4bb484e4b 100644
--- a/solr/core/src/java/org/apache/solr/jersey/JerseyApplications.java
+++ b/solr/core/src/java/org/apache/solr/jersey/JerseyApplications.java
@@ -20,6 +20,8 @@ package org.apache.solr.jersey;
import io.swagger.v3.oas.annotations.OpenAPIDefinition;
import io.swagger.v3.oas.annotations.info.Info;
import io.swagger.v3.oas.annotations.info.License;
+import javax.inject.Singleton;
+import org.apache.solr.core.PluginBag;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
@@ -42,7 +44,7 @@ import org.glassfish.jersey.server.ResourceConfig;
public class JerseyApplications {
public static class CoreContainerApp extends ResourceConfig {
- public CoreContainerApp() {
+ public CoreContainerApp(PluginBag.JerseyMetricsLookupRegistry beanRegistry) {
super();
// Authentication and authorization
@@ -61,6 +63,15 @@ public class JerseyApplications {
register(RequestMetricHandling.PreRequestMetricsFilter.class);
register(RequestMetricHandling.PostRequestMetricsFilter.class);
register(PostRequestDecorationFilter.class);
+ register(
+ new AbstractBinder() {
+ @Override
+ protected void configure() {
+ bindFactory(new MetricBeanFactory(beanRegistry))
+ .to(PluginBag.JerseyMetricsLookupRegistry.class)
+ .in(Singleton.class);
+ }
+ });
register(
new AbstractBinder() {
@Override
@@ -91,17 +102,17 @@ public class JerseyApplications {
public static class SolrCoreApp extends CoreContainerApp {
- public SolrCoreApp() {
- super();
+ public SolrCoreApp(SolrCore solrCore, PluginBag.JerseyMetricsLookupRegistry beanRegistry) {
+ super(beanRegistry);
// Dependency Injection for Jersey resources
register(
new AbstractBinder() {
@Override
protected void configure() {
- bindFactory(InjectionFactories.SolrCoreFactory.class)
+ bindFactory(new InjectionFactories.SingletonFactory<>(solrCore))
.to(SolrCore.class)
- .in(RequestScoped.class);
+ .in(Singleton.class);
}
});
}
diff --git a/solr/core/src/java/org/apache/solr/jersey/MetricBeanFactory.java b/solr/core/src/java/org/apache/solr/jersey/MetricBeanFactory.java
new file mode 100644
index 00000000000..c23851359d9
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/jersey/MetricBeanFactory.java
@@ -0,0 +1,55 @@
+/*
+ * 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.jersey;
+
+import org.apache.solr.core.PluginBag;
+import org.glassfish.hk2.api.Factory;
+
+/**
+ * Factory to inject JerseyMetricsLookupRegistry instances into Jersey resources and filters.
+ *
+ * <p>Currently, Jersey resources that have a corresponding v1 API produce the same metrics as their
+ * v1 equivalent and rely on the v1 requestHandler instance to do so. Solr facilitates this by
+ * building a map of the Jersey resource to requestHandler mapping (a {@link
+ * org.apache.solr.core.PluginBag.JerseyMetricsLookupRegistry}), and injecting it into the pre- and
+ * post- Jersey filters that handle metrics.
+ *
+ * <p>This isn't ideal, as requestHandler's don't really "fit" conceptually here. But it's
+ * unavoidable while we want our v2 APIs to exactly match the metrics produced by v1 calls.
+ *
+ * @see RequestMetricHandling.PreRequestMetricsFilter
+ * @see RequestMetricHandling.PostRequestMetricsFilter
+ */
+public class MetricBeanFactory implements Factory<PluginBag.JerseyMetricsLookupRegistry> {
+
+ private final PluginBag.JerseyMetricsLookupRegistry metricsLookupRegistry;
+
+ public MetricBeanFactory(PluginBag.JerseyMetricsLookupRegistry metricsLookupRegistry) {
+ this.metricsLookupRegistry = metricsLookupRegistry;
+ }
+
+ @Override
+ public PluginBag.JerseyMetricsLookupRegistry provide() {
+ return metricsLookupRegistry;
+ }
+
+ @Override
+ public void dispose(PluginBag.JerseyMetricsLookupRegistry instance) {
+ /* No-op */
+ }
+}
diff --git a/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java b/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java
index f300ffa4bbb..68b37aa8758 100644
--- a/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java
+++ b/solr/core/src/java/org/apache/solr/jersey/RequestContextKeys.java
@@ -23,7 +23,6 @@ import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.container.ContainerRequestContext;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.core.CoreContainer;
-import org.apache.solr.core.PluginBag;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.RequestHandlerBase;
import org.apache.solr.request.SolrQueryRequest;
@@ -43,7 +42,6 @@ public interface RequestContextKeys {
String SOLR_QUERY_REQUEST = SolrQueryRequest.class.getName();
String SOLR_QUERY_RESPONSE = SolrQueryResponse.class.getName();
String CORE_CONTAINER = CoreContainer.class.getName();
- String RESOURCE_TO_RH_MAPPING = PluginBag.JaxrsResourceToHandlerMappings.class.getName();
String SOLR_CORE = SolrCore.class.getName();
String REQUEST_TYPE = AuthorizationContext.RequestType.class.getName();
String SOLR_PARAMS = SolrParams.class.getName();
diff --git a/solr/core/src/java/org/apache/solr/jersey/RequestMetricHandling.java b/solr/core/src/java/org/apache/solr/jersey/RequestMetricHandling.java
index a6e8b03919e..595027005ad 100644
--- a/solr/core/src/java/org/apache/solr/jersey/RequestMetricHandling.java
+++ b/solr/core/src/java/org/apache/solr/jersey/RequestMetricHandling.java
@@ -24,6 +24,7 @@ import static org.apache.solr.jersey.RequestContextKeys.TIMER;
import com.codahale.metrics.Timer;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
+import javax.inject.Inject;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.container.ContainerResponseContext;
@@ -39,18 +40,9 @@ import org.slf4j.LoggerFactory;
/**
* A request and response filter used to initialize and report per-request metrics.
*
- * <p>Currently, Jersey resources that have a corresponding v1 API produce the same metrics as their
- * v1 equivalent and rely on the v1 requestHandler instance to do so. Solr facilitates this by
- * building a map of the JAX-RS resources to requestHandler mapping (a {@link
- * org.apache.solr.core.PluginBag.JaxrsResourceToHandlerMappings}), and using that to look up the
- * associated request handler (if one exists) in pre- and post- filters
- *
- * <p>This isn't ideal, as requestHandler's don't really "fit" conceptually here. But it's
- * unavoidable while we want our v2 APIs to exactly match the metrics produced by v1 calls, and
- * while metrics are bundled in with requestHandlers as they are currently.
- *
- * @see RequestMetricHandling.PreRequestMetricsFilter
- * @see RequestMetricHandling.PostRequestMetricsFilter
+ * <p>Currently, JAX-RS v2 APIs rely on a {@link
+ * org.apache.solr.handler.RequestHandlerBase.HandlerMetrics} instance from an associated request
+ * handler.
*/
public class RequestMetricHandling {
@@ -66,18 +58,16 @@ public class RequestMetricHandling {
@Context private ResourceInfo resourceInfo;
+ private PluginBag.JerseyMetricsLookupRegistry beanRegistry;
+
+ @Inject
+ public PreRequestMetricsFilter(PluginBag.JerseyMetricsLookupRegistry beanRegistry) {
+ this.beanRegistry = beanRegistry;
+ }
+
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
- final PluginBag.JaxrsResourceToHandlerMappings requestHandlerByJerseyResource =
- (PluginBag.JaxrsResourceToHandlerMappings)
- requestContext.getProperty(RequestContextKeys.RESOURCE_TO_RH_MAPPING);
- if (requestHandlerByJerseyResource == null) {
- log.debug("No jax-rs registry found for request {}", requestContext);
- return;
- }
-
- final RequestHandlerBase handlerBase =
- requestHandlerByJerseyResource.get(resourceInfo.getResourceClass());
+ final RequestHandlerBase handlerBase = beanRegistry.get(resourceInfo.getResourceClass());
if (handlerBase == null) {
log.debug("No handler found for request {}", requestContext);
return;
diff --git a/solr/core/src/test/org/apache/solr/jersey/JerseyApplicationSharingTest.java b/solr/core/src/test/org/apache/solr/jersey/JerseyApplicationSharingTest.java
deleted file mode 100644
index 6319ecb0bb2..00000000000
--- a/solr/core/src/test/org/apache/solr/jersey/JerseyApplicationSharingTest.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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.jersey;
-
-import java.util.Map;
-import org.apache.solr.client.solrj.SolrClient;
-import org.apache.solr.client.solrj.request.CollectionAdminRequest;
-import org.apache.solr.cloud.SolrCloudTestCase;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-/**
- * Tests ensuring that Jersey apps are shared between cores as expected.
- *
- * <p>Jersey applications should be shared by any cores on the same node that have the same
- * "effective configset" (i.e. the same configset content and any overlays or relevant configuration
- * properties)
- */
-public class JerseyApplicationSharingTest extends SolrCloudTestCase {
-
- private static final String collection = "collection1";
- private static final String confDir = collection + "/conf";
-
- @BeforeClass
- public static void setupCluster() throws Exception {
- configureCluster(1)
- .addConfig("conf1", configset("cloud-minimal"))
- .addConfig("conf2", configset("cloud-minimal"))
- .configure();
- }
-
- @Test
- public void testMultipleCoresWithSameConfigsetShareApplication() throws Exception {
- final SolrClient solrClient = cluster.getSolrClient();
-
- // No applications should be in the cache to start
- assertJerseyAppCacheHasSize(0);
-
- // All replicas for the created collection should share a single Jersey ApplicationHandler entry
- // in the cache
- final CollectionAdminRequest.Create coll1Create =
- CollectionAdminRequest.createCollection("coll1", "conf1", 2, 2);
- assertEquals(0, coll1Create.process(solrClient).getStatus());
- assertJerseyAppCacheHasSize(1);
-
- // A new collection using the same configset will also share the existing cached Jersey
- // ApplicationHandler
- final CollectionAdminRequest.Create coll2Create =
- CollectionAdminRequest.createCollection("coll2", "conf1", 2, 2);
- assertEquals(0, coll2Create.process(solrClient).getStatus());
- assertJerseyAppCacheHasSize(1);
-
- // Using a different configset WILL cause a new Jersey ApplicationHandler to be used (total
- // cache-count = 2)
- final CollectionAdminRequest.Create coll3Create =
- CollectionAdminRequest.createCollection("coll3", "conf2", 2, 2);
- assertEquals(0, coll3Create.process(solrClient).getStatus());
- assertJerseyAppCacheHasSize(2);
-
- // Modifying properties that affect a configset will also cause a new Jersey ApplicationHandler
- // to be created (total cache-count = 3)
- final CollectionAdminRequest.Create coll4Create =
- CollectionAdminRequest.createCollection("coll4", "conf1", 2, 2);
- coll4Create.setProperties(
- Map.of(
- "solr.commitwithin.softcommit",
- "false")); // Set any collection property used in the cloud-minimal configset
- assertEquals(0, coll4Create.process(solrClient).getStatus());
- assertJerseyAppCacheHasSize(3);
-
- // Deleting the only cores that used given ApplicationHandler will remove it from the cache
- // (total cache-count = 2)
- final CollectionAdminRequest.Delete deleteColl3 =
- CollectionAdminRequest.deleteCollection("coll3");
- assertEquals(0, deleteColl3.process(solrClient).getStatus());
- assertJerseyAppCacheHasSize(2);
- }
-
- private void assertJerseyAppCacheHasSize(int expectedSize) {
- assertEquals(
- expectedSize,
- cluster.getJettySolrRunners().get(0).getCoreContainer().getAppHandlerCache().size());
- }
-}