You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by md...@apache.org on 2022/05/18 17:46:36 UTC

[lucene-solr] branch branch_8_11 updated: SOLR-16143 SolrConfig ResourceProvider can miss updates from ZooKeeper (#2655)

This is an automated email from the ASF dual-hosted git repository.

mdrob pushed a commit to branch branch_8_11
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8_11 by this push:
     new b3bf5447c2d SOLR-16143 SolrConfig ResourceProvider can miss updates from ZooKeeper (#2655)
b3bf5447c2d is described below

commit b3bf5447c2dc9c92023e7673c21e4eb24dd31065
Author: Mike Drob <md...@apache.org>
AuthorDate: Wed May 18 12:46:26 2022 -0500

    SOLR-16143 SolrConfig ResourceProvider can miss updates from ZooKeeper (#2655)
    
    (cherry picked from commit 3ed851fc84015f092271ccf8f93c1d20737804ca)
---
 solr/CHANGES.txt                                   |  2 +
 .../src/java/org/apache/solr/core/SolrConfig.java  |  2 +-
 .../solr/configsets/_default/conf/managed-schema   | 32 ++++++++
 .../solr/configsets/_default/conf/solrconfig.xml   | 87 +++++++++++++++++++++
 .../solr/util/MultipleManagedSchemasTest.java      | 91 ++++++++++++++++++++++
 5 files changed, 213 insertions(+), 1 deletion(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 36b5ef828bf..64859b647f8 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -50,6 +50,8 @@ Bug Fixes
 
 * SOLR-16019: UTF-8 parsing errors for parameters should cause a HTTP 400 status code, not 500 (janhoy, Matthias Pigulla)
 
+* SOLR-16143: SolrConfig can miss updates from ZooKeeper when deleting and recreating file items (Mike Drob)
+
 ==================  8.11.1 ==================
 
 Consult the LUCENE_CHANGES.txt file for additional, low level, changes in this release.
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 66693f216bf..2785f76e4db 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrConfig.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrConfig.java
@@ -177,7 +177,7 @@ public class SolrConfig implements MapSerializable {
       if (in instanceof ZkSolrResourceLoader.ZkByteArrayInputStream) {
         ZkSolrResourceLoader.ZkByteArrayInputStream zkin = (ZkSolrResourceLoader.ZkByteArrayInputStream) in;
         zkVersion = zkin.getStat().getVersion();
-        hash = Objects.hash(zkVersion, overlay.getZnodeVersion());
+        hash = Objects.hash(zkin.getStat().getCtime(), zkVersion, overlay.getZnodeVersion());
         this.fileName = zkin.fileName;
       }
     }
diff --git a/solr/core/src/test-files/solr/configsets/_default/conf/managed-schema b/solr/core/src/test-files/solr/configsets/_default/conf/managed-schema
new file mode 100644
index 00000000000..fbf0cbbe6db
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/_default/conf/managed-schema
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<schema name="default-config" version="1.6">
+    <uniqueKey>id</uniqueKey>
+    <field name="id" type="string" indexed="true" stored="true" required="true" multiValued="false" />
+    <fieldType name="string" class="solr.StrField" sortMissingLast="true" docValues="true" />
+
+    <field name="_version_" type="plong" indexed="false" stored="false"/>
+    <fieldType name="plong" class="solr.LongPointField" docValues="true"/>
+
+    <fieldType name="booleans" class="solr.BoolField" sortMissingLast="true" multiValued="true"/>
+    <dynamicField name="*_bs" type="booleans" indexed="true" stored="true"/>
+
+    <!-- Used by AddSchemaFieldsUpdateProcessorFactory field type mappings -->
+    <fieldType name="text_general" class="solr.TextField" positionIncrementGap="100" multiValued="true" />
+</schema>
diff --git a/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml b/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml
new file mode 100644
index 00000000000..b6191029056
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/_default/conf/solrconfig.xml
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!--
+ 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.
+-->
+
+<config>
+  <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+
+  <dataDir>${solr.data.dir:}</dataDir>
+
+  <directoryFactory name="DirectoryFactory"
+                    class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
+
+  <codecFactory class="solr.SchemaCodecFactory"/>
+
+  <!-- The default high-performance update handler -->
+  <updateHandler class="solr.DirectUpdateHandler2">
+    <updateLog>
+      <str name="dir">${solr.ulog.dir:}</str>
+      <int name="numVersionBuckets">${solr.ulog.numVersionBuckets:65536}</int>
+    </updateLog>
+  </updateHandler>
+
+  <!-- Primary search handler, expected by most clients, examples and UI frameworks -->
+  <requestHandler name="/select" class="solr.SearchHandler">
+    <lst name="defaults">
+      <str name="echoParams">explicit</str>
+      <int name="rows">10</int>
+    </lst>
+  </requestHandler>
+
+  <!-- Add unknown fields to the schema
+
+       Field type guessing update request processors that will
+       attempt to parse string-typed field values as Booleans, Longs,
+       Doubles, or Dates, and then add schema fields with the guessed
+       field types Text content will be indexed as "text_general" as
+       well as a copy to a plain string version in *_str.
+       See the updateRequestProcessorChain defined later for the order they are executed in.
+
+       These require that the schema is both managed and mutable, by
+       declaring schemaFactory as ManagedIndexSchemaFactory, with
+       mutable specified as true.
+
+       See https://solr.apache.org/guide/schemaless-mode.html for further explanation.
+
+    -->
+  <updateProcessor class="solr.UUIDUpdateProcessorFactory" name="uuid"/>
+  <updateProcessor class="solr.AddSchemaFieldsUpdateProcessorFactory" name="add-schema-fields">
+    <lst name="typeMapping">
+      <str name="valueClass">java.lang.String</str>
+      <str name="fieldType">text_general</str>
+      <lst name="copyField">
+        <str name="dest">*_str</str>
+        <int name="maxChars">256</int>
+      </lst>
+      <!-- Use as default mapping instead of defaultFieldType -->
+      <bool name="default">true</bool>
+    </lst>
+    <lst name="typeMapping">
+      <str name="valueClass">java.lang.Boolean</str>
+      <str name="fieldType">booleans</str>
+    </lst>
+  </updateProcessor>
+
+  <!-- The update.autoCreateFields property can be turned to false to disable schemaless mode -->
+  <updateRequestProcessorChain name="add-unknown-fields-to-the-schema" default="${update.autoCreateFields:true}"
+           processor="uuid,add-schema-fields">
+    <processor class="solr.LogUpdateProcessorFactory"/>
+    <processor class="solr.DistributedUpdateProcessorFactory"/>
+    <processor class="solr.RunUpdateProcessorFactory"/>
+  </updateRequestProcessorChain>
+
+</config>
diff --git a/solr/core/src/test/org/apache/solr/util/MultipleManagedSchemasTest.java b/solr/core/src/test/org/apache/solr/util/MultipleManagedSchemasTest.java
new file mode 100644
index 00000000000..47ff874e440
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/util/MultipleManagedSchemasTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.util;
+
+import java.lang.invoke.MethodHandles;
+import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.request.CollectionAdminRequest;
+import org.apache.solr.client.solrj.request.ConfigSetAdminRequest;
+import org.apache.solr.cloud.SolrCloudTestCase;
+import org.apache.solr.common.cloud.ZkMaintenanceUtils;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MultipleManagedSchemasTest extends SolrCloudTestCase {
+  private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+  @Before
+  public void setUp() throws Exception {
+    super.setUp();
+    System.setProperty("managed.schema.mutable", "false");
+    configureCluster(1).configure();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (cluster != null) {
+      cluster.shutdown();
+    }
+    super.tearDown();
+  }
+
+  @Test
+  public void testSameCollectionNameWithMultipleSchemas() throws Exception {
+    CloudSolrClient client = cluster.getSolrClient();
+
+    String name = "COLL1";
+    String zkPath = ZkStateReader.CONFIGS_ZKNODE + "/" + name;
+
+    ZkMaintenanceUtils.uploadToZK(cluster.getZkClient(), configset("_default"), zkPath, null);
+    // Passing null for the second argument makes this test succeed
+    CollectionAdminRequest.createCollection(name, name, 1, 1).process(client);
+
+    // Verify that the config set and collection were created
+    ConfigSetAdminRequest.List list = new ConfigSetAdminRequest.List();
+    assertTrue(
+        "Should have COLL1 config set", list.process(client).getConfigSets().contains("COLL1"));
+    assertTrue(
+        "Should have created COLL1",
+        CollectionAdminRequest.listCollections(client).contains("COLL1"));
+
+    // Delete the config set and collection, and verify
+    CollectionAdminRequest.deleteCollection(name).process(client);
+    new ConfigSetAdminRequest.Delete().setConfigSetName(name).process(client);
+
+    assertFalse(
+        "Should not have COLL1 config set", list.process(client).getConfigSets().contains("COLL1"));
+    assertTrue(
+        "Should have deleted all collections",
+        CollectionAdminRequest.listCollections(client).isEmpty());
+
+    // Upload the replacement config set
+    ZkMaintenanceUtils.uploadToZK(cluster.getZkClient(), configset("cloud-managed"), zkPath, null);
+    assertTrue(
+        "Should have COLL1 config set", list.process(client).getConfigSets().contains("COLL1"));
+
+    // This is the call that fails
+    // Passing null for the config name here also lets the test pass!
+    CollectionAdminRequest.createCollection(name, name, 1, 1).process(client);
+    assertTrue(
+        "Should have created COLL1",
+        CollectionAdminRequest.listCollections(client).contains("COLL1"));
+  }
+}