Skip to content

Commit

Permalink
SOLR-17066: Add 'defaultCollection' to SolrClients (#2066)
Browse files Browse the repository at this point in the history
This commit adds a setter ('withDefaultCollection(String)') to all
SolrClient builders, and propagates the field down to each client
implementation.  All SolrClient implementations now have a getter to
fetch this property ('getDefaultCollection').

This will help users replace the anti-pattern of baking the collection/
core name into their client's base URL to achieve a sort of "poor
man's" default.
  • Loading branch information
gerlowskija committed Dec 18, 2023
1 parent c79011e commit 61e99d4
Show file tree
Hide file tree
Showing 17 changed files with 112 additions and 21 deletions.
4 changes: 4 additions & 0 deletions solr/CHANGES.txt
Expand Up @@ -55,6 +55,10 @@ Improvements

* SOLR-17063: Do not retain log param references in LogWatcher (Michael Gibney)

* SOLR-17066: SolrClient builders now allow users to specify a "default" collection or core
using the `withDefaultCollection` method. This is preferable to including the collection
in the base URL accepted by certain client implementations. (Jason Gerlowski)

Optimizations
---------------------
* SOLR-17084: LBSolrClient (used by CloudSolrClient) now returns the count of core tracked as not live AKA zombies
Expand Down
10 changes: 10 additions & 0 deletions solr/solrj/src/java/org/apache/solr/client/solrj/SolrClient.java
Expand Up @@ -52,6 +52,7 @@ public abstract class SolrClient implements Serializable, Closeable {
private static final long serialVersionUID = 1L;

private DocumentObjectBinder binder;
protected String defaultCollection;

/**
* Adds a collection of documents
Expand Down Expand Up @@ -1215,4 +1216,13 @@ public DocumentObjectBinder getBinder() {
public SolrRequest.SolrClientContext getContext() {
return SolrRequest.SolrClientContext.CLIENT;
}

/**
* Gets the collection used by default for collection or core-based requests
*
* <p>If no value is specified at client-creation time, this method will return null.
*/
public String getDefaultCollection() {
return defaultCollection;
}
}
Expand Up @@ -167,7 +167,6 @@ public static class Builder extends SolrClientBuilder<Builder> {
protected boolean shardLeadersOnly = true;
protected boolean directUpdatesToLeadersOnly = false;
protected boolean parallelUpdates = true;
protected String defaultCollection;
protected long retryExpiryTimeNano =
TimeUnit.NANOSECONDS.convert(3, TimeUnit.SECONDS); // 3 seconds or 3 million nanos
protected ClusterStateProvider stateProvider;
Expand Down Expand Up @@ -343,12 +342,6 @@ public Builder withParallelUpdates(boolean parallelUpdates) {
return this;
}

/** Sets the default collection for request. */
public Builder withDefaultCollection(String collection) {
this.defaultCollection = collection;
return this;
}

/**
* Sets the Zk connection timeout
*
Expand Down
Expand Up @@ -91,7 +91,6 @@ public abstract class CloudSolrClient extends SolrClient {

private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

protected volatile String defaultCollection;
// no of times collection state to be reloaded if stale state error is received
private static final int MAX_STALE_RETRIES =
Integer.parseInt(System.getProperty("cloudSolrClientMaxStaleRetries", "5"));
Expand Down Expand Up @@ -352,11 +351,6 @@ public void setDefaultCollection(String collection) {
this.defaultCollection = collection;
}

/** Gets the default collection for request */
public String getDefaultCollection() {
return defaultCollection;
}

/** Gets whether direct updates are sent in parallel */
public boolean isParallelUpdates() {
return parallelUpdates;
Expand Down
Expand Up @@ -149,6 +149,7 @@ protected ConcurrentUpdateHttp2SolrClient(Builder builder) {
this.runners = new ArrayDeque<>();
this.streamDeletes = builder.streamDeletes;
this.basePath = builder.baseSolrUrl;
this.defaultCollection = builder.defaultCollection;
this.pollQueueTimeMillis = builder.pollQueueTimeMillis;
this.stallTimeMillis = Integer.getInteger("solr.cloud.client.stallTime", 15000);

Expand Down Expand Up @@ -367,6 +368,7 @@ private void addRunner() {
@Override
public NamedList<Object> request(final SolrRequest<?> request, String collection)
throws SolrServerException, IOException {
if (collection == null) collection = defaultCollection;
if (!(request instanceof UpdateRequest)) {
request.setBasePath(basePath);
return client.request(request, collection);
Expand Down Expand Up @@ -721,6 +723,7 @@ public void setPollQueueTime(int pollQueueTimeMillis) {
public static class Builder {
protected Http2SolrClient client;
protected String baseSolrUrl;
protected String defaultCollection;
protected int queueSize = 10;
protected int threadCount;
protected ExecutorService executorService;
Expand Down Expand Up @@ -811,6 +814,12 @@ public Builder neverStreamDeletes() {
return this;
}

/** Sets a default collection for collection-based requests. */
public Builder withDefaultCollection(String defaultCollection) {
this.defaultCollection = defaultCollection;
return this;
}

/**
* @param pollQueueTimeMillis time for an open connection to wait for updates when the queue is
* empty.
Expand Down
Expand Up @@ -119,6 +119,7 @@ protected ConcurrentUpdateSolrClient(Builder builder) {

this.pollQueueTimeMillis = builder.pollQueueTime;
this.stallTimeMillis = Integer.getInteger("solr.cloud.client.stallTime", 15000);
this.defaultCollection = builder.defaultCollection;

// make sure the stall time is larger than the polling time
// to give a chance for the queue to change
Expand Down Expand Up @@ -487,6 +488,7 @@ public void setCollection(String collection) {
@Override
public NamedList<Object> request(final SolrRequest<?> request, String collection)
throws SolrServerException, IOException {
if (collection == null) collection = defaultCollection;
if (!(request instanceof UpdateRequest)) {
return client.request(request, collection);
}
Expand Down
Expand Up @@ -192,6 +192,7 @@ protected Http2SolrClient(String serverBaseUrl, Builder builder) {
this.parser = builder.responseParser;
}
updateDefaultMimeTypeForParser();
this.defaultCollection = builder.defaultCollection;
if (builder.requestTimeoutMillis != null) {
this.requestTimeoutMillis = builder.requestTimeoutMillis;
} else {
Expand Down Expand Up @@ -556,6 +557,7 @@ public NamedList<Object> request(SolrRequest<?> solrRequest, String collection)
throws SolrServerException, IOException {

solrRequest = unwrapV2Request(solrRequest);
if (collection == null) collection = defaultCollection;
String url = getRequestPath(solrRequest, collection);
Throwable abortCause = null;
Request req = null;
Expand Down Expand Up @@ -1110,6 +1112,7 @@ public static class Builder {
private ExecutorService executor;
protected RequestWriter requestWriter;
protected ResponseParser responseParser;
protected String defaultCollection;
private Set<String> urlParamNames;
private CookieStore cookieStore = getDefaultCookieStore();
private String proxyHost;
Expand Down Expand Up @@ -1234,6 +1237,12 @@ public Builder withResponseParser(ResponseParser responseParser) {
return this;
}

/** Sets a default collection for collection-based requests. */
public Builder withDefaultCollection(String defaultCollection) {
this.defaultCollection = defaultCollection;
return this;
}

public Builder withFollowRedirects(boolean followRedirects) {
this.followRedirects = followRedirects;
return this;
Expand Down
Expand Up @@ -190,6 +190,7 @@ protected HttpSolrClient(Builder builder) {
this.soTimeout = builder.socketTimeoutMillis;
this.useMultiPartPost = builder.useMultiPartPost;
this.urlParamNames = builder.urlParamNames;
this.defaultCollection = builder.defaultCollection;
}

/**
Expand Down Expand Up @@ -252,6 +253,7 @@ public NamedList<Object> request(final SolrRequest<?> request, final ResponsePar
public NamedList<Object> request(
final SolrRequest<?> request, final ResponseParser processor, String collection)
throws SolrServerException, IOException {
if (collection == null) collection = defaultCollection;
HttpRequestBase method = createMethod(request, collection);
setBasicAuthHeader(request, method);
if (request.getHeaders() != null) {
Expand Down
Expand Up @@ -24,7 +24,6 @@
import java.net.SocketTimeoutException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
Expand Down Expand Up @@ -95,9 +94,11 @@ public LBHttp2SolrClient(Http2SolrClient solrClient, String... baseSolrUrls) {
this.solrClient = solrClient;
}

private LBHttp2SolrClient(Http2SolrClient solrClient, List<String> baseSolrUrls) {
super(baseSolrUrls);
this.solrClient = solrClient;
private LBHttp2SolrClient(Builder builder) {
super(Arrays.asList(builder.baseSolrUrls));
this.solrClient = builder.http2SolrClient;
this.aliveCheckIntervalMillis = builder.aliveCheckIntervalMillis;
this.defaultCollection = builder.defaultCollection;
}

@Override
Expand Down Expand Up @@ -319,6 +320,7 @@ public static class Builder {
private final String[] baseSolrUrls;
private long aliveCheckIntervalMillis =
TimeUnit.MILLISECONDS.convert(60, TimeUnit.SECONDS); // 1 minute between checks
protected String defaultCollection;

public Builder(Http2SolrClient http2Client, String... baseSolrUrls) {
this.http2SolrClient = http2Client;
Expand All @@ -340,11 +342,14 @@ public LBHttp2SolrClient.Builder setAliveCheckInterval(int aliveCheckInterval, T
return this;
}

/** Sets a default collection for collection-based requests. */
public LBHttp2SolrClient.Builder withDefaultCollection(String defaultCollection) {
this.defaultCollection = defaultCollection;
return this;
}

public LBHttp2SolrClient build() {
LBHttp2SolrClient solrClient =
new LBHttp2SolrClient(this.http2SolrClient, Arrays.asList(this.baseSolrUrls));
solrClient.aliveCheckIntervalMillis = this.aliveCheckIntervalMillis;
return solrClient;
return new LBHttp2SolrClient(this);
}
}
}
Expand Up @@ -93,6 +93,10 @@ protected LBHttpSolrClient(Builder builder) {
builder.httpClient == null
? constructClient(builder.baseSolrUrls.toArray(new String[0]))
: builder.httpClient;
this.defaultCollection = builder.defaultCollection;
if (httpSolrClientBuilder != null && this.defaultCollection != null) {
httpSolrClientBuilder.defaultCollection = this.defaultCollection;
}
this.connectionTimeoutMillis = builder.connectionTimeoutMillis;
this.soTimeoutMillis = builder.socketTimeoutMillis;
this.parser = builder.responseParser;
Expand Down
Expand Up @@ -616,6 +616,7 @@ public NamedList<Object> request(
final int maxTries = (numServersToTry == null ? serverList.length : numServersToTry.intValue());
int numServersTried = 0;
Map<String, ServerWrapper> justFailed = null;
if (collection == null) collection = defaultCollection;

boolean timeAllowedExceeded = false;
long timeAllowedNano = getTimeAllowedInNanos(request);
Expand Down
Expand Up @@ -41,6 +41,7 @@ public abstract class SolrClientBuilder<B extends SolrClientBuilder<B>> {
protected int socketTimeoutMillis = 120000; // 120 seconds
private boolean socketTimeoutMillisUpdate = false;
protected boolean followRedirects = false;
protected String defaultCollection;
protected Set<String> urlParamNames;

/** The solution for the unchecked cast warning. */
Expand Down Expand Up @@ -97,6 +98,11 @@ public B withFollowRedirects(boolean followRedirects) {
return getThis();
}

public B withDefaultCollection(String defaultCollection) {
this.defaultCollection = defaultCollection;
return getThis();
}

/**
* Tells {@link Builder} that created clients should obey the following timeout when connecting to
* Solr servers.
Expand Down
Expand Up @@ -161,4 +161,15 @@ public void testProvideExternalClient() throws IOException {
// it's external, should be NOT closed when closing CloudSolrClient
verify(http2Client, never()).close();
}

@Test
public void testDefaultCollectionPassedFromBuilderToClient() throws IOException {
try (CloudHttp2SolrClient createdClient =
new CloudHttp2SolrClient.Builder(
Collections.singletonList(ANY_ZK_HOST), Optional.of(ANY_CHROOT))
.withDefaultCollection("aCollection")
.build()) {
assertEquals("aCollection", createdClient.getDefaultCollection());
}
}
}
Expand Up @@ -101,4 +101,14 @@ public void test0Timeouts() throws IOException {
assertNotNull(createdClient);
}
}

@Test
public void testDefaultCollectionPassedFromBuilderToClient() throws IOException {
try (CloudSolrClient createdClient =
new Builder(Collections.singletonList(ANY_ZK_HOST), Optional.of(ANY_CHROOT))
.withDefaultCollection("aCollection")
.build()) {
assertEquals("aCollection", createdClient.getDefaultCollection());
}
}
}
Expand Up @@ -23,6 +23,7 @@
import java.net.SocketTimeoutException;
import java.util.concurrent.TimeUnit;
import org.apache.solr.SolrTestCase;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.ConcurrentUpdateSolrClient.Builder;
import org.junit.Test;
Expand Down Expand Up @@ -71,4 +72,14 @@ public void testSocketTimeoutOnCommit() throws IOException, SolrServerException
// else test passses
}
}

@Test
public void testDefaultCollectionPassedFromBuilderToClient() throws IOException {
try (SolrClient createdClient =
new ConcurrentUpdateSolrClient.Builder("someurl")
.withDefaultCollection("aCollection")
.build()) {
assertEquals("aCollection", createdClient.getDefaultCollection());
}
}
}
Expand Up @@ -22,6 +22,7 @@
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.solr.SolrTestCase;
import org.apache.solr.client.solrj.ResponseParser;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.impl.HttpSolrClient.Builder;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.junit.Test;
Expand Down Expand Up @@ -83,4 +84,12 @@ public void testDefaultsToBinaryResponseParserWhenNoneProvided() throws IOExcept
assertTrue(usedParser instanceof BinaryResponseParser);
}
}

@Test
public void testDefaultCollectionPassedFromBuilderToClient() throws IOException {
try (final SolrClient createdClient =
new Builder(ANY_BASE_SOLR_URL).withDefaultCollection("aCollection").build()) {
assertEquals("aCollection", createdClient.getDefaultCollection());
}
}
}
Expand Up @@ -77,4 +77,15 @@ public void testUsesTimeoutProvidedByHttpClient() throws IOException {
}
HttpClientUtil.close(httpClient);
}

@Test
public void testDefaultCollectionPassedFromBuilderToClient() throws IOException {
try (LBHttpSolrClient createdClient =
new LBHttpSolrClient.Builder()
.withBaseSolrUrl(ANY_BASE_SOLR_URL)
.withDefaultCollection("aCollection")
.build()) {
assertEquals("aCollection", createdClient.getDefaultCollection());
}
}
}

0 comments on commit 61e99d4

Please sign in to comment.