You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ep...@apache.org on 2024/02/13 13:47:39 UTC
(solr) branch main updated: SOLR-17148: Fixing Config API overlay property enabling or disabling cache (#2247)
This is an automated email from the ASF dual-hosted git repository.
epugh 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 a88305d253c SOLR-17148: Fixing Config API overlay property enabling or disabling cache (#2247)
a88305d253c is described below
commit a88305d253ca7fbad444a905b652ff781d3ab41a
Author: Sanjay Dutt <sa...@gmail.com>
AuthorDate: Tue Feb 13 19:17:33 2024 +0530
SOLR-17148: Fixing Config API overlay property enabling or disabling cache (#2247)
---------
Co-authored-by: iamsanjay <sa...@yahoo.com>
---
solr/CHANGES.txt | 2 +
.../java/org/apache/solr/search/CacheConfig.java | 14 +-
.../test/org/apache/solr/core/CacheConfigTest.java | 168 +++++++++++++++++++++
.../apache/solr/core/TestSolrConfigHandler.java | 54 +++++++
4 files changed, 230 insertions(+), 8 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 1f7412baea4..08f38e724b4 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -108,6 +108,8 @@ Bug Fixes
---------------------
* SOLR-17152: Better alignment of Admin UI graph (janhoy)
+* SOLR-17148: Fixing Config API overlay property enabling or disabling the cache (Sanjay Dutt, hossman, Eric Pugh)
+
Dependency Upgrades
---------------------
(No changes)
diff --git a/solr/core/src/java/org/apache/solr/search/CacheConfig.java b/solr/core/src/java/org/apache/solr/search/CacheConfig.java
index aa4d61a2204..83ce72af836 100644
--- a/solr/core/src/java/org/apache/solr/search/CacheConfig.java
+++ b/solr/core/src/java/org/apache/solr/search/CacheConfig.java
@@ -28,7 +28,6 @@ import java.util.function.Supplier;
import org.apache.solr.common.ConfigNode;
import org.apache.solr.common.MapSerializable;
import org.apache.solr.common.util.CollectionUtil;
-import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.PluginInfo;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrResourceLoader;
@@ -81,7 +80,9 @@ public class CacheConfig implements MapSerializable {
public static Map<String, CacheConfig> getMultipleConfigs(
SolrResourceLoader loader, SolrConfig solrConfig, String configPath, List<ConfigNode> nodes) {
- if (nodes == null || nodes.size() == 0) return new LinkedHashMap<>();
+ if (nodes == null || nodes.isEmpty()) {
+ return new LinkedHashMap<>();
+ }
Map<String, CacheConfig> result = CollectionUtil.newHashMap(nodes.size());
for (ConfigNode node : nodes) {
if (node.boolAttr("enabled", true)) {
@@ -94,11 +95,8 @@ public class CacheConfig implements MapSerializable {
}
public static CacheConfig getConfig(SolrConfig solrConfig, ConfigNode node, String xpath) {
- if (!node.exists() || !"true".equals(node.attributes().get("enabled", "true"))) {
- Map<String, Object> m = solrConfig.getOverlay().getEditableSubProperties(xpath);
- if (m == null) return null;
- List<String> parts = StrUtils.splitSmart(xpath, '/');
- return getConfig(solrConfig, parts.get(parts.size() - 1), Collections.emptyMap(), xpath);
+ if (!node.boolAttr("enabled", true) || !node.exists()) {
+ return null;
}
return getConfig(solrConfig, node.name(), node.attributes().asMap(), xpath);
}
@@ -178,7 +176,7 @@ public class CacheConfig implements MapSerializable {
}
@Override
- public Map<String, Object> toMap(Map<String, Object> map) {
+ public Map<String, Object> toMap(Map<String, Object> argsMap) {
// TODO: Should not create new HashMap?
return new HashMap<>(args);
}
diff --git a/solr/core/src/test/org/apache/solr/core/CacheConfigTest.java b/solr/core/src/test/org/apache/solr/core/CacheConfigTest.java
new file mode 100644
index 00000000000..f8825a7f108
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/core/CacheConfigTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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.core;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.ConfigNode;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.search.CacheConfig;
+import org.apache.solr.util.DOMConfigNode;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.mockito.Mockito;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/** Test for {@link CacheConfig} */
+public class CacheConfigTest extends SolrTestCaseJ4 {
+ private static final String XPATH_DOCUMENT_CACHE = "query/documentCache";
+ private static final String XPATH_QUERY_RESULT_CACHE = "query/queryResultCache";
+ private SolrResourceLoader mockSolrResourceLoader;
+ private ConfigOverlay mockConfigOverlay;
+ private ConfigNode overlayConfigNode;
+ private ConfigNode domConfigNode;
+ private ConfigNode domConfigNodeDisable;
+ private SolrConfig mockSolrConfig;
+ private static final DocumentBuilder docBuilder;
+
+ static {
+ try {
+ docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
+ }
+ }
+
+ @BeforeClass
+ public static void ensureWorkingMockito() {
+ SolrTestCaseJ4.assumeWorkingMockito();
+ }
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+ resetMocks();
+ final String initialSize = "99";
+ final String size = "999";
+
+ final Document doc = docBuilder.newDocument();
+ final Element documentCacheNode = doc.createElement("documentCache");
+ documentCacheNode.setAttribute("initialSize", initialSize);
+ documentCacheNode.setAttribute("size", size);
+ documentCacheNode.setAttribute("enabled", "true");
+ domConfigNode = new DOMConfigNode(documentCacheNode);
+ Mockito.when(mockSolrConfig.getOverlay()).thenReturn(mockConfigOverlay);
+ Mockito.when(mockConfigOverlay.getEditableSubProperties(XPATH_DOCUMENT_CACHE)).thenReturn(null);
+
+ final String sizeForQueryResCache = "199";
+ final Document queryResultCacheDoc = docBuilder.newDocument();
+ final Element queryResultNode = queryResultCacheDoc.createElement("queryResultCache");
+ queryResultNode.setAttribute("initialSize", "99");
+ queryResultNode.setAttribute("size", sizeForQueryResCache);
+ queryResultNode.setAttribute("enabled", "false");
+ domConfigNodeDisable = new DOMConfigNode(queryResultNode);
+ }
+
+ public void testSolrConfigPropsForCache() {
+ final CacheConfig cacheConfig =
+ CacheConfig.getConfig(mockSolrConfig, domConfigNode, XPATH_DOCUMENT_CACHE);
+ assertNotNull(cacheConfig);
+ final Map<String, Object> args = cacheConfig.toMap(new HashMap<>());
+ assertNotNull(args);
+ assertEquals("99", args.get("initialSize"));
+ assertEquals("999", args.get("size"));
+ assertEquals("documentCache", cacheConfig.getNodeName());
+ }
+
+ public void testSolrConfigDisabledCache() {
+ Mockito.when(mockSolrConfig.getOverlay()).thenReturn(mockConfigOverlay);
+ Mockito.when(mockConfigOverlay.getEditableSubProperties(XPATH_QUERY_RESULT_CACHE))
+ .thenReturn(null);
+
+ final CacheConfig cacheConfig =
+ CacheConfig.getConfig(mockSolrConfig, domConfigNodeDisable, XPATH_QUERY_RESULT_CACHE);
+ assertNull(cacheConfig);
+ }
+
+ public void testOverlayPropsOverridingSolrConfigProps() {
+ final String overlaidSize = "199";
+ overlayConfigNode =
+ new OverlaidConfigNode(mockConfigOverlay, "documentCache", null, domConfigNode);
+ Mockito.when(mockSolrConfig.getOverlay()).thenReturn(mockConfigOverlay);
+ Mockito.when(mockConfigOverlay.getEditableSubProperties(XPATH_DOCUMENT_CACHE))
+ .thenReturn(Map.of("size", overlaidSize));
+
+ final CacheConfig cacheConfig =
+ CacheConfig.getConfig(mockSolrConfig, domConfigNode, XPATH_DOCUMENT_CACHE);
+ assertNotNull(cacheConfig);
+ final Map<String, Object> args = cacheConfig.toMap(new HashMap<>());
+ assertNotNull(args);
+ assertEquals(overlaidSize, args.get("size"));
+ }
+
+ public void testOverlaidDisabledSolrConfigEnabledCache() {
+ overlayConfigNode =
+ new OverlaidConfigNode(mockConfigOverlay, "queryResultCache", null, domConfigNode);
+ Mockito.when(mockSolrConfig.getOverlay()).thenReturn(mockConfigOverlay);
+ Mockito.when(mockConfigOverlay.getXPathProperty(Arrays.asList("queryResultCache", "enabled")))
+ .thenReturn("false");
+
+ final CacheConfig cacheConfig =
+ CacheConfig.getConfig(mockSolrConfig, overlayConfigNode, XPATH_QUERY_RESULT_CACHE);
+ assertNull(cacheConfig);
+ }
+
+ public void testOverlaidEnabledSolrConfigDisabledCache() {
+ overlayConfigNode =
+ new OverlaidConfigNode(mockConfigOverlay, "queryResultCache", null, domConfigNodeDisable);
+ Mockito.when(mockSolrConfig.getOverlay()).thenReturn(mockConfigOverlay);
+ Mockito.when(mockConfigOverlay.getXPathProperty(Arrays.asList("queryResultCache", "enabled")))
+ .thenReturn("true");
+
+ final CacheConfig cacheConfig =
+ CacheConfig.getConfig(mockSolrConfig, overlayConfigNode, XPATH_QUERY_RESULT_CACHE);
+ assertNotNull(cacheConfig);
+ final Map<String, Object> args = cacheConfig.toMap(new HashMap<>());
+ assertNotNull(args);
+ assertEquals("99", args.get("initialSize"));
+ assertEquals("queryResultCache", cacheConfig.getNodeName());
+ }
+
+ public void testEmptyConfigNodeCache() {
+ final ConfigNode emptyNodeSolrConfig = ConfigNode.EMPTY;
+ final CacheConfig cacheConfig =
+ CacheConfig.getConfig(mockSolrConfig, emptyNodeSolrConfig, null);
+ assertNull(cacheConfig);
+ }
+
+ private void resetMocks() {
+ mockSolrConfig = mock(SolrConfig.class);
+ mockConfigOverlay = mock(ConfigOverlay.class);
+ mockSolrResourceLoader = mock(SolrResourceLoader.class);
+ when(mockSolrConfig.getResourceLoader()).thenReturn(mockSolrResourceLoader);
+ }
+}
diff --git a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java
index 515f28c86eb..9ef6256d991 100644
--- a/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java
+++ b/solr/core/src/test/org/apache/solr/core/TestSolrConfigHandler.java
@@ -1011,4 +1011,58 @@ public class TestSolrConfigHandler extends RestTestBase {
return new LinkedHashMapWriter<>();
}
}
+
+ public void testCacheDisableSolrConfig() throws Exception {
+ RESTfulServerProvider oldProvider = restTestHarness.getServerProvider();
+ restTestHarness.setServerProvider(() -> getBaseUrl());
+ MapWriter confMap = getRespMap("/admin/metrics", restTestHarness);
+ assertNotNull(
+ confMap._get(
+ asList("metrics", "solr.core.collection1", "CACHE.searcher.fieldValueCache"), null));
+ // Here documentCache is disabled at initialization in SolrConfig
+ assertNull(
+ confMap._get(
+ asList("metrics", "solr.core.collection1", "CACHE.searcher.documentCache"), null));
+ restTestHarness.setServerProvider(oldProvider);
+ }
+
+ public void testSetPropertyCacheSize() throws Exception {
+ RESTfulServerProvider oldProvider = restTestHarness.getServerProvider();
+ // Changing cache size
+ String payload = "{'set-property' : { 'query.documentCache.size': 399} }";
+ runConfigCommand(restTestHarness, "/config", payload);
+ MapWriter overlay = getRespMap("/config/overlay", restTestHarness);
+ assertEquals("399", overlay._getStr("overlay/props/query/documentCache/size", null));
+ // Setting size only will not enable the cache
+ restTestHarness.setServerProvider(() -> getBaseUrl());
+ MapWriter confMap = getRespMap("/admin/metrics", restTestHarness);
+ assertNull(
+ confMap._get(
+ asList("metrics", "solr.core.collection1", "CACHE.searcher.documentCache"), null));
+ restTestHarness.setServerProvider(oldProvider);
+ }
+
+ public void testSetPropertyEnableAndDisableCache() throws Exception {
+ RESTfulServerProvider oldProvider = restTestHarness.getServerProvider();
+ // Enabling Cache
+ String payload = "{'set-property' : { 'query.documentCache.enabled': true} }";
+ runConfigCommand(restTestHarness, "/config", payload);
+ restTestHarness.setServerProvider(() -> getBaseUrl());
+ MapWriter confMap = getRespMap("/admin/metrics", restTestHarness);
+ assertNotNull(
+ confMap._get(
+ asList("metrics", "solr.core.collection1", "CACHE.searcher.documentCache"), null));
+
+ // Disabling Cache
+ payload = "{ 'set-property' : { 'query.documentCache.enabled': false } }";
+ restTestHarness.setServerProvider(oldProvider);
+ runConfigCommand(restTestHarness, "/config", payload);
+ restTestHarness.setServerProvider(() -> getBaseUrl());
+ confMap = getRespMap("/admin/metrics", restTestHarness);
+ assertNull(
+ confMap._get(
+ asList("metrics", "solr.core.collection1", "CACHE.searcher.documentCache"), null));
+
+ restTestHarness.setServerProvider(oldProvider);
+ }
}