-
Notifications
You must be signed in to change notification settings - Fork 674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SOLR-17541: LBSolrClient implementations should agree on 'getClient()' semantics #2899
base: main
Are you sure you want to change the base?
Conversation
…(2) Generate new clients whenever a previously-unseen base url is encountered.
var client = urlToClient.get(endpoint.toString()); | ||
if (client == null) { | ||
String tmpBaseSolrUrl = solrClientBuilder.baseSolrUrl; | ||
solrClientBuilder.baseSolrUrl = endpoint.getBaseUrl(); | ||
client = solrClientBuilder.build(); | ||
urlToClient.put(endpoint.getBaseUrl(), client); | ||
solrClientBuilder.baseSolrUrl = tmpBaseSolrUrl; | ||
} | ||
return client; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer calling ConcurrentHashMap.computeIfAbsent or similar to get-then-put because of it's nice atomicity properties, and avoids synchronization needs
} | ||
} | ||
|
||
private synchronized HttpSolrClientBase buildClient(Endpoint endpoint) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
synchronized is guarding what here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The synchronized
keyword was to prevent multiple threads from adding clients for the same Base Url. However, in taking your advice to use computeIfAbsent
this removes the need.
if (builder.solrClientBuilder.urlParamNames == null) { | ||
this.urlParamNames = Collections.emptySet(); | ||
} else { | ||
this.urlParamNames = Collections.unmodifiableSet(builder.solrClientBuilder.urlParamNames); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
probably fine but I'd prefer Set.copyOf here
for (HttpSolrClientBase client : urlToClient.values()) { | ||
IOUtils.closeQuietly(client); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could be a one-liner with urlToClient.values().forEach(IOUtils::closeQuiety)
As a blocker for this PR, I am getting many seemingly-unrelated solr-core test failures. For instance, Maybe this is similar to the problem I describe in #2242, in that by sharing resources between client and server in a unit test, we get automatic PKI authentication, on which the tests depend. If this speculation is true, this would be merely a test bug. Otherwise, perhaps solr-core needs to be able to share instances of In either case I do not know how to continue to make progress so any advice is appreciated. |
The problem is that org.apache.solr.handler.component.HttpShardHandlerFactory#setSecurityBuilder is being called but it only affects the built client, not clients built separately (in LB). My suspicion is that your conversion of passing the Builder as a template instead of an existing client should switch back to the client as a template and then remember to call |
I am not sure this ticket/PR has much value if we continue having the caller pass in a pre-built delegate client instead of a Builder. |
Okay with me to stay with the builder. Probably add a new method to org.apache.solr.security.HttpClientBuilderPlugin for the builder, overloading setup. As an aside, I'm totally confused about our authentication plugins, especially |
This LGTM, pending figuring out the test-failure issue and adding a CHANGES.txt entry that highlights the deprecations/removals.
+1 - Both seems like good candidates for a "lucene.experimental" annotation. (Presumably there should be a "solr.experimental", but I don't think that exists...) |
Thank you for the insight on this. I went ahead and did this, but its a bit ugly. I'd rather not have both, but then again, I want to minimize changes to solr-core with this PR. Besides, @dsmiley, I appreciate the change to synchronize on the Builder. That was a pretty bad miss on my part! I also added |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT @iamsanjay ?
@@ -305,16 +306,16 @@ public void init(PluginInfo info) { | |||
sb); | |||
int soTimeout = | |||
getParameter(args, HttpClientUtil.PROP_SO_TIMEOUT, HttpClientUtil.DEFAULT_SO_TIMEOUT, sb); | |||
|
|||
this.defaultClient = | |||
this.httpClientBuilder = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please name httpSolrClientBuilder
-- so as to clarify this isn't an Apache/Jetty HttpClient; it's a SolrClient.
.build(); | ||
this.defaultClient.addListenerFactory(this.httpListenerFactory); | ||
this.loadbalancer = new LBHttp2SolrClient.Builder<Http2SolrClient>(defaultClient).build(); | ||
.withListenerFactory(List.of(this.httpListenerFactory)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed an issue. This overwrites the list of listeners that may already be present. Shouldn't we be augmenting, not replacing?
PKI plugin handles incoming internal requests from other nodes in the cluster. Then there is indeed PKI going on 😉 It is registered whenever any auth plugin is active. |
With this PR makes
LBHttp2SolrClient
maintains an instance ofHttpSolrClientBuilderBase
per "Base Url". This makes the semantics ofLBHttp2SolrClient#getClient
consistent with that of the olderLBHttpSolrClient
.Behavior changes:
LBHttp2SolrClient
generates a Http Solr Client per base urlclose()
.LBHttp2SolrClient
mutates thebaseSolrUrl
variable of the caller-supplied instance ofHttpSolrClientBuilderBase
whenever it creates a new Http Solr Client.LBHttp2SolrClient
andCloudHttp2SolrClient
always own the internal/delegate clients. They are now always closed by us onclose()
.The following class definitions are changed in the SolrJ public API:
LBHttp2SolrClient
LBHttp2SolrClient<C extends HttpSolrClientBase> extends LBSolrClient
LBHttp2SolrClient<B extends HttpSolrClientBuilderBase<?, ?>> extends LBSolrClient
LBHttp2SolrClient.Builder
Builder<C extends HttpSolrClientBase>
Builder<B extends HttpSolrClientBuilderBase<?, ?>>
LBHttp2SolrClient.Builder
return aBuilder<B>
instead of aBuilder<C>
The following are removed from the SolrJ public API:
CloudHttp2SolrClient.Builder#withHttpClient
LBHttp2SolrClient.Builder(C solrClient, Endpoint... endpoints)
public Builder(B solrClientBuilder, Endpoint... endpoints)
HttpJdkSolrClient#requestWithBaseUrl
(main only, never released)The following were not removed, but perhaps should be considered to be marked "internal" or "Experimental"
Http2SolrClient#requestWithBaseUrl
(main only, never released)SolrClientFunction
(main only, never released)