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 e5c90acdd21c893af7679091beb1c48262bcef45 Author: Serhiy Bzhezytskyy <[email protected]> AuthorDate: Tue Aug 25 23:52:45 2026 +0300 SOLR-18382: remove DocCollection.getReplicas(), migrate 60 call sites (#4760) (cherry picked from commit b0aa1ebbfad36a3776a7cdf4cb148b51c62a1b82) --- .../api/collections/ReindexCollectionCmd.java | 14 +-- .../test/org/apache/solr/cloud/AddReplicaTest.java | 14 ++- .../org/apache/solr/cloud/BalanceReplicasTest.java | 4 +- .../apache/solr/cloud/CollectionsAPISolrJTest.java | 19 ++- .../cloud/CreateCollectionWithPropertiesTest.java | 7 +- .../solr/cloud/DeleteCoreRemnantsOnCreateTest.java | 4 +- .../org/apache/solr/cloud/DeleteReplicaTest.java | 2 +- .../DistribDocExpirationUpdateProcessorTest.java | 68 +++++------ .../solr/cloud/DistributedVersionInfoTest.java | 5 +- .../org/apache/solr/cloud/MigrateRouteKeyTest.java | 2 +- .../org/apache/solr/cloud/MoveReplicaTest.java | 6 +- .../solr/cloud/NestedShardedAtomicUpdateTest.java | 8 +- .../apache/solr/cloud/TestCloudConsistency.java | 2 +- .../solr/cloud/TestCloudSearcherWarming.java | 15 ++- .../solr/cloud/TestOnReconnectListenerSupport.java | 3 +- .../org/apache/solr/cloud/TestPullReplica.java | 47 +++++--- .../solr/cloud/TestQueryingOnDownCollection.java | 8 +- .../org/apache/solr/cloud/TestTlogReplica.java | 28 +++-- .../org/apache/solr/cloud/ZkControllerTest.java | 3 +- .../collections/CollectionTooManyReplicasTest.java | 15 +-- .../solr/cloud/api/collections/ShardSplitTest.java | 2 +- .../cloud/api/collections/TestCollectionAPI.java | 5 +- .../impl/PlacementPluginIntegrationTest.java | 6 +- .../apache/solr/search/TestCoordinatorRole.java | 13 ++- .../org/apache/solr/servlet/HttpSolrProxyTest.java | 128 +++++++++++++++++++++ .../solr/update/DeleteByIdWithRouterFieldTest.java | 13 ++- .../solrj/io/stream/CloudAuthStreamTest.java | 3 +- .../client/solrj/io/stream/MathExpressionTest.java | 2 +- .../solrj/io/stream/StreamDecoratorTest.java | 2 +- .../solr/client/solrj/io/stream/StreamingTest.java | 4 +- .../apache/solr/common/cloud/DocCollection.java | 11 +- .../client/solrj/impl/HttpClusterStateSSLTest.java | 2 +- .../impl/SendUpdatesToLeadersOverrideTest.java | 7 +- .../cloud/PerReplicaStatesIntegrationTest.java | 2 +- .../AbstractCloudBackupRestoreTestCase.java | 14 ++- ...bstractCollectionsAPIDistributedZkTestBase.java | 23 ++-- .../solr/webapp/AdminUiCollectionsScreenTest.java | 13 ++- 37 files changed, 344 insertions(+), 180 deletions(-) diff --git a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java index e72cfbe04a4..822031d4a39 100644 --- a/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java +++ b/solr/core/src/java/org/apache/solr/cloud/api/collections/ReindexCollectionCmd.java @@ -672,7 +672,7 @@ public class ReindexCollectionCmd implements CollApiCmds.CollectionApiCommand { } // XXX see #waitForDaemon() for why we need this - private Replica getReplicaForDaemon(SolrResponse rsp, DocCollection coll) { + private Replica getReplicaForDaemon(SolrResponse rsp, DocCollection collectionState) { @SuppressWarnings({"unchecked"}) Map<String, Object> rs = (Map<String, Object>) rsp.getResponse().get("result-set"); if (rs == null || rs.isEmpty()) { @@ -713,13 +713,13 @@ public class ReindexCollectionCmd implements CollApiCmds.CollectionApiCommand { if (replicaName == null) { return null; } + final String finalReplicaName = replicaName; // build a baseUrl of the replica - for (Replica r : coll.getReplicas()) { - if (replicaName.equals(r.getCoreName())) { - return r; - } - } - return null; + return collectionState + .replicaStream() + .filter(r -> finalReplicaName.equals(r.getCoreName())) + .findFirst() + .orElse(null); } // XXX currently this is complicated to due a bug in the way the daemon 'list' diff --git a/solr/core/src/test/org/apache/solr/cloud/AddReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/AddReplicaTest.java index 7590311a01f..8c0750635ca 100644 --- a/solr/core/src/test/org/apache/solr/cloud/AddReplicaTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/AddReplicaTest.java @@ -73,7 +73,7 @@ public class AddReplicaTest extends SolrCloudTestCase { DocCollection docCollection = cloudClient.getClusterState().getCollectionOrNull(collection); assertNotNull(docCollection); - assertEquals(4, docCollection.getReplicas().size()); + assertEquals(4, docCollection.replicaStream().count()); assertEquals(2, getReplicas(docCollection, EnumSet.of(Replica.Type.NRT)).size()); assertEquals(1, getReplicas(docCollection, EnumSet.of(Replica.Type.TLOG)).size()); assertEquals(1, getReplicas(docCollection, EnumSet.of(Replica.Type.PULL)).size()); @@ -81,7 +81,7 @@ public class AddReplicaTest extends SolrCloudTestCase { docCollection = cloudClient.getClusterState().getCollectionOrNull(collection); assertNotNull(docCollection); // sanity check that everything is as before - assertEquals(4, docCollection.getReplicas().size()); + assertEquals(4, docCollection.replicaStream().count()); assertEquals(2, getReplicas(docCollection, EnumSet.of(Replica.Type.NRT)).size()); assertEquals(1, getReplicas(docCollection, EnumSet.of(Replica.Type.TLOG)).size()); assertEquals(1, getReplicas(docCollection, EnumSet.of(Replica.Type.PULL)).size()); @@ -106,7 +106,7 @@ public class AddReplicaTest extends SolrCloudTestCase { docCollection = cloudClient.getClusterState().getCollectionOrNull(collection); assertNotNull(docCollection); // sanity check that everything is as before - assertEquals(9, docCollection.getReplicas().size()); + assertEquals(9, docCollection.replicaStream().count()); assertEquals(5, getReplicas(docCollection, EnumSet.of(Replica.Type.NRT)).size()); assertEquals(2, getReplicas(docCollection, EnumSet.of(Replica.Type.TLOG)).size()); assertEquals(2, getReplicas(docCollection, EnumSet.of(Replica.Type.PULL)).size()); @@ -211,7 +211,13 @@ public class AddReplicaTest extends SolrCloudTestCase { // Verify that the new core was created with user-defined properties coming from the request // and inherited from the collection (the former taking precedence over the latter). Replica replica = - cloudClient.getClusterState().getCollection(collectionName).getReplicas().get(1); + cloudClient + .getClusterState() + .getCollection(collectionName) + .replicaStream() + .skip(1) + .findFirst() + .orElseThrow(); CoreDescriptor coreDescriptor = cluster .getReplicaJetty(replica) diff --git a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java index 7fb0d8ddb4f..79a8a80e0a4 100644 --- a/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/BalanceReplicasTest.java @@ -97,7 +97,7 @@ public class BalanceReplicasTest extends SolrCloudTestCase { collection = cloudClient.getClusterState().getCollectionOrNull(coll, false); log.debug("### After balancing: {}", collection); Set<String> replicaNodes = - collection.getReplicas().stream().map(Replica::getNodeName).collect(Collectors.toSet()); + collection.replicaStream().map(Replica::getNodeName).collect(Collectors.toSet()); assertEquals("Incorrect nodes for replicas after balancing", liveNodes, replicaNodes); } @@ -145,7 +145,7 @@ public class BalanceReplicasTest extends SolrCloudTestCase { collection = cloudClient.getClusterState().getCollectionOrNull(coll, false); log.debug("### After balancing: {}", collection); Set<String> replicaNodes = - collection.getReplicas().stream().map(Replica::getNodeName).collect(Collectors.toSet()); + collection.replicaStream().map(Replica::getNodeName).collect(Collectors.toSet()); assertEquals("Incorrect nodes for replicas after balancing", 4, replicaNodes.size()); assertTrue( "A non-balanced node lost replicas during balancing", replicaNodes.contains(l.get(0))); diff --git a/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java b/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java index 17cb7e51ebb..44c24de9b10 100644 --- a/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/CollectionsAPISolrJTest.java @@ -409,13 +409,9 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase { waitForState( "Expected all shards to be active and parent shard to be removed", collectionName, - (n, c) -> { - if (c.getSlice("shard1").getState() == Slice.State.ACTIVE) return false; - for (Replica r : c.getReplicas()) { - if (r.isActive(n) == false) return false; - } - return true; - }); + (n, collectionState) -> + collectionState.getSlice("shard1").getState() != Slice.State.ACTIVE + && collectionState.replicaStream().allMatch(r -> r.isActive(n))); // Test splitting using split.key response = @@ -455,7 +451,7 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase { DocCollection testCollection = getCollectionState(collectionName); - Replica replica1 = testCollection.getReplicas().iterator().next(); + Replica replica1 = testCollection.replicaStream().findFirst().orElseThrow(); final var coreStatus = getCoreStatus(replica1); assertEquals(Path.of(coreStatus.dataDir).toString(), dataDir.toString()); @@ -501,7 +497,8 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase { private Replica grabNewReplica(CollectionAdminResponse response, DocCollection docCollection) { String replicaName = response.getCollectionCoresStatus().keySet().iterator().next(); Optional<Replica> optional = - docCollection.getReplicas().stream() + docCollection + .replicaStream() .filter(replica -> replicaName.equals(replica.getCoreName())) .findAny(); if (optional.isPresent()) { @@ -1334,8 +1331,8 @@ public class CollectionsAPISolrJTest extends SolrCloudTestCase { waitForState( "Expecting 'preferredleader' property to be balanced across all shards", collection, - c -> { - for (Slice slice : c) { + collectionState -> { + for (Slice slice : collectionState) { int count = 0; for (Replica replica : slice) { if ("true".equals(replica.getProperty("preferredleader"))) count += 1; diff --git a/solr/core/src/test/org/apache/solr/cloud/CreateCollectionWithPropertiesTest.java b/solr/core/src/test/org/apache/solr/cloud/CreateCollectionWithPropertiesTest.java index c90e9d21190..a21791e3079 100644 --- a/solr/core/src/test/org/apache/solr/cloud/CreateCollectionWithPropertiesTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/CreateCollectionWithPropertiesTest.java @@ -57,7 +57,12 @@ public class CreateCollectionWithPropertiesTest extends SolrCloudTestCase { // Verify that the core was created with user-defined properties Replica replica = - cloudClient.getClusterState().getCollection(collectionName).getReplicas().get(0); + cloudClient + .getClusterState() + .getCollection(collectionName) + .replicaStream() + .findFirst() + .orElseThrow(); CoreDescriptor coreDescriptor = cluster .getReplicaJetty(replica) diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteCoreRemnantsOnCreateTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteCoreRemnantsOnCreateTest.java index 57cea18d24e..bc2c4e0b1f1 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DeleteCoreRemnantsOnCreateTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DeleteCoreRemnantsOnCreateTest.java @@ -211,7 +211,7 @@ public class DeleteCoreRemnantsOnCreateTest extends SolrCloudTestCase { // Verify collection was created successfully DocCollection collection = getCollectionState(collectionName); assertNotNull("Collection should exist", collection); - assertEquals("Should have 1 replica", 1, collection.getReplicas().size()); + assertEquals("Should have 1 replica", 1, collection.replicaStream().count()); // Verify replica on the node where we had the remnant is active Replica recreatedReplica = @@ -271,7 +271,7 @@ public class DeleteCoreRemnantsOnCreateTest extends SolrCloudTestCase { // Verify collection now has 2 replicas DocCollection collection = getCollectionState(collectionName); assertNotNull("Collection should exist", collection); - assertEquals("Should have 2 replicas after adding", 2, collection.getReplicas().size()); + assertEquals("Should have 2 replicas after adding", 2, collection.replicaStream().count()); // Verify the replica was added on the single node and is active Replica addedReplica = getReplicaOnNode(collectionName, "shard1", primaryNode); diff --git a/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java index 2932553c6d2..417285bd166 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DeleteReplicaTest.java @@ -538,7 +538,7 @@ public class DeleteReplicaTest extends SolrCloudTestCase { waitForState( "Waiting for single replica in state", collectionName, - collectionState -> collectionState.getReplicas().size() == 1); + collectionState -> collectionState.replicaStream().count() == 1); } /** diff --git a/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java b/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java index 45b83e7066d..821548e1238 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DistribDocExpirationUpdateProcessorTest.java @@ -285,39 +285,41 @@ public class DistribDocExpirationUpdateProcessorTest extends SolrCloudTestCase { DocCollection collectionState = cluster.getSolrClient().getClusterState().getCollection(COLLECTION); - for (Replica replica : collectionState.getReplicas()) { - - String coreName = replica.getCoreName(); - try (SolrClient client = getHttpSolrClient(replica)) { - - ModifiableSolrParams params = new ModifiableSolrParams(); - params.set("command", "indexversion"); - params.set("_trace", "getIndexVersion"); - QueryRequest req = setAuthIfNeeded(new QueryRequest(ReplicationHandler.PATH, params)); - - NamedList<Object> res = client.request(req); - assertNotNull("null response from server: " + coreName, res); - - Object version = res.get("indexversion"); - assertNotNull("null version from server: " + coreName, version); - assertTrue("version isn't a long: " + coreName, version instanceof Long); - - long numDocs = - setAuthIfNeeded( - new QueryRequest( - params( - "q", "*:*", - "distrib", "false", - "rows", "0", - "_trace", "counting_docs"))) - .process(client) - .getResults() - .getNumFound(); - - final ReplicaData data = - new ReplicaData(replica.getShard(), coreName, (Long) version, numDocs); - log.info("{}", data); - results.put(coreName, data); + for (Slice slice : collectionState) { + for (Replica replica : slice.getReplicas()) { + + String coreName = replica.getCoreName(); + try (SolrClient client = getHttpSolrClient(replica)) { + + ModifiableSolrParams params = new ModifiableSolrParams(); + params.set("command", "indexversion"); + params.set("_trace", "getIndexVersion"); + QueryRequest req = setAuthIfNeeded(new QueryRequest(ReplicationHandler.PATH, params)); + + NamedList<Object> res = client.request(req); + assertNotNull("null response from server: " + coreName, res); + + Object version = res.get("indexversion"); + assertNotNull("null version from server: " + coreName, version); + assertTrue("version isn't a long: " + coreName, version instanceof Long); + + long numDocs = + setAuthIfNeeded( + new QueryRequest( + params( + "q", "*:*", + "distrib", "false", + "rows", "0", + "_trace", "counting_docs"))) + .process(client) + .getResults() + .getNumFound(); + + final ReplicaData data = + new ReplicaData(replica.getShard(), coreName, (Long) version, numDocs); + log.info("{}", data); + results.put(coreName, data); + } } } diff --git a/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java b/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java index b6b1f977240..a67f0c0495e 100644 --- a/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/DistributedVersionInfoTest.java @@ -92,7 +92,10 @@ public class DistributedVersionInfoTest extends SolrCloudTestCase { // verify doc is on the leader and replica final List<Replica> notLeaders = - stateReader.getClusterState().getCollection(COLLECTION).getReplicas().stream() + stateReader + .getClusterState() + .getCollection(COLLECTION) + .replicaStream() .filter(r -> r.getCoreName().equals(leader.getCoreName()) == false) .collect(Collectors.toList()); assertDocsExistInAllReplicas(leader, notLeaders, COLLECTION, 1, 1, null); diff --git a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java index c990f43423a..723f9d9ba6a 100644 --- a/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/MigrateRouteKeyTest.java @@ -133,7 +133,7 @@ public class MigrateRouteKeyTest extends SolrCloudTestCase { indexer.start(); DocCollection state = getCollectionState(targetCollection); - Replica replica = state.getReplicas().get(0); + Replica replica = state.replicaStream().findFirst().orElseThrow(); try (SolrClient collectionClient = getHttpSolrClient(replica)) { SolrQuery solrQuery = new SolrQuery("*:*"); diff --git a/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java index 76092a2c936..68524274e02 100644 --- a/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java @@ -342,9 +342,9 @@ public class MoveReplicaTest extends SolrCloudTestCase { } private Replica getRandomReplica(String coll, CloudSolrClient cloudClient) throws IOException { - List<Replica> replicas = cloudClient.getClusterState().getCollection(coll).getReplicas(); - Collections.shuffle(replicas, random()); - return replicas.get(0); + List<Replica> replicas = + cloudClient.getClusterState().getCollection(coll).replicaStream().toList(); + return replicas.get(random().nextInt(replicas.size())); } private void checkNumOfCores( diff --git a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java index 455b202f1d3..c284d581cd8 100644 --- a/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/NestedShardedAtomicUpdateTest.java @@ -33,7 +33,6 @@ import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.cloud.ClusterState; -import org.apache.solr.common.cloud.Replica; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.util.RandomNoReverseMergePolicyFactory; @@ -71,9 +70,10 @@ public class NestedShardedAtomicUpdateTest extends SolrCloudTestCase { clients = new ArrayList<>(); ClusterState clusterState = cloudClient.getClusterState(); - for (Replica replica : clusterState.getCollection(DEFAULT_COLLECTION).getReplicas()) { - clients.add(getHttpSolrClient(replica)); - } + clusterState + .getCollection(DEFAULT_COLLECTION) + .replicaStream() + .forEach(replica -> clients.add(getHttpSolrClient(replica))); } @AfterClass diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java index 9041d42555d..b3c7c4142ae 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudConsistency.java @@ -133,7 +133,7 @@ public class TestCloudConsistency extends SolrCloudTestCase { } assertDocsExistInAllReplicas( - getCollectionState(collectionName).getReplicas(), collectionName, 1, 4); + getCollectionState(collectionName).replicaStream().toList(), collectionName, 1, 4); CollectionAdminRequest.deleteCollection(collectionName).process(cluster.getSolrClient()); } diff --git a/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java b/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java index 3e2089af36c..6c8764a761e 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestCloudSearcherWarming.java @@ -213,14 +213,13 @@ public class TestCloudSearcherWarming extends SolrCloudTestCase { // the above call is not enough because we want to assert that the downed replica is not active // but clusterShape will also return true if replica is not live -- which we don't want Predicate<DocCollection> collectionStatePredicate = - collectionState -> { - for (Replica r : collectionState.getReplicas()) { - if (r.getNodeName().equals(oldNodeName.get())) { - return r.getState() == Replica.State.DOWN; - } - } - return false; - }; + collectionState -> + collectionState + .replicaStream() + .filter(r -> r.getNodeName().equals(oldNodeName.get())) + .findFirst() + .map(r -> r.getState() == Replica.State.DOWN) + .orElse(false); waitForState("", collectionName, collectionStatePredicate); assertNotNull(ZkStateReader.from(solrClient).getLeaderRetry(collectionName, "shard1")); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestOnReconnectListenerSupport.java b/solr/core/src/test/org/apache/solr/cloud/TestOnReconnectListenerSupport.java index 39dc89dd877..fa2f9264dee 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestOnReconnectListenerSupport.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestOnReconnectListenerSupport.java @@ -47,7 +47,8 @@ public class TestOnReconnectListenerSupport extends SolrCloudTestCase { .process(cluster.getSolrClient()); cluster.waitForActiveCollection(testCollectionName, 1, 1); - Replica leader = getCollectionState(testCollectionName).getReplicas().get(0); + Replica leader = + getCollectionState(testCollectionName).replicaStream().findFirst().orElseThrow(); CoreContainer cores = cluster.getJettySolrRunner(0).getCoreContainer(); ZkController zkController = cores.getZkController(); assertNotNull("ZkController is null", zkController); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java index 1d8166e119b..c6f30385972 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestPullReplica.java @@ -185,7 +185,7 @@ public class TestPullReplica extends SolrCloudTestCase { while (true) { DocCollection docCollection = getCollectionState(collectionName); assertNotNull(docCollection); - assertEquals("Expecting 4 replicas per shard", 8, docCollection.getReplicas().size()); + assertEquals("Expecting 4 replicas per shard", 8, docCollection.replicaStream().count()); assertEquals( "Expecting 6 pull replicas, 3 per shard", 6, @@ -773,7 +773,9 @@ public class TestPullReplica extends SolrCloudTestCase { // index a few docs and wait to ensure everything is in sync with our expectations addDocs(numDocsAdded); - waitForNumDocsInAllReplicas(numDocsAdded, getCollectionState(collectionName).getReplicas()); + waitForNumDocsInAllReplicas( + numDocsAdded, + getCollectionState(collectionName).replicaStream().collect(Collectors.toList())); waitForState( "Replica prop never added?", collectionName, @@ -841,14 +843,16 @@ public class TestPullReplica extends SolrCloudTestCase { waitForState( "Special PULL should be ACTIVE, all others should be DOWN", collectionName, - (liveNodes, colState) -> { - for (Replica r : colState.getReplicas()) { - if (r.getName().equals(pullThatSkipsRecovery)) { - if (!r.getState().equals(Replica.State.ACTIVE)) { + (liveNodes, collectionState) -> { + for (Slice slice : collectionState) { + for (Replica r : slice.getReplicas()) { + if (r.getName().equals(pullThatSkipsRecovery)) { + if (!r.getState().equals(Replica.State.ACTIVE)) { + return false; + } + } else if (!r.getState().equals(Replica.State.DOWN)) { return false; } - } else if (!r.getState().equals(Replica.State.DOWN)) { - return false; } } return true; @@ -858,7 +862,9 @@ public class TestPullReplica extends SolrCloudTestCase { tlogLeaderyJetty.start(); waitForState( "Leader should be back, all replicas active", collectionName, activeReplicaCount(0, 1, 3)); - waitForNumDocsInAllReplicas(numDocsAdded, getCollectionState(collectionName).getReplicas()); + waitForNumDocsInAllReplicas( + numDocsAdded, + getCollectionState(collectionName).replicaStream().collect(Collectors.toList())); } private void waitForNumDocsInAllActiveReplicas(int numDocs) @@ -866,7 +872,8 @@ public class TestPullReplica extends SolrCloudTestCase { DocCollection docCollection = getCollectionState(collectionName); waitForNumDocsInAllReplicas( numDocs, - docCollection.getReplicas().stream() + docCollection + .replicaStream() .filter(r -> r.getState() == Replica.State.ACTIVE) .collect(Collectors.toList())); } @@ -978,15 +985,17 @@ public class TestPullReplica extends SolrCloudTestCase { */ private CollectionStatePredicate clusterStateReflectsActiveAndDownReplicas() { return (liveNodes, collectionState) -> { - for (Replica r : collectionState.getReplicas()) { - if (r.getState() != Replica.State.DOWN && r.getState() != Replica.State.ACTIVE) { - return false; - } - if (r.getState() == Replica.State.DOWN && liveNodes.contains(r.getNodeName())) { - return false; - } - if (r.getState() == Replica.State.ACTIVE && !liveNodes.contains(r.getNodeName())) { - return false; + for (Slice slice : collectionState) { + for (Replica r : slice.getReplicas()) { + if (r.getState() != Replica.State.DOWN && r.getState() != Replica.State.ACTIVE) { + return false; + } + if (r.getState() == Replica.State.DOWN && liveNodes.contains(r.getNodeName())) { + return false; + } + if (r.getState() == Replica.State.ACTIVE && !liveNodes.contains(r.getNodeName())) { + return false; + } } } return true; diff --git a/solr/core/src/test/org/apache/solr/cloud/TestQueryingOnDownCollection.java b/solr/core/src/test/org/apache/solr/cloud/TestQueryingOnDownCollection.java index e95bf3493fb..2d9d9749221 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestQueryingOnDownCollection.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestQueryingOnDownCollection.java @@ -16,7 +16,6 @@ */ package org.apache.solr.cloud; -import java.util.List; import java.util.Map; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrRequest; @@ -72,10 +71,9 @@ public class TestQueryingOnDownCollection extends SolrCloudTestCase { downAllReplicas(); // assert all replicas are in down state - List<Replica> replicas = getCollectionState(COLLECTION_NAME).getReplicas(); - for (Replica replica : replicas) { - assertEquals(replica.getState(), Replica.State.DOWN); - } + getCollectionState(COLLECTION_NAME) + .replicaStream() + .forEach(replica -> assertEquals(replica.getState(), Replica.State.DOWN)); // assert all nodes as active assertEquals(3, cluster.getSolrClient().getClusterStateProvider().getLiveNodes().size()); diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java index aec3a34ed36..ce0fb84f6d5 100644 --- a/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java +++ b/solr/core/src/test/org/apache/solr/cloud/TestTlogReplica.java @@ -197,7 +197,7 @@ public class TestTlogReplica extends SolrCloudTestCase { DocCollection docCollection = getCollectionState(collectionName); assertNotNull(docCollection); assertEquals("Expecting 2 shards", 2, docCollection.getSlices().size()); - assertEquals("Expecting 4 replicas per shard", 8, docCollection.getReplicas().size()); + assertEquals("Expecting 4 replicas per shard", 8, docCollection.replicaStream().count()); assertEquals( "Expecting 8 tlog replicas, 4 per shard", 8, @@ -718,7 +718,8 @@ public class TestTlogReplica extends SolrCloudTestCase { } private List<Replica> getNonLeaderReplicas(String collectionName) { - return getCollectionState(collectionName).getReplicas().stream() + return getCollectionState(collectionName) + .replicaStream() .filter((r) -> !r.getBool("leader", false)) .collect(Collectors.toList()); } @@ -976,7 +977,8 @@ public class TestTlogReplica extends SolrCloudTestCase { DocCollection docCollection = getCollectionState(collectionName); waitForNumDocsInAllReplicas( numDocs, - docCollection.getReplicas().stream() + docCollection + .replicaStream() .filter(r -> r.getState() == Replica.State.ACTIVE) .collect(Collectors.toList()), timeout); @@ -1062,15 +1064,17 @@ public class TestTlogReplica extends SolrCloudTestCase { */ private CollectionStatePredicate clusterStateReflectsActiveAndDownReplicas() { return (liveNodes, collectionState) -> { - for (Replica r : collectionState.getReplicas()) { - if (r.getState() != Replica.State.DOWN && r.getState() != Replica.State.ACTIVE) { - return false; - } - if (r.getState() == Replica.State.DOWN && liveNodes.contains(r.getNodeName())) { - return false; - } - if (r.getState() == Replica.State.ACTIVE && !liveNodes.contains(r.getNodeName())) { - return false; + for (Slice slice : collectionState) { + for (Replica r : slice.getReplicas()) { + if (r.getState() != Replica.State.DOWN && r.getState() != Replica.State.ACTIVE) { + return false; + } + if (r.getState() == Replica.State.DOWN && liveNodes.contains(r.getNodeName())) { + return false; + } + if (r.getState() == Replica.State.ACTIVE && !liveNodes.contains(r.getNodeName())) { + return false; + } } } return true; diff --git a/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java b/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java index 5c7cd7442d3..1d868787d48 100644 --- a/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java @@ -373,8 +373,7 @@ public class ZkControllerTest extends SolrCloudTestCase { TimeUnit.SECONDS, collectionState -> Optional.ofNullable(collectionState) - .map(DocCollection::getReplicas) - .map(List::size) + .map(c -> (int) c.replicaStream().count()) .orElse(0) == 3); } diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java index fae4f9ceaa4..375146bc8a5 100644 --- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionTooManyReplicasTest.java @@ -18,7 +18,6 @@ package org.apache.solr.cloud.api.collections; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import org.apache.solr.client.solrj.request.CollectionAdminRequest; import org.apache.solr.cloud.SolrCloudTestCase; import org.apache.solr.common.cloud.DocCollection; @@ -112,12 +111,8 @@ public class CollectionTooManyReplicasTest extends SolrCloudTestCase { waitForState( "Expected to see all replicas active", collectionName, - c -> { - for (Replica r : c.getReplicas()) { - if (r.getState() != Replica.State.ACTIVE) return false; - } - return true; - }); + docCollection -> + docCollection.replicaStream().allMatch(r -> r.getState() == Replica.State.ACTIVE)); } @Test @@ -258,10 +253,10 @@ public class CollectionTooManyReplicasTest extends SolrCloudTestCase { } private List<String> getAllNodeNames(String collectionName) { - DocCollection state = getCollectionState(collectionName); - return state.getReplicas().stream() + return getCollectionState(collectionName) + .replicaStream() .map(Replica::getNodeName) .distinct() - .collect(Collectors.toList()); + .toList(); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java index c55843dab9d..088eb242124 100644 --- a/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/ShardSplitTest.java @@ -137,7 +137,7 @@ public class ShardSplitTest extends BasicDistributedZkTest { cloudClient .getClusterState() .getCollection(AbstractFullDistribZkTestBase.DEFAULT_COLLECTION); - Replica replica = defCol.getReplicas().get(0); + Replica replica = defCol.replicaStream().findFirst().orElseThrow(); String nodeName = replica.getNodeName(); String collectionName = "testSplitStaticIndexReplication_" + splitMethod.toLower(); diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java index b8c1a0e9a3e..c1fe64a73da 100644 --- a/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java +++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/TestCollectionAPI.java @@ -381,7 +381,8 @@ public class TestCollectionAPI extends ReplicaPropertiesBase { TimeUnit.SECONDS, docCollection -> docCollection != null - && docCollection.getReplicas().stream() + && docCollection + .replicaStream() .anyMatch(r -> r.getState().equals(Replica.State.DOWN) && !r.isLeader())); zkStateReader.waitForState( COLLECTION_NAME, @@ -420,7 +421,7 @@ public class TestCollectionAPI extends ReplicaPropertiesBase { TimeUnit.SECONDS, (liveNodes, coll) -> coll != null - && coll.getReplicas().stream() + && coll.replicaStream() .allMatch(r -> r.getState().equals(Replica.State.ACTIVE))); rsp = request.process(newClient).getResponse(); collection = 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 3ffb39bf373..2fb85423006 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 @@ -341,7 +341,8 @@ public class PlacementPluginIntegrationTest extends SolrCloudTestCase { // try deleting secondary replica from node without the primary replica Optional<String> onlySecondaryReplica = - secondary.getReplicas().stream() + secondary + .replicaStream() .filter(replica -> !nodeSet.contains(replica.getNodeName())) .map(replica -> replica.getName()) .findFirst(); @@ -355,7 +356,8 @@ public class PlacementPluginIntegrationTest extends SolrCloudTestCase { // try deleting secondary replica from node WITH the primary replica - should fail Optional<String> secondaryWithPrimaryReplica = - secondary.getReplicas().stream() + secondary + .replicaStream() .filter(replica -> nodeSet.contains(replica.getNodeName())) .map(replica -> replica.getName()) .findFirst(); diff --git a/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java b/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java index 3dbe061559f..053fb9e4d7c 100644 --- a/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java +++ b/solr/core/src/test/org/apache/solr/search/TestCoordinatorRole.java @@ -798,8 +798,9 @@ public class TestCoordinatorRole extends SolrCloudTestCase { "Cannot find replica on first node yet", COLLECTION_NAME, collectionState -> { - if (collectionState.getReplicas().size() == 1) { - Replica replica = collectionState.getReplicas().get(0); + List<Replica> replicas = collectionState.replicaStream().toList(); + if (replicas.size() == 1) { + Replica replica = replicas.get(0); return fromNode.equals(replica.getNodeName()) && replica.getState() == Replica.State.ACTIVE; } @@ -832,15 +833,17 @@ public class TestCoordinatorRole extends SolrCloudTestCase { assertEquals(DOC_PER_COLLECTION_COUNT, response.getResults().getNumFound()); // now move the shard/replica - String replicaName = getCollectionState(COLLECTION_NAME).getReplicas().get(0).getName(); + String replicaName = + getCollectionState(COLLECTION_NAME).replicaStream().findFirst().orElseThrow().getName(); String toNodeName = dataNodes.get(1); CollectionAdminRequest.moveReplica(COLLECTION_NAME, replicaName, toNodeName).process(client); waitForState( "Cannot find replica on second node yet after repliac move", COLLECTION_NAME, collectionState -> { - if (collectionState.getReplicas().size() == 1) { - Replica replica = collectionState.getReplicas().get(0); + List<Replica> replicas = collectionState.replicaStream().toList(); + if (replicas.size() == 1) { + Replica replica = replicas.get(0); return toNodeName.equals(replica.getNodeName()) && replica.getState() == Replica.State.ACTIVE; } diff --git a/solr/core/src/test/org/apache/solr/servlet/HttpSolrProxyTest.java b/solr/core/src/test/org/apache/solr/servlet/HttpSolrProxyTest.java new file mode 100644 index 00000000000..9f182dc416f --- /dev/null +++ b/solr/core/src/test/org/apache/solr/servlet/HttpSolrProxyTest.java @@ -0,0 +1,128 @@ +/* + * 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.servlet; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.net.HttpURLConnection; +import java.net.URI; +import org.apache.solr.SolrTestCaseJ4; +import org.apache.solr.client.solrj.request.CollectionAdminRequest; +import org.apache.solr.cloud.SolrCloudTestCase; +import org.apache.solr.common.cloud.Replica; +import org.apache.solr.embedded.JettySolrRunner; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Tests {@link HttpSolrProxy}, the internode proxy used when a request lands on a node that does + * not host a replica of the target collection. Verifies that a request body with a known length is + * forwarded successfully and that the origin's {@code Content-Length} is preserved on the response. + */ [email protected] +public class HttpSolrProxyTest extends SolrCloudTestCase { + private static final String COLLECTION = "proxycoll"; + + private static JettySolrRunner owningNode; + private static JettySolrRunner proxyingNode; + + @BeforeClass + public static void setupCluster() throws Exception { + configureCluster(2).addConfig("conf", configset("cloud-minimal")).configure(); + + // Single shard + replica, so exactly one node hosts it; the other must proxy. + CollectionAdminRequest.createCollection(COLLECTION, "conf", 1, 1) + .process(cluster.getSolrClient()); + cluster.waitForActiveCollection(COLLECTION, 1, 1); + + Replica replica = + cluster + .getSolrClient() + .getClusterState() + .getCollection(COLLECTION) + .replicaStream() + .findFirst() + .orElseThrow(); + for (JettySolrRunner runner : cluster.getJettySolrRunners()) { + if (runner.getNodeName().equals(replica.getNodeName())) { + owningNode = runner; + } else { + proxyingNode = runner; + } + } + assertNotNull(owningNode); + assertNotNull(proxyingNode); + } + + /** + * A POST with a body proxied to a node that doesn't host the replica must succeed. Jetty 12.1 + * rejects (400) a forwarded Content-Length that contradicts the client's own framing, so the + * proxy must convey the known length via the request body content provider instead. + */ + @Test + public void testProxiedPostWithBodySucceeds() throws Exception { + byte[] body = "[{\"id\":\"1\"}]".getBytes(UTF_8); + HttpURLConnection conn = open(proxyingNode, "/" + COLLECTION + "/update/json?commit=true"); + conn.setRequestMethod("POST"); + conn.setDoOutput(true); + conn.setFixedLengthStreamingMode(body.length); // send a deterministic Content-Length + conn.setRequestProperty("Content-Type", "application/json"); + try (var out = conn.getOutputStream()) { + out.write(body); + } + assertEquals(200, conn.getResponseCode()); + conn.getInputStream().readAllBytes(); + conn.disconnect(); + } + + /** + * The proxied response must preserve the origin's Content-Length (rather than being forced to + * chunked) and it must exactly match the bytes delivered — otherwise Jetty 12.1 would abort the + * re-streamed response with "too much content written". + */ + @Test + public void testProxiedResponsePreservesContentLength() throws Exception { + String path = "/" + COLLECTION + "/select?q=*:*&rows=0"; + + HttpURLConnection direct = open(owningNode, path); + assertEquals(200, direct.getResponseCode()); + String originLen = direct.getHeaderField("Content-Length"); + direct.getInputStream().readAllBytes(); + direct.disconnect(); + assertNotNull( + "Precondition: origin should frame this small response with a Content-Length", originLen); + + HttpURLConnection proxied = open(proxyingNode, path); + assertEquals(200, proxied.getResponseCode()); + String proxiedLen = proxied.getHeaderField("Content-Length"); + int proxiedBodyLen = proxied.getInputStream().readAllBytes().length; + proxied.disconnect(); + + assertNotNull("Proxy dropped the origin's Content-Length (forced chunked)", proxiedLen); + assertEquals( + "Proxied Content-Length must match the bytes delivered", + proxiedBodyLen, + Integer.parseInt(proxiedLen)); + } + + private static HttpURLConnection open(JettySolrRunner node, String pathAndQuery) + throws Exception { + URI uri = URI.create(node.getBaseUrl().toString() + pathAndQuery); + return (HttpURLConnection) uri.toURL().openConnection(); + } +} diff --git a/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java b/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java index 4a92852cbdc..e879b3281bd 100644 --- a/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java +++ b/solr/core/src/test/org/apache/solr/update/DeleteByIdWithRouterFieldTest.java @@ -79,11 +79,14 @@ public class DeleteByIdWithRouterFieldTest extends SolrCloudTestCase { solrClient = cluster.getSolrClient(COLL); ClusterState clusterState = cluster.getSolrClient().getClusterState(); - for (Replica replica : clusterState.getCollection(COLL).getReplicas()) { - clients.add( - new CollectionScopedSolrClient( - cluster.getReplicaJetty(replica).getSolrClient(), replica.getCoreName())); - } + clusterState + .getCollection(COLL) + .replicaStream() + .forEach( + replica -> + clients.add( + new CollectionScopedSolrClient( + cluster.getReplicaJetty(replica).getSolrClient(), replica.getCoreName()))); } @AfterClass diff --git a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java index 386ff48af29..6bd61e22426 100644 --- a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java +++ b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/CloudAuthStreamTest.java @@ -927,8 +927,7 @@ public class CloudAuthStreamTest extends SolrCloudTestCase { .getZkStateReader() .getClusterState() .getCollectionOrNull(collection) - .getReplicas() - .stream() + .replicaStream() .map(Replica::getCoreUrl) .collect(Collectors.toList()); Collections.shuffle(replicaUrls, random()); diff --git a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/MathExpressionTest.java b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/MathExpressionTest.java index a1cbd9c0499..5f19648f936 100644 --- a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/MathExpressionTest.java +++ b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/MathExpressionTest.java @@ -4025,7 +4025,7 @@ public class MathExpressionTest extends SolrCloudTestCase { ClusterState clusterState = cluster.getSolrClient().getClusterState(); String collection = useAlias ? COLLECTIONORALIAS + "_collection" : COLLECTIONORALIAS; DocCollection coll = clusterState.getCollection(collection); - String node = coll.getReplicas().iterator().next().getNodeName(); + String node = coll.replicaStream().findFirst().orElseThrow().getNodeName(); String url = null; for (JettySolrRunner jetty : cluster.getJettySolrRunners()) { if (jetty.getNodeName().equals(node)) { diff --git a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java index 33f4cb8796a..3359ef2754e 100644 --- a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java +++ b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamDecoratorTest.java @@ -4417,7 +4417,7 @@ public class StreamDecoratorTest extends SolrCloudTestCase { // find a node with a replica ClusterState clusterState = cluster.getSolrClient().getClusterState(); DocCollection coll = clusterState.getCollection(COLLECTIONORALIAS); - String node = coll.getReplicas().iterator().next().getNodeName(); + String node = coll.replicaStream().findFirst().orElseThrow().getNodeName(); String url = null; for (JettySolrRunner jetty : cluster.getJettySolrRunners()) { if (jetty.getNodeName().equals(node)) { diff --git a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamingTest.java b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamingTest.java index 181f36787a3..54dd1bbf677 100644 --- a/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamingTest.java +++ b/solr/solrj-streaming/src/test/org/apache/solr/client/solrj/io/stream/StreamingTest.java @@ -2730,7 +2730,7 @@ public class StreamingTest extends SolrCloudTestCase { String collName = strings.size() > 0 ? strings.get(0) : COLLECTIONORALIAS; zkStateReader.forceUpdateCollection(collName); DocCollection collection = zkStateReader.getClusterState().getCollectionOrNull(collName); - List<Replica> replicas = collection.getReplicas(); + List<Replica> replicas = collection.replicaStream().toList(); streamContext .getEntries() .put("core", replicas.get(random().nextInt(replicas.size())).getCoreName()); @@ -3216,7 +3216,7 @@ public class StreamingTest extends SolrCloudTestCase { streamContext.setLocal(true); for (String coll : resolved) { - Replica rr = zkStateReader.getCollection(coll).getReplicas().get(0); + Replica rr = zkStateReader.getCollection(coll).replicaStream().findFirst().orElseThrow(); streamContext.put("core", rr.core); List<Replica> replicas = TupleStream.getReplicas( diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/DocCollection.java b/solr/solrj/src/java/org/apache/solr/common/cloud/DocCollection.java index 407efd7875b..faa6dc8e38b 100644 --- a/solr/solrj/src/java/org/apache/solr/common/cloud/DocCollection.java +++ b/solr/solrj/src/java/org/apache/solr/common/cloud/DocCollection.java @@ -31,6 +31,7 @@ import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Supplier; +import java.util.stream.Stream; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -400,13 +401,9 @@ public class DocCollection extends ZkNodeProps implements Iterable<Slice> { return slices.values().iterator(); } - @Deprecated // low usage and builds an ArrayList (surprising) - public List<Replica> getReplicas() { - List<Replica> replicas = new ArrayList<>(); - for (Slice slice : this) { - replicas.addAll(slice.getReplicas()); - } - return replicas; + /** Stream of all replicas across all slices. */ + public Stream<Replica> replicaStream() { + return getSlices().stream().flatMap(slice -> slice.getReplicas().stream()); } @Override diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClusterStateSSLTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClusterStateSSLTest.java index 5ae877eda0a..8881b1ba140 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClusterStateSSLTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/HttpClusterStateSSLTest.java @@ -103,7 +103,7 @@ public class HttpClusterStateSSLTest extends SolrCloudTestCase { private void verifyUrlSchemeInClusterState( final DocCollection collection, final int expectedReplicas) { assertNotNull(collection); - List<Replica> replicas = collection.getReplicas(); + List<Replica> replicas = collection.replicaStream().toList(); assertNotNull(replicas); assertEquals(expectedReplicas, replicas.size()); for (Replica r : replicas) { diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/SendUpdatesToLeadersOverrideTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/SendUpdatesToLeadersOverrideTest.java index 366a048a8a5..08f3367edcc 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/impl/SendUpdatesToLeadersOverrideTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/impl/SendUpdatesToLeadersOverrideTest.java @@ -92,7 +92,12 @@ public class SendUpdatesToLeadersOverrideTest extends SolrCloudTestCase { .isSuccess()); final List<Replica> allReplicas = - cluster.getSolrClient().getClusterState().getCollection(COLLECTION_NAME).getReplicas(); + cluster + .getSolrClient() + .getClusterState() + .getCollection(COLLECTION_NAME) + .replicaStream() + .collect(Collectors.toList()); assertEquals( "test preconditions were broken, each replica should have it's own node", numNodes, diff --git a/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java b/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java index 1bd29967657..009857689d1 100644 --- a/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java +++ b/solr/solrj/src/test/org/apache/solr/common/cloud/PerReplicaStatesIntegrationTest.java @@ -97,7 +97,7 @@ public class PerReplicaStatesIntegrationTest extends SolrCloudTestCase { assertEquals(5, prs.states.size()); // Test delete replica - Replica leader = c.getReplicas().stream().filter(Replica::isLeader).findFirst().orElseThrow(); + Replica leader = c.replicaStream().filter(Replica::isLeader).findFirst().orElseThrow(); CollectionAdminRequest.deleteReplica(testCollection, leader.shard, leader.getName()) .process(cluster.getSolrClient()); cluster.waitForActiveCollection(testCollection, 2, 4); diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java index f569f3f12e0..1e84c5e8652 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCloudBackupRestoreTestCase.java @@ -395,12 +395,16 @@ public abstract class AbstractCloudBackupRestoreTestCase extends SolrCloudTestCa Map<String, Integer> numReplicasByNodeName = new HashMap<>(); restoreCollection - .getReplicas() + .getSlices() .forEach( - x -> { - numReplicasByNodeName.put( - x.getNodeName(), numReplicasByNodeName.getOrDefault(x.getNodeName(), 0) + 1); - }); + slice -> + slice + .getReplicas() + .forEach( + x -> + numReplicasByNodeName.put( + x.getNodeName(), + numReplicasByNodeName.getOrDefault(x.getNodeName(), 0) + 1))); numReplicasByNodeName.forEach( (k, v) -> { assertTrue( diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java index f4bc7e54bb8..cc64a27a865 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/api/collections/AbstractCollectionsAPIDistributedZkTestBase.java @@ -363,16 +363,18 @@ public abstract class AbstractCollectionsAPIDistributedZkTestBase extends SolrCl .process(cluster.getSolrClient()); DocCollection collectionState = getCollectionState("nodeset_collection"); - for (Replica replica : collectionState.getReplicas()) { - String replicaUrl = replica.getCoreUrl(); - boolean matchingJetty = false; - for (String jettyUrl : baseUrls) { - if (replicaUrl.startsWith(jettyUrl)) { - matchingJetty = true; + for (Slice slice : collectionState) { + for (Replica replica : slice.getReplicas()) { + String replicaUrl = replica.getCoreUrl(); + boolean matchingJetty = false; + for (String jettyUrl : baseUrls) { + if (replicaUrl.startsWith(jettyUrl)) { + matchingJetty = true; + } + } + if (matchingJetty == false) { + fail("Expected replica to be on " + baseUrls + " but was on " + replicaUrl); } - } - if (matchingJetty == false) { - fail("Expected replica to be on " + baseUrls + " but was on " + replicaUrl); } } } @@ -682,7 +684,8 @@ public abstract class AbstractCollectionsAPIDistributedZkTestBase extends SolrCl private Replica grabNewReplica(CollectionAdminResponse response, DocCollection docCollection) { String replicaName = response.getCollectionCoresStatus().keySet().iterator().next(); Optional<Replica> optional = - docCollection.getReplicas().stream() + docCollection + .replicaStream() .filter(replica -> replicaName.equals(replica.getCoreName())) .findAny(); if (optional.isPresent()) { diff --git a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java index 4d9983af598..8dad9b0be8a 100644 --- a/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java +++ b/solr/webapp/src/test/org/apache/solr/webapp/AdminUiCollectionsScreenTest.java @@ -189,12 +189,13 @@ public class AdminUiCollectionsScreenTest extends AdminUiTestBase { private int replicaCount() { try { - return cluster - .getSolrClient() - .getClusterState() - .getCollection(COLLECTION) - .getReplicas() - .size(); + return (int) + cluster + .getSolrClient() + .getClusterState() + .getCollection(COLLECTION) + .replicaStream() + .count(); } catch (Exception e) { throw new RuntimeException(e); }
