This is an automated email from the ASF dual-hosted git repository. dsmiley pushed a commit to branch branch_10x in repository https://gitbox.apache.org/repos/asf/solr.git
commit fbf16dedeb8c804a7a47c69daa14ac7cc552876b Author: Jalaz Kumar <[email protected]> AuthorDate: Mon Oct 12 17:46:01 2026 +0530 SOLR-16396 | Migrate GET /config/overlay and GET /config/znodeVersion to JAX-RS. (#5022) (cherry picked from commit 597ed67740831566b708b793f52554b2e49e7e17) --- .../unreleased/SOLR-16396-config-get-others.yml | 9 ++ .../apache/solr/client/api/endpoint/ConfigApi.java | 26 +++++ .../client/api/model/ConfigOverlayResponse.java | 25 +++++ .../api/model/ConfigZnodeVersionResponse.java | 32 ++++++ .../org/apache/solr/handler/SolrConfigHandler.java | 122 ++++++++++----------- .../apache/solr/handler/admin/api/GetConfig.java | 29 +++++ .../solr/handler/admin/api/GetConfigAPI.java | 2 - .../solr/handler/admin/V2ConfigAPIMappingTest.java | 2 - .../handler/admin/api/GetConfigSolrCloudTest.java | 26 ++++- .../solr/handler/admin/api/GetConfigTest.java | 24 ++++ .../solrj/src/resources/java-template/api.mustache | 8 +- 11 files changed, 234 insertions(+), 71 deletions(-) diff --git a/changelog/unreleased/SOLR-16396-config-get-others.yml b/changelog/unreleased/SOLR-16396-config-get-others.yml new file mode 100644 index 00000000000..56e36c32586 --- /dev/null +++ b/changelog/unreleased/SOLR-16396-config-get-others.yml @@ -0,0 +1,9 @@ +title: + Migrate GET /config/overlay and GET /config/znodeVersion to JAX-RS. +type: changed +authors: + - name: Jalaz Kumar + nick: jaykay12 +links: + - name: SOLR-16396 + url: https://issues.apache.org/jira/browse/SOLR-16396 diff --git a/solr/api/src/java/org/apache/solr/client/api/endpoint/ConfigApi.java b/solr/api/src/java/org/apache/solr/client/api/endpoint/ConfigApi.java index 3e0ab463af2..cc9cecc1bb5 100644 --- a/solr/api/src/java/org/apache/solr/client/api/endpoint/ConfigApi.java +++ b/solr/api/src/java/org/apache/solr/client/api/endpoint/ConfigApi.java @@ -25,6 +25,8 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.QueryParam; import org.apache.solr.client.api.model.ConfigInfoResponse; +import org.apache.solr.client.api.model.ConfigOverlayResponse; +import org.apache.solr.client.api.model.ConfigZnodeVersionResponse; import org.apache.solr.client.api.util.StoreApiParameters; /** V2 API for reading and modifying a core/collection's config */ @@ -42,5 +44,29 @@ public interface ConfigApi { @DefaultValue("false") @Parameter(description = "Expand request handler useParams and effective parameters") boolean expandParams); + + @GET + @Path("/overlay") + @StoreApiParameters + @Operation( + summary = "Fetch the config overlay of the specified core or collection", + tags = {"config"}) + ConfigOverlayResponse getOverlay(); + + @GET + @Path("/znodeVersion") + @StoreApiParameters + @Operation( + summary = "Fetch znode versions for config overlay and request params", + tags = {"config"}) + ConfigZnodeVersionResponse getZnodeVersion( + @QueryParam("overlay") + @DefaultValue("-1") + @Parameter(description = "Expected overlay znode version") + int expectedOverlayVersion, + @QueryParam("params") + @DefaultValue("-1") + @Parameter(description = "Expected request-params znode version") + int expectedParamsVersion); } } diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ConfigOverlayResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/ConfigOverlayResponse.java new file mode 100644 index 00000000000..e75aaf25fba --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/model/ConfigOverlayResponse.java @@ -0,0 +1,25 @@ +/* + * 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.client.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.Map; + +public class ConfigOverlayResponse extends SolrJerseyResponse { + @JsonProperty("overlay") + public Map<String, Object> overlay; +} diff --git a/solr/api/src/java/org/apache/solr/client/api/model/ConfigZnodeVersionResponse.java b/solr/api/src/java/org/apache/solr/client/api/model/ConfigZnodeVersionResponse.java new file mode 100644 index 00000000000..01cecfaa73f --- /dev/null +++ b/solr/api/src/java/org/apache/solr/client/api/model/ConfigZnodeVersionResponse.java @@ -0,0 +1,32 @@ +/* + * 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.client.api.model; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class ConfigZnodeVersionResponse extends SolrJerseyResponse { + @JsonProperty("znodeVersion") + public ZnodeVersions znodeVersion; + + public static class ZnodeVersions { + @JsonProperty("overlay") + public int overlay; + + @JsonProperty("params") + public int params; + } +} 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 f8b96086fd7..7f79e5a55e3 100644 --- a/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/SolrConfigHandler.java @@ -173,7 +173,7 @@ public class SolrConfigHandler extends RequestHandlerBase return immutable != null && Boolean.parseBoolean(immutable.toString()); } - private class Command { + private static class Command { private final SolrQueryRequest req; private final SolrQueryResponse resp; private final String method; @@ -201,7 +201,7 @@ public class SolrConfigHandler extends RequestHandlerBase resp, new GetConfig(req).getConfig(req.getParams().getBool("expandParams", false))); } else { if (ConfigOverlay.NAME.equals(parts.get(1))) { - resp.add(ConfigOverlay.NAME, req.getCore().getSolrConfig().getOverlay()); + V2ApiUtils.squashIntoSolrResponseWithoutHeader(resp, new GetConfig(req).getOverlay()); } else if (RequestParams.NAME.equals(parts.get(1))) { if (parts.size() == 3) { RequestParams params = req.getCore().getSolrConfig().getRequestParams(); @@ -218,66 +218,12 @@ public class SolrConfigHandler extends RequestHandlerBase } else { if (ZNODEVER.equals(parts.get(1))) { - resp.add( - ZNODEVER, - Map.of( - ConfigOverlay.NAME, - req.getCore().getSolrConfig().getOverlay().getVersion(), - 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(); - if (expectedVersion > actualVersion) { - log.info( - "expecting overlay version {} but my version is {}", - expectedVersion, - actualVersion); - isStale = true; - } else if (expectedVersion != -1) { - log.info("I already have the expected version {} of config", expectedVersion); - } - expectedVersion = req.getParams().getInt(RequestParams.NAME, -1); - actualVersion = req.getCore().getSolrConfig().getRequestParams().getZnodeVersion(); - if (expectedVersion > actualVersion) { - log.info( - "expecting params version {} but my version is {}", - expectedVersion, - actualVersion); - isStale = true; - } else if (expectedVersion != -1) { - log.info("I already have the expected version {} of params", expectedVersion); - } - if (isStale && req.getCore().getResourceLoader() instanceof ZkSolrResourceLoader) { - new Thread( - () -> { - if (!reloadLock.tryLock()) { - log.info("Another reload is in progress . Not doing anything"); - return; - } - try { - log.info("Trying to update my configs"); - SolrCore.getConfListener( - req.getCore(), - (ZkSolrResourceLoader) req.getCore().getResourceLoader()) - .run(); - } catch (Exception e) { - log.error("Unable to refresh conf ", e); - } finally { - reloadLock.unlock(); - } - }, - SolrConfigHandler.class.getSimpleName() + "-refreshconf") - .start(); - } else { - if (log.isInfoEnabled()) { - log.info( - "isStale {} , resourceloader {}", - isStale, - req.getCore().getResourceLoader().getClass().getName()); - } - } - + V2ApiUtils.squashIntoSolrResponseWithoutHeader( + resp, + new GetConfig(req) + .getZnodeVersion( + req.getParams().getInt(ConfigOverlay.NAME, -1), + req.getParams().getInt(RequestParams.NAME, -1))); } else { Map<String, Object> m = getConfigDetails(parts.get(1), req); Map<String, Object> val = new LinkedHashMap<>(); @@ -970,6 +916,58 @@ public class SolrConfigHandler extends RequestHandlerBase return activeReplicas; } + public static void maybeRefreshStaleConfig( + SolrCore core, int expectedOverlayVersion, int expectedParamsVersion) { + boolean isStale = + isExpectedVersionStale( + "overlay", expectedOverlayVersion, core.getSolrConfig().getOverlay().getVersion()) + | isExpectedVersionStale( + "params", + expectedParamsVersion, + core.getSolrConfig().getRequestParams().getZnodeVersion()); + if (isStale && core.getResourceLoader() instanceof ZkSolrResourceLoader) { + final Lock reloadLock = + ((SolrConfigHandler) core.getRequestHandler("/config")).getReloadLock(); + new Thread( + () -> { + if (!reloadLock.tryLock()) { + log.info("Another reload is in progress . Not doing anything"); + return; + } + try { + log.info("Trying to update my configs"); + SolrCore.getConfListener(core, (ZkSolrResourceLoader) core.getResourceLoader()) + .run(); + } catch (Exception e) { + log.error("Unable to refresh conf ", e); + } finally { + reloadLock.unlock(); + } + }, + SolrConfigHandler.class.getSimpleName() + "-refreshconf") + .start(); + } else { + if (log.isInfoEnabled()) { + log.info( + "isStale {} , resourceloader {}", + isStale, + core.getResourceLoader().getClass().getName()); + } + } + } + + private static boolean isExpectedVersionStale(String label, int expected, int actual) { + if (expected == -1) { + return false; + } + if (expected > actual) { + log.info("expecting {} version {} but my version is {}", label, expected, actual); + return true; + } + log.info("I already have the expected version {} of {}", expected, label); + return false; + } + @Override public Name getPermissionName(AuthorizationContext ctx) { switch (ctx.getHttpMethod()) { diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java index d46738ea347..80d46e7bac6 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfig.java @@ -30,6 +30,8 @@ import java.util.Map; import org.apache.solr.api.JerseyResource; import org.apache.solr.client.api.endpoint.ConfigApi; import org.apache.solr.client.api.model.ConfigInfoResponse; +import org.apache.solr.client.api.model.ConfigOverlayResponse; +import org.apache.solr.client.api.model.ConfigZnodeVersionResponse; import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.NamedList; @@ -37,6 +39,7 @@ import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; import org.apache.solr.core.PluginInfo; import org.apache.solr.handler.RequestHandlerBase; +import org.apache.solr.handler.SolrConfigHandler; import org.apache.solr.jersey.NullKeyTolerantMap; import org.apache.solr.jersey.PermissionName; import org.apache.solr.request.SolrQueryRequest; @@ -60,6 +63,32 @@ public class GetConfig extends JerseyResource implements ConfigApi.Get { return response; } + @Override + @PermissionName(CONFIG_READ_PERM) + public ConfigOverlayResponse getOverlay() { + final var response = instantiateJerseyResponse(ConfigOverlayResponse.class); + response.overlay = + Utils.convertToMap( + solrQueryRequest.getCore().getSolrConfig().getOverlay(), new LinkedHashMap<>()); + return response; + } + + @Override + @PermissionName(CONFIG_READ_PERM) + public ConfigZnodeVersionResponse getZnodeVersion( + int expectedOverlayVersion, int expectedParamsVersion) { + final var response = instantiateJerseyResponse(ConfigZnodeVersionResponse.class); + final var core = solrQueryRequest.getCore(); + final var solrConfig = core.getSolrConfig(); + + response.znodeVersion = new ConfigZnodeVersionResponse.ZnodeVersions(); + response.znodeVersion.overlay = solrConfig.getOverlay().getVersion(); + response.znodeVersion.params = solrConfig.getRequestParams().getZnodeVersion(); + + SolrConfigHandler.maybeRefreshStaleConfig(core, expectedOverlayVersion, expectedParamsVersion); + return response; + } + @SuppressWarnings({"unchecked"}) private Map<String, Object> buildConfigMap( SolrQueryRequest solrQueryRequest, boolean expandParams) { diff --git a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfigAPI.java b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfigAPI.java index 2a2db95683e..6a0567c987c 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfigAPI.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/api/GetConfigAPI.java @@ -59,8 +59,6 @@ public class GetConfigAPI { // Delete a path from this list when that section is migrated to Jersey @EndPoint( path = { - "/config/overlay", - "/config/znodeVersion", "/config/luceneMatchVersion", "/config/query", "/config/requestHandler", diff --git a/solr/core/src/test/org/apache/solr/handler/admin/V2ConfigAPIMappingTest.java b/solr/core/src/test/org/apache/solr/handler/admin/V2ConfigAPIMappingTest.java index 0498b25dd5c..252946a5971 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/V2ConfigAPIMappingTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/V2ConfigAPIMappingTest.java @@ -49,11 +49,9 @@ public class V2ConfigAPIMappingTest extends V2ApiMappingTest<SolrConfigHandler> // the API lookup works for a handful of the valid config "components". @Test public void testGetSingleComponentConfig() { - assertAnnotatedApiExistsFor("GET", "/config/overlay"); assertAnnotatedApiExistsFor("GET", "/config/query"); assertAnnotatedApiExistsFor("GET", "/config/jmx"); assertAnnotatedApiExistsFor("GET", "/config/requestDispatcher"); - assertAnnotatedApiExistsFor("GET", "/config/znodeVersion"); assertAnnotatedApiExistsFor("GET", "/config/luceneMatchVersion"); assertAnnotatedApiExistsFor("GET", "/config/indexConfigdeletionPolicy"); assertAnnotatedApiExistsFor("GET", "/config/updateHandlerupdateLog"); diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigSolrCloudTest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigSolrCloudTest.java index 297da96353d..7ce43a5ff3d 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigSolrCloudTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigSolrCloudTest.java @@ -40,7 +40,7 @@ public class GetConfigSolrCloudTest extends SolrCloudTestCase { } @Test - public void testGetConfigFromCore() throws Exception { + public void testGetConfigFromCollection() throws Exception { var request = new ConfigApi.GetConfig(IndexType.COLLECTION, COLLECTION_NAME); var response = request.process(cluster.getSolrClient()); @@ -52,4 +52,28 @@ public class GetConfigSolrCloudTest extends SolrCloudTestCase { assertTrue(response.config.containsKey("query")); assertTrue(response.config.containsKey("requestHandler")); } + + @Test + public void testGetOverlayFromCollection() throws Exception { + var request = new ConfigApi.GetOverlay(IndexType.COLLECTION, COLLECTION_NAME); + var response = request.process(cluster.getSolrClient()); + + assertNotNull(response); + assertNull(response.error); + assertNotNull(response.overlay); + assertTrue(response.overlay.containsKey("znodeVersion")); + assertEquals(-1, response.overlay.get("znodeVersion")); + } + + @Test + public void testGetZnodeVersionFromCollection() throws Exception { + var request = new ConfigApi.GetZnodeVersion(IndexType.COLLECTION, COLLECTION_NAME); + var response = request.process(cluster.getSolrClient()); + + assertNotNull(response); + assertNull(response.error); + assertNotNull(response.znodeVersion); + assertTrue(response.znodeVersion.overlay >= -1); + assertTrue(response.znodeVersion.params >= -1); + } } diff --git a/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java b/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java index c122e8d497a..a17d9258a18 100644 --- a/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java +++ b/solr/core/src/test/org/apache/solr/handler/admin/api/GetConfigTest.java @@ -56,4 +56,28 @@ public class GetConfigTest extends SolrTestCase { assertTrue(response.config.containsKey("searchComponent")); assertTrue(response.config.containsKey("updateProcessor")); } + + @Test + public void testGetOverlayFromCore() throws Exception { + var request = new ConfigApi.GetOverlay(IndexType.CORE, CORE_NAME); + var response = request.process(solrTestRule.getSolrClient(CORE_NAME)); + + assertNotNull(response); + assertNull(response.error); + assertNotNull(response.overlay); + assertTrue(response.overlay.containsKey("znodeVersion")); + assertEquals(-1, response.overlay.get("znodeVersion")); + } + + @Test + public void testGetZnodeVersionFromCore() throws Exception { + var request = new ConfigApi.GetZnodeVersion(IndexType.CORE, CORE_NAME); + var response = request.process(solrTestRule.getSolrClient(CORE_NAME)); + + assertNotNull(response); + assertNull(response.error); + assertNotNull(response.znodeVersion); + assertTrue(response.znodeVersion.overlay >= -1); + assertTrue(response.znodeVersion.params >= -1); + } } diff --git a/solr/solrj/src/resources/java-template/api.mustache b/solr/solrj/src/resources/java-template/api.mustache index 4aae4828561..b8c0dce8168 100644 --- a/solr/solrj/src/resources/java-template/api.mustache +++ b/solr/solrj/src/resources/java-template/api.mustache @@ -233,14 +233,14 @@ public class {{classname}} { @Override public SolrParams getParams() { - final ModifiableSolrParams params = new ModifiableSolrParams(); + final ModifiableSolrParams solrParams = new ModifiableSolrParams(); {{#queryParams}} if ({{paramName}} != null) { - {{#isArray}}{{paramName}}.forEach(v -> params.add("{{baseName}}", v{{^items.isString}}.toString(){{/items.isString}}));{{/isArray}} - {{^isArray}}params.add("{{baseName}}", {{paramName}}{{^isString}}.toString(){{/isString}});{{/isArray}} + {{#isArray}}{{paramName}}.forEach(v -> solrParams.add("{{baseName}}", v{{^items.isString}}.toString(){{/items.isString}}));{{/isArray}} + {{^isArray}}solrParams.add("{{baseName}}", {{paramName}}{{^isString}}.toString(){{/isString}});{{/isArray}} } {{/queryParams}} - return params; + return solrParams; } @Override
