You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ma...@apache.org on 2021/02/10 23:52:46 UTC

[lucene-solr] 02/03: @1341 Finishing moving to http2 client in final spots, clean up proxy forwarding more and some other things.

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

markrmiller pushed a commit to branch reference_impl_dev
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git

commit da3a67b484b3ca780982132f18a2c2bb2f602615
Author: markrmiller@gmail.com <ma...@gmail.com>
AuthorDate: Wed Feb 10 13:08:36 2021 -0600

    @1341 Finishing moving to http2 client in final spots, clean up proxy forwarding more and some other things.
---
 .../client/solrj/embedded/JettySolrRunner.java     | 15 ++--
 .../src/java/org/apache/solr/cloud/Overseer.java   |  4 +-
 .../java/org/apache/solr/cloud/ZkController.java   |  2 +-
 .../apache/solr/filestore/DistribPackageStore.java |  6 +-
 .../packagemanager/DefaultPackageRepository.java   |  7 +-
 .../apache/solr/packagemanager/PackageManager.java | 16 ++--
 .../apache/solr/packagemanager/PackageUtils.java   | 26 +++---
 .../solr/packagemanager/RepositoryManager.java     | 11 +--
 .../apache/solr/schema/JsonPreAnalyzedParser.java  |  2 +-
 .../solr/security/PKIAuthenticationPlugin.java     | 12 +--
 .../apache/solr/servlet/SolrDispatchFilter.java    |  4 +-
 .../org/apache/solr/update/UpdateShardHandler.java | 15 ----
 .../src/java/org/apache/solr/util/PackageTool.java | 10 +--
 .../src/java/org/apache/solr/util/SolrCLI.java     | 77 ++++++++---------
 .../org/apache/solr/cloud/MoveReplicaTest.java     |  2 +
 .../CollectionsAPIDistClusterPerZkTest.java        |  2 +-
 .../CollectionsAPIDistributedZkTest.java           | 14 ++-
 .../CreateCollectionsIndexAndRestartTest.java      |  3 +-
 .../SimpleCollectionCreateDeleteTest.java          |  2 +-
 .../solr/filestore/TestDistribPackageStore.java    | 20 +++--
 .../solr/handler/admin/ZookeeperReadAPITest.java   | 12 +--
 .../src/test/org/apache/solr/pkg/TestPackages.java | 10 +--
 solr/server/resources/log4j2.xml                   |  2 +-
 .../org/apache/solr/cli/ClusterStateCommand.java   | 16 ++--
 .../client/solrj/cloud/DelegatingCloudManager.java |  5 --
 .../solr/client/solrj/cloud/SolrCloudManager.java  |  3 -
 .../client/solrj/impl/SolrClientCloudManager.java  | 84 ++----------------
 .../solrj/impl/SolrClientNodeStateProvider.java    | 14 +--
 .../solr/common/cloud/ConnectionManager.java       |  6 +-
 .../org/apache/solr/common/cloud/DocRouter.java    |  4 +-
 .../org/apache/solr/common/cloud/SolrZkClient.java | 44 ++++++++--
 .../apache/solr/common/cloud/ZkCmdExecutor.java    |  3 +-
 .../java/org/apache/solr/common/util/Utils.java    | 99 +++++++++++-----------
 33 files changed, 243 insertions(+), 309 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java b/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
index ad6b18c..dfda359 100644
--- a/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
+++ b/solr/core/src/java/org/apache/solr/client/solrj/embedded/JettySolrRunner.java
@@ -20,7 +20,6 @@ import org.apache.lucene.util.Constants;
 import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.cloud.SocketProxy;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
-import org.apache.solr.client.solrj.impl.HttpSolrClient;
 import org.apache.solr.common.ParWork;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.SolrZkClient;
@@ -86,7 +85,7 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.LongAdder;
 
 /**
  * Run solr using jetty
@@ -145,12 +144,12 @@ public class JettySolrRunner implements Closeable {
   public static class DebugFilter implements Filter {
     private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
-    private final AtomicLong nRequests = new AtomicLong();
+    private final LongAdder nRequests = new LongAdder();
 
     private Set<Delay> delays = ConcurrentHashMap.newKeySet(12);
 
     public long getTotalRequests() {
-      return nRequests.get();
+      return nRequests.longValue();
 
     }
     
@@ -178,7 +177,7 @@ public class JettySolrRunner implements Closeable {
 
     @Override
     public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
-      nRequests.incrementAndGet();
+      nRequests.increment();
       executeDelay();
       filterChain.doFilter(servletRequest, servletResponse);
     }
@@ -842,9 +841,9 @@ public class JettySolrRunner implements Closeable {
   }
 
 
-  public SolrClient newHttp1Client() {
-    return new HttpSolrClient.Builder(getBaseUrl()).
-        withHttpClient(getCoreContainer().getUpdateShardHandler().getDefaultHttpClient()).build();
+  public SolrClient newHttp2Client() {
+    return new Http2SolrClient.Builder(getBaseUrl()).
+        withHttpClient(getCoreContainer().getUpdateShardHandler().getTheSharedHttpClient()).build();
   }
 
   public SolrClient newClient(int connectionTimeoutMillis, int socketTimeoutMillis) {
diff --git a/solr/core/src/java/org/apache/solr/cloud/Overseer.java b/solr/core/src/java/org/apache/solr/cloud/Overseer.java
index b1a4b61..f38d2da 100644
--- a/solr/core/src/java/org/apache/solr/cloud/Overseer.java
+++ b/solr/core/src/java/org/apache/solr/cloud/Overseer.java
@@ -295,13 +295,13 @@ public class Overseer implements SolrCloseable {
 //     stateManagmentExecutor = ParWork.getParExecutorService("stateManagmentExecutor",
 //        1, 1, 3000, new SynchronousQueue());
      taskExecutor = (ParWorkExecutor) ParWork.getParExecutorService("overseerTaskExecutor",
-         4, SysStats.PROC_COUNT, 1000, new BlockingArrayQueue<>(32, 64));
+         4, SysStats.PROC_COUNT * 2, 1000, new BlockingArrayQueue<>(32, 64));
     for (int i = 0; i < 4; i++) {
       taskExecutor.prestartCoreThread();
     }
 
     zkWriterExecutor = (ParWorkExecutor) ParWork.getParExecutorService("overseerZkWriterExecutor",
-        4, SysStats.PROC_COUNT, 1000, new BlockingArrayQueue<>(64, 128));
+        4, SysStats.PROC_COUNT * 2, 1000, new BlockingArrayQueue<>(64, 128));
     for (int i = 0; i < 4; i++) {
       zkWriterExecutor.prestartCoreThread();
     }
diff --git a/solr/core/src/java/org/apache/solr/cloud/ZkController.java b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
index 922e19e..010a1ce 100644
--- a/solr/core/src/java/org/apache/solr/cloud/ZkController.java
+++ b/solr/core/src/java/org/apache/solr/cloud/ZkController.java
@@ -749,7 +749,7 @@ public class ZkController implements Closeable, Runnable {
       cloudManager = new SolrClientCloudManager(
           new ZkDistributedQueueFactory(zkClient),
           cloudSolrClient,
-          cc.getObjectCache(), cc.getUpdateShardHandler().getDefaultHttpClient());
+          cc.getObjectCache(), cc.getUpdateShardHandler().getTheSharedHttpClient());
       cloudManager.getClusterStateProvider().connect();
     }
     return cloudManager;
diff --git a/solr/core/src/java/org/apache/solr/filestore/DistribPackageStore.java b/solr/core/src/java/org/apache/solr/filestore/DistribPackageStore.java
index 3193433..29cc96c 100644
--- a/solr/core/src/java/org/apache/solr/filestore/DistribPackageStore.java
+++ b/solr/core/src/java/org/apache/solr/filestore/DistribPackageStore.java
@@ -198,7 +198,7 @@ public class DistribPackageStore implements PackageStore {
       ByteBuffer metadata = null;
       Map m = null;
       try {
-        metadata = Utils.executeGET(coreContainer.getUpdateShardHandler().getDefaultHttpClient(),
+        metadata = Utils.executeGET(coreContainer.getUpdateShardHandler().getTheSharedHttpClient(),
             baseUrl + "/node/files" + getMetaPath(),
             Utils.newBytesConsumer((int) MAX_PKG_SIZE));
         m = (Map) Utils.fromJSON(metadata.array(), metadata.arrayOffset(), metadata.limit());
@@ -207,7 +207,7 @@ public class DistribPackageStore implements PackageStore {
       }
 
       try {
-        ByteBuffer filedata = Utils.executeGET(coreContainer.getUpdateShardHandler().getDefaultHttpClient(),
+        ByteBuffer filedata = Utils.executeGET(coreContainer.getUpdateShardHandler().getTheSharedHttpClient(),
             baseUrl + "/node/files" + path,
             Utils.newBytesConsumer((int) MAX_PKG_SIZE));
         String sha512 = DigestUtils.sha512Hex(new ByteBufferInputStream(filedata));
@@ -235,7 +235,7 @@ public class DistribPackageStore implements PackageStore {
           String reqUrl = url + "/node/files" + path +
               "?meta=true&wt=javabin&omitHeader=true";
           boolean nodeHasBlob = false;
-          Object nl = Utils.executeGET(coreContainer.getUpdateShardHandler().getDefaultHttpClient(), reqUrl, Utils.JAVABINCONSUMER);
+          Object nl = Utils.executeGET(coreContainer.getUpdateShardHandler().getTheSharedHttpClient(), reqUrl, Utils.JAVABINCONSUMER);
           if (Utils.getObjectByPath(nl, false, Arrays.asList("files", path)) != null) {
             nodeHasBlob = true;
           }
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/DefaultPackageRepository.java b/solr/core/src/java/org/apache/solr/packagemanager/DefaultPackageRepository.java
index cbff8cf..0829736 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/DefaultPackageRepository.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/DefaultPackageRepository.java
@@ -27,8 +27,7 @@ import java.util.Map;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.io.FilenameUtils;
-import org.apache.http.impl.client.CloseableHttpClient;
-import org.apache.http.impl.client.HttpClientBuilder;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
 import org.slf4j.Logger;
@@ -101,7 +100,7 @@ public class DefaultPackageRepository extends PackageRepository {
   }
 
   private void initPackages() {
-    try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
+    try (Http2SolrClient client = new Http2SolrClient.Builder().build()) {
       SolrPackage[] items = PackageUtils.getJson(client, repositoryURL + "/repository.json", SolrPackage[].class);
 
       packages = new HashMap<>(items.length);
@@ -109,7 +108,7 @@ public class DefaultPackageRepository extends PackageRepository {
         pkg.setRepository(name);
         packages.put(pkg.name, pkg);
       }
-    } catch (IOException ex) {
+    } catch (Exception ex) {
       throw new SolrException(ErrorCode.INVALID_STATE, ex);
     }
     if (log.isDebugEnabled()) {
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
index caf300c..dcad3a1 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageManager.java
@@ -33,7 +33,7 @@ import java.util.Scanner;
 import java.util.Set;
 import java.util.stream.Collectors;
 
-import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.common.NavigableObject;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
@@ -59,7 +59,7 @@ import com.jayway.jsonpath.PathNotFoundException;
 public class PackageManager implements Closeable {
 
   final String solrBaseUrl;
-  final HttpSolrClient solrClient;
+  final Http2SolrClient solrClient;
   final SolrZkClient zkClient;
 
   private Map<String, List<SolrPackageInstance>> packages = null;
@@ -67,7 +67,7 @@ public class PackageManager implements Closeable {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
 
-  public PackageManager(HttpSolrClient solrClient, String solrBaseUrl, String zkHost) {
+  public PackageManager(Http2SolrClient solrClient, String solrBaseUrl, String zkHost) {
     this.solrBaseUrl = solrBaseUrl;
     this.solrClient = solrClient;
     this.zkClient = new SolrZkClient(zkHost, 30000);
@@ -117,7 +117,7 @@ public class PackageManager implements Closeable {
   public Map<String, SolrPackageInstance> getPackagesDeployed(String collection) {
     Map<String, String> packages = null;
     try {
-      NavigableObject result = (NavigableObject) Utils.executeGET(solrClient.getHttpClient(),
+      NavigableObject result = (NavigableObject) Utils.executeGET(solrClient,
           solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/PKG_VERSIONS?omitHeader=true&wt=javabin", Utils.JAVABINCONSUMER);
       packages = (Map<String, String>) result._get("/response/params/PKG_VERSIONS", Collections.emptyMap());
     } catch (PathNotFoundException ex) {
@@ -171,7 +171,7 @@ public class PackageManager implements Closeable {
 
       // Get package params
       try {
-        boolean packageParamsExist = ((Map)PackageUtils.getJson(solrClient.getHttpClient(), solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/packages", Map.class)
+        boolean packageParamsExist = ((Map)PackageUtils.getJson(solrClient, solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/packages", Map.class)
             .getOrDefault("response", Collections.emptyMap())).containsKey("params");
         SolrCLI.postJsonToSolr(solrClient, PackageUtils.getCollectionParamsPath(collection),
             getMapper().writeValueAsString(Collections.singletonMap(packageParamsExist? "update": "set",
@@ -274,7 +274,7 @@ public class PackageManager implements Closeable {
   Map<String, String> getPackageParams(String packageName, String collection) {
     try {
       return (Map<String, String>)((Map)((Map)((Map)
-          PackageUtils.getJson(solrClient.getHttpClient(), solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/packages", Map.class)
+          PackageUtils.getJson(solrClient, solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/packages", Map.class)
           .get("response"))
           .get("params"))
           .get("packages")).get(packageName);
@@ -301,7 +301,7 @@ public class PackageManager implements Closeable {
           PackageUtils.printGreen("Executing " + url + " for collection:" + collection);
 
           if ("GET".equalsIgnoreCase(cmd.method)) {
-            String response = PackageUtils.getJsonStringFromUrl(solrClient.getHttpClient(), url);
+            String response = PackageUtils.getJsonStringFromUrl(solrClient, url);
             PackageUtils.printGreen(response);
             String actualValue = JsonPath.parse(response, PackageUtils.jsonPathConfiguration())
                 .read(PackageUtils.resolve(cmd.condition, pkg.parameterDefaults, collectionParameterOverrides, systemParams));
@@ -439,7 +439,7 @@ public class PackageManager implements Closeable {
     Map<String, String> deployed = new HashMap<String, String>();
     for (String collection: allCollections) {
       // Check package version installed
-      String paramsJson = PackageUtils.getJsonStringFromUrl(solrClient.getHttpClient(), solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/PKG_VERSIONS?omitHeader=true");
+      String paramsJson = PackageUtils.getJsonStringFromUrl(solrClient,solrBaseUrl + PackageUtils.getCollectionParamsPath(collection) + "/PKG_VERSIONS?omitHeader=true");
       String version = null;
       try {
         version = JsonPath.parse(paramsJson, PackageUtils.jsonPathConfiguration())
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java b/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
index 602a9e5..e355cdd 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/PackageUtils.java
@@ -26,14 +26,11 @@ import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
 import org.apache.commons.io.IOUtils;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
 import org.apache.lucene.util.SuppressForbidden;
 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.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.request.V2Request;
 import org.apache.solr.client.solrj.response.V2Response;
 import org.apache.solr.common.SolrException;
@@ -109,7 +106,7 @@ public class PackageUtils {
   /**
    * Download JSON from the url and deserialize into klass.
    */
