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/07/04 01:23:29 UTC

[09/53] [abbrv] lucene-solr:feature/autoscaling: SOLR-10910: Clean up a few details left over from pluggable transient core and untangling CoreDescriptor/CoreContainer references

SOLR-10910: Clean up a few details left over from pluggable transient core and untangling CoreDescriptor/CoreContainer references


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

Branch: refs/heads/feature/autoscaling
Commit: 8f71bb40a55f6e7906e596938d0bf13900f77a94
Parents: 811621c
Author: Erick Erickson <er...@apache.org>
Authored: Wed Jun 28 21:02:14 2017 -0700
Committer: Erick Erickson <er...@apache.org>
Committed: Wed Jun 28 21:02:14 2017 -0700

----------------------------------------------------------------------
 solr/CHANGES.txt                                |  3 +
 .../org/apache/solr/core/CoreContainer.java     | 56 ++++++------
 .../src/java/org/apache/solr/core/SolrCore.java |  2 +-
 .../java/org/apache/solr/core/SolrCores.java    | 91 +++++++++++---------
 .../apache/solr/core/SolrResourceLoader.java    |  1 -
 .../solr/cloud/BasicDistributedZkTest.java      | 29 +++----
 .../solr/cloud/UnloadDistributedZkTest.java     | 12 ++-
 .../org/apache/solr/cloud/ZkControllerTest.java | 19 ++--
 .../org/apache/solr/core/TestCoreDiscovery.java |  3 +-
 .../org/apache/solr/core/TestLazyCores.java     | 44 ++++++----
 10 files changed, 138 insertions(+), 122 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/CHANGES.txt
----------------------------------------------------------------------
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 39fc14c..62204cd 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -495,6 +495,9 @@ when using one of Exact*StatsCache (Mikhail Khludnev)
 * SOLR-10963: Fix example json in MultipleAdditiveTreesModel javadocs.
   (Stefan Langenmaier via Christine Poerschke)
 
