You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by sh...@apache.org on 2017/01/04 05:48:42 UTC

[1/2] lucene-solr:branch_6x: SOLR-9877: Use instrumented http client and connection pool

Repository: lucene-solr
Updated Branches:
  refs/heads/branch_6x 93d1bba8f -> f65dc0618


SOLR-9877: Use instrumented http client and connection pool


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/a50ebcb4
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/a50ebcb4
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/a50ebcb4

Branch: refs/heads/branch_6x
Commit: a50ebcb412b1a884b826b62418e9f5d8b3c1f40c
Parents: 93d1bba
Author: Shalin Shekhar Mangar <sh...@apache.org>
Authored: Wed Jan 4 11:05:40 2017 +0530
Committer: Shalin Shekhar Mangar <sh...@apache.org>
Committed: Wed Jan 4 11:05:40 2017 +0530

----------------------------------------------------------------------
 solr/CHANGES.txt                                |   4 +-
 .../org/apache/solr/core/CoreContainer.java     |   8 +-
 .../component/HttpShardHandlerFactory.java      |  68 ++++++++--
 .../apache/solr/update/UpdateShardHandler.java  |  70 +++++++++--
 .../solr/util/stats/InstrumentedHttpClient.java |  83 +++++++++++++
 .../stats/InstrumentedHttpRequestExecutor.java  | 124 +++++++++++++++++++
 ...trumentedPoolingClientConnectionManager.java | 111 +++++++++++++++++
 7 files changed, 450 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 283e47b..df4b911 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -152,6 +152,8 @@ New Features
 
 * SOLR-8530: Add HavingStream to Streaming API and StreamingExpressions (Joel Bernstein)
 
+* SOLR-9877: Use instrumented http client and connection pool. (shalin)
+
 Optimizations
 ----------------------
 * SOLR-9704: Facet Module / JSON Facet API: Optimize blockChildren facets that have
@@ -249,7 +251,7 @@ Bug Fixes
 
 * SOLR-9154: Fix DirectSolrSpellChecker to work when added through the Config API. (Anshum Gupta)
 
-* SOLR-9859: replication.properties cannot be updated after being written and neither replication.properties or 
+* SOLR-9859: replication.properties cannot be updated after being written and neither replication.properties or
   index.properties are durable in the face of a crash. (Pushkar Raste, Chris de Kok, Cao Manh Dat, Mark Miller)
 
 * SOLR-9901: Implement move in HdfsDirectoryFactory. (Mark Miller)

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/core/src/java/org/apache/solr/core/CoreContainer.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/CoreContainer.java b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
index 2727a5a..7294679 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -438,10 +438,16 @@ public class CoreContainer {
       }
     }
 
+    metricManager = new SolrMetricManager();
 
     shardHandlerFactory = ShardHandlerFactory.newInstance(cfg.getShardHandlerFactoryPluginInfo(), loader);
+    if (shardHandlerFactory instanceof SolrMetricProducer) {
+      SolrMetricProducer metricProducer = (SolrMetricProducer) shardHandlerFactory;
+      metricProducer.initializeMetrics(metricManager, SolrInfoMBean.Group.http.toString(), "httpShardHandler");
+    }
 
     updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig());
+    updateShardHandler.initializeMetrics(metricManager, SolrInfoMBean.Group.http.toString(), "updateShardHandler");
 
     solrCores.allocateLazyCores(cfg.getTransientCacheSize(), loader);
 
