blob: 59322d18c5c1c34214e2e5386eb833caf52f9fc3 [file] [log] [blame]
/*
* 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.cloud;
import java.io.File;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;
import java.util.SortedMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import org.apache.commons.io.FileUtils;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.SolrTestUtil;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrRequest;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;
import org.apache.solr.client.solrj.impl.Http2SolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient;
import org.apache.solr.client.solrj.request.CollectionAdminRequest;
import org.apache.solr.client.solrj.request.CoreAdminRequest;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.CollectionAdminResponse;
import org.apache.solr.client.solrj.response.CoreAdminResponse;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.cloud.api.collections.OverseerCollectionMessageHandler;
import org.apache.solr.common.ParWork;
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.CollectionStatePredicate;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Replica.State;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CollectionParams;
import org.apache.solr.common.params.CommonAdminParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.common.util.Utils;
import org.apache.solr.util.RestTestHarness;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public abstract class SolrCloudBridgeTestCase extends SolrCloudTestCase {
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
protected static String COLLECTION;
protected static AtomicInteger collectionCount = new AtomicInteger(0);
protected volatile static CloudHttp2SolrClient cloudClient;
protected static final String SHARD1 = "s1";
protected String id = "id";
private static final List<SolrClient> newClients = Collections.synchronizedList(new ArrayList<>());
protected Map<String, Integer> handle = new ConcurrentHashMap<>();
private static final List<RestTestHarness> restTestHarnesses = Collections.synchronizedList(new ArrayList<>());
public final static int ORDERED = 1;
public final static int SKIP = 2;
public final static int SKIPVAL = 4;
public final static int UNORDERED = 8;
String t1="a_t";
String i1="a_i1";
String tlong = "other_tl1";
String tsort="t_sortable";
String oddField="oddField_s";
String missingField="ignore_exception__missing_but_valid_field_t";
public static RandVal rdate = new RandDate();
protected static String[] fieldNames = null;
protected volatile static int numJettys = 3;
protected volatile static int sliceCount = 2;
protected volatile static int replicationFactor = 1;
protected volatile static boolean enableProxy = false;
protected final List<SolrClient> clients = Collections.synchronizedList(new ArrayList<>());
protected volatile static boolean createCollection1 = true;
protected volatile static boolean createControl;
protected volatile static CloudHttp2SolrClient controlClient;
protected volatile static MiniSolrCloudCluster controlCluster;
protected volatile static String schemaString;
protected volatile static String solrconfigString;
protected volatile static String solrxmlString = "solr.xml";
protected volatile static boolean uploadSelectCollection1Config = true;
protected volatile static boolean formatZk = true;
protected volatile static SortedMap<ServletHolder, String> extraServlets;
final Pattern filenameExclusions = Pattern.compile(".*solrconfig(?:-|_).*?\\.xml|.*schema(?:-|_).*?\\.xml");
@Before
public void setUp() throws Exception {
super.setUp();
Path TEST_PATH = SolrTestUtil.getFile("solr/collection1").getParentFile().toPath();
COLLECTION = "collection" + collectionCount.incrementAndGet();
System.setProperty("solr.test.sys.prop1", "propone");
System.setProperty("solr.test.sys.prop2", "proptwo");
cluster = configureCluster(numJettys).formatZk(formatZk).withSolrXml(TEST_PATH.resolve(solrxmlString)).withJettyConfig(jettyCfg -> jettyCfg.withServlets(extraServlets).enableProxy(enableProxy)).build();
SolrZkClient zkClient = cluster.getSolrClient().getZkStateReader().getZkClient();
if (!zkClient.exists("/configs/_default")) {
zkClient.uploadToZK(Paths.get(SolrTestUtil.TEST_HOME()).resolve("collection1").resolve("conf"), "/configs" + "/" + "_default", filenameExclusions);
}
if (schemaString != null) {
if (zkClient.exists("/configs/_default/schema.xml")) {
zkClient.setData("/configs/_default/schema.xml", TEST_PATH.resolve("collection1").resolve("conf").resolve(schemaString).toFile(), true);
} else {
byte[] data = FileUtils.readFileToByteArray(TEST_PATH.resolve("collection1").resolve("conf").resolve(schemaString).toFile());
zkClient.create("/configs/_default/schema.xml", data, CreateMode.PERSISTENT, true);
}
if (zkClient.exists("/configs/_default/managed-schema")) {
byte[] data = FileUtils.readFileToByteArray(TEST_PATH.resolve("collection1").resolve("conf").resolve(schemaString).toFile());
zkClient.setData("/configs/_default/managed-schema", data, true);
}
}
if (solrconfigString != null) {
//cloudClient.getZkStateReader().getZkClient().uploadToZK(TEST_PATH().resolve("collection1").resolve("conf").resolve(solrconfigString), "/configs/_default, null);
zkClient.setData("/configs/_default/solrconfig.xml", TEST_PATH.resolve("collection1").resolve("conf").resolve(solrconfigString).toFile(), true);
}
if (uploadSelectCollection1Config) {
String path = null;
try {
path = "/configs/_default/solrconfig.snippet.randomindexconfig.xml";
zkClient.create(path, TEST_PATH.resolve("collection1").resolve("conf").resolve(new File(path).getName()).toFile(), CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException exists) {
log.info("extra collection config file already exist in zk {}", path);
}
try {
path = "/configs/_default/enumsConfig.xml";
zkClient.create(path, TEST_PATH.resolve("collection1").resolve("conf").resolve(new File(path).getName()).toFile(), CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException exists) {
log.info("extra collection config file already exist in zk {}", path);
}
try {
path = "/configs/_default/currency.xml";
zkClient.create(path, TEST_PATH.resolve("collection1").resolve("conf").resolve(new File(path).getName()).toFile(), CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException exists) {
log.info("extra collection config file already exist in zk {}", path);
}
try {
path = "/configs/_default/old_synonyms.txt";
zkClient.create(path, TEST_PATH.resolve("collection1").resolve("conf").resolve(new File(path).getName()).toFile(), CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException exists) {
log.info("extra collection config file already exist in zk {}", path);
}
try {
path = "/configs/_default/open-exchange-rates.json";
zkClient.create(path, TEST_PATH.resolve("collection1").resolve("conf").resolve(new File(path).getName()).toFile(), CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException exists) {
log.info("extra collection config file already exist in zk {}", path);
}
try {
path = "/configs/_default/mapping-ISOLatin1Accent.txt";
zkClient.create(path, TEST_PATH.resolve("collection1").resolve("conf").resolve(new File(path).getName()).toFile(), CreateMode.PERSISTENT, true);
} catch (KeeperException.NodeExistsException exists) {
log.info("extra collection config file already exist in zk {}", path);
}
}
if (createCollection1) {
CollectionAdminRequest.createCollection(COLLECTION, "_default", sliceCount, replicationFactor).waitForFinalState(true).setMaxShardsPerNode(10).process(cluster.getSolrClient());
}
cloudClient = cluster.getSolrClient();
if (createCollection1) {
cloudClient.setDefaultCollection(COLLECTION);
}
for (int i =0;i < cluster.getJettySolrRunners().size(); i++) {
clients.add(getClient(i));
}
if (createControl) {
controlCluster = configureCluster(1).withSolrXml(TEST_PATH.resolve(solrxmlString)).formatZk(formatZk).build();
SolrZkClient zkClientControl = controlCluster.getSolrClient().getZkStateReader().getZkClient();
zkClientControl.uploadToZK(TEST_PATH.resolve("collection1").resolve("conf"), "/configs" + "/" + "_default", filenameExclusions);
if (schemaString != null) {
//cloudClient.getZkStateReader().getZkClient().uploadToZK(TEST_PATH().resolve("collection1").resolve("conf").resolve(schemaString), "/configs/_default", null);
zkClientControl.setData("/configs/_default/schema.xml", TEST_PATH.resolve("collection1").resolve("conf").resolve(schemaString).toFile(), true);
byte[] data = FileUtils.readFileToByteArray(TEST_PATH.resolve("collection1").resolve("conf").resolve(schemaString).toFile());
}
if (solrconfigString != null) {
//cloudClient.getZkStateReader().getZkClient().uploadToZK(TEST_PATH().resolve("collection1").resolve("conf").resolve(solrconfigString), "/configs/_default", null);
zkClientControl.setData("/configs/_default/solrconfig.xml", TEST_PATH.resolve("collection1").resolve("conf").resolve(solrconfigString).toFile(), true);
}
CollectionAdminRequest.createCollection(COLLECTION, "_default", 1, 1)
.setMaxShardsPerNode(10)
.process(controlCluster.getSolrClient());
controlClient = controlCluster.getSolrClient();
controlClient.setDefaultCollection(COLLECTION);
}
}
@After
public void tearDown() throws Exception {
if (cluster != null) cluster.shutdown();
if (controlCluster != null) controlCluster.shutdown();
cluster = null;
controlCluster = null;
synchronized (clients) {
for (SolrClient client : clients) {
client.close();
}
}
clients.clear();
controlClient = null;
cluster = null;
super.tearDown();
}
@BeforeClass
public static void beforeSolrCloudBridgeTestClass() {
fieldNames = new String[]{"n_ti1", "n_f1", "n_tf1", "n_d1", "n_td1", "n_l1", "n_tl1", "n_dt1", "n_tdt1"};
randVals = new RandVal[]{rint, rfloat, rfloat, rdouble, rdouble, rlong, rlong, rdate, rdate};
}
@AfterClass
public static void afterSolrCloudBridgeTestCase() throws Exception {
closeRestTestHarnesses();
synchronized (newClients) {
for (SolrClient client : newClients) {
client.close();
}
}
newClients.clear();
cloudClient = null;
extraServlets = null;
createCollection1 = true;
createControl = false;
solrconfigString = null;
schemaString = null;
solrxmlString = "solr.xml";
numJettys = 3;
formatZk = true;
uploadSelectCollection1Config = true;
sliceCount = 2;
replicationFactor = 1;
enableProxy = false;
fieldNames = null;
randVals = null;
}
protected String getBaseUrl(HttpSolrClient client) {
return client .getBaseURL().substring(
0, client.getBaseURL().length()
- COLLECTION.length() - 1);
}
protected String getBaseUrl(Http2SolrClient client) {
return client .getBaseURL().substring(
0, client.getBaseURL().length()
- COLLECTION.length() - 1);
}
protected String getShardsString() {
StringBuilder sb = new StringBuilder();
for (JettySolrRunner runner : cluster.getJettySolrRunners()) {
if (sb.length() > 0) sb.append(',');
sb.append(runner.getBaseUrl() + "/" + COLLECTION);
}
return sb.toString();
}
public Http2SolrClient getClient(int i) {
return getClient(COLLECTION, i);
}
public Http2SolrClient getClient(String collection, int i) {
String baseUrl = cluster.getJettySolrRunner(i).getBaseUrl().toString() + "/" + collection;
Http2SolrClient client = new Http2SolrClient.Builder(baseUrl)
.idleTimeout(Integer.getInteger("socketTimeout", 30000))
.build();
newClients.add(client);
return client;
}
public Http2SolrClient getClientByNode(String collection, String node) {
ClusterState cs = cluster.getSolrClient().getZkStateReader().getClusterState();
DocCollection coll = cs.getCollection(collection);
List<Replica> replicas = coll.getReplicas();
for (Replica replica : replicas) {
if (replica.getNodeName().equals(node)) {
String baseUrl = replica.getBaseUrl() + "/" + collection;
Http2SolrClient client = new Http2SolrClient.Builder(baseUrl)
.idleTimeout(Integer.getInteger("socketTimeout", 30000))
.build();
newClients.add(client);
return client;
}
}
throw new IllegalArgumentException("Could not find replica with nodename=" + node);
}
public Http2SolrClient getClient(String collection, String url) {
return getClient(url + "/" + collection);
}
public Http2SolrClient getClient(String baseUrl) {
Http2SolrClient client = new Http2SolrClient.Builder(baseUrl)
.idleTimeout(Integer.getInteger("socketTimeout", 30000))
.build();
newClients.add(client);
return client;
}
protected CollectionAdminResponse createCollection(String collectionName, int numShards, int numReplicas) throws SolrServerException, IOException {
CollectionAdminResponse resp = CollectionAdminRequest.createCollection(collectionName, "_default", numShards, numReplicas)
.setMaxShardsPerNode(10)
.waitForFinalState(true)
.process(cluster.getSolrClient());
return resp;
}
protected CollectionAdminResponse createCollection(String collectionName, int numShards, int numReplicas, int maxShardsPerNode, String createNodeSetStr, String routerField) throws SolrServerException, IOException {
CollectionAdminResponse resp = CollectionAdminRequest.createCollection(collectionName, "_default", numShards, numReplicas)
.setMaxShardsPerNode(maxShardsPerNode)
.setRouterField(routerField)
.setCreateNodeSet(createNodeSetStr)
.waitForFinalState(true)
.process(cluster.getSolrClient());
return resp;
}
protected CollectionAdminResponse createCollection(String collectionName, int numShards, int numReplicas, String createNodeSetStr, String routerField, String conf) throws SolrServerException, IOException {
CollectionAdminResponse resp = CollectionAdminRequest.createCollection(collectionName, conf, numShards, numReplicas)
.setRouterField(routerField)
.waitForFinalState(true)
.process(cluster.getSolrClient());
return resp;
}
protected CollectionAdminResponse createCollection(String collectionName, int numShards, int numReplicas, int maxShardsPerNode, String createNodeSetStr) throws SolrServerException, IOException {
CollectionAdminResponse resp = CollectionAdminRequest.createCollection(collectionName, "_default", numShards, numReplicas)
.setMaxShardsPerNode(maxShardsPerNode)
.setCreateNodeSet(createNodeSetStr)
.waitForFinalState(true)
.process(cluster.getSolrClient());
return resp;
}
protected void index(Object... fields) throws Exception {
SolrInputDocument doc = new SolrInputDocument();
addFields(doc, fields);
indexDoc(doc);
}
protected void index_specific(int serverNumber, Object... fields) throws Exception {
SolrInputDocument doc = new SolrInputDocument();
for (int i = 0; i < fields.length; i += 2) {
doc.addField((String) (fields[i]), fields[i + 1]);
}
controlClient.add(doc);
SolrClient client = clients.get(serverNumber);
client.add(doc);
}
protected void index_specific(SolrClient client, Object... fields)
throws Exception {
SolrInputDocument doc = new SolrInputDocument();
for (int i = 0; i < fields.length; i += 2) {
doc.addField((String) (fields[i]), fields[i + 1]);
}
UpdateRequest ureq = new UpdateRequest();
ureq.add(doc);
// ureq.setParam("update.chain", DISTRIB_UPDATE_CHAIN);
ureq.process(client);
// add to control second in case adding to shards fails
controlClient.add(doc);
}
protected int getReplicaPort(Replica replica) {
String replicaNode = replica.getNodeName();
String tmp = replicaNode.substring(replicaNode.indexOf(':')+1);
if (tmp.indexOf('_') != -1)
tmp = tmp.substring(0,tmp.indexOf('_'));
return Integer.parseInt(tmp);
}
protected Replica getShardLeader(String testCollectionName, String shardId, int timeoutms) throws Exception {
return cloudClient.getZkStateReader().getLeaderRetry(cluster.getSolrClient().getHttpClient(), testCollectionName, shardId, timeoutms, true);
}
protected JettySolrRunner getJettyOnPort(int port) {
JettySolrRunner theJetty = null;
for (JettySolrRunner jetty : cluster.getJettySolrRunners()) {
if (port == jetty.getLocalPort()) {
theJetty = jetty;
break;
}
}
if (createControl) {
if (theJetty == null) {
if (controlCluster.getJettySolrRunner(0).getLocalPort() == port) {
theJetty = controlCluster.getJettySolrRunner(0);
}
}
}
if (theJetty == null)
fail("Not able to find JettySolrRunner for port: "+port);
return theJetty;
}
public static void commit() throws SolrServerException, IOException {
if (controlClient != null) controlClient.commit();
cloudClient.commit();
}
protected int getShardCount() {
return numJettys;
}
public static abstract class RandVal {
public static Set uniqueValues = new HashSet();
public abstract Object val();
public Object uval() {
for (; ;) {
Object v = val();
if (uniqueValues.add(v)) return v;
}
}
}
void doQuery(String expectedDocs, String... queryParams) throws Exception {
Set<String> expectedIds = new HashSet<>( StrUtils.splitSmart(expectedDocs, ",", true) );
QueryResponse rsp = cloudClient.query(params(queryParams));
Set<String> obtainedIds = new HashSet<>();
for (SolrDocument doc : rsp.getResults()) {
obtainedIds.add((String) doc.get("id"));
}
assertEquals(expectedIds, obtainedIds);
}
protected void setDistributedParams(ModifiableSolrParams params) {
params.set("shards", getShardsString());
}
protected QueryResponse query(SolrParams p) throws Exception {
return query(true, p);
}
protected QueryResponse query(boolean setDistribParams, SolrParams p) throws Exception {
final ModifiableSolrParams params = new ModifiableSolrParams(p);
// TODO: look into why passing true causes fails
//params.set("distrib", "false");
//final QueryResponse controlRsp = controlClient.query(params);
//validateControlData(controlRsp);
//params.remove("distrib");
if (setDistribParams) setDistributedParams(params);
QueryResponse rsp = queryServer(params);
//compareResponses(rsp, controlRsp);
return rsp;
}
protected QueryResponse query(boolean setDistribParams, Object[] q) throws Exception {
final ModifiableSolrParams params = new ModifiableSolrParams();
for (int i = 0; i < q.length; i += 2) {
params.add(q[i].toString(), q[i + 1].toString());
}
return query(setDistribParams, params);
}
protected QueryResponse queryServer(ModifiableSolrParams params) throws Exception {
return cloudClient.query(params);
}
protected QueryResponse query(Object... q) throws Exception {
return query(true, q);
}
protected void indexr(Object... fields) throws Exception {
SolrInputDocument doc = new SolrInputDocument();
addFields(doc, fields);
addFields(doc, "rnd_b", true);
addRandFields(doc);
indexDoc(doc);
}
protected UpdateResponse indexDoc(SolrClient client, SolrParams params, SolrInputDocument... sdocs) throws IOException, SolrServerException {
UpdateResponse specificRsp = add(cloudClient, params, sdocs);
return specificRsp;
}
protected UpdateResponse add(SolrClient client, SolrParams params, SolrInputDocument... sdocs) throws IOException, SolrServerException {
UpdateRequest ureq = new UpdateRequest();
ureq.setParams(new ModifiableSolrParams(params));
for (SolrInputDocument sdoc : sdocs) {
ureq.add(sdoc);
}
return ureq.process(client);
}
protected static void addFields(SolrInputDocument doc, Object... fields) {
for (int i = 0; i < fields.length; i += 2) {
doc.addField((String) (fields[i]), fields[i + 1]);
}
}
public static Object[] getRandFields(String[] fields, RandVal[] randVals) {
Object[] o = new Object[fields.length * 2];
for (int i = 0; i < fields.length; i++) {
o[i * 2] = fields[i];
o[i * 2 + 1] = randVals[i].uval();
}
return o;
}
protected SolrInputDocument addRandFields(SolrInputDocument sdoc) {
addFields(sdoc, getRandFields(fieldNames, randVals));
return sdoc;
}
protected SolrInputDocument getDoc(Object... fields) throws Exception {
SolrInputDocument doc = new SolrInputDocument();
addFields(doc, fields);
return doc;
}
protected void indexDoc(SolrInputDocument doc) throws IOException, SolrServerException {
if (controlClient != null) controlClient.add(doc);
cloudClient.add(doc);
}
protected void del(String query) throws SolrServerException, IOException {
if (controlClient != null) controlClient.deleteByQuery(query);
cloudClient.deleteByQuery(query);
}
protected void waitForRecoveriesToFinish(String collectionName) throws InterruptedException, TimeoutException {
cloudClient.getZkStateReader().waitForState(collectionName, 30, TimeUnit.SECONDS, new AllActive());
}
protected void waitForRecoveriesToFinish() throws InterruptedException, TimeoutException {
waitForRecoveriesToFinish(COLLECTION);
}
protected Replica getLeaderUrlFromZk(String collection, String slice) {
ClusterState clusterState = cloudClient.getZkStateReader().getClusterState();
Replica leader = clusterState.getCollection(collection).getLeader(slice);
if (leader == null) {
throw new RuntimeException("Could not find leader:" + collection + " " + slice);
}
return leader;
}
/**
* Create a collection in single node
*/
protected void createCollectionInOneInstance(final SolrClient client, String nodeName,
ExecutorService executor, final String collection,
final int numShards, int numReplicas) throws ExecutionException, InterruptedException {
assertNotNull(nodeName);
try {
assertEquals(0, CollectionAdminRequest.createCollection(collection, "_default", numShards, 1)
.setCreateNodeSet(ZkStateReader.CREATE_NODE_SET_EMPTY)
.waitForFinalState(true)
.process(client).getStatus());
} catch (SolrServerException | IOException e) {
throw new RuntimeException(e);
}
List<Future> futures = new ArrayList<>();
for (int i = 0; i < numReplicas; i++) {
final int freezeI = i;
Future future = executor.submit(() -> {
try {
String shard = "s" + ((freezeI % numShards) + 1);
log.info("add replica to shard {}", shard);
CollectionAdminRequest.addReplicaToShard(collection, shard).setNode(nodeName).process(client);
} catch (Exception e) {
log.error("", e);
}
});
futures.add(future);
}
for (Future future : futures) {
future.get();
}
}
protected boolean useTlogReplicas() {
return false; // MRM TODO:
}
protected int getPullReplicaCount() {
return 0; // MRM TODO:
}
public static CloudHttp2SolrClient getCloudSolrClient(String zkHost, boolean shardLeadersOnly) {
if (shardLeadersOnly) {
return new CloudHttp2SolrClient.Builder(Collections.singletonList(zkHost), Optional.empty())
.build();
}
return new CloudHttp2SolrClient.Builder(Collections.singletonList(zkHost), Optional.empty())
.build();
}
protected CollectionAdminResponse createCollection(Map<String, List<Integer>> collectionInfos,
String collectionName, int numShards, int replicationFactor, SolrClient client, String createNodeSetStr, String configName) throws SolrServerException, IOException, InterruptedException, TimeoutException {
int numNrtReplicas = useTlogReplicas()?0:replicationFactor;
int numTlogReplicas = useTlogReplicas()?replicationFactor:0;
return createCollection(collectionInfos, collectionName,
Utils.makeMap(
ZkStateReader.NUM_SHARDS_PROP, numShards,
ZkStateReader.NRT_REPLICAS, numNrtReplicas,
ZkStateReader.TLOG_REPLICAS, numTlogReplicas,
ZkStateReader.PULL_REPLICAS, getPullReplicaCount(),
ZkStateReader.CREATE_NODE_SET, createNodeSetStr),
client, configName);
}
protected CloudHttp2SolrClient createCloudClient(String defaultCollection) {
CloudHttp2SolrClient client = getCloudSolrClient(cluster.getZkServer().getZkAddress(), random().nextBoolean());
if (defaultCollection != null) client.setDefaultCollection(defaultCollection);
return client;
}
// TODO: Use CollectionAdminRequest#createCollection() instead of a raw request
protected CollectionAdminResponse createCollection(Map<String, List<Integer>> collectionInfos, String collectionName, Map<String, Object> collectionProps, SolrClient client, String confSetName) throws SolrServerException, IOException, InterruptedException, TimeoutException{
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("action", CollectionParams.CollectionAction.CREATE.toString());
params.set(CommonAdminParams.WAIT_FOR_FINAL_STATE, "true");
for (Map.Entry<String, Object> entry : collectionProps.entrySet()) {
if(entry.getValue() !=null) params.set(entry.getKey(), String.valueOf(entry.getValue()));
}
Integer numShards = (Integer) collectionProps.get(ZkStateReader.NUM_SHARDS_PROP);
if(numShards==null){
String shardNames = (String) collectionProps.get(OverseerCollectionMessageHandler.SHARDS_PROP);
numShards = StrUtils.splitSmart(shardNames,',').size();
}
Integer numNrtReplicas = (Integer) collectionProps.get(ZkStateReader.NRT_REPLICAS);
if (numNrtReplicas == null) {
numNrtReplicas = (Integer) collectionProps.get(ZkStateReader.REPLICATION_FACTOR);
}
if(numNrtReplicas == null){
numNrtReplicas = (Integer) OverseerCollectionMessageHandler.COLLECTION_PROPS_AND_DEFAULTS.get(ZkStateReader.REPLICATION_FACTOR);
}
if (numNrtReplicas == null) {
numNrtReplicas = Integer.valueOf(0);
}
Integer numTlogReplicas = (Integer) collectionProps.get(ZkStateReader.TLOG_REPLICAS);
if (numTlogReplicas == null) {
numTlogReplicas = Integer.valueOf(0);
}
Integer numPullReplicas = (Integer) collectionProps.get(ZkStateReader.PULL_REPLICAS);
if (numPullReplicas == null) {
numPullReplicas = Integer.valueOf(0);
}
if (confSetName != null) {
params.set("collection.configName", confSetName);
} else {
params.set("collection.configName", "_default");
}
int clientIndex = random().nextInt(2);
List<Integer> list = new ArrayList<>();
list.add(numShards);
list.add(numNrtReplicas + numTlogReplicas + numPullReplicas);
if (collectionInfos != null) {
collectionInfos.put(collectionName, list);
}
params.set("name", collectionName);
SolrRequest request = new QueryRequest(params);
request.setPath("/admin/collections");
CollectionAdminResponse res = new CollectionAdminResponse();
if (client == null) {
final String baseUrl = getBaseUrl((Http2SolrClient) clients.get(clientIndex));
try (SolrClient adminClient = createNewSolrClient("", baseUrl)) {
res.setResponse(adminClient.request(request));
}
} else {
res.setResponse(client.request(request));
}
try {
cloudClient.waitForState(collectionName, 30, TimeUnit.SECONDS, SolrCloudTestCase.activeClusterShape(numShards,
numShards * (numNrtReplicas + numTlogReplicas + numPullReplicas)));
} catch (TimeoutException e) {
throw new RuntimeException("Timeout waiting for " + numShards + " shards and " + (numNrtReplicas + numTlogReplicas + numPullReplicas) + " replicas.", e);
}
return res;
}
protected SolrClient createNewSolrClient(String collection, String baseUrl) {
try {
// setup the server...
Http2SolrClient client = getHttpSolrClient(baseUrl + "/" + collection, DEFAULT_CONNECTION_TIMEOUT, DEFAULT_SOCKET_TIMEOUT_MILLIS);
return client;
}
catch (Exception ex) {
ParWork.propagateInterrupt(ex);
throw new RuntimeException(ex);
}
}
public static Http2SolrClient getHttpSolrClient(String url, int connectionTimeoutMillis, int socketTimeoutMillis) {
return new Http2SolrClient.Builder(url)
.build();
}
protected boolean reloadCollection(Replica replica, String testCollectionName) throws Exception {
String coreName = replica.getName();
boolean reloadedOk = true;
try (Http2SolrClient client = SolrTestCaseJ4.getHttpSolrClient(replica.getBaseUrl())) {
CoreAdminResponse statusResp = CoreAdminRequest.getStatus(coreName, client);
long leaderCoreStartTime = statusResp.getStartTime(coreName).getTime();
// send reload command for the collection
log.info("Sending RELOAD command for {}", testCollectionName);
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("action", CollectionParams.CollectionAction.RELOAD.toString());
params.set("name", testCollectionName);
QueryRequest request = new QueryRequest(params);
request.setPath("/admin/collections");
client.request(request);
// verify reload is done, waiting up to 30 seconds for slow test environments
// MRM TODO: we should do this to check status, but should not be need to wait for reload like it was
// long timeout = System.nanoTime() + TimeUnit.NANOSECONDS.convert(30, TimeUnit.SECONDS);
// while (System.nanoTime() < timeout) {
// statusResp = CoreAdminRequest.getStatus(coreName, client);
// long startTimeAfterReload = statusResp.getStartTime(coreName).getTime();
// if (startTimeAfterReload > leaderCoreStartTime) {
// reloadedOk = true;
// break;
// }
// // else ... still waiting to see the reloaded core report a later start time
// Thread.sleep(1000);
// }
}
return reloadedOk;
}
protected void setupRestTestHarnesses() {
for (final SolrClient client : clients) {
RestTestHarness harness = new RestTestHarness(() -> ((Http2SolrClient) client).getBaseURL(), cluster.getSolrClient().getHttpClient(), cluster.getJettySolrRunners().get(0).getCoreContainer()
.getResourceLoader());
restTestHarnesses.add(harness);
}
}
protected static void closeRestTestHarnesses() throws IOException {
synchronized (restTestHarnesses) {
for (RestTestHarness h : restTestHarnesses) {
h.close();
}
restTestHarnesses.clear();
}
}
protected static RestTestHarness randomRestTestHarness() {
return restTestHarnesses.get(random().nextInt(restTestHarnesses.size()));
}
protected static RestTestHarness randomRestTestHarness(Random random) {
return restTestHarnesses.get(random.nextInt(restTestHarnesses.size()));
}
protected static void forAllRestTestHarnesses(Consumer<RestTestHarness> op) {
restTestHarnesses.forEach(op);
}
public static class AllActive implements CollectionStatePredicate {
@Override
public boolean matches(Set<String> liveNodes, DocCollection coll) {
if (coll == null) return false;
Collection<Slice> slices = coll.getActiveSlices();
if (slices == null) return false;
for (Slice slice : slices) {
Collection<Replica> replicas = slice.getReplicas();
for (Replica replica : replicas) {
if (!replica.getState().equals(State.ACTIVE)) return false;
}
}
return true;
}
}
public static RandVal rint = new RandVal() {
@Override
public Object val() {
return random().nextInt();
}
};
public static RandVal rlong = new RandVal() {
@Override
public Object val() {
return random().nextLong();
}
};
public static RandVal rfloat = new RandVal() {
@Override
public Object val() {
return random().nextFloat();
}
};
public static RandVal rdouble = new RandVal() {
@Override
public Object val() {
return random().nextDouble();
}
};
public static class RandDate extends RandVal {
@Override
public Object val() {
long v = random().nextLong();
Date d = new Date(v);
return d.toInstant().toString();
}
}
protected static RandVal[] randVals;
}