You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mk...@apache.org on 2016/10/02 18:45:25 UTC
lucene-solr:branch_6x: SOLR-9554: adding a test for concurrent schema
upgrade in cloud.
Repository: lucene-solr
Updated Branches:
refs/heads/branch_6x a2e24d1fc -> cc1841cbb
SOLR-9554: adding a test for concurrent schema upgrade in cloud.
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/cc1841cb
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/cc1841cb
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/cc1841cb
Branch: refs/heads/branch_6x
Commit: cc1841cbb73f1c5c54208549cb20cf8244fa5104
Parents: a2e24d1
Author: Mikhail Khludnev <mk...@apache.org>
Authored: Wed Sep 28 12:33:15 2016 +0300
Committer: Mikhail Khludnev <mk...@apache.org>
Committed: Sun Oct 2 21:33:01 2016 +0300
----------------------------------------------------------------------
.../cloud-managed-upgrade/conf/schema.xml | 27 ++++
.../cloud-managed-upgrade/conf/solrconfig.xml | 50 ++++++
.../schema/TestManagedSchemaThreadSafety.java | 162 +++++++++++++++++++
.../java/org/apache/solr/SolrTestCaseJ4.java | 4 +
.../apache/solr/cloud/SolrCloudTestCase.java | 4 -
5 files changed, 243 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc1841cb/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/schema.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/schema.xml b/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/schema.xml
new file mode 100644
index 0000000..b9f09f9
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/schema.xml
@@ -0,0 +1,27 @@
+<?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="minimal" version="1.1">
+ <fieldType name="string" class="solr.StrField"/>
+ <fieldType name="int" class="solr.TrieIntField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
+ <fieldType name="long" class="solr.TrieLongField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
+ <!-- for versioning -->
+ <field name="_version_" type="long" indexed="true" stored="true"/>
+ <field name="_root_" type="int" indexed="true" stored="true" multiValued="false" required="false"/>
+ <field name="id" type="string" indexed="true" stored="true"/>
+ <uniqueKey>id</uniqueKey>
+</schema>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc1841cb/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/solrconfig.xml
----------------------------------------------------------------------
diff --git a/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/solrconfig.xml b/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/solrconfig.xml
new file mode 100644
index 0000000..fc4db3b
--- /dev/null
+++ b/solr/core/src/test-files/solr/configsets/cloud-managed-upgrade/conf/solrconfig.xml
@@ -0,0 +1,50 @@
+<?xml version="1.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.
+-->
+
+<!-- Minimal solrconfig.xml with /select, /admin and /update only -->
+
+<config>
+
+ <dataDir>${solr.data.dir:}</dataDir>
+
+ <directoryFactory name="DirectoryFactory"
+ class="${solr.directoryFactory:solr.NRTCachingDirectoryFactory}"/>
+
+ <schemaFactory class="ManagedIndexSchemaFactory">
+ <str name="managedSchemaResourceName">managed-schema</str>
+ </schemaFactory>
+
+ <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
+
+ <updateHandler class="solr.DirectUpdateHandler2">
+ <commitWithin>
+ <softCommit>${solr.commitwithin.softcommit:true}</softCommit>
+ </commitWithin>
+ <updateLog></updateLog>
+ </updateHandler>
+
+ <requestHandler name="/select" class="solr.SearchHandler">
+ <lst name="defaults">
+ <str name="echoParams">explicit</str>
+ <str name="indent">true</str>
+ <str name="df">text</str>
+ </lst>
+
+ </requestHandler>
+</config>
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc1841cb/solr/core/src/test/org/apache/solr/schema/TestManagedSchemaThreadSafety.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/schema/TestManagedSchemaThreadSafety.java b/solr/core/src/test/org/apache/solr/schema/TestManagedSchemaThreadSafety.java
new file mode 100644
index 0000000..043632e
--- /dev/null
+++ b/solr/core/src/test/org/apache/solr/schema/TestManagedSchemaThreadSafety.java
@@ -0,0 +1,162 @@
+/*
+ * 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.schema;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.cloud.ZkController;
+import org.apache.solr.cloud.ZkSolrResourceLoader;
+import org.apache.solr.cloud.ZkTestServer;
+import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.core.SolrConfig;
+import org.apache.solr.core.SolrResourceLoader;
+import org.apache.solr.util.LogLevel;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.NoNodeException;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.data.Stat;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+public class TestManagedSchemaThreadSafety extends SolrTestCaseJ4 {
+
+ private static final class SuspendingZkClient extends SolrZkClient {
+ AtomicReference<Thread> slowpoke = new AtomicReference<>();
+
+ private SuspendingZkClient(String zkServerAddress, int zkClientTimeout) {
+ super(zkServerAddress, zkClientTimeout);
+ }
+
+ boolean isSlowpoke(){
+ Thread youKnow;
+ if ((youKnow = slowpoke.get())!=null) {
+ return youKnow == Thread.currentThread();
+ } else {
+ return slowpoke.compareAndSet(null, Thread.currentThread());
+ }
+ }
+
+ @Override
+ public byte[] getData(String path, Watcher watcher, Stat stat, boolean retryOnConnLoss)
+ throws KeeperException, InterruptedException {
+ byte[] data;
+ try {
+ data = super.getData(path, watcher, stat, retryOnConnLoss);
+ } catch (NoNodeException e) {
+ if (isSlowpoke()) {
+ //System.out.println("suspending "+Thread.currentThread()+" on " + path);
+ Thread.sleep(500);
+ }
+ throw e;
+ }
+ return data;
+ }
+ }
+
+ private static ZkTestServer zkServer;
+ private static Path loaderPath;
+
+ @BeforeClass
+ public static void startZkServer() throws Exception {
+ zkServer = new ZkTestServer(createTempDir().toString());
+ zkServer.run();
+ loaderPath = createTempDir();
+ }
+
+ @AfterClass
+ public static void stopZkServer() throws Exception {
+ zkServer.shutdown();
+ }
+
+ @Test
+ @LogLevel("org.apache.solr.common.cloud.SolrZkClient=debug")
+ public void testThreadSafety() throws Exception {
+
+ final String configsetName = "managed-config";//
+
+ try (SolrZkClient client = new SuspendingZkClient(zkServer.getZkHost(), 30)) {
+ // we can pick any to load configs, I suppose, but here we check
+ client.upConfig(configset("cloud-managed-upgrade"), configsetName);
+ }
+
+ ExecutorService executor = ExecutorUtil.newMDCAwareCachedThreadPool("threadpool");
+
+ try (SolrZkClient raceJudge = new SuspendingZkClient(zkServer.getZkHost(), 30)) {
+
+ ZkController zkController = createZkController(raceJudge);
+
+ List<Future<?>> futures = new ArrayList<>();
+ for (int i = 0; i < 2; i++) {
+ futures.add(executor.submit(indexSchemaLoader(configsetName, zkController)));
+ }
+
+ for (Future<?> future : futures) {
+ future.get();
+ }
+ }
+ finally {
+ ExecutorUtil.shutdownAndAwaitTermination(executor);
+ }
+ }
+
+ private ZkController createZkController(SolrZkClient client) throws KeeperException, InterruptedException {
+ ZkController zkController = mock(ZkController.class,
+ Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS));
+
+ when(zkController.getZkClient()).thenReturn(client);
+ Mockito.doAnswer(new Answer<Boolean>() {
+ @Override
+ public Boolean answer(InvocationOnMock invocation) throws Throwable {
+ return client.exists((String) invocation.getArguments()[0], true);
+ }
+ }).when(zkController).pathExists(Mockito.anyString());
+ return zkController;
+ }
+
+ private Runnable indexSchemaLoader(String configsetName, final ZkController zkController) {
+ return () -> {
+ try {
+ SolrResourceLoader loader = new ZkSolrResourceLoader(loaderPath, configsetName, zkController);
+ SolrConfig solrConfig = SolrConfig.readFromResourceLoader(loader, "solrconfig.xml");
+
+ ManagedIndexSchemaFactory factory = new ManagedIndexSchemaFactory();
+ factory.init(new NamedList());
+ factory.create("schema.xml", solrConfig);
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ };
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc1841cb/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
index 3659446..88ddc54 100644
--- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
+++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
@@ -1804,6 +1804,10 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase {
public static Path TEST_PATH() { return getFile("solr/collection1").getParentFile().toPath(); }
+ public static Path configset(String name) {
+ return TEST_PATH().resolve("configsets").resolve(name).resolve("conf");
+ }
+
public static Throwable getRootCause(Throwable t) {
Throwable result = t;
for (Throwable cause = t; null != cause; cause = cause.getCause()) {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/cc1841cb/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
----------------------------------------------------------------------
diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
index 777e80a..02a4895 100644
--- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
+++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudTestCase.java
@@ -69,10 +69,6 @@ public class SolrCloudTestCase extends SolrTestCaseJ4 {
public static final int DEFAULT_TIMEOUT = 30;
- public static Path configset(String name) {
- return TEST_PATH().resolve("configsets").resolve(name).resolve("conf");
- }
-
private static class Config {
final String name;
final Path path;