@@ -454,8 +460,6 @@ public class CoreContainer {
 
     MDCLoggingContext.setNode(this);
 
-    metricManager = new SolrMetricManager();
-
     ZkStateReader.ConfigData securityConfig = isZooKeeperAware() ? getZkController().getZkStateReader().getSecurityProps(false) : new ZkStateReader.ConfigData(EMPTY_MAP, -1);
     initializeAuthorizationPlugin((Map<String, Object>) securityConfig.data.get("authorization"));
     initializeAuthenticationPlugin((Map<String, Object>) securityConfig.data.get("authentication"));

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
index 71e9fe3..ff50cbc 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HttpShardHandlerFactory.java
@@ -20,7 +20,6 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
-import org.apache.http.impl.conn.PoolingClientConnectionManager;
 import org.apache.http.impl.conn.SchemeRegistryFactory;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
@@ -40,15 +39,22 @@ import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.common.util.URLUtil;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.PluginInfo;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
 import org.apache.solr.update.UpdateShardHandler;
 import org.apache.solr.update.UpdateShardHandlerConfig;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.util.DefaultSolrThreadFactory;
+import org.apache.solr.util.stats.InstrumentedHttpClient;
+import org.apache.solr.util.stats.InstrumentedPoolingClientConnectionManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
 import java.lang.invoke.MethodHandles;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Arrays;
 import java.util.Comparator;
 import java.util.List;
@@ -62,7 +68,7 @@ import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
 
-public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.apache.solr.util.plugin.PluginInfoInitialized {
+public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.apache.solr.util.plugin.PluginInfoInitialized, SolrMetricProducer {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
   private static final String DEFAULT_SCHEME = "http";
   
@@ -80,7 +86,7 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.
       new DefaultSolrThreadFactory("httpShardExecutor")
   );
 
-  protected PoolingClientConnectionManager clientConnectionManager;
+  protected InstrumentedPoolingClientConnectionManager clientConnectionManager;
   protected CloseableHttpClient defaultClient;
   private LBHttpSolrClient loadbalancer;
   //default values:
@@ -189,11 +195,12 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.
     );
 
     ModifiableSolrParams clientParams = getClientParams();
-
-    this.clientConnectionManager = new PoolingClientConnectionManager(SchemeRegistryFactory.createSystemDefault());
+    clientConnectionManager = new InstrumentedPoolingClientConnectionManager(SchemeRegistryFactory.createSystemDefault());
     clientConnectionManager.setDefaultMaxPerRoute(maxConnectionsPerHost);
     clientConnectionManager.setMaxTotal(maxConnections);
-    this.defaultClient = HttpClientUtil.createClient(clientParams, clientConnectionManager);
+    InstrumentedHttpClient httpClient = new InstrumentedHttpClient(clientConnectionManager);
+    HttpClientUtil.configureClient(httpClient, clientParams);
+    this.defaultClient = httpClient;
     this.idleConnectionsEvictor = new UpdateShardHandler.IdleConnectionsEvictor(clientConnectionManager,
         connectionsEvictorSleepDelay, TimeUnit.MILLISECONDS, maxConnectionIdleTime, TimeUnit.MILLISECONDS);
     idleConnectionsEvictor.start();
@@ -204,10 +211,9 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.
       // but for these read only requests we can use the standard DefaultHttpRequestRetryHandler rules
       ((DefaultHttpClient) this.defaultClient).setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler());
     }
-    
     this.loadbalancer = createLoadbalancer(defaultClient);
   }
-  
+
   protected ModifiableSolrParams getClientParams() {
     ModifiableSolrParams clientParams = new ModifiableSolrParams();
     clientParams.set(HttpClientUtil.PROP_SO_TIMEOUT, soTimeout);
@@ -399,4 +405,50 @@ public class HttpShardHandlerFactory extends ShardHandlerFactory implements org.
     
     return url;
   }
+
+  @Override
+  public String getName() {
+    return this.getClass().getName();
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getSpecificationVersion();
+  }
+
+  @Override
+  public Collection<String> initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+    List<String> metricNames = new ArrayList<>(4);
+    metricNames.addAll(clientConnectionManager.initializeMetrics(manager, registry, scope));
+    if (defaultClient instanceof SolrMetricProducer) {
+      SolrMetricProducer solrMetricProducer = (SolrMetricProducer) defaultClient;
+      metricNames.addAll(solrMetricProducer.initializeMetrics(manager, registry, scope));
+    }
+    return metricNames;
+  }
+
+  @Override
+  public String getDescription() {
+    return "Metrics tracked by HttpShardHandlerFactory for distributed query requests";
+  }
+
+  @Override
+  public Category getCategory() {
+    return Category.OTHER;
+  }
+
+  @Override
+  public String getSource() {
+    return null;
+  }
+
+  @Override
+  public URL[] getDocs() {
+    return new URL[0];
+  }
+
+  @Override
+  public NamedList getStatistics() {
+    return null;
+  }
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
index 3ed31dc..a1725b3 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
@@ -17,6 +17,10 @@
 package org.apache.solr.update;
 
 import java.lang.invoke.MethodHandles;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.TimeUnit;