-  public static <T> T getJson(HttpClient client, String url, Class<T> klass) {
+  public static <T> T getJson(Http2SolrClient client, String url, Class<T> klass) {
     try {
       return getMapper().readValue(getJsonStringFromUrl(client, url), klass);
     } catch (IOException e) {
@@ -139,15 +136,14 @@ public class PackageUtils {
   /**
    * Returns JSON string from a given URL
    */
-  public static String getJsonStringFromUrl(HttpClient client, String url) {
+  public static String getJsonStringFromUrl(Http2SolrClient client, String url) {
     try {
-      HttpResponse resp = client.execute(new HttpGet(url));
-      if (resp.getStatusLine().getStatusCode() != 200) {
-        throw new SolrException(ErrorCode.NOT_FOUND,
-            "Error (code="+resp.getStatusLine().getStatusCode()+") fetching from URL: "+url);
+      Http2SolrClient.SimpleResponse resp = Http2SolrClient.GET(url, client);
+      if (resp.status != 200) {
+        throw new SolrException(ErrorCode.NOT_FOUND, "Error (code=" + resp.status + ") fetching from URL: " + url);
       }
-      return IOUtils.toString(resp.getEntity().getContent(), "UTF-8");
-    } catch (UnsupportedOperationException | IOException e) {
+      return resp.asString;
+    } catch (Exception e) {
       throw new RuntimeException(e);
     }
   }
@@ -162,8 +158,8 @@ public class PackageUtils {
   /**
    * Fetches a manifest file from the File Store / Package Store. A SHA512 check is enforced after fetching.
    */
-  public static Manifest fetchManifest(HttpSolrClient solrClient, String solrBaseUrl, String manifestFilePath, String expectedSHA512) throws MalformedURLException, IOException {
-    String manifestJson = PackageUtils.getJsonStringFromUrl(solrClient.getHttpClient(), solrBaseUrl + "/api/node/files" + manifestFilePath);
+  public static Manifest fetchManifest(Http2SolrClient solrClient, String solrBaseUrl, String manifestFilePath, String expectedSHA512) throws MalformedURLException, IOException {
+    String manifestJson = PackageUtils.getJsonStringFromUrl(solrClient, solrBaseUrl + "/api/node/files" + manifestFilePath);
     String calculatedSHA512 = BlobRepository.sha512Digest(ByteBuffer.wrap(manifestJson.getBytes("UTF-8")));
     if (expectedSHA512.equals(calculatedSHA512) == false) {
       throw new SolrException(ErrorCode.UNAUTHORIZED, "The manifest SHA512 doesn't match expected SHA512. Possible unauthorized manipulation. "
@@ -254,7 +250,7 @@ public class PackageUtils {
     return "/api/collections/" + collection + "/config/params";
   }
 
-  public static void uploadKey(byte bytes[], String path, Path home, HttpSolrClient client) throws IOException {
+  public static void uploadKey(byte bytes[], String path, Path home) throws IOException {
     ByteBuffer buf = ByteBuffer.wrap(bytes);
     PackageStoreAPI.MetaData meta = PackageStoreAPI._createJsonMetaData(buf, null);
     DistribPackageStore._persistToFile(home, path, buf, ByteBuffer.wrap(Utils.toJSON(meta)));
diff --git a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
index 4090094..c6b9f4d 100644
--- a/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
+++ b/solr/core/src/java/org/apache/solr/packagemanager/RepositoryManager.java
@@ -40,6 +40,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.lucene.util.Version;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
 import org.apache.solr.client.solrj.request.V2Request;
 import org.apache.solr.client.solrj.request.beans.Package;
@@ -70,9 +71,9 @@ public class RepositoryManager {
 
   public static final String systemVersion = Version.LATEST.toString();
 
-  final HttpSolrClient solrClient;
+  final Http2SolrClient solrClient;
 
-  public RepositoryManager(HttpSolrClient solrClient, PackageManager packageManager) {
+  public RepositoryManager(Http2SolrClient solrClient, PackageManager packageManager) {
     this.packageManager = packageManager;
     this.solrClient = solrClient;
   }
@@ -136,13 +137,13 @@ public class RepositoryManager {
   public void addKey(byte[] key, String destinationKeyFilename) throws Exception {
     // get solr_home directory from info servlet
     String systemInfoUrl = solrClient.getBaseURL() + "/solr/admin/info/system";
-    Map<String,Object> systemInfo = SolrCLI.getJson(solrClient.getHttpClient(), systemInfoUrl, 2, true);
+    Map<String,Object> systemInfo = SolrCLI.getJson(solrClient, systemInfoUrl, 2, true);
     String solrHome = (String) systemInfo.get("solr_home");
     
     // put the public key into package store's trusted key store and request a sync.
     String path = PackageStoreAPI.KEYS_DIR + "/" + destinationKeyFilename;
-    PackageUtils.uploadKey(key, path, Paths.get(solrHome), solrClient);
-    PackageUtils.getJsonStringFromUrl(solrClient.getHttpClient(), solrClient.getBaseURL() + "/api/node/files" + path + "?sync=true");
+    PackageUtils.uploadKey(key, path, Paths.get(solrHome));
+    PackageUtils.getJsonStringFromUrl(solrClient, solrClient.getBaseURL() + "/api/node/files" + path + "?sync=true");
   }
 
   private String getRepositoriesJson(SolrZkClient zkClient) throws UnsupportedEncodingException, KeeperException, InterruptedException {
diff --git a/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java b/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java
index 7cad0f4..c5fad49 100644
--- a/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java
+++ b/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java
@@ -70,7 +70,7 @@ public class JsonPreAnalyzedParser implements PreAnalyzedParser {
   public ParseResult parse(Reader reader, AttributeSource parent)
       throws IOException {
     ParseResult res = new ParseResult();
-    StringBuilder sb = new StringBuilder();
+    StringBuilder sb = new StringBuilder(128);
     char[] buf = new char[128];
     int cnt;
     while ((cnt = reader.read(buf)) > 0) {
diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
index 7cdbeb2..fbd334f 100644
--- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
+++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java
@@ -34,9 +34,7 @@ import org.apache.http.HttpEntity;
 import org.apache.http.HttpException;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpRequestInterceptor;
-import org.apache.http.HttpResponse;
 import org.apache.http.auth.BasicUserPrincipal;
-import org.apache.http.client.methods.HttpGet;
 import org.apache.http.protocol.HttpContext;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
@@ -191,13 +189,11 @@ public class PKIAuthenticationPlugin extends AuthenticationPlugin implements Htt
     InputStream is = null;
     try {
       String uri = url + PublicKeyHandler.PATH + "?wt=json&omitHeader=true";
-      log.debug("Fetching fresh public key from : {}",uri);
-      HttpResponse rsp = cores.getUpdateShardHandler().getDefaultHttpClient()
-          .execute(new HttpGet(uri), HttpClientUtil.createNewHttpClientRequestContext());
-      is  = rsp.getEntity().getContent();
+      if (log.isDebugEnabled()) log.debug("Fetching fresh public key from : {}",uri);
 
-      byte[] bytes = is.readAllBytes();
-      Map m = (Map) Utils.fromJSON(bytes);
+      Http2SolrClient.SimpleResponse resp = Http2SolrClient.GET(uri, cores.getUpdateShardHandler().getTheSharedHttpClient());
+
+      Map m = (Map) Utils.fromJSON(resp.bytes);
       String key = (String) m.get("key");
       if (key == null) {
         log.error("No key available from {} {}", url, PublicKeyHandler.PATH);
diff --git a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
index f866a15..828368a 100644
--- a/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
+++ b/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
@@ -236,8 +236,8 @@ public class SolrDispatchFilter extends BaseSolrFilter {
         }
       }
     } finally {
-      if (cores != null) {
-        this.httpClient = cores.getUpdateShardHandler().getTheSharedHttpClient().getHttpClient();
+      if (coresInit != null) {
+        this.httpClient = coresInit.getUpdateShardHandler().getTheSharedHttpClient().getHttpClient();
       }
       init.countDown();
       log.info("SolrDispatchFilter.init() end");
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 a9179c4..92aa409 100644
--- a/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
+++ b/solr/core/src/java/org/apache/solr/update/UpdateShardHandler.java
@@ -23,8 +23,6 @@ import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 
 import com.google.common.annotations.VisibleForTesting;
-import org.apache.http.client.HttpClient;
-import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
 import org.apache.solr.client.solrj.impl.BaseCloudSolrClient;
 import org.apache.solr.client.solrj.impl.Http2SolrClient;
@@ -61,8 +59,6 @@ public class UpdateShardHandler implements SolrInfoBean {
 
   private final Http2SolrClient recoveryOnlyClient;
 
-  private final CloseableHttpClient defaultClient;
-
   private ExecutorService recoveryExecutor;
 
   private final InstrumentedPoolingHttpClientConnectionManager defaultConnectionManager;
@@ -100,8 +96,6 @@ public class UpdateShardHandler implements SolrInfoBean {
     httpRequestExecutor = new InstrumentedHttpRequestExecutor(getMetricNameStrategy(cfg));
     //updateHttpListenerFactory = new InstrumentedHttpListenerFactory(getNameStrategy(cfg));
 
-    defaultClient = HttpClientUtil.createClient(clientParams, defaultConnectionManager, true, httpRequestExecutor);
-
     Http2SolrClient.Builder updateOnlyClientBuilder = new Http2SolrClient.Builder();
     if (cfg != null) {
       updateOnlyClientBuilder
@@ -200,11 +194,6 @@ public class UpdateShardHandler implements SolrInfoBean {
   public SolrMetricsContext getSolrMetricsContext() {
     return solrMetricsContext;
   }
-
-  // if you are looking for a client to use, it's probably this one.
-  public HttpClient getDefaultHttpClient() {
-    return defaultClient;
-  }
   
   // don't introduce a bug, this client is for sending updates only!
   public Http2SolrClient getTheSharedHttpClient() {
@@ -240,10 +229,6 @@ public class UpdateShardHandler implements SolrInfoBean {
 
 
     try (ParWork closer = new ParWork(this, true, false)) {
-      closer.collect("", () -> {
-        HttpClientUtil.close(defaultClient);
-        return defaultClient;
-      });
       closer.collect(recoveryOnlyClient);
       closer.collect(searchOnlyClient);
       closer.collect(updateOnlyClient);
diff --git a/solr/core/src/java/org/apache/solr/util/PackageTool.java b/solr/core/src/java/org/apache/solr/util/PackageTool.java
index 5adeccd..74bd7f6 100644
--- a/solr/core/src/java/org/apache/solr/util/PackageTool.java
+++ b/solr/core/src/java/org/apache/solr/util/PackageTool.java
@@ -25,12 +25,10 @@ import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.Option;
 import org.apache.commons.cli.OptionBuilder;
 import org.apache.commons.io.FileUtils;
-import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.config.Configurator;
 import org.apache.lucene.util.SuppressForbidden;
-import org.apache.solr.client.solrj.impl.HttpClientUtil;
-import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.common.ParWork;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrException.ErrorCode;
@@ -82,7 +80,7 @@ public class PackageTool extends SolrCLI.ToolBase {
       log.info("ZK: {}", zkHost);
       String cmd = cli.getArgList().size() == 0? "help": cli.getArgs()[0];
 
-      try (HttpSolrClient solrClient = new HttpSolrClient.Builder(solrBaseUrl).markInternalRequest().build()) {
+      try (Http2SolrClient solrClient = new Http2SolrClient.Builder(solrBaseUrl).markInternalRequest().build()) {
         if (cmd != null) {
           packageManager = new PackageManager(solrClient, solrBaseUrl, zkHost); 
           try {
@@ -279,7 +277,7 @@ public class PackageTool extends SolrCLI.ToolBase {
       return zkHost;
 
     String systemInfoUrl = solrUrl+"/admin/info/system";
-    CloseableHttpClient httpClient = SolrCLI.getHttpClient();
+    Http2SolrClient httpClient = SolrCLI.getHttpClient();
     try {
       // hit Solr to get system info
       Map<String,Object> systemInfo = SolrCLI.getJson(httpClient, systemInfoUrl, 2, true);
@@ -296,7 +294,7 @@ public class PackageTool extends SolrCLI.ToolBase {
         zkHost = zookeeper;
       }
     } finally {
-      HttpClientUtil.close(httpClient);
+      httpClient.close();
     }
 
     return zkHost;
diff --git a/solr/core/src/java/org/apache/solr/util/SolrCLI.java b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
index 255ac85..325fe0b 100755
--- a/solr/core/src/java/org/apache/solr/util/SolrCLI.java
+++ b/solr/core/src/java/org/apache/solr/util/SolrCLI.java
@@ -37,12 +37,8 @@ import org.apache.http.HttpResponse;
 import org.apache.http.NoHttpResponseException;
 import org.apache.http.StatusLine;
 import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.HttpClient;
 import org.apache.http.client.HttpResponseException;
 import org.apache.http.client.ResponseHandler;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpHead;
-import org.apache.http.client.utils.URIBuilder;
 import org.apache.http.conn.ConnectTimeoutException;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.util.EntityUtils;
@@ -51,7 +47,9 @@ import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServerException;
+import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;
 import org.apache.solr.client.solrj.impl.CloudSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
 import org.apache.solr.client.solrj.impl.HttpSolrClient;
 import org.apache.solr.client.solrj.impl.ZkClientClusterStateProvider;
@@ -70,10 +68,10 @@ import org.apache.solr.common.cloud.ZkConfigManager;
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CollectionAdminParams;
 import org.apache.solr.common.params.CommonParams;
-import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.ContentStreamBase;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.StrUtils;
+import org.apache.solr.common.util.Utils;
 import org.apache.solr.security.Sha256AuthenticationProvider;
 import org.apache.solr.util.configuration.SSLConfigurationsFactory;
 import org.noggit.CharArr;
@@ -122,6 +120,7 @@ import java.util.Optional;
 import java.util.Scanner;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import java.util.stream.Collectors;
@@ -208,7 +207,7 @@ public class SolrCLI implements CLIO {
       String zkHost = cli.getOptionValue("zkHost", ZK_HOST);
 
       log.debug("Connecting to Solr cluster: {}", zkHost);
-      try (CloudSolrClient cloudSolrClient = new CloudSolrClient.Builder(Collections.singletonList(zkHost), Optional.empty()).build()) {
+      try (CloudHttp2SolrClient cloudSolrClient = new CloudHttp2SolrClient.Builder(Collections.singletonList(zkHost), Optional.empty()).build()) {
 
         String collection = cli.getOptionValue("collection");
         if (collection != null)
@@ -222,7 +221,7 @@ public class SolrCLI implements CLIO {
     /**
      * Runs a SolrCloud tool with CloudSolrClient initialized
      */
-    protected abstract void runCloudTool(CloudSolrClient cloudSolrClient, CommandLine cli)
+    protected abstract void runCloudTool(CloudHttp2SolrClient cloudSolrClient, CommandLine cli)
         throws Exception;
   }
 
@@ -582,9 +581,11 @@ public class SolrCLI implements CLIO {
    * @throws SolrException if auth/autz problems
    * @throws IOException if connection failure
    */
-  private static int attemptHttpHead(String url, HttpClient httpClient) throws SolrException, IOException {
-    HttpResponse response = httpClient.execute(new HttpHead(url), HttpClientUtil.createNewHttpClientRequestContext());
-    int code = response.getStatusLine().getStatusCode();
+  private static int attemptHttpHead(String url, Http2SolrClient httpClient) throws SolrException, IOException, InterruptedException, ExecutionException, TimeoutException {
+
+
+    int code = Http2SolrClient.HEAD(url, httpClient);
+
     if (code == UNAUTHORIZED.code || code == FORBIDDEN.code) {
       throw new SolrException(SolrException.ErrorCode.getErrorCode(code),
           "Solr requires authentication for " + url + ". Please supply valid credentials. HTTP code=" + code);
@@ -597,12 +598,8 @@ public class SolrCLI implements CLIO {
         && Arrays.asList(UNAUTHORIZED.code, FORBIDDEN.code).contains(((SolrException) exc).code()));
   }
 
-  public static CloseableHttpClient getHttpClient() {
-    ModifiableSolrParams params = new ModifiableSolrParams();
-    params.set(HttpClientUtil.PROP_MAX_CONNECTIONS, 128);
-    params.set(HttpClientUtil.PROP_MAX_CONNECTIONS_PER_HOST, 32);
-    params.set(HttpClientUtil.PROP_FOLLOW_REDIRECTS, false);
-    return HttpClientUtil.createClient(params);
+  public static Http2SolrClient getHttpClient() {
+    return new Http2SolrClient.Builder().build();
   }
 
   @SuppressWarnings("deprecation")
@@ -632,11 +629,11 @@ public class SolrCLI implements CLIO {
    */
   public static Map<String,Object> getJson(String getUrl) throws Exception {
     Map<String,Object> json = null;
-    CloseableHttpClient httpClient = getHttpClient();
+    Http2SolrClient httpClient = getHttpClient();
     try {
       json = getJson(httpClient, getUrl, 2, true);
     } finally {
-      closeHttpClient(httpClient);
+      httpClient.close();
     }
     return json;
   }
@@ -644,7 +641,7 @@ public class SolrCLI implements CLIO {
   /**
    * Utility function for sending HTTP GET request to Solr with built-in retry support.
    */
-  public static Map<String,Object> getJson(HttpClient httpClient, String getUrl, int attempts, boolean isFirstAttempt) throws Exception {
+  public static Map<String,Object> getJson(Http2SolrClient httpClient, String getUrl, int attempts, boolean isFirstAttempt) throws Exception {
     Map<String,Object> json = null;
     if (attempts >= 1) {
       try {
@@ -705,13 +702,13 @@ public class SolrCLI implements CLIO {
    * validation of the response.
    */
   @SuppressWarnings({"unchecked"})
-  public static Map<String,Object> getJson(HttpClient httpClient, String getUrl) throws Exception {
+  public static Map<String,Object> getJson(Http2SolrClient httpClient, String getUrl) throws Exception {
     try {
       // ensure we're requesting JSON back from Solr
-      HttpGet httpGet = new HttpGet(new URIBuilder(getUrl).setParameter(CommonParams.WT, CommonParams.JSON).build());
+      Http2SolrClient.SimpleResponse resp = Http2SolrClient.GET(getUrl + "?" + CommonParams.WT + "=" + CommonParams.JSON, httpClient);
 
       // make the request and get back a parsed JSON object
-      Map<String, Object> json = httpClient.execute(httpGet, new SolrResponseHandler(), HttpClientUtil.createNewHttpClientRequestContext());
+      Map<String, Object> json = (Map<String,Object>) Utils.fromJSON(resp.bytes);
       // check the response JSON from Solr to see if it is an error
       Long statusCode = asLong("/responseHeader/status", json);
       if (statusCode == -1) {
@@ -735,7 +732,7 @@ public class SolrCLI implements CLIO {
         }
       }
       return json;
-    } catch (ClientProtocolException cpe) {
+    } catch (Exception cpe) {
       // Currently detecting authentication by string-matching the HTTP response
       // Perhaps SolrClient should have thrown an exception itself??
       if (cpe.getMessage().contains("HTTP ERROR 401") || cpe.getMessage().contentEquals("HTTP ERROR 403")) {
@@ -932,20 +929,20 @@ public class SolrCLI implements CLIO {
         solrUrl += "/";
 
       String systemInfoUrl = solrUrl+"admin/info/system";
-      CloseableHttpClient httpClient = getHttpClient();
+      Http2SolrClient httpClient = getHttpClient();
       try {
         // hit Solr to get system info
         Map<String,Object> systemInfo = getJson(httpClient, systemInfoUrl, 2, true);
         // convert raw JSON into user-friendly output
         status = reportStatus(solrUrl, systemInfo, httpClient);
       } finally {
-        closeHttpClient(httpClient);
+        httpClient.close();
       }
 
       return status;
     }
 
-    public Map<String,Object> reportStatus(String solrUrl, Map<String,Object> info, HttpClient httpClient)
+    public Map<String,Object> reportStatus(String solrUrl, Map<String,Object> info, Http2SolrClient httpClient)
         throws Exception
     {
       Map<String,Object> status = new LinkedHashMap<String,Object>();
@@ -973,7 +970,7 @@ public class SolrCLI implements CLIO {
      * Calls the CLUSTERSTATUS endpoint in Solr to get basic status information about
      * the SolrCloud cluster.
      */
-    protected Map<String,String> getCloudStatus(HttpClient httpClient, String solrUrl, String zkHost)
+    protected Map<String,String> getCloudStatus(Http2SolrClient httpClient, String solrUrl, String zkHost)
         throws Exception
     {
       Map<String,String> cloudStatus = new LinkedHashMap<String,String>();
@@ -1190,7 +1187,7 @@ public class SolrCLI implements CLIO {
     }
 
     @Override
-    protected void runCloudTool(CloudSolrClient cloudSolrClient, CommandLine cli) throws Exception {
+    protected void runCloudTool(CloudHttp2SolrClient cloudSolrClient, CommandLine cli) throws Exception {
       raiseLogLevelUnlessVerbose(cli);
       String collection = cli.getOptionValue("collection");
       if (collection == null)
@@ -1258,7 +1255,7 @@ public class SolrCLI implements CLIO {
             q = new SolrQuery("*:*");
             q.setRows(0);
             q.set(DISTRIB, "false");
-            try (HttpSolrClient solr = new HttpSolrClient.Builder(coreUrl).markInternalRequest().build()) {
+            try (Http2SolrClient solr = new Http2SolrClient.Builder(coreUrl).markInternalRequest().build()) {
 
               String solrUrl = solr.getBaseURL();
 
@@ -1267,7 +1264,7 @@ public class SolrCLI implements CLIO {
 
               int lastSlash = solrUrl.lastIndexOf('/');
               String systemInfoUrl = solrUrl.substring(0,lastSlash)+"/admin/info/system";
-              Map<String,Object> info = getJson(solr.getHttpClient(), systemInfoUrl, 2, true);
+              Map<String,Object> info = getJson(solr, systemInfoUrl, 2, true);
               uptime = uptime(asLong("/jvm/jmx/upTimeMS", info));
               String usedMemory = asString("/jvm/memory/used", info);
               String totalMemory = asString("/jvm/memory/total", info);
@@ -1419,7 +1416,7 @@ public class SolrCLI implements CLIO {
       solrUrl += "/";
 
     String systemInfoUrl = solrUrl+"admin/info/system";
-    CloseableHttpClient httpClient = getHttpClient();
+    Http2SolrClient httpClient = getHttpClient();
     try {
       // hit Solr to get system info
       Map<String,Object> systemInfo = getJson(httpClient, systemInfoUrl, 2, true);
@@ -1437,7 +1434,7 @@ public class SolrCLI implements CLIO {
         zkHost = zookeeper;
       }
     } finally {
-      HttpClientUtil.close(httpClient);
+      httpClient.close();
     }
 
     return zkHost;
@@ -1690,7 +1687,7 @@ public class SolrCLI implements CLIO {
       String coreName = cli.getOptionValue(NAME);
 
       String systemInfoUrl = solrUrl+"admin/info/system";
-      CloseableHttpClient httpClient = getHttpClient();
+      Http2SolrClient httpClient = getHttpClient();
       String solrHome = null;
       try {
         Map<String,Object> systemInfo = getJson(httpClient, systemInfoUrl, 2, true);
@@ -1705,7 +1702,7 @@ public class SolrCLI implements CLIO {
           solrHome = configsetsDir.getParentFile().getAbsolutePath();
 
       } finally {
-        closeHttpClient(httpClient);
+        httpClient.close();
       }
 
       String coreStatusUrl = solrUrl+"admin/cores?action=STATUS&core="+coreName;
@@ -1783,7 +1780,7 @@ public class SolrCLI implements CLIO {
         solrUrl += "/";
 
       String systemInfoUrl = solrUrl+"admin/info/system";
-      CloseableHttpClient httpClient = getHttpClient();
+      Http2SolrClient httpClient = getHttpClient();
 
       ToolBase tool = null;
       try {
@@ -1795,7 +1792,7 @@ public class SolrCLI implements CLIO {
         }
         tool.runImpl(cli);
       } finally {
-        closeHttpClient(httpClient);
+        httpClient.close();
       }
     }
 
@@ -2388,16 +2385,16 @@ public class SolrCLI implements CLIO {
         solrUrl += "/";
 
       String systemInfoUrl = solrUrl+"admin/info/system";
-      CloseableHttpClient httpClient = getHttpClient();
+      Http2SolrClient httpClient = getHttpClient();
       try {
         Map<String,Object> systemInfo = getJson(httpClient, systemInfoUrl, 2, true);
         if ("solrcloud".equals(systemInfo.get("mode"))) {
           deleteCollection(cli);
         } else {
-          deleteCore(cli, httpClient, solrUrl);
+          deleteCore(cli, solrUrl);
         }
       } finally {
-        closeHttpClient(httpClient);
+        httpClient.close();
       }
     }
 
@@ -2490,7 +2487,7 @@ public class SolrCLI implements CLIO {
       echo("Deleted collection '" + collectionName + "' using command:\n" + deleteCollectionUrl);
     }
 
-    protected void deleteCore(CommandLine cli, CloseableHttpClient httpClient, String solrUrl) throws Exception {
+    protected void deleteCore(CommandLine cli, String solrUrl) throws Exception {
       String coreName = cli.getOptionValue(NAME);
       String deleteCoreUrl =
           String.format(Locale.ROOT,
diff --git a/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java b/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java
index 582a57b..4362e75 100644
--- a/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/MoveReplicaTest.java
@@ -157,6 +157,8 @@ public class MoveReplicaTest extends SolrCloudTestCase {
     }
     assertTrue(success);
 
+    Thread.sleep(50);
+
     assertEquals(100,  cluster.getSolrClient().query(coll, new SolrQuery("*:*")).getResults().getNumFound());
 
 //    assertEquals("should be one less core on the source node!", sourceNumCores - 1, getNumOfCores(cloudClient, replica.getNodeName(), coll, replica.getType().name()));
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistClusterPerZkTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistClusterPerZkTest.java
index 5d2c829..8c40162 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistClusterPerZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistClusterPerZkTest.java
@@ -105,7 +105,7 @@ public class CollectionsAPIDistClusterPerZkTest extends SolrCloudTestCase {
   
   @After
   public void tearDownCluster() throws Exception {
-    cluster.deleteAllCollections();
+
   }
 
   @Test
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
index b044358..f54aa39 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CollectionsAPIDistributedZkTest.java
@@ -17,8 +17,6 @@
 package org.apache.solr.cloud.api.collections;
 
 import org.apache.solr.client.solrj.SolrRequest;
-import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.impl.BaseHttpSolrClient;
 import org.apache.solr.client.solrj.impl.CloudHttp2SolrClient;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.request.QueryRequest;
@@ -33,8 +31,8 @@ import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.RetryUtil;
 import org.apache.solr.util.TestInjection;
-import org.junit.After;
-import org.junit.Before;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.slf4j.Logger;
@@ -58,8 +56,8 @@ public class CollectionsAPIDistributedZkTest extends SolrCloudTestCase {
     return configSet;
   }
 
-  @Before
-  public void setupCluster() throws Exception {
+  @BeforeClass
+  public static void setupCluster() throws Exception {
     // we don't want this test to have zk timeouts
     System.setProperty("zkClientTimeout", "60000");
     if (TEST_NIGHTLY) {
@@ -74,8 +72,8 @@ public class CollectionsAPIDistributedZkTest extends SolrCloudTestCase {
         .configure();
   }
   
-  @After
-  public void tearDownCluster() throws Exception {
+  @AfterClass
+  public static void tearDownCluster() throws Exception {
     if (cluster != null) cluster.shutdown();
     cluster = null;
   }
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/CreateCollectionsIndexAndRestartTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/CreateCollectionsIndexAndRestartTest.java
index ca54954..455f553 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/CreateCollectionsIndexAndRestartTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/CreateCollectionsIndexAndRestartTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.solr.cloud.api.collections;
 
+import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
@@ -35,7 +36,7 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 @Slow
-//@LuceneTestCase.AwaitsFix(bugUrl = "This an experimental test class")
+@LuceneTestCase.Nightly
 public class CreateCollectionsIndexAndRestartTest extends SolrCloudTestCase {
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
 
diff --git a/solr/core/src/test/org/apache/solr/cloud/api/collections/SimpleCollectionCreateDeleteTest.java b/solr/core/src/test/org/apache/solr/cloud/api/collections/SimpleCollectionCreateDeleteTest.java
index e5e35a0..423d2e9 100644
--- a/solr/core/src/test/org/apache/solr/cloud/api/collections/SimpleCollectionCreateDeleteTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/api/collections/SimpleCollectionCreateDeleteTest.java
@@ -65,7 +65,7 @@ public class SimpleCollectionCreateDeleteTest extends SolrCloudBridgeTestCase {
       assertFalse(cloudClient.getZkStateReader().getZkClient().exists(ZkStateReader.COLLECTIONS_ZKNODE + "/" + collectionName));
       
       // currently, removing a collection does not wait for cores to be unloaded
-      TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, TimeSource.NANO_TIME);
+      TimeOut timeout = new TimeOut(30, TimeUnit.SECONDS, 50, TimeSource.NANO_TIME);
       while (true) {
         
         if( timeout.hasTimedOut() ) {
diff --git a/solr/core/src/test/org/apache/solr/filestore/TestDistribPackageStore.java b/solr/core/src/test/org/apache/solr/filestore/TestDistribPackageStore.java
index 4f83b8f..9fbbdd4 100644
--- a/solr/core/src/test/org/apache/solr/filestore/TestDistribPackageStore.java
+++ b/solr/core/src/test/org/apache/solr/filestore/TestDistribPackageStore.java
@@ -23,7 +23,7 @@ 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.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.request.V2Request;
 import org.apache.solr.client.solrj.response.V2Response;
 import org.apache.solr.cloud.MiniSolrCloudCluster;
@@ -176,8 +176,8 @@ public class TestDistribPackageStore extends SolrCloudTestCase {
       assertResponseValues(10, new Fetcher(url, jettySolrRunner), expected);
 
       if (verifyContent) {
-        try (HttpSolrClient solrClient = (HttpSolrClient) jettySolrRunner.newHttp1Client()) {
-          ByteBuffer buf = Utils.executeGET(solrClient.getHttpClient(), baseUrl + "/node/files" + path,
+        try (Http2SolrClient solrClient = (Http2SolrClient) jettySolrRunner.newHttp2Client()) {
+          ByteBuffer buf = Utils.executeGET(solrClient, baseUrl + "/node/files" + path,
               Utils.newBytesConsumer(Integer.MAX_VALUE));
           assertEquals(
               "d01b51de67ae1680a84a813983b1de3b592fc32f1a22b662fc9057da5953abd1b72476388ba342cad21671cd0b805503c78ab9075ff2f3951fdf75fa16981420",
@@ -199,8 +199,8 @@ public class TestDistribPackageStore extends SolrCloudTestCase {
     }
     @Override
     public NavigableObject call() throws Exception {
-      try (HttpSolrClient solrClient = (HttpSolrClient) jetty.newHttp1Client()) {
-        return (NavigableObject) Utils.executeGET(solrClient.getHttpClient(), this.url, JAVABINCONSUMER);
+      try (Http2SolrClient solrClient = (Http2SolrClient) jetty.newHttp2Client()) {
+        return (NavigableObject) Utils.executeGET(solrClient, this.url, JAVABINCONSUMER);
       }
     }
 
@@ -254,10 +254,12 @@ public class TestDistribPackageStore extends SolrCloudTestCase {
 
   public static void uploadKey(byte[] bytes, String path, MiniSolrCloudCluster cluster) throws Exception {
     JettySolrRunner jetty = cluster.getRandomJetty(random());
-    try(HttpSolrClient client = (HttpSolrClient) jetty.newHttp1Client()) {
-      PackageUtils.uploadKey(bytes, path, Paths.get(jetty.getCoreContainer().getSolrHome()), client);
-      Object resp = Utils.executeGET(client.getHttpClient(), jetty.getBaseURLV2().toString() + "/node/files" + path + "?sync=true", null);
-      log.info("sync resp: "+jetty.getBaseURLV2().toString() + "/node/files" + path + "?sync=true"+" ,is: "+resp);
+    try(Http2SolrClient client = (Http2SolrClient) jetty.newHttp2Client()) {
+      PackageUtils.uploadKey(bytes, path, Paths.get(jetty.getCoreContainer().getSolrHome()));
+
+      Http2SolrClient.SimpleResponse resp = Http2SolrClient.GET(jetty.getBaseURLV2().toString() + "/node/files" + path + "?sync=true", client);
+      
+      log.info("sync resp: "+jetty.getBaseURLV2().toString() + "/node/files" + path + "?sync=true"+" ,is: "+resp.asString);
     }
     waitForAllNodesHaveFile(cluster,path, Utils.makeMap(":files:" + path + ":name", (Predicate<Object>) Objects::nonNull),
         false);
diff --git a/solr/core/src/test/org/apache/solr/handler/admin/ZookeeperReadAPITest.java b/solr/core/src/test/org/apache/solr/handler/admin/ZookeeperReadAPITest.java
index d5ad026..34c0539 100644
--- a/solr/core/src/test/org/apache/solr/handler/admin/ZookeeperReadAPITest.java
+++ b/solr/core/src/test/org/apache/solr/handler/admin/ZookeeperReadAPITest.java
@@ -20,7 +20,7 @@ package org.apache.solr.handler.admin;
 import java.lang.invoke.MethodHandles;
 import java.util.Map;
 
-import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.cloud.SolrCloudTestCase;
 import org.apache.solr.common.util.Utils;
 import org.apache.zookeeper.CreateMode;
@@ -63,17 +63,17 @@ public class ZookeeperReadAPITest extends SolrCloudTestCase {
     String basezk = baseUrl.toString().replace("/solr", "/api") + "/cluster/zk/data";
     String basezkls = baseUrl.toString().replace("/solr", "/api") + "/cluster/zk/ls";
 
-    try (HttpSolrClient client = new HttpSolrClient.Builder(baseUrl.toString()).build()) {
-      Object o = Utils.executeGET(client.getHttpClient(),
+    try (Http2SolrClient client = new Http2SolrClient.Builder(baseUrl.toString()).build()) {
+      Object o = Utils.executeGET(client,
           basezk + "/security.json",
           Utils.JSONCONSUMER);
       assertNotNull(o);
-      o = Utils.executeGET(client.getHttpClient(),
+      o = Utils.executeGET(client,
           basezkls + "/configs",
           Utils.JSONCONSUMER);
       assertEquals("0", String.valueOf(getObjectByPath(o, true, split(":/configs:_default:dataLength", ':'))));
 
-      o = Utils.executeGET(client.getHttpClient(),
+      o = Utils.executeGET(client,
           basezk + "/configs",
           Utils.JSONCONSUMER);
       assertTrue(((Map)o).containsKey("/configs"));
@@ -84,7 +84,7 @@ public class ZookeeperReadAPITest extends SolrCloudTestCase {
         bytes[i] = (byte) random().nextInt(128);
       }
       cluster.getZkClient().create("/configs/_default/testdata", bytes, CreateMode.PERSISTENT, true);
-      Utils.executeGET(client.getHttpClient(),
+      Utils.executeGET(client,
           basezk + "/configs/_default/testdata",
           is -> {
             byte[] newBytes = new byte[bytes.length];
diff --git a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
index 6fe4740..ebf98d8 100644
--- a/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
+++ b/solr/core/src/test/org/apache/solr/pkg/TestPackages.java
@@ -32,7 +32,7 @@ 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.BaseHttpSolrClient;
-import org.apache.solr.client.solrj.impl.HttpSolrClient;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
 import org.apache.solr.client.solrj.request.CollectionAdminRequest;
 import org.apache.solr.client.solrj.request.GenericSolrRequest;
 import org.apache.solr.client.solrj.request.RequestWriter;
@@ -446,10 +446,10 @@ public class TestPackages extends SolrCloudTestCase {
   }
 
   private void executeReq(String uri, JettySolrRunner jetty, Utils.InputStreamConsumer parser, Map expected) throws Exception {
-    try(HttpSolrClient client = (HttpSolrClient) jetty.newHttp1Client()){
+    try(Http2SolrClient client = (Http2SolrClient) jetty.newHttp2Client()){
       TestDistribPackageStore.assertResponseValues(10,
           () -> {
-            Object o = Utils.executeGET(client.getHttpClient(),
+            Object o = Utils.executeGET(client,
                 jetty.getBaseUrl() + uri, parser);
             if(o instanceof NavigableObject) return (NavigableObject) o;
             if(o instanceof Map) return new MapWriterMap((Map) o);
@@ -591,8 +591,8 @@ public class TestPackages extends SolrCloudTestCase {
         TestDistribPackageStore.assertResponseValues(10, new Callable<NavigableObject>() {
           @Override
           public NavigableObject call() throws Exception {
-            try (HttpSolrClient solrClient = (HttpSolrClient) jetty.newHttp1Client()) {
-              return (NavigableObject) Utils.executeGET(solrClient.getHttpClient(), path, Utils.JAVABINCONSUMER);
+            try (Http2SolrClient solrClient = (Http2SolrClient) jetty.newHttp2Client()) {
+              return (NavigableObject) Utils.executeGET(solrClient, path, Utils.JAVABINCONSUMER);
             }
           }
         }, Utils.makeMap(
diff --git a/solr/server/resources/log4j2.xml b/solr/server/resources/log4j2.xml
index def3f9b..191b1cb 100644
--- a/solr/server/resources/log4j2.xml
+++ b/solr/server/resources/log4j2.xml
@@ -86,7 +86,7 @@
         <AsyncLogger name="org.apache.zookeeper.ClientCnxn" level="ERROR"/>
         <AsyncLogger name="org.apache.zookeeper.server.ZooKeeperCriticalThread" level="OFF"/>
 
-        <AsyncLogger name="org.apache.solr.update.processor.LogUpdateProcessorFactory" level="INFO"/>
+        <AsyncLogger name="org.apache.solr.update.processor.LogUpdateProcessorFactory" level="WARN"/>
         <AsyncLogger name="org.apache.solr.update.LoggingInfoStream" level="OFF"/>
         <AsyncLogger name="org.apache.solr.core.SolrCore.SlowRequest" level="INFO" additivity="false">
             <AppenderRef ref="SlowLogFile"/>
diff --git a/solr/solrj/src/java/org/apache/solr/cli/ClusterStateCommand.java b/solr/solrj/src/java/org/apache/solr/cli/ClusterStateCommand.java
index 63c9bdd..ef194ad 100644
--- a/solr/solrj/src/java/org/apache/solr/cli/ClusterStateCommand.java
+++ b/solr/solrj/src/java/org/apache/solr/cli/ClusterStateCommand.java
@@ -34,7 +34,7 @@ public class ClusterStateCommand extends CliCommand {
   private CommandLine cl;
 
   static {
-    //options.addOption("s", "state", false, "Outputs the Solr state in Zookeeper");
+    options.addOption("u", "unlimited", false, "Don't suppress node output by byte size");
 
   }
 
@@ -71,16 +71,22 @@ public class ClusterStateCommand extends CliCommand {
 
    if (args.length == 2) {
      try {
-
-       zkStateReader.getZkClient().printLayoutToStream(out, args[1]);
+       if (cl.hasOption("u")) {
+         zkStateReader.getZkClient().printLayoutToStream(out, args[1], Integer.MAX_VALUE);
+       } else {
+         zkStateReader.getZkClient().printLayoutToStream(out, args[1]);
+       }
 
      } catch (IllegalArgumentException ex) {
        throw new MalformedPathException(ex.getMessage());
      }
    } else {
      try {
-
-       zkStateReader.getZkClient().printLayoutToStream(out);
+       if (cl.hasOption("u")) {
+         zkStateReader.getZkClient().printLayoutToStream(out, Integer.MAX_VALUE);
+       } else {
+         zkStateReader.getZkClient().printLayoutToStream(out);
+       }
 
      } catch (IllegalArgumentException ex) {
        throw new MalformedPathException(ex.getMessage());
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DelegatingCloudManager.java b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DelegatingCloudManager.java
index 98dee96..4718477 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DelegatingCloudManager.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/DelegatingCloudManager.java
@@ -78,11 +78,6 @@ public class DelegatingCloudManager implements SolrCloudManager {
     }
 
     @Override
-    public byte[] httpRequest(String url, SolrRequest.METHOD method, Map<String, String> headers, String payload, int timeout, boolean followRedirects) throws IOException {
-        return delegate.httpRequest(url, method, headers, payload, timeout, followRedirects);
-    }
-
-    @Override
     public void close() throws IOException {
         delegate.close();
     }
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/SolrCloudManager.java b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/SolrCloudManager.java
index 4ce87d9..43f8b96 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/SolrCloudManager.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/SolrCloudManager.java
@@ -18,7 +18,6 @@
 package org.apache.solr.client.solrj.cloud;
 
 import java.io.IOException;
-import java.util.Map;
 
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrResponse;
@@ -49,6 +48,4 @@ public interface SolrCloudManager extends SolrCloseable {
   // Solr-like methods
 
   SolrResponse request(SolrRequest req) throws IOException;
-
-  byte[] httpRequest(String url, SolrRequest.METHOD method, Map<String, String> headers, String payload, int timeout, boolean followRedirects) throws IOException;
 }
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientCloudManager.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientCloudManager.java
index cfbef61..b2e4fc8 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientCloudManager.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientCloudManager.java
@@ -17,28 +17,11 @@
 
 package org.apache.solr.client.solrj.impl;
 
-
-import java.io.IOException;
-import java.lang.invoke.MethodHandles;
-import java.util.Map;
-
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.config.RequestConfig;
-import org.apache.http.client.methods.HttpDelete;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.client.methods.HttpPost;
-import org.apache.http.client.methods.HttpPut;
-import org.apache.http.client.methods.HttpRequestBase;
-import org.apache.http.client.protocol.HttpClientContext;
-import org.apache.http.entity.StringEntity;
-import org.apache.http.util.EntityUtils;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrResponse;
 import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.client.solrj.cloud.DistributedQueueFactory;
 import org.apache.solr.client.solrj.cloud.DistribStateManager;
+import org.apache.solr.client.solrj.cloud.DistributedQueueFactory;
 import org.apache.solr.client.solrj.cloud.NodeStateProvider;
 import org.apache.solr.client.solrj.cloud.SolrCloudManager;
 import org.apache.solr.common.cloud.SolrZkClient;
@@ -49,6 +32,9 @@ import org.apache.solr.common.util.TimeSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.lang.invoke.MethodHandles;
+
 /**
  * Class that implements {@link SolrCloudManager} using a SolrClient
  */
@@ -62,14 +48,14 @@ public class SolrClientCloudManager implements SolrCloudManager {
   private final SolrZkClient zkClient;
   private final ObjectCache objectCache;
   private final boolean closeObjectCache;
-  private final HttpClient httpClient;
+  private final Http2SolrClient httpClient;
   private volatile boolean isClosed;
 
   public SolrClientCloudManager(DistributedQueueFactory queueFactory, BaseCloudSolrClient solrClient) {
     this(queueFactory, solrClient, null, null);
   }
 
-  public SolrClientCloudManager(DistributedQueueFactory queueFactory, BaseCloudSolrClient solrClient, HttpClient httpClient) {
+  public SolrClientCloudManager(DistributedQueueFactory queueFactory, BaseCloudSolrClient solrClient, Http2SolrClient httpClient) {
     this(queueFactory, solrClient, null, httpClient);
   }
 
@@ -79,12 +65,12 @@ public class SolrClientCloudManager implements SolrCloudManager {
   }
 
   public SolrClientCloudManager(DistributedQueueFactory queueFactory, BaseCloudSolrClient solrClient,
-                                ObjectCache objectCache, HttpClient httpClient) {
+                                ObjectCache objectCache, Http2SolrClient httpClient) {
     this.queueFactory = queueFactory;
     this.solrClient = solrClient;
 
     if (httpClient == null && solrClient instanceof  CloudSolrClient) {
-      this.httpClient = ((CloudSolrClient) solrClient).getHttpClient();
+      this.httpClient = ((CloudHttp2SolrClient) solrClient).getHttpClient();
     } else if (httpClient == null) {
       throw new IllegalArgumentException("Must specify apache httpclient with non CloudSolrServer impls");
     } else {
@@ -154,60 +140,6 @@ public class SolrClientCloudManager implements SolrCloudManager {
   private static final byte[] EMPTY = new byte[0];
 
   @Override
-  public byte[] httpRequest(String url, SolrRequest.METHOD method, Map<String, String> headers, String payload, int timeout, boolean followRedirects) throws IOException {
-    HttpClient client = httpClient;
-    final HttpRequestBase req;
-    HttpEntity entity = null;
-    if (payload != null) {
-      entity = new StringEntity(payload, "UTF-8");
-    }
-    switch (method) {
-      case GET:
-        req = new HttpGet(url);
-        break;
-      case POST:
-        req = new HttpPost(url);
-        if (entity != null) {
-          ((HttpPost)req).setEntity(entity);
-        }
-        break;
-      case PUT:
-        req = new HttpPut(url);
-        if (entity != null) {
-          ((HttpPut)req).setEntity(entity);
-        }
-        break;
-      case DELETE:
-        req = new HttpDelete(url);
-        break;
-      default:
-        throw new IOException("Unsupported method " + method);
-    }
-    if (headers != null) {
-      headers.forEach((k, v) -> req.addHeader(k, v));
-    }
-    RequestConfig.Builder requestConfigBuilder = HttpClientUtil.createDefaultRequestConfigBuilder();
-    if (timeout > 0) {
-      requestConfigBuilder.setSocketTimeout(timeout);
-      requestConfigBuilder.setConnectTimeout(timeout);
-    }
-    requestConfigBuilder.setRedirectsEnabled(followRedirects);
-    req.setConfig(requestConfigBuilder.build());
-    HttpClientContext httpClientRequestContext = HttpClientUtil.createNewHttpClientRequestContext();
-    HttpResponse rsp = client.execute(req, httpClientRequestContext);
-    int statusCode = rsp.getStatusLine().getStatusCode();
-    if (statusCode != 200) {
-      throw new IOException("Error sending request to " + url + ", HTTP response: " + rsp.toString());
-    }
-    HttpEntity responseEntity = rsp.getEntity();
-    if (responseEntity != null && responseEntity.getContent() != null) {
-      return EntityUtils.toByteArray(responseEntity);
-    } else {
-      return EMPTY;
-    }
-  }
-
-  @Override
   public DistributedQueueFactory getDistributedQueueFactory() {
     return queueFactory;
   }
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
index 0b4d393..94713fd 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/SolrClientNodeStateProvider.java
@@ -31,7 +31,6 @@ import java.util.function.Consumer;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-import org.apache.http.client.HttpClient;
 import org.apache.solr.client.solrj.SolrRequest;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.cloud.NodeStateProvider;
@@ -66,6 +65,7 @@ import static java.util.Collections.emptyMap;
 public class SolrClientNodeStateProvider implements NodeStateProvider, MapWriter {
   public static final String METRICS_PREFIX = "metrics:";
   private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+  public static final String[] EMPTY_STRINGS = new String[0];
   //only for debugging
   public static SolrClientNodeStateProvider INST;
 
@@ -73,12 +73,12 @@ public class SolrClientNodeStateProvider implements NodeStateProvider, MapWriter
 
   private final BaseCloudSolrClient solrClient;
   protected final Map<String, Map<String, Map<String, List<ReplicaInfo>>>> nodeVsCollectionVsShardVsReplicaInfo = new HashMap<>();
-  private final HttpClient httpClient;
+  private final Http2SolrClient httpClient;
   private Map<String, Object> snitchSession = new HashMap<>();
   private Map<String, Map> nodeVsTags = new HashMap<>();
   private Map<String, String> withCollectionsMap = new HashMap<>();
 
-  public SolrClientNodeStateProvider(BaseCloudSolrClient solrClient, HttpClient httpClient) {
+  public SolrClientNodeStateProvider(BaseCloudSolrClient solrClient, Http2SolrClient httpClient) {
     this.solrClient = solrClient;
     this.httpClient = httpClient;
     try {
@@ -188,7 +188,7 @@ public class SolrClientNodeStateProvider implements NodeStateProvider, MapWriter
   static void fetchReplicaMetrics(String solrNode, ClientSnitchCtx ctx, Map<String, Object> metricsKeyVsTag) {
     if (!ctx.isNodeAlive(solrNode)) return;
     ModifiableSolrParams params = new ModifiableSolrParams();
-    params.add("key", metricsKeyVsTag.keySet().toArray(new String[0]));
+    params.add("key", metricsKeyVsTag.keySet().toArray(EMPTY_STRINGS));
     try {
       SimpleSolrResponse rsp = ctx.invokeWithRetry(solrNode, CommonParams.METRICS_PATH, params);
       metricsKeyVsTag.forEach((key, tag) -> {
@@ -317,7 +317,7 @@ public class SolrClientNodeStateProvider implements NodeStateProvider, MapWriter
     ZkClientClusterStateProvider zkClientClusterStateProvider;
     BaseCloudSolrClient solrClient;
 
-    HttpClient httpClient;
+    Http2SolrClient httpClient;
 
     public boolean isNodeAlive(String node) {
       if (zkClientClusterStateProvider != null) {
@@ -327,7 +327,7 @@ public class SolrClientNodeStateProvider implements NodeStateProvider, MapWriter
     }
     public ClientSnitchCtx(SnitchInfo perSnitch,
                            String node, Map<String, Object> session,
-                           BaseCloudSolrClient solrClient, HttpClient httpClient) {
+                           BaseCloudSolrClient solrClient, Http2SolrClient httpClient) {
       super(perSnitch, node, session);
       this.solrClient = solrClient;
       this.httpClient = httpClient;
@@ -381,7 +381,7 @@ public class SolrClientNodeStateProvider implements NodeStateProvider, MapWriter
 
       try {
         GenericSolrRequest request = new GenericSolrRequest(SolrRequest.METHOD.POST, path, params);
-        try (HttpSolrClient client = new HttpSolrClient.Builder().withHttpClient(httpClient).withBaseSolrUrl(url).withResponseParser(new BinaryResponseParser()).markInternalRequest().build()) {
+        try (Http2SolrClient client = new Http2SolrClient.Builder().withHttpClient(httpClient).withBaseUrl(url).markInternalRequest().build()) {
           NamedList<Object> rsp = client.request(request);
           request.response.nl = rsp;
           return request.response;
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java
index aea1ffa..ac98db6 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ConnectionManager.java
@@ -334,10 +334,8 @@ public class ConnectionManager implements Watcher, Closeable {
 
     client.zkCallbackExecutor.shutdown();
 
-    ExecutorUtil.awaitTermination(client.zkCallbackExecutor);
     SolrZooKeeper fkeeper = keeper;
     if (fkeeper != null) {
-      fkeeper.register(new NullWatcher());
       fkeeper.close();
     }
     client.zkConnManagerCallbackExecutor.shutdown();
@@ -396,6 +394,10 @@ public class ConnectionManager implements Watcher, Closeable {
 
   protected SolrZooKeeper createSolrZooKeeper(final String serverAddress, final int zkSessionTimeout,
                                               final Watcher watcher) throws IOException {
+    if (isClosed) {
+      throw new AlreadyClosedException();
+    }
+
     SolrZooKeeper result = new SolrZooKeeper(serverAddress, zkSessionTimeout, watcher);
 
     if (zkCredentialsToAddAutomatically != null) {
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/DocRouter.java b/solr/solrj/src/java/org/apache/solr/common/cloud/DocRouter.java
index 65688f4..6df188c 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/DocRouter.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/DocRouter.java
@@ -86,8 +86,8 @@ public abstract class DocRouter {
   // TODO: ranges may not be all contiguous in the future (either that or we will
   // need an extra class to model a collection of ranges)
   public static class Range implements JSONWriter.Writable, Comparable<Range> {
-    public int min;  // inclusive
-    public int max;  // inclusive
+    public final int min;  // inclusive
+    public final int max;  // inclusive
 
     public Range(int min, int max) {
       assert min <= max;
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java b/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java
index d644752..99e1282 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/SolrZkClient.java
@@ -921,9 +921,17 @@ public class SolrZkClient implements Closeable {
     }
   }
 
+  public void printLayout(String path, int indent, int maxBytesBeforeSuppress, StringBuilder output) {
+    try {
+      printLayout(path, "", indent, maxBytesBeforeSuppress, output);
+    } catch (Exception e) {
+      log.error("Exception printing layout", e);
+    }
+  }
+
   public void printLayout(String path, int indent, StringBuilder output) {
     try {
-      printLayout(path, "", indent, output);
+      printLayout(path, "", indent, MAX_BYTES_FOR_ZK_LAYOUT_DATA_SHOW, output);
     } catch (Exception e) {
       log.error("Exception printing layout", e);
     }
@@ -932,7 +940,7 @@ public class SolrZkClient implements Closeable {
   /**
    * Fills string with printout of current ZooKeeper layout.
    */
-  public void printLayout(String path, String node, int indent, StringBuilder output) {
+  public void printLayout(String path, String node, int indent, int maxBytesBeforeSuppress, StringBuilder output) {
     try {
       //log.info("path={} node={} indext={}", path, node, indent);
 
@@ -977,8 +985,14 @@ public class SolrZkClient implements Closeable {
 //          } else {
             dataString = new String(data, StandardCharsets.UTF_8);
         //  }
-          int lines = dataString.split("\\r\\n|\\r|\\n").length;
-          if ((stat != null && stat.getDataLength() < MAX_BYTES_FOR_ZK_LAYOUT_DATA_SHOW && lines < 4) || path.endsWith("state.json") || path
+          int lines;
+          if (maxBytesBeforeSuppress != MAX_BYTES_FOR_ZK_LAYOUT_DATA_SHOW) {
+            lines = 0;
+          } else {
+            lines = dataString.split("\\r\\n|\\r|\\n").length;
+          }
+
+          if ((stat != null && stat.getDataLength() < maxBytesBeforeSuppress && lines < 4) || path.endsWith("state.json") || path
               .endsWith("security.json") || (path.endsWith("solrconfig.xml") && Boolean.getBoolean("solr.tests.printsolrconfig")) || path.endsWith("_statupdates") || path.contains("/terms/")) {
             //        if (path.endsWith(".xml")) {
             //          // this is the cluster state in xml format - lets pretty print
@@ -1014,7 +1028,7 @@ public class SolrZkClient implements Closeable {
       if (children != null) {
         for (String child : children) {
           if (!child.equals("quota") && !child.equals("/zookeeper")) {
-            printLayout(path.equals("/") ? "/" + child : path + "/" + child, child, indent, output);
+            printLayout(path.equals("/") ? "/" + child : path + "/" + child, child, indent, maxBytesBeforeSuppress, output);
           }
         }
       }
@@ -1024,25 +1038,37 @@ public class SolrZkClient implements Closeable {
   }
 
   public void printLayout() {
-    StringBuilder sb = new StringBuilder(512);
+    StringBuilder sb = new StringBuilder(1024);
     printLayout("/",0, sb);
     log.warn("\n\n_____________________________________________________________________\n\n\nZOOKEEPER LAYOUT:\n\n" + sb.toString() + "\n\n_____________________________________________________________________\n\n");
   }
 
   public void printLayoutToStream(PrintStream out) {
-    StringBuilder sb = new StringBuilder(512);
+    StringBuilder sb = new StringBuilder(1024);
     printLayout("/", 0, sb);
     out.println(sb.toString());
   }
 
   public void printLayoutToStream(PrintStream out, String path) {
-    StringBuilder sb = new StringBuilder(512);
+    StringBuilder sb = new StringBuilder(1024);
     printLayout(path, 0, sb);
     out.println(sb.toString());
   }
 
+  public void printLayoutToStream(PrintStream out, int maxBytesBeforeSuppress) {
+    StringBuilder sb = new StringBuilder(1024);
+    printLayout("/", 0, maxBytesBeforeSuppress, sb);
+    out.println(sb.toString());
+  }
+
+  public void printLayoutToStream(PrintStream out, String path, int maxBytesBeforeSuppress) {
+    StringBuilder sb = new StringBuilder(1024);
+    printLayout(path, 0, maxBytesBeforeSuppress, sb);
+    out.println(sb.toString());
+  }
+
   public void printLayoutToFile(Path file) {
-    StringBuilder sb = new StringBuilder(512);
+    StringBuilder sb = new StringBuilder(1024);
     printLayout("/",0, sb);
     try {
       Files.writeString(file, sb.toString(), StandardOpenOption.CREATE);
diff --git a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCmdExecutor.java b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCmdExecutor.java
index 03b200c..74a0bbc 100644
--- a/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCmdExecutor.java
+++ b/solr/solrj/src/java/org/apache/solr/common/cloud/ZkCmdExecutor.java
@@ -20,6 +20,7 @@ import org.apache.solr.common.AlreadyClosedException;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.ConnectionManager.IsClosed;
 import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.ZooKeeper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -70,7 +71,7 @@ public class ZkCmdExecutor {
         if (exception == null) {
           exception = e;
         }
-        if (!zkCmdExecutor.solrZkClient.getSolrZooKeeper().getState().isAlive()) {
+        if (zkCmdExecutor.solrZkClient.getSolrZooKeeper().getState() == ZooKeeper.States.CLOSED) {
           throw e;
         }
         zkCmdExecutor.retryDelay(tryCnt);
diff --git a/solr/solrj/src/java/org/apache/solr/common/util/Utils.java b/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
index dfc43ef..0d107d3 100644
--- a/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
+++ b/solr/solrj/src/java/org/apache/solr/common/util/Utils.java
@@ -16,6 +16,36 @@
  */
 package org.apache.solr.common.util;
 
+import org.apache.solr.client.solrj.cloud.DistribStateManager;
+import org.apache.solr.client.solrj.cloud.VersionedData;
+import org.apache.solr.client.solrj.impl.BinaryRequestWriter;
+import org.apache.solr.client.solrj.impl.Http2SolrClient;
+import org.apache.solr.common.IteratorWriter;
+import org.apache.solr.common.LinkedHashMapWriter;
+import org.apache.solr.common.MapWriter;
+import org.apache.solr.common.MapWriterMap;
+import org.apache.solr.common.ParWork;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SpecProvider;
+import org.apache.solr.common.cloud.SolrZkClient;
+import org.apache.solr.common.cloud.ZkStateReader;
+import org.apache.solr.common.params.CommonParams;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.server.ByteBufferInputStream;
+import org.noggit.CharArr;
+import org.noggit.JSONParser;
+import org.noggit.JSONWriter;
+import org.noggit.ObjectBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static java.util.Collections.singletonList;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.concurrent.TimeUnit.NANOSECONDS;
+import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -47,47 +77,15 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.TreeSet;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.BiConsumer;
 import java.util.function.Function;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.util.EntityUtils;
-import org.apache.solr.client.solrj.cloud.DistribStateManager;
-import org.apache.solr.client.solrj.cloud.VersionedData;
-import org.apache.solr.client.solrj.impl.BinaryRequestWriter;
-import org.apache.solr.common.IteratorWriter;
-import org.apache.solr.common.LinkedHashMapWriter;
-import org.apache.solr.common.MapWriter;
-import org.apache.solr.common.MapWriterMap;
-import org.apache.solr.common.ParWork;
-import org.apache.solr.common.SolrException;
-import org.apache.solr.common.SpecProvider;
-import org.apache.solr.common.cloud.SolrZkClient;
-import org.apache.solr.common.cloud.ZkStateReader;
-import org.apache.solr.common.params.CommonParams;
-import org.apache.zookeeper.KeeperException;
-import org.apache.zookeeper.server.ByteBufferInputStream;
-import org.noggit.CharArr;
-import org.noggit.JSONParser;
-import org.noggit.JSONWriter;
-import org.noggit.ObjectBuilder;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.MDC;
-
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.Collections.singletonList;
-import static java.util.Collections.unmodifiableList;
-import static java.util.Collections.unmodifiableSet;
-import static java.util.concurrent.TimeUnit.NANOSECONDS;
-
 public class Utils {
   @SuppressWarnings({"rawtypes"})
   public static final Function NEW_HASHMAP_FUN = o -> new HashMap<>();
@@ -803,30 +801,33 @@ public class Utils {
       }
 
 
-      public static <T > T executeGET(HttpClient client, String url, InputStreamConsumer < T > consumer) throws SolrException {
+      public static <T > T executeGET(Http2SolrClient client, String url, InputStreamConsumer < T > consumer) throws SolrException {
         T result = null;
-        HttpGet httpGet = new HttpGet(url);
-        HttpResponse rsp = null;
+
+        Http2SolrClient.SimpleResponse resp = null;
         try {
-          rsp = client.execute(httpGet);
-        } catch (IOException e) {
-          log.error("Error in request to url : {}", url, e);
-          throw new SolrException(SolrException.ErrorCode.UNKNOWN, "error sending request");
+          resp = Http2SolrClient.GET(url, client);
+        } catch (InterruptedException e) {
+          ParWork.propagateInterrupt(e, true);
+          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
+        } catch (ExecutionException e) {
+          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
+        } catch (TimeoutException e) {
+          throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
         }
-        int statusCode = rsp.getStatusLine().getStatusCode();
+
+        int statusCode = resp.status;
         if (statusCode != 200) {
-          try {
-            log.error("Failed a request to: {}, status: {}, body: {}", url, rsp.getStatusLine(), EntityUtils.toString(rsp.getEntity(), StandardCharsets.UTF_8)); // logOk
-          } catch (IOException e) {
-            log.error("could not print error", e);
-          }
+
+          log.error("Failed a request to: {}, status: {}, body: {}", url, resp.status, resp.asString); // logOk
+
           throw new SolrException(SolrException.ErrorCode.getErrorCode(statusCode), "Unknown error");
         }
-        HttpEntity entity = rsp.getEntity();
+
         InputStream is = null;
 
         try {
-          is = entity.getContent();
+          is = new ByteArrayInputStream(resp.bytes);
           if (consumer != null) {
 
             result = consumer.accept(is);