+* SOLR-10910: Clean up a few details left over from pluggable transient core and untangling
+  CoreDescriptor/CoreContainer references (Erick Erickson)
+
 Optimizations
 ----------------------
 * SOLR-10634: JSON Facet API: When a field/terms facet will retrieve all buckets (i.e. limit:-1)

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/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 90bbf5d..322952b 100644
--- a/solr/core/src/java/org/apache/solr/core/CoreContainer.java
+++ b/solr/core/src/java/org/apache/solr/core/CoreContainer.java
@@ -135,7 +135,7 @@ public class CoreContainer {
 
   protected CoreAdminHandler coreAdminHandler = null;
   protected CollectionsHandler collectionsHandler = null;
-  protected TransientSolrCoreCache transientSolrCoreCache = null;
+
   private InfoHandler infoHandler;
   protected ConfigSetsHandler configSetsHandler = null;
 
@@ -150,8 +150,6 @@ public class CoreContainer {
 
   private UpdateShardHandler updateShardHandler;
 
-  private TransientSolrCoreCacheFactory transientCoreCache;
-
   private ExecutorService coreContainerWorkExecutor = ExecutorUtil.newMDCAwareCachedThreadPool(
       new DefaultSolrThreadFactory("coreContainerWorkExecutor") );
 
@@ -507,7 +505,8 @@ public class CoreContainer {
     updateShardHandler = new UpdateShardHandler(cfg.getUpdateShardHandlerConfig());
     updateShardHandler.initializeMetrics(metricManager, SolrInfoBean.Group.node.toString(), "updateShardHandler");
 
-    transientCoreCache = TransientSolrCoreCacheFactory.newInstance(loader, this);
+    solrCores.load(loader);
+
 
     logging = LogWatcher.newRegisteredLogWatcher(cfg.getLogWatcherConfig(), loader);
 
@@ -596,7 +595,7 @@ public class CoreContainer {
 
       for (final CoreDescriptor cd : cds) {
         if (cd.isTransient() || !cd.isLoadOnStartup()) {
-          getTransientCacheHandler().addTransientDescriptor(cd.getName(), cd);
+          solrCores.getTransientCacheHandler().addTransientDescriptor(cd.getName(), cd);
         } else if (asyncSolrCoreLoad) {
           solrCores.markCoreAsLoading(cd);
         }
@@ -660,16 +659,6 @@ public class CoreContainer {
   }
 
 
-  public TransientSolrCoreCache getTransientCacheHandler() {
-
-    if (transientCoreCache == null) {
-      log.error("No transient handler has been defined. Check solr.xml to see if an attempt to provide a custom " +
-          "TransientSolrCoreCacheFactory was done incorrectly since the default should have been used otherwise.");
-      return null;
-    }
-    return transientCoreCache.getTransientSolrCoreCache();
-  }
-
   public void securityNodeChanged() {
     log.info("Security node changed, reloading security.json");
     reloadSecurityProperties();
@@ -843,13 +832,13 @@ public class CoreContainer {
       core.close();
       throw new IllegalStateException("This CoreContainer has been closed");
     }
+    solrCores.addCoreDescriptor(cd);
     SolrCore old = solrCores.putCore(cd, core);
       /*
       * set both the name of the descriptor and the name of the
       * core, since the descriptors name is used for persisting.
       */
 
-    solrCores.addCoreDescriptor(new CoreDescriptor(cd.getName(), cd));
     core.setName(cd.getName());
 
     coreInitFailures.remove(cd.getName());
@@ -893,7 +882,8 @@ public class CoreContainer {
     CoreDescriptor cd = new CoreDescriptor(coreName, instancePath, parameters, getContainerProperties(), isZooKeeperAware());
 
     // TODO: There's a race here, isn't there?
-    if (getLoadedCoreNames().contains(coreName)) {
+    // Since the core descriptor is removed when a core is unloaded, it should never be anywhere when a core is created.
+    if (getAllCoreNames().contains(coreName)) {
       log.warn("Creating a core with existing name is not allowed");
       // TODO: Shouldn't this be a BAD_REQUEST?
       throw new SolrException(ErrorCode.SERVER_ERROR, "Core with name '" + coreName + "' already exists.");
@@ -991,6 +981,7 @@ public class CoreContainer {
       return core;
     } catch (Exception e) {
       coreInitFailures.put(dcore.getName(), new CoreLoadFailure(dcore, e));
+      solrCores.removeCoreDescriptor(dcore);
       final SolrException solrException = new SolrException(ErrorCode.SERVER_ERROR, "Unable to create core [" + dcore.getName() + "]", e);
       if(core != null && !core.isClosed())
         IOUtils.closeQuietly(core);
@@ -998,6 +989,7 @@ public class CoreContainer {
     } catch (Throwable t) {
       SolrException e = new SolrException(ErrorCode.SERVER_ERROR, "JVM Error creating core [" + dcore.getName() + "]: " + t.getMessage(), t);
       coreInitFailures.put(dcore.getName(), new CoreLoadFailure(dcore, e));
+      solrCores.removeCoreDescriptor(dcore);
       if(core != null && !core.isClosed())
         IOUtils.closeQuietly(core);
       throw t;
@@ -1104,24 +1096,30 @@ public class CoreContainer {
   }
 
   /**
-   * @return a Collection of the names that loaded cores are mapped to
+   * Gets the cores that are currently loaded, i.e. cores that have
+   * 1: loadOnStartup=true and are either not-transient or, if transient, have been loaded and have not been aged out
+   * 2: loadOnStartup=false and have been loaded but are either non-transient or have not been aged out.
+   *
+   * Put another way, this will not return any names of cores that are lazily loaded but have not been called for yet
+   * or are transient and either not loaded or have been swapped out.
+   *
    */
   public Collection<String> getLoadedCoreNames() {
     return solrCores.getLoadedCoreNames();
   }
 
   /** This method is currently experimental.
-   * @return a Collection of the names that a specific core is mapped to.
+   *
+   * @return a Collection of the names that a specific core object is mapped to, there are more than one.
    */
-  public Collection<String> getCoreNames(SolrCore core) {
-    return solrCores.getCoreNames(core);
+  public Collection<String> getNamesForCore(SolrCore core) {
+    return solrCores.getNamesForCore(core);
   }
 
   /**
-   * get a list of all the cores that are currently loaded
-   * @return a list of al lthe available core names in either permanent or transient core lists.
+   * get a list of all the cores that are currently known, whether currently loaded or not
+   * @return a list of all the available core names in either permanent or transient cores
    *
-   * Note: this implies that the core is loaded
    */
   public Collection<String> getAllCoreNames() {
     return solrCores.getAllCoreNames();
@@ -1266,6 +1264,8 @@ public class CoreContainer {
    */
   public void unload(String name, boolean deleteIndexDir, boolean deleteDataDir, boolean deleteInstanceDir) {
 
+    CoreDescriptor cd = solrCores.getCoreDescriptor(name);
+    
     if (name != null) {
       // check for core-init errors first
       CoreLoadFailure loadFailure = coreInitFailures.remove(name);
@@ -1274,11 +1274,15 @@ public class CoreContainer {
         // which we may not be able to do because of the init error.  So we just go with what we
         // can glean from the CoreDescriptor - datadir and instancedir
         SolrCore.deleteUnloadedCore(loadFailure.cd, deleteDataDir, deleteInstanceDir);
+        // If last time around we didn't successfully load, make sure that all traces of the coreDescriptor are gone.
+        if (cd != null) {
+          solrCores.removeCoreDescriptor(cd);
+          coresLocator.delete(this, cd);
+        }
         return;
       }
     }
-
-    CoreDescriptor cd = solrCores.getCoreDescriptor(name);
+      
     if (cd == null) {
       throw new SolrException(ErrorCode.BAD_REQUEST, "Cannot unload non-existent core [" + name + "]");
     }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/java/org/apache/solr/core/SolrCore.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCore.java b/solr/core/src/java/org/apache/solr/core/SolrCore.java
index 76e2cad..5319881 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCore.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCore.java
@@ -1137,7 +1137,7 @@ public final class SolrCore implements SolrInfoBean, SolrMetricProducer, Closeab
     manager.registerGauge(this, registry, () -> getIndexSize(), true, "sizeInBytes", Category.INDEX.toString());
     manager.registerGauge(this, registry, () -> NumberUtils.readableSize(getIndexSize()), true, "size", Category.INDEX.toString());
     if (coreContainer != null) {
-      manager.registerGauge(this, registry, () -> coreContainer.getCoreNames(this), true, "aliases", Category.CORE.toString());
+      manager.registerGauge(this, registry, () -> coreContainer.getNamesForCore(this), true, "aliases", Category.CORE.toString());
       final CloudDescriptor cd = getCoreDescriptor().getCloudDescriptor();
       if (cd != null) {
         manager.registerGauge(this, registry, () -> {

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/java/org/apache/solr/core/SolrCores.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrCores.java b/solr/core/src/java/org/apache/solr/core/SolrCores.java
index 87ffac3..7f4b9a0 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrCores.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrCores.java
@@ -64,6 +64,10 @@ class SolrCores implements Observer {
   // to essentially queue them up to be handled via pendingCoreOps.
   private static final List<SolrCore> pendingCloses = new ArrayList<>();
 
+  private TransientSolrCoreCacheFactory transientCoreCache;
+
+  private TransientSolrCoreCache transientSolrCoreCache = null;
+  
   SolrCores(CoreContainer container) {
     this.container = container;
   }
@@ -71,8 +75,10 @@ class SolrCores implements Observer {
   protected void addCoreDescriptor(CoreDescriptor p) {
     synchronized (modifyLock) {
       if (p.isTransient()) {
-        if (container.getTransientCacheHandler() != null) {
-          container.getTransientCacheHandler().addTransientDescriptor(p.getName(), p);
+        if (getTransientCacheHandler() != null) {
+          getTransientCacheHandler().addTransientDescriptor(p.getName(), p);
+        } else {
+          log.warn("We encountered a core marked as transient, but there is no transient handler defined. This core will be inaccessible");
         }
       } else {
         residentDesciptors.put(p.getName(), p);
@@ -83,8 +89,8 @@ class SolrCores implements Observer {
   protected void removeCoreDescriptor(CoreDescriptor p) {
     synchronized (modifyLock) {
       if (p.isTransient()) {
-        if (container.getTransientCacheHandler() != null) {
-          container.getTransientCacheHandler().removeTransientDescriptor(p.getName());
+        if (getTransientCacheHandler() != null) {
+          getTransientCacheHandler().removeTransientDescriptor(p.getName());
         }
       } else {
         residentDesciptors.remove(p.getName());
@@ -92,6 +98,9 @@ class SolrCores implements Observer {
     }
   }
 
+  public void load(SolrResourceLoader loader) {
+    transientCoreCache = TransientSolrCoreCacheFactory.newInstance(loader, container);
+  }
   // We are shutting down. You can't hold the lock on the various lists of cores while they shut down, so we need to
   // make a temporary copy of the names and shut them down outside the lock.
   protected void close() {
@@ -99,7 +108,7 @@ class SolrCores implements Observer {
     Collection<SolrCore> coreList = new ArrayList<>();
 
     
-    TransientSolrCoreCache transientSolrCoreCache = container.getTransientCacheHandler();
+    TransientSolrCoreCache transientSolrCoreCache = getTransientCacheHandler();
     // Release observer
     if (transientSolrCoreCache != null) {
       transientSolrCoreCache.close();
@@ -147,25 +156,14 @@ class SolrCores implements Observer {
 
     } while (coreList.size() > 0);
   }
-
-  //WARNING! This should be the _only_ place you put anything into the list of transient cores!
-  protected SolrCore putTransientCore(NodeConfig cfg, String name, SolrCore core, SolrResourceLoader loader) {
-    SolrCore retCore = null;
-    log.info("Opening transient core {}", name);
-    synchronized (modifyLock) {
-      if (container.getTransientCacheHandler() != null) {
-        retCore = container.getTransientCacheHandler().addCore(name, core);
-      }
-    }
-    return retCore;
-  }
-
+  
   // Returns the old core if there was a core of the same name.
+  //WARNING! This should be the _only_ place you put anything into the list of transient cores!
   protected SolrCore putCore(CoreDescriptor cd, SolrCore core) {
     synchronized (modifyLock) {
       if (cd.isTransient()) {
-        if (container.getTransientCacheHandler() != null) {
-          return container.getTransientCacheHandler().addCore(cd.getName(), core);
+        if (getTransientCacheHandler() != null) {
+          return getTransientCacheHandler().addCore(cd.getName(), core);
         }
       } else {
         return cores.put(cd.getName(), core);
@@ -196,8 +194,8 @@ class SolrCores implements Observer {
 
   /**
    * Gets the cores that are currently loaded, i.e. cores that have
-   * 1> loadOnStartup=true and are either not-transient or, if transient, have been loaded and have not been swapped out
-   * 2> loadOnStartup=false and have been loaded but either non-transient or have not been swapped out.
+   * 1> loadOnStartup=true and are either not-transient or, if transient, have been loaded and have not been aged out
+   * 2> loadOnStartup=false and have been loaded but either non-transient or have not been aged out.
    * 
    * Put another way, this will not return any names of cores that are lazily loaded but have not been called for yet
    * or are transient and either not loaded or have been swapped out.
@@ -209,20 +207,19 @@ class SolrCores implements Observer {
 
     synchronized (modifyLock) {
       set.addAll(cores.keySet());
-      if (container.getTransientCacheHandler() != null) {
-        set.addAll(container.getTransientCacheHandler().getLoadedCoreNames());
+      if (getTransientCacheHandler() != null) {
+        set.addAll(getTransientCacheHandler().getLoadedCoreNames());
       }
     }
     return set;
   }
 
   /** This method is currently experimental.
-   * @return a Collection of the names that a specific core is mapped to.
-   * 
-   * Note: this implies that the core is loaded
+   *
+   * @return a Collection of the names that a specific core object is mapped to, there are more than one.
    */
   @Experimental
-  List<String> getCoreNames(SolrCore core) {
+  List<String> getNamesForCore(SolrCore core) {
     List<String> lst = new ArrayList<>();
 
     synchronized (modifyLock) {
@@ -231,8 +228,8 @@ class SolrCores implements Observer {
           lst.add(entry.getKey());
         }
       }
-      if (container.getTransientCacheHandler() != null) {
-        lst.addAll(container.getTransientCacheHandler().getNamesForCore(core));
+      if (getTransientCacheHandler() != null) {
+        lst.addAll(getTransientCacheHandler().getNamesForCore(core));
       }
     }
     return lst;
@@ -241,14 +238,14 @@ class SolrCores implements Observer {
   /**
    * Gets a list of all cores, loaded and unloaded 
    *
-   * @return all cores names, whether loaded or unloaded, transient or permenent.
+   * @return all cores names, whether loaded or unloaded, transient or permanent.
    */
   public Collection<String> getAllCoreNames() {
     Set<String> set = new TreeSet<>();
     synchronized (modifyLock) {
       set.addAll(cores.keySet());
-      if (container.getTransientCacheHandler() != null) {
-        set.addAll(container.getTransientCacheHandler().getAllCoreNames());
+      if (getTransientCacheHandler() != null) {
+        set.addAll(getTransientCacheHandler().getAllCoreNames());
       }
       set.addAll(residentDesciptors.keySet());
     }
@@ -302,7 +299,7 @@ class SolrCores implements Observer {
       SolrCore ret = cores.remove(name);
       // It could have been a newly-created core. It could have been a transient core. The newly-created cores
       // in particular should be checked. It could have been a dynamic core.
-      TransientSolrCoreCache transientHandler = container.getTransientCacheHandler();
+      TransientSolrCoreCache transientHandler = getTransientCacheHandler();
       if (ret == null && transientHandler != null) {
         ret = transientHandler.removeCore(name);
       }
@@ -315,8 +312,8 @@ class SolrCores implements Observer {
     synchronized (modifyLock) {
       SolrCore core = cores.get(name);
 
-      if (core == null && container.getTransientCacheHandler() != null) {
-        core = container.getTransientCacheHandler().getCore(name);
+      if (core == null && getTransientCacheHandler() != null) {
+        core = getTransientCacheHandler().getCore(name);
       }
 
       if (core != null && incRefCount) {
@@ -336,7 +333,7 @@ class SolrCores implements Observer {
       if (cores.containsKey(name)) {
         return true;
       }
-      if (container.getTransientCacheHandler() != null && container.getTransientCacheHandler().containsCore(name)) {
+      if (getTransientCacheHandler() != null && getTransientCacheHandler().containsCore(name)) {
         // Check pending
         for (SolrCore core : pendingCloses) {
           if (core.getName().equals(name)) {
@@ -355,7 +352,7 @@ class SolrCores implements Observer {
       if (cores.containsKey(name)) {
         return true;
       }
-      if (container.getTransientCacheHandler() != null && container.getTransientCacheHandler().containsCore(name)) {
+      if (getTransientCacheHandler() != null && getTransientCacheHandler().containsCore(name)) {
         return true;
       }
     }
@@ -367,8 +364,8 @@ class SolrCores implements Observer {
     synchronized (modifyLock) {
       CoreDescriptor desc = residentDesciptors.get(cname);
       if (desc == null) {
-        if (container.getTransientCacheHandler() == null) return null;
-        desc = container.getTransientCacheHandler().getTransientDescriptor(cname);
+        if (getTransientCacheHandler() == null) return null;
+        desc = getTransientCacheHandler().getTransientDescriptor(cname);
         if (desc == null) {
           return null;
         }
@@ -456,7 +453,7 @@ class SolrCores implements Observer {
     synchronized (modifyLock) {
       if (residentDesciptors.containsKey(coreName))
         return residentDesciptors.get(coreName);
-      return container.getTransientCacheHandler().getTransientDescriptor(coreName);
+      return getTransientCacheHandler().getTransientDescriptor(coreName);
     }
   }
 
@@ -545,4 +542,16 @@ class SolrCores implements Observer {
       modifyLock.notifyAll(); // Wakes up closer thread too
     }
   }
+
+  public TransientSolrCoreCache getTransientCacheHandler() {
+
+    if (transientCoreCache == null) {
+      log.error("No transient handler has been defined. Check solr.xml to see if an attempt to provide a custom " +
+          "TransientSolrCoreCacheFactory was done incorrectly since the default should have been used otherwise.");
+      return null;
+    }
+    return transientCoreCache.getTransientSolrCoreCache();
+  }
+
+
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
index ef79875..22753dd 100644
--- a/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
+++ b/solr/core/src/java/org/apache/solr/core/SolrResourceLoader.java
@@ -105,7 +105,6 @@ public class SolrResourceLoader implements ResourceLoader,Closeable
   private final List<ResourceLoaderAware> waitingForResources = Collections.synchronizedList(new ArrayList<ResourceLoaderAware>());
   private static final Charset UTF_8 = StandardCharsets.UTF_8;
 
-  //TODO: Solr5. Remove this completely when you obsolete putting <core> tags in solr.xml (See Solr-4196)
   private final Properties coreProperties;
 
   private volatile boolean live;

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
index fcc51ac..518142a 100644
--- a/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/BasicDistributedZkTest.java
@@ -535,9 +535,8 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
   }
 
   private void testStopAndStartCoresInOneInstance() throws Exception {
-    SolrClient client = clients.get(0);
-    String url3 = getBaseUrl(client);
-    try (final HttpSolrClient httpSolrClient = getHttpSolrClient(url3)) {
+    JettySolrRunner jetty = jettys.get(0);
+    try (final HttpSolrClient httpSolrClient = (HttpSolrClient) jetty.newClient()) {
       httpSolrClient.setConnectionTimeout(15000);
       httpSolrClient.setSoTimeout(60000);
       ThreadPoolExecutor executor = null;
@@ -548,7 +547,7 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
         int cnt = 3;
 
         // create the cores
-        createCores(httpSolrClient, executor, "multiunload2", 1, cnt);
+        createCollectionInOneInstance(httpSolrClient, jetty.getNodeName(), executor, "multiunload2", 1, cnt);
       } finally {
         if (executor != null) {
           ExecutorUtil.shutdownAndAwaitTermination(executor);
@@ -573,8 +572,13 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
 
   }
 
-  protected void createCores(final HttpSolrClient client,
-      ThreadPoolExecutor executor, final String collection, final int numShards, int cnt) {
+  /**
+   * Create a collection in single node
+   */
+  protected void createCollectionInOneInstance(final SolrClient client, String nodeName,
+                                               ThreadPoolExecutor executor, final String collection,
+                                               final int numShards, int numReplicas) {
+    assertNotNull(nodeName);
     try {
       assertEquals(0, CollectionAdminRequest.createCollection(collection, "conf1", numShards, 1)
           .setCreateNodeSet("")
@@ -582,22 +586,13 @@ public class BasicDistributedZkTest extends AbstractFullDistribZkTestBase {
     } catch (SolrServerException | IOException e) {
       throw new RuntimeException(e);
     }
-    String nodeName = null;
-    for (JettySolrRunner jetty : jettys) {
-      if (client.getBaseURL().contains(":"+jetty.getLocalPort())) {
-        nodeName = jetty.getNodeName();
-        break;
-      }
-    }
-    assertNotNull(nodeName);
-    for (int i = 0; i < cnt; i++) {
+    for (int i = 0; i < numReplicas; i++) {
       final int freezeI = i;
-      final String freezeNodename = nodeName;
       executor.execute(() -> {
         try {
           assertTrue(CollectionAdminRequest.addReplicaToShard(collection, "shard"+((freezeI%numShards)+1))
               .setCoreName(collection + freezeI)
-              .setNode(freezeNodename).process(client).isSuccess());
+              .setNode(nodeName).process(client).isSuccess());
         } catch (SolrServerException | IOException e) {
           throw new RuntimeException(e);
         }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java b/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
index 19dd998..daa73cf 100644
--- a/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/UnloadDistributedZkTest.java
@@ -18,7 +18,6 @@ package org.apache.solr.cloud;
 
 import org.apache.lucene.util.LuceneTestCase.Slow;
 import org.apache.solr.SolrTestCaseJ4.SuppressSSL;
-import org.apache.solr.client.solrj.SolrClient;
 import org.apache.solr.client.solrj.SolrQuery;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
@@ -348,18 +347,17 @@ public class UnloadDistributedZkTest extends BasicDistributedZkTest {
   }
   
   private void testUnloadLotsOfCores() throws Exception {
-    SolrClient client = clients.get(2);
-    String url3 = getBaseUrl(client);
-    try (final HttpSolrClient adminClient = getHttpSolrClient(url3)) {
+    JettySolrRunner jetty = jettys.get(0);
+    try (final HttpSolrClient adminClient = (HttpSolrClient) jetty.newClient()) {
       adminClient.setConnectionTimeout(15000);
       adminClient.setSoTimeout(60000);
-      int cnt = atLeast(3);
+      int numReplicas = atLeast(3);
       ThreadPoolExecutor executor = new ExecutorUtil.MDCAwareThreadPoolExecutor(0, Integer.MAX_VALUE,
           5, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
           new DefaultSolrThreadFactory("testExecutor"));
       try {
         // create the cores
-        createCores(adminClient, executor, "multiunload", 2, cnt);
+        createCollectionInOneInstance(adminClient, jetty.getNodeName(), executor, "multiunload", 2, numReplicas);
       } finally {
         ExecutorUtil.shutdownAndAwaitTermination(executor);
       }
@@ -368,7 +366,7 @@ public class UnloadDistributedZkTest extends BasicDistributedZkTest {
           TimeUnit.SECONDS, new SynchronousQueue<Runnable>(),
           new DefaultSolrThreadFactory("testExecutor"));
       try {
-        for (int j = 0; j < cnt; j++) {
+        for (int j = 0; j < numReplicas; j++) {
           final int freezeJ = j;
           executor.execute(() -> {
             Unload unloadCmd = new Unload(true);

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java b/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java
index d05cec9..d17d779 100644
--- a/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java
+++ b/solr/core/src/test/org/apache/solr/cloud/ZkControllerTest.java
@@ -30,7 +30,6 @@ import org.apache.solr.core.CloudConfig;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.SolrXmlConfig;
-import org.apache.solr.core.TransientSolrCoreCache;
 import org.apache.solr.handler.admin.CoreAdminHandler;
 import org.apache.solr.handler.component.HttpShardHandlerFactory;
 import org.apache.solr.update.UpdateShardHandler;
@@ -328,30 +327,26 @@ public class ZkControllerTest extends SolrTestCaseJ4 {
 
   private static class MockCoreContainer extends CoreContainer {
     UpdateShardHandler updateShardHandler = new UpdateShardHandler(UpdateShardHandlerConfig.DEFAULT);
+
     public MockCoreContainer() {
       super(SolrXmlConfig.fromString(null, "<solr/>"));
       this.shardHandlerFactory = new HttpShardHandlerFactory();
       this.coreAdminHandler = new CoreAdminHandler();
     }
-    
+
     @Override
-    public void load() {}
-    
+    public void load() {
+    }
+
     @Override
     public UpdateShardHandler getUpdateShardHandler() {
       return updateShardHandler;
     }
-    
+
     @Override
     public void shutdown() {
       updateShardHandler.close();
       super.shutdown();
     }
-    
-    @Override
-    public TransientSolrCoreCache getTransientCacheHandler() {
-      return transientSolrCoreCache;
-    }
-
-  }
+  }    
 }

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java b/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
index 95c8cb9..bf0568f 100644
--- a/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
+++ b/solr/core/src/test/org/apache/solr/core/TestCoreDiscovery.java
@@ -22,6 +22,7 @@ import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.Properties;
 
 import com.google.common.collect.ImmutableMap;
@@ -152,7 +153,7 @@ public class TestCoreDiscovery extends SolrTestCaseJ4 {
     try {
 
       TestLazyCores.checkInCores(cc, "core1");
-      TestLazyCores.checkNotInCores(cc, "lazy1", "core2");
+      TestLazyCores.checkNotInCores(cc, Arrays.asList("lazy1", "core2"));
 
       // force loading of core2 and lazy1 by getting them from the CoreContainer
       try (SolrCore core1 = cc.getCore("core1");

http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/8f71bb40/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/core/TestLazyCores.java b/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
index 7c41470..4c50480 100644
--- a/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
+++ b/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
@@ -22,6 +22,7 @@ import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -100,8 +101,8 @@ public class TestLazyCores extends SolrTestCaseJ4 {
 
       // NOTE: This checks the initial state for loading, no need to do this elsewhere.
       checkInCores(cc, "collection1", "collection2", "collection5");
-      checkNotInCores(cc, "collection3", "collection4", "collection6", "collection7",
-          "collection8", "collection9");
+      checkNotInCores(cc, Arrays.asList("collection3", "collection4", "collection6", "collection7",
+          "collection8", "collection9"));
 
       SolrCore core1 = cc.getCore("collection1");
       assertFalse("core1 should not be transient", core1.getCoreDescriptor().isTransient());
@@ -176,7 +177,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
     CoreContainer cc = init();
     try {
       // Make sure Lazy4 isn't loaded. Should be loaded on the get
-      checkNotInCores(cc, "collection4");
+      checkNotInCores(cc, Arrays.asList("collection4"));
       SolrCore core4 = cc.getCore("collection4");
 
       checkSearch(core4);
@@ -205,7 +206,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
       // First check that all the cores that should be loaded at startup actually are.
 
       checkInCores(cc, "collection1", "collection2", "collection5");
-      checkNotInCores(cc, "collection3", "collection4", "collection6", "collection7", "collection8", "collection9");
+      checkNotInCores(cc, Arrays.asList("collection3", "collection4", "collection6", "collection7", "collection8", "collection9"));
 
       // By putting these in non-alpha order, we're also checking that we're  not just seeing an artifact.
       SolrCore core1 = cc.getCore("collection1");
@@ -215,28 +216,28 @@ public class TestLazyCores extends SolrTestCaseJ4 {
       SolrCore core5 = cc.getCore("collection5");
 
       checkInCores(cc, "collection1", "collection2", "collection3", "collection4", "collection5");
-      checkNotInCores(cc, "collection6", "collection7", "collection8", "collection9");
+      checkNotInCores(cc, Arrays.asList("collection6", "collection7", "collection8", "collection9"));
 
       // map should be full up, add one more and verify
       SolrCore core6 = cc.getCore("collection6");
       checkInCores(cc, "collection1", "collection2", "collection3", "collection4", "collection5",
           "collection6");
-      checkNotInCores(cc, "collection7", "collection8", "collection9");
+      checkNotInCores(cc, Arrays.asList("collection7", "collection8", "collection9"));
 
       SolrCore core7 = cc.getCore("collection7");
       checkInCores(cc, "collection1", "collection2", "collection3", "collection4", "collection5",
           "collection6", "collection7");
-      checkNotInCores(cc, "collection8", "collection9");
+      checkNotInCores(cc, Arrays.asList("collection8", "collection9"));
 
       SolrCore core8 = cc.getCore("collection8");
       checkInCores(cc, "collection1", "collection2", "collection4", "collection5", "collection6",
           "collection7", "collection8");
-      checkNotInCores(cc, "collection3", "collection9");
+      checkNotInCores(cc, Arrays.asList("collection3", "collection9"));
 
       SolrCore core9 = cc.getCore("collection9");
       checkInCores(cc, "collection1", "collection4", "collection5", "collection6", "collection7",
           "collection8", "collection9");
-      checkNotInCores(cc, "collection2", "collection3");
+      checkNotInCores(cc, Arrays.asList("collection2", "collection3"));
 
 
       // Note decrementing the count when the core is removed from the lazyCores list is appropriate, since the
@@ -396,8 +397,8 @@ public class TestLazyCores extends SolrTestCaseJ4 {
       final SolrCore c4 = cc.getCore("core4");
       final SolrCore c5 = cc.getCore("core5");
 
-      checkNotInCores(cc, "core1", "collection2", "collection3", "collection4", "collection6"
-          , "collection7", "collection8", "collection9");
+      checkNotInCores(cc, Arrays.asList("core1", "collection2", "collection3", "collection4", "collection6"
+          , "collection7", "collection8", "collection9"));
 
       checkInCores(cc, "collection1", "collection5", "core2", "core3", "core4", "core5");
 
@@ -467,7 +468,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
       checkInCores(cc, "core1", "core2");
 
       // Did the bad cores fail to load?
-      checkNotInCores(cc, "badSchema1", "badSchema2", "badConfig1", "badConfig2");
+      checkNotInCores(cc, Collections.emptyList(), Arrays.asList("badSchema1", "badSchema2", "badConfig1", "badConfig2"));
 
       //  Can we still search the "good" cores even though there were core init failures?
       SolrCore core1 = cc.getCore("core1");
@@ -644,7 +645,10 @@ public class TestLazyCores extends SolrTestCaseJ4 {
     }
   }
 
-  public static void checkNotInCores(CoreContainer cc, String... nameCheck) {
+  public static void checkNotInCores(CoreContainer cc, List<String> nameCheck) {
+    checkNotInCores(cc, nameCheck, Collections.emptyList());
+  }
+  public static void checkNotInCores(CoreContainer cc, List<String> nameCheck, List<String> namesBad) {
     Collection<String> loadedNames = cc.getLoadedCoreNames();
     for (String name : nameCheck) {
       assertFalse("core " + name + " was found in the list of cores", loadedNames.contains(name));
@@ -657,7 +661,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
     // the names in nameCheck should be loaded and thus should not be in names.
     
     Collection<String> allNames = cc.getAllCoreNames();
-    // Every core, loaded or not should be in the accumulated coredescriptors:
+    // Every core that has not failed to load should be in coreDescriptors.
     List<CoreDescriptor> descriptors = cc.getCoreDescriptors();
 
     assertEquals("There should be as many coreDescriptors as coreNames", allNames.size(), descriptors.size());
@@ -671,10 +675,18 @@ public class TestLazyCores extends SolrTestCaseJ4 {
           allNames.contains(name));
     }
 
+    // failed cores should have had their descriptors removed.
     for (String name : nameCheck) {
       assertTrue("Not-currently-loaded core " + name + " should have been found in the list of all possible core names",
           allNames.contains(name));
     }
+
+    // Failed cores should not be in coreDescriptors.
+    for (String name : namesBad) {
+      assertFalse("Failed core " + name + " should have been found in the list of all possible core names",
+          allNames.contains(name));
+    }
+
   }
 
   public static void checkInCores(CoreContainer cc, String... nameCheck) {
@@ -795,7 +807,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
       }
       
       // Just proving that some cores have been aged out.
-      checkNotInCores(cc, "collection2", "collection3");
+      checkNotInCores(cc, Arrays.asList("collection2", "collection3"));
 
       // Close our get of all cores above.
       for (SolrCore core : openCores) core.close();
@@ -807,7 +819,7 @@ public class TestLazyCores extends SolrTestCaseJ4 {
       for (String coreName : coreList) {
         // The point of this test is to insure that when cores are aged out and re-opened
         // that the docs are there, so insure that the core we're testing is gone, gone, gone. 
-        checkNotInCores(cc, coreName);
+        checkNotInCores(cc, Arrays.asList(coreName));
         
         // Load the core up again.
         SolrCore core = cc.getCore(coreName);