You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ro...@apache.org on 2014/07/16 17:29:29 UTC

svn commit: r1611051 - in /lucene/dev/branches/branch_4x: ./ solr/ solr/core/ solr/core/src/java/org/apache/solr/core/ solr/core/src/java/org/apache/solr/handler/admin/ solr/core/src/test/org/apache/solr/core/ solr/core/src/test/org/apache/solr/update/...

Author: romseygeek
Date: Wed Jul 16 15:29:28 2014
New Revision: 1611051

URL: http://svn.apache.org/r1611051
Log:
SOLR-6232: Allow unloading of cores that have failed to init

Modified:
    lucene/dev/branches/branch_4x/   (props changed)
    lucene/dev/branches/branch_4x/solr/   (props changed)
    lucene/dev/branches/branch_4x/solr/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_4x/solr/core/   (props changed)
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/CoreContainer.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/SolrCore.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/CoreContainerCoreInitFailuresTest.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreCheckLockOnStartupTest.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistence.java
    lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/SolrIndexSplitterTest.java
    lucene/dev/branches/branch_4x/solr/test-framework/   (props changed)
    lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
    lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/core/AbstractBadConfigTestBase.java

Modified: lucene/dev/branches/branch_4x/solr/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/CHANGES.txt?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/CHANGES.txt (original)
+++ lucene/dev/branches/branch_4x/solr/CHANGES.txt Wed Jul 16 15:29:28 2014
@@ -44,11 +44,15 @@ Upgrading from Solr 4.9
   additional call to CoreContainer.register() to make it available to clients
   (see SOLR-6170).
 
+* CoreContainer.remove() has been removed.  You should now use CoreContainer.unload() to
+  delete a SolrCore (see SOLR-6232).
+
 Detailed Change List
 ----------------------
 
 New Features
 ----------------------
+
 * SOLR-6196: The overseerstatus collection API instruments amILeader and ZK state update calls.
   (shalin)
 
@@ -63,6 +67,8 @@ New Features
   It includes extra score relevancy modes in addition to distance: score=overlapRatio|area|area2D.
   (David Smiley, Ryan McKinley)
 
+* SOLR-6232: You can now unload/delete cores that have failed to initialize (Alan Woodward)
+
 Bug Fixes
 ----------------------
 
@@ -156,7 +162,10 @@ Other Changes
   of a java error about a missing class. (shalin, Shawn Heisey)
   
 * SOLR-6179: Better strategy for handling empty managed data to avoid spurious
-  warning messages in the logs. (Timothy Potter) 
+  warning messages in the logs. (Timothy Potter)
+
+* SOLR-6232: CoreContainer.remove() replaced with CoreContainer.unload().  A call to
+  unload will also close the core.
 
 ==================  4.9.0 ==================
 

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/CoreContainer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/CoreContainer.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/CoreContainer.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/CoreContainer.java Wed Jul 16 15:29:28 2014
@@ -17,6 +17,7 @@
 
 package org.apache.solr.core;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Maps;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.SolrException;
@@ -30,19 +31,19 @@ import org.apache.solr.logging.LogWatche
 import org.apache.solr.update.UpdateShardHandler;
 import org.apache.solr.util.DefaultSolrThreadFactory;
 import org.apache.solr.util.FileUtils;
+import org.apache.zookeeper.KeeperException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
 import java.util.concurrent.Callable;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
