Improve the test by actually checking that the version of Aliases is

more recent, instead of simply waiting.
This commit is contained in:
Andrzej Bialecki 2019-06-11 12:13:22 +02:00
parent 142a20bb0b
commit 6527e74ed8
2 changed files with 55 additions and 26 deletions

View File

@ -19,6 +19,7 @@ package org.apache.solr.cloud;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
@ -51,7 +52,9 @@ import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CollectionAdminParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.TimeSource;
import org.apache.solr.common.util.Utils;
import org.apache.solr.util.TimeOut;
import org.apache.zookeeper.KeeperException;
import org.junit.After;
import org.junit.Before;
@ -275,7 +278,14 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
@Test
public void testClusterStateProviderAPI() throws Exception {
final String aliasName = getSaferTestName();
ZkStateReader zkStateReader = createColectionsAndAlias(aliasName);
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
Aliases aliases = zkStateReader.getAliases();
int lastVersion = aliases.getZNodeVersion();
createColectionsAndAlias(aliasName);
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
CollectionAdminRequest.SetAliasProperty setAliasProperty = CollectionAdminRequest.setAliasProperty(aliasName);
setAliasProperty.addProperty("foo","baz");
setAliasProperty.addProperty("bar","bam");
@ -283,7 +293,7 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
checkFooAndBarMeta(aliasName, zkStateReader);
SolrCloudManager cloudManager = cluster.getJettySolrRunner(0).getCoreContainer().getZkController().getSolrCloudManager();
// make sure we have the latest version in cache
zkStateReader.aliasesManager.update();
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
ClusterStateProvider stateProvider = cloudManager.getClusterStateProvider();
List<String> collections = stateProvider.resolveAlias(aliasName);
assertEquals(collections.toString(), 2, collections.size());
@ -300,7 +310,7 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
setAliasProperty.addProperty(CollectionAdminParams.ROUTER_PREFIX + "foo","baz");
setAliasProperty.process(cluster.getSolrClient());
// refresh
zkStateReader.aliasesManager.update();
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
stateProvider = cloudManager.getClusterStateProvider();
assertTrue("should be a routed alias", stateProvider.isRoutedAlias(aliasName));
@ -312,6 +322,24 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
}
}
private int waitForAliasesUpdate(int lastVersion, ZkStateReader zkStateReader) throws Exception {
TimeOut timeOut = new TimeOut(30, TimeUnit.SECONDS, TimeSource.NANO_TIME);
while (!timeOut.hasTimedOut()) {
zkStateReader.aliasesManager.update();
Aliases aliases = zkStateReader.getAliases();
if (aliases.getZNodeVersion() > lastVersion) {
return aliases.getZNodeVersion();
} else if (aliases.getZNodeVersion() < lastVersion) {
fail("unexpected znode version, expected greater than " + lastVersion + " but was " + aliases.getZNodeVersion());
}
timeOut.sleep(1000);
}
if (timeOut.hasTimedOut()) {
fail("timed out waiting for aliases to update");
}
return -1;
}
private void checkFooAndBarMeta(String aliasName, ZkStateReader zkStateReader) throws Exception {
zkStateReader.aliasesManager.update(); // ensure our view is up to date
Map<String, String> meta = zkStateReader.getAliases().getCollectionAliasProperties(aliasName);
@ -397,11 +425,15 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
QueryResponse res = cluster.getSolrClient().query("collection_old", new SolrQuery("*:*"));
assertEquals(3, res.getResults().getNumFound());
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
int lastVersion = zkStateReader.aliasesManager.getAliases().getZNodeVersion();
// Let's insure we have a "handle" to the old collection
CollectionAdminRequest.createAlias("collection_old_reserve", "collection_old").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
// This is the critical bit. The alias uses the _old collection name.
CollectionAdminRequest.createAlias("collection_old", "collection_new").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
// aliases: collection_old->collection_new, collection_old_reserve -> collection_old -> collection_new
// collections: collection_new and collection_old
@ -433,7 +465,9 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
// Clean up
CollectionAdminRequest.deleteAlias("collection_old_reserve").processAndWait(cluster.getSolrClient(), 60);
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
CollectionAdminRequest.deleteAlias("collection_old").processAndWait(cluster.getSolrClient(), 60);
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
CollectionAdminRequest.deleteCollection("collection_new").processAndWait(cluster.getSolrClient(), 60);
CollectionAdminRequest.deleteCollection("collection_old").processAndWait(cluster.getSolrClient(), 60);
// collection_old already deleted as well as collection_old_reserve
@ -471,8 +505,12 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
.add("id", "11", "a_t", "humpty dumpy sat on a low wall")
.commit(cluster.getSolrClient(), "collection_two");
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
int lastVersion = zkStateReader.aliasesManager.getAliases().getZNodeVersion();
// Create an alias pointing to both
CollectionAdminRequest.createAlias("collection_alias_pair", "collection_one,collection_two").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
QueryResponse res = cluster.getSolrClient().query("collection_alias_pair", new SolrQuery("*:*"));
assertEquals(3, res.getResults().getNumFound());
@ -484,6 +522,7 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
// Now redefine the alias to only point to colletion two
CollectionAdminRequest.createAlias("collection_alias_pair", "collection_two").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
//Delete collection_one.
delResp = CollectionAdminRequest.deleteCollection("collection_one").processAndWait(cluster.getSolrClient(), 60);
@ -507,6 +546,7 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
CollectionAdminRequest.deleteAlias("collection_alias_pair").processAndWait(cluster.getSolrClient(), 60);
CollectionAdminRequest.deleteCollection("collection_two").processAndWait(cluster.getSolrClient(), 60);
// collection_one already deleted
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
assertNull("collection_alias_pair should be gone",
cluster.getSolrClient().getZkStateReader().getAliases().getCollectionAliasMap().get("collection_alias_pair"));
@ -544,12 +584,15 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
///////////////
// make sure there's only one level of alias
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
int lastVersion = zkStateReader.aliasesManager.getAliases().getZNodeVersion();
CollectionAdminRequest.deleteAlias("collection1").process(cluster.getSolrClient());
CollectionAdminRequest.createAlias("testalias1", "collection1").process(cluster.getSolrClient());
// verify proper resolution on the server-side
ZkStateReader zkStateReader = cluster.getSolrClient().getZkStateReader();
zkStateReader.aliasesManager.update();
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
Aliases aliases = zkStateReader.getAliases();
List<String> collections = aliases.resolveAliases("testalias1");
assertEquals(collections.toString(), 1, collections.size());
@ -569,27 +612,29 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
// test alias pointing to two collections. collection2 first because it's not on every node
CollectionAdminRequest.createAlias("testalias2", "collection2,collection1").process(cluster.getSolrClient());
Thread.sleep(100);
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
searchSeveralWays("testalias2", new SolrQuery("*:*"), 5);
///////////////
// update alias
CollectionAdminRequest.createAlias("testalias2", "collection2").process(cluster.getSolrClient());
sleepToAllowZkPropagation();
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
searchSeveralWays("testalias2", new SolrQuery("*:*"), 2);
///////////////
// alias pointing to alias. One level of indirection is supported; more than that is not (may or may not work)
// TODO dubious; remove?
CollectionAdminRequest.createAlias("testalias3", "testalias2").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
searchSeveralWays("testalias3", new SolrQuery("*:*"), 2);
///////////////
// Test 2 aliases pointing to the same collection
CollectionAdminRequest.createAlias("testalias4", "collection2").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
CollectionAdminRequest.createAlias("testalias5", "collection2").process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
// add one document to testalias4, thus to collection2
new UpdateRequest()
@ -622,8 +667,8 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
///////////////
for (int i = 1; i <= 6 ; i++) {
CollectionAdminRequest.deleteAlias("testalias" + i).process(cluster.getSolrClient());
lastVersion = waitForAliasesUpdate(lastVersion, zkStateReader);
}
sleepToAllowZkPropagation();
SolrException e = expectThrows(SolrException.class, () -> {
SolrQuery q = new SolrQuery("*:*");
@ -633,23 +678,6 @@ public class AliasIntegrationTest extends SolrCloudTestCase {
assertTrue("Unexpected exception message: " + e.getMessage(), e.getMessage().contains("Collection not found: testalias1"));
}
/**
* Sleep a bit to allow Zookeeper state propagation.
*
* Solr's view of the cluster is eventually consistent. *Eventually* all nodes and CloudSolrClients will be aware of
* alias changes, but not immediately. If a newly created alias is queried, things should work right away since Solr
* will attempt to see if it needs to get the latest aliases when it can't otherwise resolve the name. However
* modifications to an alias will take some time.
*/
private void sleepToAllowZkPropagation() {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}
private void searchSeveralWays(String collectionList, SolrParams solrQuery, int expectedNumFound) throws IOException, SolrServerException {
searchSeveralWays(collectionList, solrQuery, res -> assertEquals(expectedNumFound, res.getResults().getNumFound()));
}

View File

@ -1950,6 +1950,7 @@ public class ZkStateReader implements SolrCloseable {
* Update the internal aliases reference with a new one, provided that its ZK version has increased.
*
* @param newAliases the potentially newer version of Aliases
* @return true if aliases have been updated to a new version, false otherwise
*/
private boolean setIfNewer(Aliases newAliases) {
assert newAliases.getZNodeVersion() >= 0;