This is an automated email from the ASF dual-hosted git repository.

jackie pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 2050376adc Fix Bottleneck for Server Bootstrap by Making 
maxConnsPerRoute Configurable (#10487)
2050376adc is described below

commit 2050376adcb67041972d9707b338373a5e6bc468
Author: Ankit Sultana <[email protected]>
AuthorDate: Fri Mar 31 04:05:22 2023 +0530

    Fix Bottleneck for Server Bootstrap by Making maxConnsPerRoute Configurable 
(#10487)
---
 .../common/utils/FileUploadDownloadClient.java     | 11 ++-
 .../common/utils/fetcher/HttpSegmentFetcher.java   |  3 +-
 .../common/utils/fetcher/HttpsSegmentFetcher.java  |  3 +-
 .../apache/pinot/common/utils/http/HttpClient.java | 22 +++++-
 .../pinot/common/utils/http/HttpClientConfig.java  | 92 ++++++++++++++++++++++
 .../common/utils/http/HttpClientConfigTest.java    | 43 ++++++++++
 6 files changed, 167 insertions(+), 7 deletions(-)

diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUploadDownloadClient.java
 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUploadDownloadClient.java
index f78e3b4818..c369843a61 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUploadDownloadClient.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUploadDownloadClient.java
@@ -57,6 +57,7 @@ import org.apache.pinot.common.auth.AuthProviderUtils;
 import org.apache.pinot.common.exception.HttpErrorStatusException;
 import org.apache.pinot.common.restlet.resources.StartReplaceSegmentsRequest;
 import org.apache.pinot.common.utils.http.HttpClient;
+import org.apache.pinot.common.utils.http.HttpClientConfig;
 import org.apache.pinot.spi.auth.AuthProvider;
 import org.apache.pinot.spi.config.table.TableType;
 import org.apache.pinot.spi.utils.CommonConstants;
@@ -129,8 +130,16 @@ public class FileUploadDownloadClient implements 
AutoCloseable {
     _httpClient = new HttpClient();
   }
 
+  public FileUploadDownloadClient(HttpClientConfig httpClientConfig) {
+    _httpClient = new HttpClient(httpClientConfig, null);
+  }
+
   public FileUploadDownloadClient(SSLContext sslContext) {
-    _httpClient = new HttpClient(sslContext);
+    _httpClient = new HttpClient(HttpClientConfig.DEFAULT_HTTP_CLIENT_CONFIG, 
sslContext);
+  }
+
+  public FileUploadDownloadClient(HttpClientConfig httpClientConfig, 
SSLContext sslContext) {
+    _httpClient = new HttpClient(httpClientConfig, sslContext);
   }
 
   public HttpClient getHttpClient() {
diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpSegmentFetcher.java
 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpSegmentFetcher.java
index 741ac18315..8dc6162fd0 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpSegmentFetcher.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpSegmentFetcher.java
@@ -32,6 +32,7 @@ import org.apache.http.message.BasicHeader;
 import org.apache.pinot.common.exception.HttpErrorStatusException;
 import org.apache.pinot.common.utils.FileUploadDownloadClient;
 import org.apache.pinot.common.utils.RoundRobinURIProvider;
+import org.apache.pinot.common.utils.http.HttpClientConfig;
 import org.apache.pinot.spi.env.PinotConfiguration;
 import org.apache.pinot.spi.utils.retry.RetryPolicies;
 
@@ -41,7 +42,7 @@ public class HttpSegmentFetcher extends BaseSegmentFetcher {
 
   @Override
   protected void doInit(PinotConfiguration config) {
-    _httpClient = new FileUploadDownloadClient();
+    _httpClient = new 
FileUploadDownloadClient(HttpClientConfig.newBuilder(config).build());
   }
 
   @Override
diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpsSegmentFetcher.java
 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpsSegmentFetcher.java
index 64dcb601c1..71528595d8 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpsSegmentFetcher.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/fetcher/HttpsSegmentFetcher.java
@@ -22,6 +22,7 @@ import java.util.Set;
 import javax.net.ssl.SSLContext;
 import org.apache.pinot.common.utils.ClientSSLContextGenerator;
 import org.apache.pinot.common.utils.FileUploadDownloadClient;
+import org.apache.pinot.common.utils.http.HttpClientConfig;
 import org.apache.pinot.spi.env.PinotConfiguration;
 import org.apache.pinot.spi.utils.CommonConstants;
 
@@ -69,6 +70,6 @@ public class HttpsSegmentFetcher extends HttpSegmentFetcher {
     }
 
     SSLContext sslContext = new 
ClientSSLContextGenerator(sslConfig).generate();
-    _httpClient = new FileUploadDownloadClient(sslContext);
+    _httpClient = new 
FileUploadDownloadClient(HttpClientConfig.newBuilder(config).build(), 
sslContext);
   }
 }
diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClient.java 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClient.java
index 4bd7117ab8..6a74512aae 100644
--- 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClient.java
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClient.java
@@ -53,6 +53,7 @@ import org.apache.http.entity.ContentType;
 import org.apache.http.entity.StringEntity;
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClientBuilder;
 import org.apache.http.impl.client.HttpClients;
 import org.apache.http.util.EntityUtils;
 import org.apache.pinot.common.auth.AuthProviderUtils;
@@ -86,14 +87,14 @@ public class HttpClient implements AutoCloseable {
   private final CloseableHttpClient _httpClient;
 
   public HttpClient() {
-    this(null);
+    this(HttpClientConfig.DEFAULT_HTTP_CLIENT_CONFIG, null);
   }
 
-  public HttpClient(@Nullable SSLContext sslContext) {
+  public HttpClient(HttpClientConfig httpClientConfig, @Nullable SSLContext 
sslContext) {
     SSLContext context = sslContext != null ? sslContext : 
TlsUtils.getSslContext();
     // Set NoopHostnameVerifier to skip validating hostname when 
uploading/downloading segments.
     SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(context, 
NoopHostnameVerifier.INSTANCE);
-    _httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
+    _httpClient = buildCloseableHttpClient(httpClientConfig, csf);
   }
 
   public static HttpClient getInstance() {
@@ -101,7 +102,8 @@ public class HttpClient implements AutoCloseable {
   }
 
   private static final class HttpClientHolder {
-    static final HttpClient HTTP_CLIENT = new 
HttpClient(TlsUtils.getSslContext());
+    static final HttpClient HTTP_CLIENT =
+        new HttpClient(HttpClientConfig.DEFAULT_HTTP_CLIENT_CONFIG, 
TlsUtils.getSslContext());
   }
 
   // --------------------------------------------------------------------------
@@ -464,6 +466,18 @@ public class HttpClient implements AutoCloseable {
     requestBuilder.setConfig(requestConfig);
   }
 
+  private static CloseableHttpClient buildCloseableHttpClient(HttpClientConfig 
httpClientConfig,
+      SSLConnectionSocketFactory csf) {
+    HttpClientBuilder httpClientBuilder = 
HttpClients.custom().setSSLSocketFactory(csf);
+    if (httpClientConfig.getMaxConnTotal() > 0) {
+      httpClientBuilder.setMaxConnTotal(httpClientConfig.getMaxConnTotal());
+    }
+    if (httpClientConfig.getMaxConnPerRoute() > 0) {
+      
httpClientBuilder.setMaxConnPerRoute(httpClientConfig.getMaxConnPerRoute());
+    }
+    return httpClientBuilder.build();
+  }
+
   private static String getErrorMessage(HttpUriRequest request, 
CloseableHttpResponse response) {
     String controllerHost = null;
     String controllerVersion = null;
diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClientConfig.java
 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClientConfig.java
new file mode 100644
index 0000000000..d7eedf5380
--- /dev/null
+++ 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/http/HttpClientConfig.java
@@ -0,0 +1,92 @@
+/**
+ * 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.pinot.common.utils.http;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.pinot.spi.env.PinotConfiguration;
+
+
+public class HttpClientConfig {
+  // Default config uses default values which are same as what Apache Commons 
Http-Client uses.
+  public static final HttpClientConfig DEFAULT_HTTP_CLIENT_CONFIG = 
HttpClientConfig.newBuilder().build();
+
+  protected static final String MAX_CONNS_CONFIG_NAME = 
"http.client.maxConnTotal";
+  protected static final String MAX_CONNS_PER_ROUTE_CONFIG_NAME = 
"http.client.maxConnPerRoute";
+
+  private final int _maxConnTotal;
+  private final int _maxConnPerRoute;
+
+  private HttpClientConfig(int maxConnTotal, int maxConnPerRoute) {
+    _maxConnTotal = maxConnTotal;
+    _maxConnPerRoute = maxConnPerRoute;
+  }
+
+  public int getMaxConnTotal() {
+    return _maxConnTotal;
+  }
+
+  public int getMaxConnPerRoute() {
+    return _maxConnPerRoute;
+  }
+
+  /**
+   * Creates a {@link HttpClientConfig.Builder} and initializes it with 
relevant configs from the provided
+   * configuration. Since http-clients are used in a bunch of places in the 
code, each use-case can have their own
+   * prefix for their config. The caller should call {@link 
PinotConfiguration#subset(String)} to remove their prefix
+   * and this builder will look for exact matches of its relevant configs.
+   */
+  public static Builder newBuilder(PinotConfiguration pinotConfiguration) {
+    Builder builder = new Builder();
+    String maxConns = pinotConfiguration.getProperty(MAX_CONNS_CONFIG_NAME);
+    if (StringUtils.isNotEmpty(maxConns)) {
+      builder.withMaxConns(Integer.parseInt(maxConns));
+    }
+    String maxConnsPerRoute = 
pinotConfiguration.getProperty(MAX_CONNS_PER_ROUTE_CONFIG_NAME);
+    if (StringUtils.isNotEmpty(maxConnsPerRoute)) {
+      builder.withMaxConnsPerRoute(Integer.parseInt(maxConnsPerRoute));
+    }
+    return builder;
+  }
+
+  private static Builder newBuilder() {
+    return new Builder();
+  }
+
+  public static class Builder {
+    private int _maxConns = -1;
+    private int _maxConnsPerRoute = -1;
+
+    private Builder() {
+    }
+
+    public Builder withMaxConns(int maxConns) {
+      _maxConns = maxConns;
+      return this;
+    }
+
+    public Builder withMaxConnsPerRoute(int maxConnsPerRoute) {
+      _maxConnsPerRoute = maxConnsPerRoute;
+      return this;
+    }
+
+    public HttpClientConfig build() {
+      return new HttpClientConfig(_maxConns, _maxConnsPerRoute);
+    }
+  }
+}
diff --git 
a/pinot-common/src/test/java/org/apache/pinot/common/utils/http/HttpClientConfigTest.java
 
b/pinot-common/src/test/java/org/apache/pinot/common/utils/http/HttpClientConfigTest.java
new file mode 100644
index 0000000000..3cccac0f0e
--- /dev/null
+++ 
b/pinot-common/src/test/java/org/apache/pinot/common/utils/http/HttpClientConfigTest.java
@@ -0,0 +1,43 @@
+/**
+ * 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.pinot.common.utils.http;
+
+import org.apache.pinot.spi.env.PinotConfiguration;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+
+public class HttpClientConfigTest {
+
+  @Test
+  public void testNewBuilder() {
+    // Ensure config values are picked up by the builder.
+    PinotConfiguration pinotConfiguration = new PinotConfiguration();
+    pinotConfiguration.setProperty(HttpClientConfig.MAX_CONNS_CONFIG_NAME, 
"123");
+    
pinotConfiguration.setProperty(HttpClientConfig.MAX_CONNS_PER_ROUTE_CONFIG_NAME,
 "11");
+    HttpClientConfig httpClientConfig = 
HttpClientConfig.newBuilder(pinotConfiguration).build();
+    Assert.assertEquals(123, httpClientConfig.getMaxConnTotal());
+    Assert.assertEquals(11, httpClientConfig.getMaxConnPerRoute());
+
+    // Ensure default builder uses negative values
+    HttpClientConfig defaultConfig = HttpClientConfig.newBuilder(new 
PinotConfiguration()).build();
+    Assert.assertTrue(defaultConfig.getMaxConnTotal() < 0, "default value 
should be < 0");
+    Assert.assertTrue(defaultConfig.getMaxConnPerRoute() < 0, "default value 
should be < 0");
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to