@@ -59,8 +60,18 @@ public class CoreContainer {
 
   private final SolrCores solrCores = new SolrCores(this);
 
-  protected final Map<String,Exception> coreInitFailures =
-    Collections.synchronizedMap(new LinkedHashMap<String,Exception>());
+  public static class CoreLoadFailure {
+
+    public final CoreDescriptor cd;
+    public final Exception exception;
+
+    public CoreLoadFailure(CoreDescriptor cd, Exception loadFailure) {
+      this.cd = cd;
+      this.exception = loadFailure;
+    }
+  }
+
+  protected final Map<String, CoreLoadFailure> coreInitFailures = new ConcurrentHashMap<>();
 
   protected CoreAdminHandler coreAdminHandler = null;
   protected CollectionsHandler collectionsHandler = null;
@@ -423,9 +434,7 @@ public class CoreContainer {
 
     core.setName(name);
 
-    synchronized (coreInitFailures) {
-      coreInitFailures.remove(name);
-    }
+    coreInitFailures.remove(name);
 
     if( old == null || old == core) {
       log.info( "registering core: "+name );
@@ -489,7 +498,8 @@ public class CoreContainer {
 
     }
     catch (Exception e) {
-      throw recordAndThrow(dcore.getName(), "Unable to create core: " + dcore.getName(), e);
+      coreInitFailures.put(dcore.getName(), new CoreLoadFailure(dcore, e));
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to create core [" + dcore.getName() + "]", e);
     }
 
   }
@@ -542,11 +552,8 @@ public class CoreContainer {
    *  <li>Registering an existing SolrCore with a name already contained in this Map (ie: ALIAS or SWAP) will remove the Exception.</li>
    * </ul>
    */
-  public Map<String,Exception> getCoreInitFailures() {
-    synchronized ( coreInitFailures ) {
-      return Collections.unmodifiableMap(new LinkedHashMap<>
-                                         (coreInitFailures));
-    }
+  public Map<String, CoreLoadFailure> getCoreInitFailures() {
+    return ImmutableMap.copyOf(coreInitFailures);
   }
 
 
@@ -559,28 +566,29 @@ public class CoreContainer {
    * @param name the name of the SolrCore to reload
    */
   public void reload(String name) {
-    try {
-      name = checkDefault(name);
 
-      SolrCore core = solrCores.getCoreFromAnyList(name, false);
-      if (core == null)
-        throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
+    name = checkDefault(name);
 
-      try {
-        solrCores.waitAddPendingCoreOps(name);
-        CoreDescriptor cd = core.getCoreDescriptor();
-        ConfigSet coreConfig = coreConfigService.getConfig(cd);
-        log.info("Reloading SolrCore '{}' using configuration from {}", cd.getName(), coreConfig.getName());
-        SolrCore newCore = core.reload(coreConfig, core);
-        registerCore(name, newCore, false);
-      } finally {
-        solrCores.removeFromPendingOps(name);
-      }
-      // :TODO: Java7...
-      // http://docs.oracle.com/javase/7/docs/technotes/guides/language/catch-multiple.html
-    } catch (Exception ex) {
-      throw recordAndThrow(name, "Unable to reload core: " + name, ex);
+    SolrCore core = solrCores.getCoreFromAnyList(name, false);
+    if (core == null)
+      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
+
+    CoreDescriptor cd = core.getCoreDescriptor();
+    try {
+      solrCores.waitAddPendingCoreOps(name);
+      ConfigSet coreConfig = coreConfigService.getConfig(cd);
+      log.info("Reloading SolrCore '{}' using configuration from {}", cd.getName(), coreConfig.getName());
+      SolrCore newCore = core.reload(coreConfig, core);
+      registerCore(name, newCore, false);
+    }
+    catch (Exception e) {
+      coreInitFailures.put(cd.getName(), new CoreLoadFailure(cd, e));
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to reload core [" + cd.getName() + "]", e);
+    }
+    finally {
+      solrCores.removeFromPendingOps(name);
     }
+
   }
 
   //5.0 remove all checkDefaults?
@@ -603,14 +611,71 @@ public class CoreContainer {
 
     log.info("swapped: "+n0 + " with " + n1);
   }
-  
-  /** Removes and returns registered core w/o decrementing it's reference count */
-  public SolrCore remove( String name ) {
+
+  /**
+   * Unload a core from this container, leaving all files on disk
+   * @param name the name of the core to unload
+   */
+  public void unload(String name) {
+    unload(name, false, false, false);
+  }
+
+  /**
+   * Unload a core from this container, optionally removing the core's data and configuration
+   *
+   * @param name the name of the core to unload
+   * @param deleteIndexDir if true, delete the core's index on close
+   * @param deleteDataDir if true, delete the core's data directory on close
+   * @param deleteInstanceDir if true, delete the core's instance directory on close
+   */
+  public void unload(String name, boolean deleteIndexDir, boolean deleteDataDir, boolean deleteInstanceDir) {
+
     name = checkDefault(name);
+
+    // check for core-init errors first
+    CoreLoadFailure loadFailure = coreInitFailures.remove(name);
+    if (loadFailure != null) {
+      // getting the index directory requires opening a DirectoryFactory with a SolrConfig, etc,
+      // 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);
+      return;
+    }
+
     CoreDescriptor cd = solrCores.getCoreDescriptor(name);
-    SolrCore removed = solrCores.remove(name);
+    if (cd == null)
+      throw new SolrException(ErrorCode.BAD_REQUEST, "Cannot unload non-existent core [" + name + "]");
+
+    boolean close = solrCores.isLoadedNotPendingClose(name);
+    SolrCore core = solrCores.remove(name);
     coresLocator.delete(this, cd);
-    return removed;
+
+    if (core == null) {
+      // transient core
+      SolrCore.deleteUnloadedCore(cd, deleteDataDir, deleteInstanceDir);
+      return;
+    }
+
+    if (zkSys.getZkController() != null) {
+      // cancel recovery in cloud mode
+      core.getSolrCoreState().cancelRecovery();
+    }
+
+    core.unloadOnClose(deleteIndexDir, deleteDataDir, deleteInstanceDir);
+    if (close)
+      core.close();
+
+    if (zkSys.getZkController() != null) {
+      try {
+        zkSys.getZkController().unregister(name, cd);
+      } catch (InterruptedException e) {
+        Thread.currentThread().interrupt();
+        throw new SolrException(ErrorCode.SERVER_ERROR, "Interrupted while unregistering core [" + name + "] from cloud state");
+      } catch (KeeperException e) {
+        throw new SolrException(ErrorCode.SERVER_ERROR, "Error unregistering core [" + name + "] from cloud state", e);
+      }
+    }
+
   }
 
   public void rename(String name, String toName) {
@@ -670,11 +735,11 @@ public class CoreContainer {
 
       // if there was an error initalizing this core, throw a 500
       // error with the details for clients attempting to access it.
-      Exception e = getCoreInitFailures().get(name);
-      if (null != e) {
+      CoreLoadFailure loadFailure = getCoreInitFailures().get(name);
+      if (null != loadFailure) {
         throw new SolrException(ErrorCode.SERVER_ERROR, "SolrCore '" + name +
                                 "' is not available due to init failure: " +
-                                e.getMessage(), e);
+                                loadFailure.exception.getMessage(), loadFailure.exception);
       }
       // otherwise the user is simply asking for something that doesn't exist.
       return null;
@@ -688,13 +753,10 @@ public class CoreContainer {
     try {
       if (core == null) {
         core = create(desc); // This should throw an error if it fails.
-        core.open();
-      } else {
-        core.open();
       }
-    } catch(Exception ex){
-      throw recordAndThrow(name, "Unable to create core: " + name, ex);
-    } finally {
+      core.open();
+    }
+    finally {
       solrCores.removeFromPendingOps(name);
     }
 
@@ -801,16 +863,6 @@ public class CoreContainer {
   public UpdateShardHandler getUpdateShardHandler() {
     return updateShardHandler;
   }
-  
-  // Just to tidy up the code where it did this in-line.
-  private SolrException recordAndThrow(String name, String msg, Exception ex) {
-    synchronized (coreInitFailures) {
-      coreInitFailures.remove(name);
-      coreInitFailures.put(name, ex);
-    }
-    log.error(msg, ex);
-    return new SolrException(ErrorCode.SERVER_ERROR, msg, ex);
-  }
 
   public SolrResourceLoader getResourceLoader() {
     return loader;

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/SolrCore.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/SolrCore.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/SolrCore.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/core/SolrCore.java Wed Jul 16 15:29:28 2014
@@ -17,6 +17,7 @@
 
 package org.apache.solr.core;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.lucene.codecs.Codec;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.index.IndexDeletionPolicy;
@@ -2430,6 +2431,65 @@ public final class SolrCore implements S
     return codec;
   }
 
+  public void unloadOnClose(boolean deleteIndexDir, boolean deleteDataDir, boolean deleteInstanceDir) {
+    if (deleteIndexDir) {
+      try {
+        directoryFactory.remove(getIndexDir());
+      } catch (Exception e) {
+        SolrException.log(log, "Failed to flag index dir for removal for core:" + name + " dir:" + getIndexDir());
+      }
+    }
+    if (deleteDataDir) {
+      try {
+        directoryFactory.remove(getDataDir(), true);
+      } catch (Exception e) {
+        SolrException.log(log, "Failed to flag data dir for removal for core:" + name + " dir:" + getDataDir());
+      }
+    }
+    if (deleteInstanceDir) {
+      addCloseHook(new CloseHook() {
+        @Override
+        public void preClose(SolrCore core) {
+        }
+
+        @Override
+        public void postClose(SolrCore core) {
+          CoreDescriptor cd = core.getCoreDescriptor();
+          if (cd != null) {
+            File instanceDir = new File(cd.getInstanceDir());
+            try {
+              FileUtils.deleteDirectory(instanceDir);
+            } catch (IOException e) {
+              SolrException.log(log, "Failed to delete instance dir for core:"
+                  + core.getName() + " dir:" + instanceDir.getAbsolutePath());
+            }
+          }
+        }
+      });
+    }
+  }
+
+  public static void deleteUnloadedCore(CoreDescriptor cd, boolean deleteDataDir, boolean deleteInstanceDir) {
+    if (deleteDataDir) {
+      File dataDir = new File(cd.getDataDir());
+      try {
+        FileUtils.deleteDirectory(dataDir);
+      } catch (IOException e) {
+        SolrException.log(log, "Failed to delete data dir for unloaded core:" + cd.getName()
+            + " dir:" + dataDir.getAbsolutePath());
+      }
+    }
+    if (deleteInstanceDir) {
+      File instanceDir = new File(cd.getInstanceDir());
+      try {
+        FileUtils.deleteDirectory(instanceDir);
+      } catch (IOException e) {
+        SolrException.log(log, "Failed to delete instance dir for unloaded core:" + cd.getName()
+            + " dir:" + instanceDir.getAbsolutePath());
+      }
+    }
+  }
+
   public final class LazyQueryResponseWriterWrapper implements QueryResponseWriter {
     private SolrCore _core;
     private String _className;

Modified: lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java Wed Jul 16 15:29:28 2014
@@ -19,7 +19,6 @@ package org.apache.solr.handler.admin;
 
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Lists;
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.lucene.index.DirectoryReader;
 import org.apache.lucene.search.MatchAllDocsQuery;
@@ -45,7 +44,6 @@ import org.apache.solr.common.params.Upd
 import org.apache.solr.common.util.ExecutorUtil;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
-import org.apache.solr.core.CloseHook;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.DirectoryFactory;
@@ -638,100 +636,16 @@ public class CoreAdminHandler extends Re
   /**
    * Handle "UNLOAD" Action
    */
-  protected void handleUnloadAction(SolrQueryRequest req,
-      SolrQueryResponse rsp) throws SolrException {
+  protected void handleUnloadAction(SolrQueryRequest req, SolrQueryResponse rsp) throws SolrException {
+
     SolrParams params = req.getParams();
     String cname = params.get(CoreAdminParams.CORE);
-    Boolean closeCore = true;
-    if (!coreContainer.isLoadedNotPendingClose(cname)) {
-      closeCore = false;
-    }
-    SolrCore core = coreContainer.remove(cname);
-    try {
-      if (core == null) {
-        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
-            "No such core exists '" + cname + "'");
-      } else {
-        if (coreContainer.getZkController() != null) {
-          // we are unloading, cancel any ongoing recovery
-          if (core != null) {
-            if (coreContainer.getZkController() != null) {
-              core.getSolrCoreState().cancelRecovery();
-            }
-          }
-        }
-        
-        if (params.getBool(CoreAdminParams.DELETE_INDEX, false)) {
-          try {
-            core.getDirectoryFactory().remove(core.getIndexDir());
-          } catch (Exception e) {
-            SolrException.log(log, "Failed to flag index dir for removal for core:"
-                    + core.getName() + " dir:" + core.getIndexDir());
-          }
-        }
-      }
+    boolean deleteIndexDir = params.getBool(CoreAdminParams.DELETE_INDEX, false);
+    boolean deleteDataDir = params.getBool(CoreAdminParams.DELETE_DATA_DIR, false);
+    boolean deleteInstanceDir = params.getBool(CoreAdminParams.DELETE_INSTANCE_DIR, false);
+
+    coreContainer.unload(cname, deleteIndexDir, deleteDataDir, deleteInstanceDir);
 
-      if (params.getBool(CoreAdminParams.DELETE_DATA_DIR, false)) {
-        try {
-          core.getDirectoryFactory().remove(core.getDataDir(), true);
-        } catch (Exception e) {
-          SolrException.log(log, "Failed to flag data dir for removal for core:"
-                  + core.getName() + " dir:" + core.getDataDir());
-        }
-      }
-      
-      if (params.getBool(CoreAdminParams.DELETE_INSTANCE_DIR, false)) {
-        core.addCloseHook(new CloseHook() {
-          @Override
-          public void preClose(SolrCore core) {}
-          
-          @Override
-          public void postClose(SolrCore core) {
-            CoreDescriptor cd = core.getCoreDescriptor();
-            if (cd != null) {
-              File instanceDir = new File(cd.getInstanceDir());
-              try {
-                FileUtils.deleteDirectory(instanceDir);
-              } catch (IOException e) {
-                SolrException.log(log, "Failed to delete instance dir for core:"
-                    + core.getName() + " dir:" + instanceDir.getAbsolutePath());
-              }
-            }
-          }
-        });
-      }
-    } finally {
-      // it's important that we try and cancel recovery
-      // before we close here - else we might close the
-      // core *in* recovery and end up locked in recovery
-      // waiting to for recovery to be cancelled
-      if (core != null) {
-        if (coreContainer.getZkController() != null) {
-          core.getSolrCoreState().cancelRecovery();
-        }
-        if (closeCore) {
-          core.close();
-        }
-        
-        if (coreContainer.getZkController() != null) {
-          log.info("Unregistering core " + core.getName() + " from cloudstate.");
-          try {
-            coreContainer.getZkController().unregister(cname,
-                core.getCoreDescriptor());
-          } catch (InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
-                "Could not unregister core " + cname + " from cloudstate: "
-                    + e.getMessage(), e);
-          } catch (KeeperException e) {
-            throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
-                "Could not unregister core " + cname + " from cloudstate: "
-                    + e.getMessage(), e);
-          }
-        }
-      }
-    }
-    
   }
 
   /**
@@ -744,20 +658,22 @@ public class CoreAdminHandler extends Re
     String cname = params.get(CoreAdminParams.CORE);
     String indexInfo = params.get(CoreAdminParams.INDEX_INFO);
     boolean isIndexInfoNeeded = Boolean.parseBoolean(null == indexInfo ? "true" : indexInfo);
-    boolean doPersist = false;
     NamedList<Object> status = new SimpleOrderedMap<>();
-    Map<String,Exception> allFailures = coreContainer.getCoreInitFailures();
+    Map<String, Exception> failures = new HashMap<>();
+    for (Map.Entry<String, CoreContainer.CoreLoadFailure> failure : coreContainer.getCoreInitFailures().entrySet()) {
+      failures.put(failure.getKey(), failure.getValue().exception);
+    }
     try {
       if (cname == null) {
         rsp.add("defaultCoreName", coreContainer.getDefaultCoreName());
         for (String name : coreContainer.getAllCoreNames()) {
           status.add(name, getCoreStatus(coreContainer, name, isIndexInfoNeeded));
         }
-        rsp.add("initFailures", allFailures);
+        rsp.add("initFailures", failures);
       } else {
-        Map failures = allFailures.containsKey(cname)
-          ? Collections.singletonMap(cname, allFailures.get(cname))
-          : Collections.emptyMap();
+        failures = failures.containsKey(cname)
+          ? Collections.singletonMap(cname, failures.get(cname))
+          : Collections.<String, Exception>emptyMap();
         rsp.add("initFailures", failures);
         status.add(cname, getCoreStatus(coreContainer, cname, isIndexInfoNeeded));
       }

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/CoreContainerCoreInitFailuresTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/CoreContainerCoreInitFailuresTest.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/CoreContainerCoreInitFailuresTest.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/CoreContainerCoreInitFailuresTest.java Wed Jul 16 15:29:28 2014
@@ -50,7 +50,7 @@ public class CoreContainerCoreInitFailur
 
   public void testFlowWithEmpty() throws Exception {
     // reused state
-    Map<String,Exception> failures = null;
+    Map<String,CoreContainer.CoreLoadFailure> failures = null;
     Collection<String> cores = null;
     Exception fail = null;
 
@@ -97,7 +97,7 @@ public class CoreContainerCoreInitFailur
     failures = cc.getCoreInitFailures();
     assertNotNull("core failures is a null map", failures);
     assertEquals("wrong number of core failures", 1, failures.size());
-    fail = failures.get("bogus");
+    fail = failures.get("bogus").exception;
     assertNotNull("null failure for test core", fail);
     assertTrue("init failure doesn't mention problem: " + fail.getCause().getMessage(),
                0 < fail.getCause().getMessage().indexOf("bogus_path"));
@@ -125,7 +125,7 @@ public class CoreContainerCoreInitFailur
   public void testFlowBadFromStart() throws Exception {
 
     // reused state
-    Map<String,Exception> failures = null;
+    Map<String,CoreContainer.CoreLoadFailure> failures = null;
     Collection<String> cores = null;
     Exception fail = null;
 
@@ -164,7 +164,7 @@ public class CoreContainerCoreInitFailur
     failures = cc.getCoreInitFailures();
     assertNotNull("core failures is a null map", failures);
     assertEquals("wrong number of core failures", 1, failures.size());
-    fail = failures.get("col_bad");
+    fail = failures.get("col_bad").exception;
     assertNotNull("null failure for test core", fail);
     assertTrue("init failure doesn't mention problem: " + fail.getMessage(),
                0 < fail.getMessage().indexOf("DummyMergePolicy"));
@@ -227,7 +227,7 @@ public class CoreContainerCoreInitFailur
     failures = cc.getCoreInitFailures();
     assertNotNull("core failures is a null map", failures);
     assertEquals("wrong number of core failures", 1, failures.size());
-    fail = failures.get("bogus");
+    fail = failures.get("bogus").exception;
     assertNotNull("null failure for test core", fail);
     assertTrue("init failure doesn't mention problem: " + fail.getCause().getMessage(),
                0 < fail.getCause().getMessage().indexOf("bogus_path"));
@@ -284,7 +284,7 @@ public class CoreContainerCoreInitFailur
     failures = cc.getCoreInitFailures();
     assertNotNull("core failures is a null map", failures);
     assertEquals("wrong number of core failures", 2, failures.size());
-    Throwable ex = getWrappedException(failures.get("col_bad"));
+    Throwable ex = getWrappedException(failures.get("col_bad").exception);
     assertNotNull("null failure for test core", ex);
     assertTrue("init failure isn't SAXParseException",
                ex instanceof SAXParseException);

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreCheckLockOnStartupTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreCheckLockOnStartupTest.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreCheckLockOnStartupTest.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreCheckLockOnStartupTest.java Wed Jul 16 15:29:28 2014
@@ -17,9 +17,6 @@ package org.apache.solr.core;
  * limitations under the License.
  */
 
-import java.io.File;
-import java.util.Map;
-
 import org.apache.lucene.index.IndexWriter;
 import org.apache.lucene.index.IndexWriterConfig;
 import org.apache.lucene.store.Directory;
@@ -30,6 +27,9 @@ import org.apache.solr.SolrTestCaseJ4;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.File;
+import java.util.Map;
+
 public class SolrCoreCheckLockOnStartupTest extends SolrTestCaseJ4 {
 
   @Override
@@ -96,8 +96,8 @@ public class SolrCoreCheckLockOnStartupT
   }
 
   private boolean checkForCoreInitException(Class<? extends Exception> clazz) {
-    for (Map.Entry<String, Exception> entry : h.getCoreContainer().getCoreInitFailures().entrySet()) {
-      for (Throwable t = entry.getValue(); t != null; t = t.getCause()) {
+    for (Map.Entry<String, CoreContainer.CoreLoadFailure> entry : h.getCoreContainer().getCoreInitFailures().entrySet()) {
+      for (Throwable t = entry.getValue().exception; t != null; t = t.getCause()) {
         if (clazz.isInstance(t))
           return true;
       }

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/SolrCoreTest.java Wed Jul 16 15:29:28 2014
@@ -59,8 +59,7 @@ public class SolrCoreTest extends SolrTe
 
     assertEquals(COLLECTION1, cores.getDefaultCoreName());
     
-    cores.remove("");
-    core.close();
+    cores.unload("");
     core.close();
 
     CoreDescriptor cd = new CoreDescriptor(cores, COLLECTION1, "collection1",

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestCoreContainer.java Wed Jul 16 15:29:28 2014
@@ -19,6 +19,7 @@ package org.apache.solr.core;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
+import org.apache.solr.common.SolrException;
 import org.apache.solr.handler.admin.CollectionsHandler;
 import org.apache.solr.handler.admin.CoreAdminHandler;
 import org.apache.solr.handler.admin.InfoHandler;
@@ -39,8 +40,11 @@ import java.util.List;
 import java.util.jar.JarEntry;
 import java.util.jar.JarOutputStream;
 
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
 import static org.hamcrest.core.Is.is;
 import static org.hamcrest.core.IsInstanceOf.instanceOf;
+import static org.junit.matchers.JUnitMatchers.containsString;
 
 public class TestCoreContainer extends SolrTestCaseJ4 {
 
@@ -168,14 +172,19 @@ public class TestCoreContainer extends S
             "/solr/cores[@transientCacheSize='32']");
       }
 
-      newCore.close();
-      cores.remove("core1");
+      cores.unload("core1");
       //assert cero cores
       assertEquals("There should not be cores", 0, cores.getCores().size());
       
       // try and remove a core that does not exist
-      SolrCore ret = cores.remove("non_existent_core");
-      assertNull(ret);
+      try {
+        cores.unload("non_existent_core");
+        fail("Should have thrown an exception when unloading a non-existent core");
+      }
+      catch (SolrException e) {
+        assertThat(e.getMessage(), containsString("Cannot unload non-existent core [non_existent_core]"));
+      }
+
     } finally {
       cores.shutdown();
     }
@@ -207,6 +216,37 @@ public class TestCoreContainer extends S
   }
 
   @Test
+  public void testDeleteBadCores() throws Exception {
+
+    MockCoresLocator cl = new MockCoresLocator();
+
+    solrHomeDirectory = createTempDir("_deleteBadCores");
+    SolrResourceLoader resourceLoader = new SolrResourceLoader(solrHomeDirectory.getAbsolutePath());
+    File instanceDir = new File(solrHomeDirectory, "_deleteBadCores");
+    System.setProperty("configsets", getFile("solr/configsets").getAbsolutePath());
+
+    final CoreContainer cc = new CoreContainer(resourceLoader, ConfigSolr.fromString(resourceLoader, EMPTY_SOLR_XML2), cl);
+    CoreDescriptor badcore = new CoreDescriptor(cc, "badcore", instanceDir.getAbsolutePath(), "configSet", "nosuchconfigset");
+    cl.add(badcore);
+
+    try {
+      cc.load();
+      assertThat(cc.getCoreInitFailures().size(), is(1));
+      assertThat(cc.getCoreInitFailures().get("badcore").exception.getMessage(), containsString("nosuchconfigset"));
+      cc.unload("badcore", true, true, true);
+      assertThat(cc.getCoreInitFailures().size(), is(0));
+
+      // can we create the core now with a good config?
+      SolrCore core = cc.create(new CoreDescriptor(cc, "badcore", instanceDir.getAbsolutePath(), "configSet", "minimal"));
+      assertThat(core, not(nullValue()));
+
+    }
+    finally {
+      cc.shutdown();
+    }
+  }
+
+  @Test
   public void testClassLoaderHierarchy() throws Exception {
     final CoreContainer cc = init("_classLoaderHierarchy");
     try {
@@ -277,6 +317,7 @@ public class TestCoreContainer extends S
   
   private static final String EMPTY_SOLR_XML2 ="<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
       "<solr>\n" +
+      "<str name=\"configSetBaseDir\">${configsets:configsets}</str>" +
       "</solr>";
 
   private static final String CUSTOM_HANDLERS_SOLR_XML = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n" +
@@ -322,4 +363,43 @@ public class TestCoreContainer extends S
     }
 
   }
+
+  private static class MockCoresLocator implements CoresLocator {
+
+    List<CoreDescriptor> cores = new ArrayList<>();
+
+    void add(CoreDescriptor cd) {
+      cores.add(cd);
+    }
+
+    @Override
+    public void create(CoreContainer cc, CoreDescriptor... coreDescriptors) {
+      // noop
+    }
+
+    @Override
+    public void persist(CoreContainer cc, CoreDescriptor... coreDescriptors) {
+
+    }
+
+    @Override
+    public void delete(CoreContainer cc, CoreDescriptor... coreDescriptors) {
+
+    }
+
+    @Override
+    public void rename(CoreContainer cc, CoreDescriptor oldCD, CoreDescriptor newCD) {
+
+    }
+
+    @Override
+    public void swap(CoreContainer cc, CoreDescriptor cd1, CoreDescriptor cd2) {
+
+    }
+
+    @Override
+    public List<CoreDescriptor> discover(CoreContainer cc) {
+      return cores;
+    }
+  }
 }

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestLazyCores.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestLazyCores.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestLazyCores.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestLazyCores.java Wed Jul 16 15:29:28 2014
@@ -17,16 +17,6 @@ package org.apache.solr.core;
  * limitations under the License.
  */
 
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
-
 import org.apache.commons.codec.Charsets;
 import org.apache.commons.io.FileUtils;
 import org.apache.solr.SolrTestCaseJ4;
@@ -45,6 +35,16 @@ import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Pattern;
+
 public class TestLazyCores extends SolrTestCaseJ4 {
 
   @BeforeClass
@@ -554,10 +554,10 @@ public class TestLazyCores extends SolrT
   }
 
   // See fi the message you expect is in the list of failures
-  private void testMessage(Map<String, Exception> failures, String lookFor) {
+  private void testMessage(Map<String, CoreContainer.CoreLoadFailure> failures, String lookFor) {
     List<String> messages = new ArrayList<>();
-    for (Exception e : failures.values()) {
-      String message = e.getCause().getMessage();
+    for (CoreContainer.CoreLoadFailure e : failures.values()) {
+      String message = e.exception.getCause().getMessage();
       messages.add(message);
       if (message.contains(lookFor)) return;
     }
@@ -673,8 +673,7 @@ public class TestLazyCores extends SolrT
   }
 
   private void removeOne(CoreContainer cc, String coreName) {
-    SolrCore tmp = cc.remove(coreName);
-    if (tmp != null) tmp.close();
+    cc.unload(coreName);
   }
   public static void checkNotInCores(CoreContainer cc, String... nameCheck) {
     Collection<String> names = cc.getCoreNames();

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistence.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistence.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistence.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/core/TestSolrXmlPersistence.java Wed Jul 16 15:29:28 2014
@@ -458,8 +458,7 @@ public class TestSolrXmlPersistence exte
       TestHarness.validateXPath(locator.xml,
           "/solr/cores/core[@name='X' and not(@solr.core.instanceDir) and not (@solr.core.configName)]");
 
-      // delete a core, check persistence again
-      assertNotNull("removing X returned null", cores.remove("X"));
+      cores.unload("X");
 
       TestHarness.validateXPath(locator.xml, "/solr[@persistent='true']",
           "/solr/cores[@defaultCoreName='collection1']",
@@ -468,15 +467,6 @@ public class TestSolrXmlPersistence exte
           "2=count(/solr/cores/core)");
 
     } finally {
-      // y is closed by the container, but
-      // x has been removed from the container
-      if (x != null) {
-        try {
-          x.close();
-        } catch (Exception e) {
-          log.error("", e);
-        }
-      }
       cores.shutdown();
     }
   }

Modified: lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/SolrIndexSplitterTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/SolrIndexSplitterTest.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/SolrIndexSplitterTest.java (original)
+++ lucene/dev/branches/branch_4x/solr/core/src/test/org/apache/solr/update/SolrIndexSplitterTest.java Wed Jul 16 15:29:28 2014
@@ -187,10 +187,8 @@ public class SolrIndexSplitterTest exten
       assertEquals("id:dorothy should not be present in split index2", 0, server2.query(new SolrQuery("id:dorothy")).getResults().getNumFound());
       assertEquals("id:kansas should be present in split index2", 1, server2.query(new SolrQuery("id:kansas")).getResults().getNumFound());
     } finally {
-      h.getCoreContainer().remove("split2");
-      h.getCoreContainer().remove("split1");
-      if (core2 != null) core2.close();
-      if (core1 != null) core1.close();
+      h.getCoreContainer().unload("split2");
+      h.getCoreContainer().unload("split1");
     }
   }
 

Modified: lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java (original)
+++ lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java Wed Jul 16 15:29:28 2014
@@ -17,35 +17,9 @@
 
 package org.apache.solr;
 
-import static com.google.common.base.Preconditions.checkNotNull;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.logging.ConsoleHandler;
-import java.util.logging.Handler;
-import java.util.logging.Level;
-import java.util.regex.Pattern;
-
-import javax.xml.xpath.XPathExpressionException;
-
+import com.carrotsearch.randomizedtesting.RandomizedContext;
+import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
+import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
 import org.apache.commons.codec.Charsets;
 import org.apache.commons.io.FileUtils;
 import org.apache.lucene.analysis.MockAnalyzer;
@@ -53,9 +27,9 @@ import org.apache.lucene.index.IndexWrit
 import org.apache.lucene.util.Constants;
 import org.apache.lucene.util.IOUtils;
 import org.apache.lucene.util.LuceneTestCase;
+import org.apache.lucene.util.LuceneTestCase.SuppressSysoutChecks;
 import org.apache.lucene.util.QuickPatchThreadsFilter;
 import org.apache.lucene.util.TestUtil;
-import org.apache.lucene.util.LuceneTestCase.SuppressSysoutChecks;
 import org.apache.solr.client.solrj.impl.HttpClientConfigurer;
 import org.apache.solr.client.solrj.impl.HttpClientUtil;
 import org.apache.solr.client.solrj.util.ClientUtils;
@@ -102,9 +76,35 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.SAXException;
 
-import com.carrotsearch.randomizedtesting.RandomizedContext;
-import com.carrotsearch.randomizedtesting.annotations.ThreadLeakFilters;
-import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule;
+import javax.xml.xpath.XPathExpressionException;
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.logging.ConsoleHandler;
+import java.util.logging.Handler;
+import java.util.logging.Level;
+import java.util.regex.Pattern;
+
+import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * A junit4 Solr test harness that extends LuceneTestCaseJ4. To change which core is used when loading the schema and solrconfig.xml, simply
@@ -575,16 +575,16 @@ public abstract class SolrTestCaseJ4 ext
   }
 
   public static boolean hasInitException(String message) {
-    for (Map.Entry<String, Exception> entry : h.getCoreContainer().getCoreInitFailures().entrySet()) {
-      if (entry.getValue().getMessage().indexOf(message) != -1)
+    for (Map.Entry<String, CoreContainer.CoreLoadFailure> entry : h.getCoreContainer().getCoreInitFailures().entrySet()) {
+      if (entry.getValue().exception.getMessage().contains(message))
         return true;
     }
     return false;
   }
 
   public static boolean hasInitException(Class<? extends Exception> exceptionType) {
-    for (Map.Entry<String, Exception> entry : h.getCoreContainer().getCoreInitFailures().entrySet()) {
-      if (exceptionType.isAssignableFrom(entry.getValue().getClass()))
+    for (Map.Entry<String, CoreContainer.CoreLoadFailure> entry : h.getCoreContainer().getCoreInitFailures().entrySet()) {
+      if (exceptionType.isAssignableFrom(entry.getValue().exception.getClass()))
         return true;
     }
     return false;

Modified: lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/core/AbstractBadConfigTestBase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/core/AbstractBadConfigTestBase.java?rev=1611051&r1=1611050&r2=1611051&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/core/AbstractBadConfigTestBase.java (original)
+++ lucene/dev/branches/branch_4x/solr/test-framework/src/java/org/apache/solr/core/AbstractBadConfigTestBase.java Wed Jul 16 15:29:28 2014
@@ -57,8 +57,8 @@ public abstract class AbstractBadConfigT
       }
 
       CoreContainer cc = h.getCoreContainer();
-      for (Map.Entry<String, Exception> entry : cc.getCoreInitFailures().entrySet()) {
-        if (matches(entry.getValue(), errString))
+      for (Map.Entry<String, CoreContainer.CoreLoadFailure> entry : cc.getCoreInitFailures().entrySet()) {
+        if (matches(entry.getValue().exception, errString))
           return;
       }
     }