@@ -25,7 +29,6 @@ import org.apache.http.client.HttpClient;
 import org.apache.http.conn.ClientConnectionManager;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.http.impl.conn.PoolingClientConnectionManager;
 import org.apache.http.impl.conn.SchemeRegistryFactory;
 import org.apache.http.util.Args;
 import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
@@ -35,11 +38,16 @@ import org.apache.solr.common.SolrException;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.common.util.IOUtils;
+import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SolrjNamedThreadFactory;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
+import org.apache.solr.util.stats.InstrumentedHttpClient;
+import org.apache.solr.util.stats.InstrumentedPoolingClientConnectionManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class UpdateShardHandler {
+public class UpdateShardHandler implements SolrMetricProducer {
   
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
@@ -56,17 +64,17 @@ public class UpdateShardHandler {
   private ExecutorService recoveryExecutor = ExecutorUtil.newMDCAwareCachedThreadPool(
       new SolrjNamedThreadFactory("recoveryExecutor"));
   
-  private PoolingClientConnectionManager clientConnectionManager;
-
   private final CloseableHttpClient client;
 
+  private final InstrumentedPoolingClientConnectionManager clientConnectionManager;
+
   private final UpdateShardHandlerConfig cfg;
 
   private IdleConnectionsEvictor idleConnectionsEvictor;
 
   public UpdateShardHandler(UpdateShardHandlerConfig cfg) {
     this.cfg = cfg;
-    clientConnectionManager = new PoolingClientConnectionManager(SchemeRegistryFactory.createSystemDefault());
+    clientConnectionManager = new InstrumentedPoolingClientConnectionManager(SchemeRegistryFactory.createSystemDefault());
     if (cfg != null ) {
       clientConnectionManager.setMaxTotal(cfg.getMaxUpdateConnections());
       clientConnectionManager.setDefaultMaxPerRoute(cfg.getMaxUpdateConnectionsPerHost());
@@ -74,8 +82,9 @@ public class UpdateShardHandler {
 
     ModifiableSolrParams clientParams = getClientParams();
     log.info("Creating UpdateShardHandler HTTP client with params: {}", clientParams);
-    client = HttpClientUtil.createClient(clientParams, clientConnectionManager);
-
+    InstrumentedHttpClient httpClient = new InstrumentedHttpClient(clientConnectionManager);
+    HttpClientUtil.configureClient(httpClient, clientParams);
+    client = httpClient;
     if (cfg != null)  {
       idleConnectionsEvictor = new IdleConnectionsEvictor(clientConnectionManager,
           cfg.getUpdateConnectionsEvictorSleepDelay(), TimeUnit.MILLISECONDS,
@@ -101,6 +110,53 @@ public class UpdateShardHandler {
   }
 
 
+
+  @Override
+  public String getName() {
+    return this.getClass().getName();
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getSpecificationVersion();
+  }
+
+  @Override
+  public Collection<String> initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+    List<String> metricNames = new ArrayList<>(4);
+    metricNames.addAll(clientConnectionManager.initializeMetrics(manager, registry, scope));
+    if (client instanceof SolrMetricProducer) {
+      SolrMetricProducer solrMetricProducer = (SolrMetricProducer) client;
+      metricNames.addAll(solrMetricProducer.initializeMetrics(manager, registry, scope));
+    }
+    return metricNames;
+  }
+
+  @Override
+  public String getDescription() {
+    return "Metrics tracked by UpdateShardHandler for distributed updates and recovery";
+  }
+
+  @Override
+  public Category getCategory() {
+    return null;
+  }
+
+  @Override
+  public String getSource() {
+    return null;
+  }
+
+  @Override
+  public URL[] getDocs() {
+    return new URL[0];
+  }
+
+  @Override
+  public NamedList getStatistics() {
+    return null;
+  }
+
   public HttpClient getHttpClient() {
     return client;
   }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpClient.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpClient.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpClient.java
new file mode 100644
index 0000000..35c58aa
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpClient.java
@@ -0,0 +1,83 @@
+/*
+ * 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.util.stats;
+
+import java.net.URL;
+import java.util.Collection;
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
+
+public class InstrumentedHttpClient extends DefaultHttpClient implements SolrMetricProducer {
+
+  protected final InstrumentedHttpRequestExecutor requestExecutor;
+
+  public InstrumentedHttpClient(ClientConnectionManager conman) {
+    super(conman);
+    this.requestExecutor = new InstrumentedHttpRequestExecutor();
+  }
+
+  @Override
+  protected HttpRequestExecutor createRequestExecutor() {
+    return requestExecutor;
+  }
+
+  @Override
+  public String getName() {
+    return this.getClass().getName();
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getSpecificationVersion();
+  }
+
+  @Override
+  public Collection<String> initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+    return requestExecutor.initializeMetrics(manager, registry, scope);
+  }
+
+  @Override
+  public String getDescription() {
+    return "Metrics tracked by http client";
+  }
+
+  @Override
+  public Category getCategory() {
+    return Category.OTHER;
+  }
+
+  @Override
+  public String getSource() {
+    return null;
+  }
+
+  @Override
+  public URL[] getDocs() {
+    return new URL[0];
+  }
+
+  @Override
+  public NamedList getStatistics() {
+    return null;
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
new file mode 100644
index 0000000..ad76d73
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
@@ -0,0 +1,124 @@
+/*
+ * 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.util.stats;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Locale;
+
+import com.codahale.metrics.MetricRegistry;
+import com.codahale.metrics.Timer;
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.RequestLine;
+import org.apache.http.client.methods.HttpRequestWrapper;
+import org.apache.http.client.utils.URIBuilder;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
+
+/**
+ * Sub-class of HttpRequestExecutor which tracks metrics interesting to solr
+ * Inspired and partially copied from dropwizard httpclient library
+ */
+public class InstrumentedHttpRequestExecutor extends HttpRequestExecutor implements SolrMetricProducer {
+  protected MetricRegistry metricsRegistry;
+  protected String scope;
+
+  private static String methodNameString(HttpRequest request) {
+    return request.getRequestLine().getMethod().toLowerCase(Locale.ROOT) + "-requests";
+  }
+
+  @Override
+  public HttpResponse execute(HttpRequest request, HttpClientConnection conn, HttpContext context) throws IOException, HttpException {
+    final Timer.Context timerContext = timer(request).time();
+    try {
+      return super.execute(request, conn, context);
+    } finally {
+      timerContext.stop();
+    }
+  }
+
+  private Timer timer(HttpRequest request) {
+    return metricsRegistry.timer(getNameFor(request));
+  }
+
+  @Override
+  public String getName() {
+    return this.getClass().getName();
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getSpecificationVersion();
+  }
+
+  @Override
+  public Collection<String> initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+    this.metricsRegistry = manager.registry(registry);
+    this.scope = scope;
+    return Collections.emptyList(); // we do not know the names of the metrics yet
+  }
+
+  @Override
+  public String getDescription() {
+    return null;
+  }
+
+  @Override
+  public Category getCategory() {
+    return Category.OTHER;
+  }
+
+  @Override
+  public String getSource() {
+    return null;
+  }
+
+  @Override
+  public URL[] getDocs() {
+    return null;
+  }
+
+  @Override
+  public NamedList getStatistics() {
+    return null;
+  }
+
+  private String getNameFor(HttpRequest request) {
+    try {
+      final RequestLine requestLine = request.getRequestLine();
+      String schemeHostPort = null;
+      if (request instanceof HttpRequestWrapper) {
+        HttpRequestWrapper wrapper = (HttpRequestWrapper) request;
+        schemeHostPort = wrapper.getTarget().getSchemeName() + "://" + wrapper.getTarget().getHostName() + ":" +  wrapper.getTarget().getPort();
+      }
+      final URIBuilder url = new URIBuilder(requestLine.getUri());
+      return SolrMetricManager.mkName((schemeHostPort != null ? schemeHostPort : "") + url.removeQuery().build().toString() + "." + methodNameString(request), scope);
+    } catch (URISyntaxException e) {
+      throw new IllegalArgumentException(e);
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/a50ebcb4/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingClientConnectionManager.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingClientConnectionManager.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingClientConnectionManager.java
new file mode 100644
index 0000000..2f51c46
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedPoolingClientConnectionManager.java
@@ -0,0 +1,111 @@
+/*
+ * 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.util.stats;
+
+import java.net.URL;
+import java.util.Arrays;
+import java.util.Collection;
+
+import com.codahale.metrics.Gauge;
+import com.codahale.metrics.MetricRegistry;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.impl.conn.PoolingClientConnectionManager;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.metrics.SolrMetricManager;
+import org.apache.solr.metrics.SolrMetricProducer;
+
+/**
+ * Sub-class of PoolingHttpClientConnectionManager which tracks metrics interesting to Solr.
+ * Inspired by dropwizard metrics-httpclient library implementation.
+ */
+public class InstrumentedPoolingClientConnectionManager extends PoolingClientConnectionManager implements SolrMetricProducer {
+  protected MetricRegistry metricsRegistry;
+
+  public InstrumentedPoolingClientConnectionManager(SchemeRegistry schreg) {
+    super(schreg);
+  }
+
+  public MetricRegistry getMetricsRegistry() {
+    return metricsRegistry;
+  }
+
+  public void setMetricsRegistry(MetricRegistry metricRegistry) {
+    this.metricsRegistry = metricRegistry;
+  }
+
+  @Override
+  public String getName() {
+    return this.getClass().getName();
+  }
+
+  @Override
+  public String getVersion() {
+    return getClass().getPackage().getSpecificationVersion();
+  }
+
+  @Override
+  public Collection<String> initializeMetrics(SolrMetricManager manager, String registry, String scope) {
+    this.metricsRegistry = manager.registry(registry);
+    metricsRegistry.register(SolrMetricManager.mkName("availableConnections", scope),
+        (Gauge<Integer>) () -> {
+          // this acquires a lock on the connection pool; remove if contention sucks
+          return getTotalStats().getAvailable();
+        });
+    metricsRegistry.register(SolrMetricManager.mkName("leasedConnections", scope),
+        (Gauge<Integer>) () -> {
+          // this acquires a lock on the connection pool; remove if contention sucks
+          return getTotalStats().getLeased();
+        });
+    metricsRegistry.register(SolrMetricManager.mkName("maxConnections", scope),
+        (Gauge<Integer>) () -> {
+          // this acquires a lock on the connection pool; remove if contention sucks
+          return getTotalStats().getMax();
+        });
+    metricsRegistry.register(SolrMetricManager.mkName("pendingConnections", scope),
+        (Gauge<Integer>) () -> {
+          // this acquires a lock on the connection pool; remove if contention sucks
+          return getTotalStats().getPending();
+        });
+    return Arrays.asList("availableConnections", "leasedConnections", "maxConnections", "pendingConnections");
+  }
+
+  @Override
+  public String getDescription() {
+    return "";
+  }
+
+  @Override
+  public Category getCategory() {
+    return Category.OTHER;
+  }
+
+  @Override
+  public String getSource() {
+    return null;
+  }
+
+  @Override
+  public URL[] getDocs() {
+    return null;
+  }
+
+  @Override
+  public NamedList getStatistics() {
+    return null;
+  }
+}


[2/2] lucene-solr:branch_6x: SOLR-9877: Null check for metric registry before attempting to use it

Posted by sh...@apache.org.
SOLR-9877: Null check for metric registry before attempting to use it

(cherry picked from commit 662be93)


Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/f65dc061
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/f65dc061
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/f65dc061

Branch: refs/heads/branch_6x
Commit: f65dc06180bdb02cfbfa048e2f08d1183c250d5d
Parents: a50ebcb
Author: Shalin Shekhar Mangar <sh...@apache.org>
Authored: Thu Dec 29 09:57:03 2016 +0530
Committer: Shalin Shekhar Mangar <sh...@apache.org>
Committed: Wed Jan 4 11:06:06 2017 +0530

----------------------------------------------------------------------
 .../solr/util/stats/InstrumentedHttpRequestExecutor.java    | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/f65dc061/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
index ad76d73..0426780 100644
--- a/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
+++ b/solr/core/src/java/org/apache/solr/util/stats/InstrumentedHttpRequestExecutor.java
@@ -53,11 +53,16 @@ public class InstrumentedHttpRequestExecutor extends HttpRequestExecutor impleme
 
   @Override
   public HttpResponse execute(HttpRequest request, HttpClientConnection conn, HttpContext context) throws IOException, HttpException {
-    final Timer.Context timerContext = timer(request).time();
+    Timer.Context timerContext = null;
+    if (metricsRegistry != null)  {
+      timerContext = timer(request).time();
+    }
     try {
       return super.execute(request, conn, context);
     } finally {
-      timerContext.stop();
+      if (timerContext != null) {
+        timerContext.stop();
+      }
     }
   }