You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ab...@apache.org on 2021/01/18 18:01:04 UTC
[lucene-solr] branch jira/solr-15055-2 updated: SOLR-15055: More
unit tests + minor fixes.
This is an automated email from the ASF dual-hosted git repository.
ab pushed a commit to branch jira/solr-15055-2
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/jira/solr-15055-2 by this push:
new ecc50d1 SOLR-15055: More unit tests + minor fixes.
ecc50d1 is described below
commit ecc50d1c2b6d4638b6369cc6634450285fe28572
Author: Andrzej Bialecki <ab...@apache.org>
AuthorDate: Mon Jan 18 19:00:33 2021 +0100
SOLR-15055: More unit tests + minor fixes.
---
.../cloud/api/collections/DeleteCollectionCmd.java | 19 +++++
.../cloud/api/collections/DeleteReplicaCmd.java | 22 +++---
.../placement/impl/ModificationRequestImpl.java | 14 +++-
.../impl/PlacementPluginIntegrationTest.java | 85 +++++++++++++++++++++-
4 files changed, 128 insertions(+), 12 deletions(-)
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java
index d9b6679..7674577 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteCollectionCmd.java
@@ -29,12 +29,18 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import org.apache.solr.cloud.Overseer;
+import org.apache.solr.cluster.placement.DeleteReplicasRequest;
+import org.apache.solr.cluster.placement.PlacementContext;
+import org.apache.solr.cluster.placement.PlacementPlugin;
+import org.apache.solr.cluster.placement.impl.ModificationRequestImpl;
+import org.apache.solr.cluster.placement.impl.PlacementContextImpl;
import org.apache.solr.common.NonExistentCoreException;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.cloud.Aliases;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
+import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.cloud.ZkStateReader;
@@ -92,6 +98,19 @@ public class DeleteCollectionCmd implements OverseerCollectionMessageHandler.Cmd
collection = extCollection;
}
+ PlacementPlugin placementPlugin = ocmh.overseer.getCoreContainer().getPlacementPluginFactory().createPluginInstance();
+ if (placementPlugin != null) {
+ // verify the placement modifications caused by the deletion are allowed
+ PlacementContext placementContext = new PlacementContextImpl(ocmh.cloudManager);
+ DocCollection coll = state.getCollection(collection);
+ for (Slice slice : coll.getActiveSlices()) {
+ DeleteReplicasRequest deleteReplicasRequest = ModificationRequestImpl
+ .deleteReplicasRequest(coll, slice.getName(),
+ slice.getReplicas().stream().map(Replica::getName).collect(Collectors.toSet()));
+ placementPlugin.verifyAllowedModification(deleteReplicasRequest, placementContext);
+ }
+ }
+
final boolean deleteHistory = message.getBool(CoreAdminParams.DELETE_METRICS_HISTORY, true);
boolean removeCounterNode = true;
diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
index 93ababd..f5cf6db 100644
--- a/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
+++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/DeleteReplicaCmd.java
@@ -92,7 +92,7 @@ public class DeleteReplicaCmd implements Cmd {
deleteReplicaBasedOnCount(clusterState, message, results, onComplete, parallel, placementPlugin, placementContext);
} catch (PlacementException pe) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
- "Delete replica(s) rejected by replica placement plugin: " + pe.getMessage(), pe);
+ "Delete replica(s) rejected by replica placement plugin: " + pe.toString(), pe);
}
return;
}
@@ -122,7 +122,7 @@ public class DeleteReplicaCmd implements Cmd {
deleteCore(coll, shard, replicaName, message, results, onComplete, parallel, placementPlugin, placementContext);
} catch (PlacementException pe) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
- "Delete replica rejected by replica placement plugin: " + pe.getMessage(), pe);
+ "Delete replica rejected by replica placement plugin: " + pe.toString(), pe);
}
}
@@ -170,14 +170,16 @@ public class DeleteReplicaCmd implements Cmd {
}
}
- // verify that all replicas can be deleted
- for (Map.Entry<Slice, Set<String>> entry : shardToReplicasMapping.entrySet()) {
- Slice shardSlice = entry.getKey();
- String shardId = shardSlice.getName();
- Set<String> replicas = entry.getValue();
- //verify all replicas
- DeleteReplicasRequest deleteReplicasRequest = ModificationRequestImpl.deleteReplicasRequest(coll, shardId, replicas);
- placementPlugin.verifyAllowedModification(deleteReplicasRequest, placementContext);
+ if (placementPlugin != null) {
+ // verify that all replicas can be deleted
+ for (Map.Entry<Slice, Set<String>> entry : shardToReplicasMapping.entrySet()) {
+ Slice shardSlice = entry.getKey();
+ String shardId = shardSlice.getName();
+ Set<String> replicas = entry.getValue();
+ //verify all replicas
+ DeleteReplicasRequest deleteReplicasRequest = ModificationRequestImpl.deleteReplicasRequest(coll, shardId, replicas);
+ placementPlugin.verifyAllowedModification(deleteReplicasRequest, placementContext);
+ }
}
for (Map.Entry<Slice, Set<String>> entry : shardToReplicasMapping.entrySet()) {
diff --git a/solr/core/src/java/org/apache/solr/cluster/placement/impl/ModificationRequestImpl.java b/solr/core/src/java/org/apache/solr/cluster/placement/impl/ModificationRequestImpl.java
index 8ae4935..7a62e28 100644
--- a/solr/core/src/java/org/apache/solr/cluster/placement/impl/ModificationRequestImpl.java
+++ b/solr/core/src/java/org/apache/solr/cluster/placement/impl/ModificationRequestImpl.java
@@ -29,10 +29,15 @@ import java.util.HashSet;
import java.util.Set;
/**
- *
+ * Helper class to create modification request instances.
*/
public class ModificationRequestImpl {
+ /**
+ * Create a delete replicas request.
+ * @param collection collection to delete replicas from
+ * @param replicas replicas to delete
+ */
public static DeleteReplicasRequest deleteReplicasRequest(SolrCollection collection, Set<Replica> replicas) {
return new DeleteReplicasRequest() {
@Override
@@ -53,6 +58,13 @@ public class ModificationRequestImpl {
};
}
+ /**
+ * Create a delete replicas request using the internal Solr API.
+ * @param docCollection Solr collection
+ * @param shardName shard name
+ * @param replicaNames replica names (aka. core-node names)
+ * @return
+ */
public static DeleteReplicasRequest deleteReplicasRequest(DocCollection docCollection, String shardName, Set<String> replicaNames) {
SolrCollection solrCollection = SimpleClusterAbstractionsImpl.SolrCollectionImpl.fromDocCollection(docCollection);
Shard shard = solrCollection.getShard(shardName);
diff --git a/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java b/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java
index 6967550..e0dfc46 100644
--- a/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java
+++ b/solr/core/src/test/org/apache/solr/cluster/placement/impl/PlacementPluginIntegrationTest.java
@@ -55,6 +55,7 @@ import org.slf4j.LoggerFactory;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
@@ -71,7 +72,7 @@ import static java.util.Collections.singletonMap;
public class PlacementPluginIntegrationTest extends SolrCloudTestCase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
- private static final String COLLECTION = PlacementPluginIntegrationTest.class.getName() + "_collection";
+ private static final String COLLECTION = PlacementPluginIntegrationTest.class.getSimpleName() + "_collection";
private static SolrCloudManager cloudManager;
private static CoreContainer cc;
@@ -232,6 +233,88 @@ public class PlacementPluginIntegrationTest extends SolrCloudTestCase {
}
@Test
+ public void testWithCollectionIntegration() throws Exception {
+ PlacementPluginFactory<? extends PlacementPluginConfig> pluginFactory = cc.getPlacementPluginFactory();
+ assertTrue("wrong type " + pluginFactory.getClass().getName(), pluginFactory instanceof DelegatingPlacementPluginFactory);
+ DelegatingPlacementPluginFactory wrapper = (DelegatingPlacementPluginFactory) pluginFactory;
+
+ int version = wrapper.getVersion();
+ log.debug("--initial version={}", version);
+
+ Set<String> nodeSet = new HashSet<>();
+ for (String node : cloudManager.getClusterStateProvider().getLiveNodes()) {
+ if (nodeSet.size() > 1) {
+ break;
+ }
+ nodeSet.add(node);
+ }
+
+ String SECONDARY_COLLECTION = COLLECTION + "_secondary";
+ PluginMeta plugin = new PluginMeta();
+ plugin.name = PlacementPluginFactory.PLUGIN_NAME;
+ plugin.klass = AffinityPlacementFactory.class.getName();
+ plugin.config = new AffinityPlacementConfig(1, 2, Map.of(COLLECTION, SECONDARY_COLLECTION));
+ V2Request req = new V2Request.Builder("/cluster/plugin")
+ .forceV2(true)
+ .POST()
+ .withPayload(singletonMap("add", plugin))
+ .build();
+ req.process(cluster.getSolrClient());
+
+ version = waitForVersionChange(version, wrapper, 10);
+
+ CollectionAdminResponse rsp = CollectionAdminRequest.createCollection(SECONDARY_COLLECTION, "conf", 1, 3)
+ .process(cluster.getSolrClient());
+ assertTrue(rsp.isSuccess());
+ cluster.waitForActiveCollection(SECONDARY_COLLECTION, 1, 3);
+ DocCollection secondary = cloudManager.getClusterStateProvider().getClusterState().getCollection(SECONDARY_COLLECTION);
+ Set<String> secondaryNodes = new HashSet<>();
+ secondary.forEachReplica((shard, replica) -> secondaryNodes.add(replica.getNodeName()));
+
+ rsp = CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 2)
+ .setCreateNodeSet(String.join(",", nodeSet))
+ .process(cluster.getSolrClient());
+ assertTrue(rsp.isSuccess());
+ cluster.waitForActiveCollection(COLLECTION, 2, 4);
+ // make sure the primary replicas were placed on the nodeset
+ DocCollection primary = cloudManager.getClusterStateProvider().getClusterState().getCollection(COLLECTION);
+ primary.forEachReplica((shard, replica) ->
+ assertTrue("primary replica not on secondary node!", nodeSet.contains(replica.getNodeName())));
+
+ // try deleting secondary replica from node without the primary replica
+ Optional<String> onlySecondaryReplica = secondary.getReplicas().stream()
+ .filter(replica -> !nodeSet.contains(replica.getNodeName()))
+ .map(replica -> replica.getName()).findFirst();
+ assertTrue("no secondary node without primary replica", onlySecondaryReplica.isPresent());
+
+ rsp = CollectionAdminRequest.deleteReplica(SECONDARY_COLLECTION, "shard1", onlySecondaryReplica.get())
+ .process(cluster.getSolrClient());
+ assertTrue("delete of a lone secondary replica should succeed", rsp.isSuccess());
+
+ // try deleting secondary replica from node WITH the primary replica - should fail
+ Optional<String> secondaryWithPrimaryReplica = secondary.getReplicas().stream()
+ .filter(replica -> nodeSet.contains(replica.getNodeName()))
+ .map(replica -> replica.getName()).findFirst();
+ assertTrue("no secondary node with primary replica", secondaryWithPrimaryReplica.isPresent());
+ try {
+ rsp = CollectionAdminRequest.deleteReplica(SECONDARY_COLLECTION, "shard1", secondaryWithPrimaryReplica.get())
+ .process(cluster.getSolrClient());
+ fail("should have failed: " + rsp);
+ } catch (Exception e) {
+ assertTrue(e.toString(), e.toString().contains("co-located with replicas"));
+ }
+
+ // try deleting secondary collection
+ try {
+ rsp = CollectionAdminRequest.deleteCollection(SECONDARY_COLLECTION)
+ .process(cluster.getSolrClient());
+ fail("should have failed: " + rsp);
+ } catch (Exception e) {
+ assertTrue(e.toString(), e.toString().contains("delete replica(s) rejected"));
+ }
+ }
+
+ @Test
public void testAttributeFetcherImpl() throws Exception {
CollectionAdminResponse rsp = CollectionAdminRequest.createCollection(COLLECTION, "conf", 2, 2)
.process(cluster.getSolrClient());