You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-dev@lucene.apache.org by Noble Paul നോബിള്‍ नोब्ळ् <no...@gmail.com> on 2008/08/18 17:31:15 UTC

Re: svn commit: r686780 - in /lucene/solr/trunk: ./ client/java/solrj/src/org/apache/solr/client/solrj/embedded/ client/java/solrj/test/org/apache/solr/client/solrj/embedded/ src/java/org/apache/solr/core/ src/java/org/apache/solr/handler/admin/ src/

do we really need the get to be synchronized (as I posted on the issue) ?

On Mon, Aug 18, 2008 at 8:38 PM,  <yo...@apache.org> wrote:
> Author: yonik
> Date: Mon Aug 18 08:08:28 2008
> New Revision: 686780
>
> URL: http://svn.apache.org/viewvc?rev=686780&view=rev
> Log:
> SOLR-647: refcount cores
>
> Modified:
>    lucene/solr/trunk/CHANGES.txt
>    lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
>    lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java
>    lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java
>    lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
>    lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java
>    lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java
>    lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
>    lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java
>    lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java
>    lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java
>    lucene/solr/trunk/src/webapp/web/admin/index.jsp
>
> Modified: lucene/solr/trunk/CHANGES.txt
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/CHANGES.txt (original)
> +++ lucene/solr/trunk/CHANGES.txt Mon Aug 18 08:08:28 2008
> @@ -358,6 +358,9 @@
>    1.3 release.  Speciffically, solr.xml has replaced multicore.xml, and uses a slightly
>    different syntax.  The solrj classes: MultiCore{Request/Response/Params} have been
>    renamed:  CoreAdmin{Request/Response/Params}  (hossman, ryan, Henri Biestro)
> +
> + 3. SOLR-647: reference count the SolrCore uses to prevent a premature
> +    close while a core is still in use.  (Henri Biestro, Noble Paul, yonik)
>
>  Optimizations
>  1. SOLR-276: improve JSON writer speed. (yonik)
>
> Modified: lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java (original)
> +++ lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java Mon Aug 18 08:08:28 2008
> @@ -36,6 +36,7 @@
>  import org.apache.solr.common.util.NamedList;
>  import org.apache.solr.core.CoreContainer;
>  import org.apache.solr.core.SolrCore;
> +import org.apache.solr.core.CoreDescriptor;
>  import org.apache.solr.request.BinaryResponseWriter;
>  import org.apache.solr.request.QueryResponseWriter;
>  import org.apache.solr.request.SolrQueryRequest;
> @@ -54,38 +55,46 @@
>  */
>  public class EmbeddedSolrServer extends SolrServer
>  {
> -
> -  protected final CoreContainer multicore; // either cores
> -  protected final SolrCore core; // or single core
> -  protected final String coreName;  // use CoreContainer registry
> -
> +  protected final CoreContainer coreContainer;
> +  protected final String coreName;
>   private final SolrRequestParsers _parser;
>
> +  /**
> +   * Use the other constructor using a CoreContainer and a name.
> +   * @param core
> +   * @deprecated
> +   */
> +  @Deprecated
>   public EmbeddedSolrServer( SolrCore core )
>   {
>     if ( core == null ) {
>       throw new NullPointerException("SolrCore instance required");
>     }
> -    this.core = core;
> -    if (core.getCoreDescriptor() != null) {
> -      this.multicore = core.getCoreDescriptor().getMultiCore();
> -      this.coreName = core.getCoreDescriptor().getName();
> -    } else {
> -      this.multicore = null;
> -      this.coreName = null;
> -    }
> +    CoreDescriptor dcore = core.getCoreDescriptor();
> +    if (dcore == null)
> +      throw new NullPointerException("CoreDescriptor required");
> +
> +    CoreContainer cores = dcore.getCoreContainer();
> +    if (cores == null)
> +      throw new NullPointerException("CoreContainer required");
> +
> +    coreName = dcore.getName();
> +    coreContainer = cores;
>     _parser = new SolrRequestParsers( null );
>   }
>
> -  public EmbeddedSolrServer(  CoreContainer multicore, String coreName )
> +  /**
> +   * Creates a SolrServer.
> +   * @param coreContainer the core container
> +   * @param coreName the core name
> +   */
> +  public EmbeddedSolrServer(  CoreContainer coreContainer, String coreName )
>   {
> -    if ( multicore == null ) {
> +    if ( coreContainer == null ) {
>       throw new NullPointerException("CoreContainer instance required");
>     }
> -    this.core = null;
> -    this.multicore = multicore;
> +    this.coreContainer = coreContainer;
>     this.coreName = coreName == null? "" : coreName;
> -
>     _parser = new SolrRequestParsers( null );
>   }
>
> @@ -98,15 +107,10 @@
>     }
>
>     // Check for cores action
> -    SolrCore core = this.core;
> -    if( core == null )
> -      core = multicore.getCore( coreName );
> -    // solr-647
> -    //else
> -    //  core = core.open();
> +    SolrCore core =  coreContainer.getCore( coreName );
>     if( core == null ) {
>       throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
> -          coreName == null? "No core": "No such core: " + coreName );
> +                               "No such core: " + coreName );
>     }
>
>     SolrParams params = request.getParams();
> @@ -126,14 +130,13 @@
>       }
>       // Perhaps the path is to manage the cores
>       if( handler == null &&
> -          multicore != null &&
> -          path.equals( multicore.getAdminPath() ) ) {
> -        handler = multicore.getMultiCoreHandler();
> +          coreContainer != null &&
> +          path.equals( coreContainer.getAdminPath() ) ) {
> +        handler = coreContainer.getMultiCoreHandler();
>       }
>     }
>     if( handler == null ) {
> -      // solr-647
> -      // core.close();
> +      core.close();
>       throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "unknown handler: "+path );
>     }
>
> @@ -158,8 +161,7 @@
>       throw new SolrServerException( ex );
>     }
>     finally {
> -      // solr-647
> -      // core.close();
> +      core.close();
>     }
>   }
>
>
> Modified: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java (original)
> +++ lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java Mon Aug 18 08:08:28 2008
> @@ -45,6 +45,6 @@
>   @Override
>   protected SolrServer createNewSolrServer()
>   {
> -    return new EmbeddedSolrServer( h.getCore() );
> +    return new EmbeddedSolrServer( h.getCoreContainer(), "" );
>   }
>  }
>
> Modified: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java (original)
> +++ lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java Mon Aug 18 08:08:28 2008
> @@ -47,6 +47,6 @@
>   @Override
>   protected SolrServer createNewSolrServer()
>   {
> -    return new EmbeddedSolrServer( h.getCore() );
> +    return new EmbeddedSolrServer( h.getCoreContainer(), "" );
>   }
>  }
>
> Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java (original)
> +++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java Mon Aug 18 08:08:28 2008
> @@ -25,9 +25,7 @@
>  import java.io.OutputStreamWriter;
>  import java.io.Writer;
>  import java.nio.channels.FileChannel;
> -import java.util.Collection;
> -import java.util.LinkedHashMap;
> -import java.util.Map;
> +import java.util.*;
>  import java.util.logging.Logger;
>
>  import javax.xml.parsers.ParserConfigurationException;
> @@ -36,6 +34,7 @@
>  import org.apache.solr.common.SolrException;
>  import org.apache.solr.common.util.DOMUtil;
>  import org.apache.solr.common.util.XML;
> +import org.apache.solr.common.util.StrUtils;
>  import org.apache.solr.handler.admin.CoreAdminHandler;
>  import org.apache.solr.schema.IndexSchema;
>  import org.w3c.dom.Node;
> @@ -51,7 +50,7 @@
>  {
>   protected static Logger log = Logger.getLogger(CoreContainer.class.getName());
>
> -  protected final Map<String, CoreDescriptor> cores = new LinkedHashMap<String, CoreDescriptor>();
> +  protected final Map<String, SolrCore> cores = new LinkedHashMap<String, SolrCore>();
>   protected boolean persistent = false;
>   protected String adminPath = null;
>   protected String managementPath = null;
> @@ -69,8 +68,7 @@
>   public static class Initializer {
>     protected String solrConfigFilename = null;
>     protected boolean abortOnConfigurationError = true;
> -    protected String managementPath = null;
> -
> +
>     public boolean isAbortOnConfigurationError() {
>       return abortOnConfigurationError;
>     }
> @@ -86,14 +84,6 @@
>     public void setSolrConfigFilename(String solrConfigFilename) {
>       this.solrConfigFilename = solrConfigFilename;
>     }
> -
> -    public String getManagementPath() {
> -      return managementPath;
> -    }
> -
> -    public void setManagementPath(String managementPath) {
> -      this.managementPath = managementPath;
> -    }
>
>     // core container instantiation
>     public CoreContainer initialize() throws IOException, ParserConfigurationException, SAXException {
> @@ -116,16 +106,13 @@
>         solrConfigFilename = cores.getConfigFile().getName();
>       } else {
>         // perform compatibility init
> -        cores = new CoreContainer();
> -        cores.loader = new SolrResourceLoader(instanceDir);
> +        cores = new CoreContainer(new SolrResourceLoader(instanceDir));
>         SolrConfig cfg = solrConfigFilename == null ? new SolrConfig() : new SolrConfig(solrConfigFilename);
> -        CoreDescriptor dcore = new CoreDescriptor(cores);
> -        dcore.init("", cfg.getResourceLoader().getInstanceDir());
> +        CoreDescriptor dcore = new CoreDescriptor(cores, "", cfg.getResourceLoader().getInstanceDir());
>         SolrCore singlecore = new SolrCore(null, null, cfg, null, dcore);
> -        dcore.setCore(singlecore);
>         abortOnConfigurationError = cfg.getBool(
>                 "abortOnConfigurationError", abortOnConfigurationError);
> -        cores.register(dcore);
> +        cores.register("", singlecore, false);
>         cores.setPersistent(false);
>         solrConfigFilename = cfg.getName();
>       }
> @@ -147,6 +134,14 @@
>     this.load(dir, configFile);
>   }
>
> +  /**
> +   * Minimal CoreContainer constructor.
> +   * @param loader the CoreContainer resource loader
> +   */
> +  public CoreContainer(SolrResourceLoader loader) {
> +    this.loader = loader;
> +  }
> +
>   //-------------------------------------------------------------------
>   // Initialization / Cleanup
>   //-------------------------------------------------------------------
> @@ -165,54 +160,60 @@
>     FileInputStream cfgis = new FileInputStream(configFile);
>     try {
>       Config cfg = new Config(loader, null, cfgis, null);
> -
> +
>       persistent = cfg.getBool( "solr/@persistent", false );
>       libDir     = cfg.get(     "solr/@sharedLib", null);
>       adminPath  = cfg.get(     "solr/cores/@adminPath", null );
>       managementPath  = cfg.get("solr/cores/@managementPath", null );
> -
> +
>       if (libDir != null) {
>         // relative dir to conf
>         File f = new File(dir, libDir);
> -        libDir = f.getPath();
> +        libDir = f.getPath();
>         log.info( "loading shared library: "+f.getAbsolutePath() );
>         libLoader = SolrResourceLoader.createClassLoader(f, null);
>       }
> -
> +
>       if( adminPath != null ) {
>         coreAdminHandler = this.createMultiCoreHandler();
>       }
> -
> +
>       NodeList nodes = (NodeList)cfg.evaluate("solr/cores/core", XPathConstants.NODESET);
> -      synchronized (cores) {
> -        for (int i=0; i<nodes.getLength(); i++) {
> -          Node node = nodes.item(i);
> -          try {
> -            CoreDescriptor p = new CoreDescriptor(this);
> -            p.init(DOMUtil.getAttr(node, "name", null), DOMUtil.getAttr(node, "instanceDir", null));
> -            // deal with optional settings
> -            String opt = DOMUtil.getAttr(node, "config", null);
> -            if (opt != null) {
> -              p.setConfigName(opt);
> -            }
> -            opt = DOMUtil.getAttr(node, "schema", null);
> -            if (opt != null) {
> -              p.setSchemaName(opt);
> -            }
> -            CoreDescriptor old = cores.get(p.getName());
> -            if (old != null && old.getName() != null && old.getName().equals(p.getName())) {
> -              throw new RuntimeException( cfg.getName() +
> -                " registers multiple cores to the same name: " + p.name);
> -            }
> -            p.setCore(create(p));
> +
> +      for (int i=0; i<nodes.getLength(); i++) {
> +        Node node = nodes.item(i);
> +        try {
> +          String names = DOMUtil.getAttr(node, "name", null);
> +          List<String> aliases = StrUtils.splitSmart(names,',');
> +          String name = aliases.get(0);
> +          CoreDescriptor p = new CoreDescriptor(this, name, DOMUtil.getAttr(node, "instanceDir", null));
> +
> +          // deal with optional settings
> +          String opt = DOMUtil.getAttr(node, "config", null);
> +          if (opt != null) {
> +            p.setConfigName(opt);
>           }
> -          catch (Throwable ex) {
> -            SolrConfig.severeErrors.add( ex );
> -            SolrException.logOnce(log,null,ex);
> +          opt = DOMUtil.getAttr(node, "schema", null);
> +          if (opt != null) {
> +            p.setSchemaName(opt);
>           }
> +
> +          SolrCore core = create(p);
> +
> +          for (int a=1; a<aliases.size(); a++) {
> +            core.open();
> +            register(aliases.get(i), core, false);
> +          }
> +
> +          register(name, core, false);
> +        }
> +        catch (Throwable ex) {
> +          SolrConfig.severeErrors.add( ex );
> +          SolrException.logOnce(log,null,ex);
>         }
>       }
>     }
> +
>     finally {
>       if (cfgis != null) {
>         try { cfgis.close(); } catch (Exception xany) {}
> @@ -225,11 +226,8 @@
>    */
>   public void shutdown() {
>     synchronized(cores) {
> -      for(CoreDescriptor descriptor : cores.values()) {
> -        SolrCore core = descriptor.getCore();
> -        if( core != null ) {
> -          core.close();
> -        }
> +      for(SolrCore core : cores.values()) {
> +        core.close();
>       }
>       cores.clear();
>     }
> @@ -239,40 +237,44 @@
>   protected void finalize() {
>     shutdown();
>   }
> -
> -  // ---------------- CoreDescriptor related methods ---------------
> +
>   /**
>    * Registers a SolrCore descriptor in the registry.
> -   * @param descr the Solr core descriptor
> -   * @return a previous descriptor having the same name if it existed, null otherwise
> +   * @return a previous core having the same name if it existed and returnPrev==true
>    */
> -  public CoreDescriptor register( CoreDescriptor descr ) {
> -    if( descr == null ) {
> +  public SolrCore register(String name, SolrCore core, boolean returnPrev) {
> +    if( core == null ) {
>       throw new RuntimeException( "Can not register a null core." );
>     }
> -    String name = descr.getName();
> -    if( name == null ||
> +    if( name == null ||
>         name.indexOf( '/'  ) >= 0 ||
>         name.indexOf( '\\' ) >= 0 ){
>       throw new RuntimeException( "Invalid core name: "+name );
>     }
>
> -    CoreDescriptor old = null;
> +    SolrCore old = null;
>     synchronized (cores) {
> -      old = cores.put(name, descr);
> +      old = cores.put(name, core);
> +      core.setName(name);
>     }
> -    if( old == null ) {
> +
> +
> +    if( old == null || old == core) {
>       log.info( "registering core: "+name );
>       return null;
> -    }
> +    }
>     else {
>       log.info( "replacing core: "+name );
> +      if (!returnPrev) {
> +        old.close();
> +      }
>       return old;
>     }
>   }
>
> +
>   /**
> -   * Creates a new core based on a descriptor.
> +   * Creates a new core based on a descriptor but does not register it.
>    *
>    * @param dcore a core descriptor
>    * @return the newly created core
> @@ -293,10 +295,6 @@
>     SolrConfig config = new SolrConfig(solrLoader, dcore.getConfigName(), null);
>     IndexSchema schema = new IndexSchema(config, dcore.getSchemaName(), null);
>     SolrCore core = new SolrCore(dcore.getName(), null, config, schema, dcore);
> -    dcore.setCore(core);
> -
> -    // Register the new core
> -    CoreDescriptor old = this.register(dcore);
>     return core;
>   }
>
> @@ -304,37 +302,39 @@
>    * @return a Collection of registered SolrCores
>    */
>   public Collection<SolrCore> getCores() {
> -    java.util.List<SolrCore> l = new java.util.ArrayList<SolrCore>();
> +    List<SolrCore> lst = new ArrayList<SolrCore>();
>     synchronized (cores) {
> -      for(CoreDescriptor descr : this.cores.values()) {
> -        if (descr.getCore() != null)
> -          l.add(descr.getCore());
> -      }
> +      lst.addAll(this.cores.values());
>     }
> -    return l;
> +    return lst;
>   }
> -
> +
>   /**
> -   * @return a Collection of registered CoreDescriptors
> +   * @return a Collection of the names that cores are mapped to
>    */
> -  public Collection<CoreDescriptor> getDescriptors() {
> -   java.util.List<CoreDescriptor> l = new java.util.ArrayList<CoreDescriptor>();
> -   synchronized (cores) {
> -     l.addAll(cores.values());
> -   }
> -   return l;
> +  public Collection<String> getCoreNames() {
> +    List<String> lst = new ArrayList<String>();
> +    synchronized (cores) {
> +      lst.addAll(this.cores.keySet());
> +    }
> +    return lst;
>   }
>
>   /**
> -   * @return the CoreDescriptor registered under that name
> +   * @return a Collection of the names that a specific core is mapped to.
>    */
> -  public CoreDescriptor getDescriptor(String name) {
> -    synchronized(cores) {
> -      return cores.get( name );
> +  public Collection<String> getCoreNames(SolrCore core) {
> +    List<String> lst = new ArrayList<String>();
> +    synchronized (cores) {
> +      for (Map.Entry<String,SolrCore> entry : cores.entrySet()) {
> +        if (core == entry.getValue()) {
> +          lst.add(entry.getKey());
> +        }
> +      }
>     }
> +    return lst;
>   }
> -
> -
> +
>   // ---------------- Core name related methods ---------------
>   /**
>    * Recreates a SolrCore.
> @@ -348,12 +348,14 @@
>    */
>
>   public void reload(String name) throws ParserConfigurationException, IOException, SAXException {
> +    SolrCore core;
>     synchronized(cores) {
> -      CoreDescriptor dcore = cores.get(name);
> -      if (dcore == null)
> -        throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
> -      create(new CoreDescriptor(dcore));
> +      core = cores.get(name);
>     }
> +    if (core == null)
> +      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
> +
> +    register(name, create(core.getCoreDescriptor()), false);
>   }
>
>
> @@ -367,36 +369,27 @@
>       throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Can not swap unnamed cores." );
>     }
>     synchronized( cores ) {
> -      CoreDescriptor c0 = cores.get(n0);
> +      SolrCore c0 = cores.get(n0);
> +      SolrCore c1 = cores.get(n1);
>       if (c0 == null)
>         throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n0 );
> -      CoreDescriptor c1 = cores.get(n1);
>       if (c1 == null)
>         throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n1 );
>       cores.put(n0, c1);
>       cores.put(n1, c0);
> -      c0.setName( n1 );
> -      if (c0.getCore() != null)
> -        c0.getCore().setName(n1);
> -      c1.setName( n0 );
> -      if (c1.getCore() != null)
> -        c1.getCore().setName(n0);
> -      log.info( "swaped: "+c0.getName() + " with " + c1.getName() );
> +
> +      c0.setName(n1);
> +      c1.setName(n0);
>     }
> +
> +
> +    log.info("swaped: "+n0 + " with " + n1);
>   }
>
> -  /** Removes & closes a registered core. */
> -  public void remove( String name ) {
> +  /** Removes and returns registered core w/o decrementing it's reference count */
> +  public SolrCore remove( String name ) {
>     synchronized(cores) {
> -      CoreDescriptor dcore = cores.remove( name );
> -      if (dcore == null) {
> -        return;
> -      }
> -
> -      SolrCore core = dcore.getCore();
> -      if (core != null) {
> -        core.close();
> -      }
> +      return cores.remove( name );
>     }
>   }
>
> @@ -408,15 +401,10 @@
>    */
>   public SolrCore getCore(String name) {
>     synchronized(cores) {
> -      CoreDescriptor dcore = cores.get(name);
> -       SolrCore core = null;
> -      if (dcore != null)
> -        core = dcore.getCore();
> -       return core;
> -// solr-647
> -//      if (core != null)
> -//        return core.open();
> -//      return null;
> +      SolrCore core = cores.get(name);
> +      if (core != null)
> +        core.open();  // increment the ref count while still synchronized
> +      return core;
>     }
>   }
>
> @@ -433,20 +421,17 @@
>    * Ensures there is a valid core to handle MultiCore admin taks and
>    * increase its refcount.
>    * @return the acquired admin core, null if no core is available
> -   */
> +   */
>   public SolrCore getAdminCore() {
>     synchronized (cores) {
>       SolrCore core = adminCore != null ? adminCore.get() : null;
> -//      solr-647
> -//      if (core != null)
> -//        core = core.open();
> -      if (core == null) {
> -        for (CoreDescriptor descr : this.cores.values()) {
> -          core = descr.getCore();
> -//          solr-647
> -//          if (core != null)
> -//            core = core.open();
> -          if (core != null) {
> +      if (core != null) {
> +        core.open();
> +      } else {
> +        for (SolrCore c : cores.values()) {
> +          if (c != null) {
> +            core = c;
> +            core.open();
>             break;
>           }
>         }
> @@ -517,7 +502,7 @@
>   public void persist() {
>     persistFile(null);
>   }
> -
> +
>   /** Persists the cores config file in a user provided file. */
>   public void persistFile(File file) {
>     File tmpFile = null;
> @@ -527,7 +512,6 @@
>         file = tmpFile = File.createTempFile("solr", ".xml", configFile.getParentFile());
>       }
>       java.io.FileOutputStream out = new java.io.FileOutputStream(file);
> -      synchronized(cores) {
>         Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
>         persist(writer);
>         writer.flush();
> @@ -540,7 +524,6 @@
>           else
>             fileCopy(tmpFile, configFile);
>         }
> -      }
>     }
>     catch(java.io.FileNotFoundException xnf) {
>       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, xnf);
> @@ -578,20 +561,35 @@
>     writer.write('\'');
>     writer.write(">\n");
>
> +    Map<SolrCore, LinkedList<String>> aliases = new HashMap<SolrCore,LinkedList<String>>();
> +
>     synchronized(cores) {
> -      for (Map.Entry<String, CoreDescriptor> entry : cores.entrySet()) {
> -        persist(writer, entry.getValue());
> +      for (Map.Entry<String, SolrCore> entry : cores.entrySet()) {
> +        String name = entry.getKey();
> +        LinkedList<String> a = aliases.get(entry.getValue());
> +        if (a==null) a = new LinkedList<String>();
> +        if (name.equals(entry.getValue().getName())) {
> +          a.addFirst(name);
> +        } else {
> +          a.addLast(name);
> +        }
> +        aliases.put(entry.getValue(), a);
>       }
>     }
> +
> +    for (Map.Entry<SolrCore, LinkedList<String>> entry : aliases.entrySet()) {
> +      persist(writer, entry.getValue(), entry.getKey().getCoreDescriptor());
> +    }
> +
>     writer.write("</cores>\n");
>     writer.write("</solr>\n");
>   }
>
>   /** Writes the cores configuration node for a given core. */
> -  void persist(Writer writer, CoreDescriptor dcore) throws IOException {
> +  void persist(Writer writer, List<String> aliases, CoreDescriptor dcore) throws IOException {
>     writer.write("  <core");
>     writer.write (" name='");
> -    XML.escapeAttributeValue(dcore.getName(), writer);
> +    XML.escapeAttributeValue(StrUtils.join(aliases,','), writer);
>     writer.write("' instanceDir='");
>     XML.escapeAttributeValue(dcore.getInstanceDir(), writer);
>     writer.write('\'');
>
> Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java (original)
> +++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java Mon Aug 18 08:08:28 2008
> @@ -28,22 +28,17 @@
>   protected String instanceDir;
>   protected String configName;
>   protected String schemaName;
> -  protected SolrCore core = null;
>   private final CoreContainer coreContainer;
>
> -  public CoreDescriptor(CoreContainer coreContainer) {
> +  public CoreDescriptor(CoreContainer coreContainer, String name, String instanceDir) {
>     this.coreContainer = coreContainer;
> -  }
> -
> -  /** Initialize defaults from instance directory. */
> -  public void init(String name, String instanceDir) {
> +    this.name = name;
>     if (name == null) {
>       throw new RuntimeException("Core needs a name");
>     }
>     if (instanceDir == null) {
>       throw new NullPointerException("Missing required \'instanceDir\'");
>     }
> -    this.name = name;
>     if (!instanceDir.endsWith("/")) instanceDir = instanceDir + "/";
>     this.instanceDir = instanceDir;
>     this.configName = getDefaultConfigName();
> @@ -51,10 +46,10 @@
>   }
>
>   public CoreDescriptor(CoreDescriptor descr) {
> -    this.name = descr.name;
>     this.instanceDir = descr.instanceDir;
>     this.configName = descr.configName;
>     this.schemaName = descr.schemaName;
> +    this.name = descr.name;
>     coreContainer = descr.coreContainer;
>   }
>
> @@ -72,17 +67,7 @@
>   public String getDefaultDataDir() {
>     return this.instanceDir + "data/";
>   }
> -
> -  /**@return the core name. */
> -  public String getName() {
> -    return name;
> -  }
> -
> -  /** Sets the core name. */
> -  public void setName(String name) {
> -    this.name = name;
> -  }
> -
> +
>   /**@return the core instance directory. */
>   public String getInstanceDir() {
>     return instanceDir;
> @@ -111,16 +96,13 @@
>   public String getSchemaName() {
>     return this.schemaName;
>   }
> -
> -  public SolrCore getCore() {
> -    return core;
> -  }
> -
> -  public void setCore(SolrCore core) {
> -    this.core = core;
> +
> +  /**@return the initial core name */
> +  public String getName() {
> +    return this.name;
>   }
>
> -  public CoreContainer getMultiCore() {
> +  public CoreContainer getCoreContainer() {
>     return coreContainer;
>   }
>  }
>
> Modified: lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java (original)
> +++ lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java Mon Aug 18 08:08:28 2008
> @@ -62,13 +62,15 @@
>  import java.io.IOException;
>  import java.util.*;
>  import java.util.concurrent.*;
> +import java.util.concurrent.atomic.AtomicInteger;
>  import java.util.logging.Logger;
> +import java.net.URL;
>
>
>  /**
>  * @version $Id$
>  */
> -public final class SolrCore {
> +public final class SolrCore implements SolrInfoMBean {
>   public static final String version="1.0";
>
>   public static Logger log = Logger.getLogger(SolrCore.class.getName());
> @@ -374,7 +376,7 @@
>    * @since solr 1.0
>    */
>   public SolrCore(String dataDir, IndexSchema schema) throws ParserConfigurationException, IOException, SAXException {
> -    this( null, dataDir, new SolrConfig(), schema, null );
> +    this(null, dataDir, new SolrConfig(), schema, null );
>   }
>
>   /**
> @@ -479,8 +481,9 @@
>         latch.countDown();
>       }
>     } // end synchronized
> +
> +    infoRegistry.put("core", this);
>   }
> -
>
>
>   /**
> @@ -569,16 +572,39 @@
>     }
>     return chain;
>   }
> +
> +  // this core current usage count
> +  private final AtomicInteger refCount = new AtomicInteger(1);
>
> +  final void open() {
> +    refCount.incrementAndGet();
> +  }
> +
>   /**
>    * Close all resources allocated by the core.
>    *  1. searcher
>    *  2. updateHandler
>    *  3. all CloseHooks will be notified
>    *  4. All MBeans will be unregistered from MBeanServer if JMX was enabled
> +   * <p>
> +   * This should always be called when the core is obtained through:
> +   * @see CoreContainer.getCore
> +   * @see CoreContainer.getAdminCore
> +   * </p>
> +   * The actual close is performed if the core usage count is 1.
> +   * (A core is created with a usage count of 1).
> +   * If usage count is > 1, the usage count is decreased by 1.
> +   * If usage count is &lt; 0, this is an error and a runtime exception is thrown.
>    */
>   public void close() {
> -    log.info(logid+" CLOSING SolrCore!");
> +    int count = refCount.decrementAndGet();
> +    if (count > 0) return;
> +    if (count < 0) {
> +      //throw new RuntimeException("Too many closes on " + this);
> +      log.severe("Too many close {count:"+count+"} on " + this + ". Please report this exception to solr-user@lucene.apache.org");
> +      return;
> +    }
> +    log.info(logid+" CLOSING SolrCore " + this);
>     try {
>       infoRegistry.clear();
>     } catch (Exception e) {
> @@ -602,16 +628,22 @@
>     if( closeHooks != null ) {
>        for( CloseHook hook : closeHooks ) {
>          hook.close( this );
> -       }
> +      }
>     }
>   }
>
> +  /** Current core usage count. */
> +  public int getOpenCount() {
> +    return refCount.get();
> +  }
> +
> +  /** Whether this core is closed. */
>   public boolean isClosed() {
> -    return _searcher == null;
> +      return refCount.get() <= 0;
>   }
>
> -  @Override
> -  protected void finalize() { close(); }
> +  // this can cause an extra close
> +  // protected void finalize() { close(); }
>
>   private List<CloseHook> closeHooks = null;
>
> @@ -1380,6 +1412,45 @@
>   public CoreDescriptor getCoreDescriptor() {
>     return coreDescriptor;
>   }
> +
> +
> +  /////////////////////////////////////////////////////////////////////
> +  // SolrInfoMBean stuff: Statistics and Module Info
> +  /////////////////////////////////////////////////////////////////////
> +
> +  public String getVersion() {
> +    return SolrCore.version;
> +  }
> +
> +  public String getDescription() {
> +    return "SolrCore";
> +  }
> +
> +  public Category getCategory() {
> +    return Category.CORE;
> +  }
> +
> +  public String getSourceId() {
> +    return "$Id:$";
> +  }
> +
> +  public String getSource() {
> +    return "$URL:$";
> +  }
> +
> +  public URL[] getDocs() {
> +    return null;
> +  }
> +
> +  public NamedList getStatistics() {
> +    NamedList lst = new SimpleOrderedMap();
> +    lst.add("coreName", name==null ? "(null)" : name);
> +    lst.add("startTime", new Date(startTime));
> +    lst.add("refCount", getOpenCount());
> +    lst.add("aliases", getCoreDescriptor().getCoreContainer().getCoreNames(this));
> +    return lst;
> +  }
> +
>  }
>
>
>
> Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java (original)
> +++ lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java Mon Aug 18 08:08:28 2008
> @@ -90,9 +90,8 @@
>
>     switch(action) {
>       case CREATE: {
> -        CoreDescriptor dcore = new CoreDescriptor(cores);
> -        dcore.init(params.get(CoreAdminParams.NAME),
> -                  params.get(CoreAdminParams.INSTANCE_DIR));
> +        String name = params.get(CoreAdminParams.NAME);
> +        CoreDescriptor dcore = new CoreDescriptor(cores, name, params.get(CoreAdminParams.INSTANCE_DIR));
>
>         // fillup optional parameters
>         String opts = params.get(CoreAdminParams.CONFIG);
> @@ -104,6 +103,7 @@
>           dcore.setSchemaName(opts);
>
>         SolrCore core = cores.create(dcore);
> +        cores.register(name, core,false);
>         rsp.add("core", core.getName());
>         do_persist = cores.isPersistent();
>         break;
> @@ -112,9 +112,8 @@
>       case STATUS: {
>         NamedList<Object> status = new SimpleOrderedMap<Object>();
>         if( cname == null ) {
> -          for (CoreDescriptor d : cores.getDescriptors()) {
> -            cname = d.getName();
> -            status.add(d.getName(), getCoreStatus( cores, cname  ) );
> +          for (SolrCore core : cores.getCores()) {
> +            status.add(core.getName(), getCoreStatus( cores, cname  ) );
>           }
>         }
>         else {
> @@ -172,8 +171,7 @@
>         info.add("index", LukeRequestHandler.getIndexInfo(searcher.get().getReader(), false));
>         searcher.decref();
>       } finally {
> -        // solr-647
> -        // core.close();
> +        core.close();
>       }
>     }
>     return info;
>
> Modified: lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java (original)
> +++ lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java Mon Aug 18 08:08:28 2008
> @@ -21,6 +21,9 @@
>  import org.apache.solr.common.util.XML;
>  import org.apache.solr.core.SolrConfig;
>  import org.apache.solr.core.SolrCore;
> +import org.apache.solr.core.CoreContainer;
> +import org.apache.solr.core.CoreDescriptor;
> +import org.apache.solr.core.SolrResourceLoader;
>  import org.apache.solr.handler.XmlUpdateRequestHandler;
>  import org.apache.solr.request.LocalSolrQueryRequest;
>  import org.apache.solr.request.QueryResponseWriter;
> @@ -32,6 +35,7 @@
>
>  import javax.xml.parsers.DocumentBuilder;
>  import javax.xml.parsers.DocumentBuilderFactory;
> +import javax.xml.parsers.ParserConfigurationException;
>  import javax.xml.xpath.XPath;
>  import javax.xml.xpath.XPathConstants;
>  import javax.xml.xpath.XPathExpressionException;
> @@ -60,7 +64,7 @@
>  * @version $Id:$
>  */
>  public class TestHarness {
> -
> +  protected CoreContainer container;
>   private SolrCore core;
>   private XPath xpath = XPathFactory.newInstance().newXPath();
>   private DocumentBuilder builder;
> @@ -123,8 +127,19 @@
>   public TestHarness( String dataDirectory,
>                       SolrConfig solrConfig,
>                       IndexSchema indexSchema) {
> +      this("", new Initializer("", dataDirectory, solrConfig, indexSchema));
> +  }
> +
> +  public TestHarness(String coreName, CoreContainer.Initializer init) {
>     try {
> -      core = new SolrCore( null, dataDirectory, solrConfig, indexSchema, null);
> +      container = init.initialize();
> +      if (coreName == null)
> +        coreName = "";
> +      // get the core & decrease its refcount:
> +      // the container holds the core for the harness lifetime
> +      core = container.getCore(coreName);
> +      if (core != null)
> +        core.close();
>       builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
>
>       updater = new XmlUpdateRequestHandler();
> @@ -133,6 +148,42 @@
>       throw new RuntimeException(e);
>     }
>   }
> +
> +  // Creates a container based on infos needed to create one core
> +  static class Initializer extends CoreContainer.Initializer {
> +    String coreName;
> +    String dataDirectory;
> +    SolrConfig solrConfig;
> +    IndexSchema indexSchema;
> +    public Initializer(String coreName,
> +                      String dataDirectory,
> +                      SolrConfig solrConfig,
> +                      IndexSchema indexSchema) {
> +      if (coreName == null)
> +        coreName = "";
> +      this.coreName = coreName;
> +      this.dataDirectory = dataDirectory;
> +      this.solrConfig = solrConfig;
> +      this.indexSchema = indexSchema;
> +    }
> +    public String getCoreName() {
> +      return coreName;
> +    }
> +    @Override
> +    public CoreContainer initialize() {
> +      CoreContainer container = new CoreContainer(new SolrResourceLoader(SolrResourceLoader.locateInstanceDir()));
> +      CoreDescriptor dcore = new CoreDescriptor(container, coreName, solrConfig.getResourceLoader().getInstanceDir());
> +      dcore.setConfigName(solrConfig.getResourceName());
> +      dcore.setSchemaName(indexSchema.getResourceName());
> +      SolrCore core = new SolrCore( null, dataDirectory, solrConfig, indexSchema, dcore);
> +      container.register(coreName, core, false);
> +      return container;
> +    }
> +  }
> +
> +  public CoreContainer getCoreContainer() {
> +    return container;
> +  }
>
>   public SolrCore getCore() {
>     return core;
> @@ -152,9 +203,7 @@
>
>     StringReader req = new StringReader(xml);
>     StringWriter writer = new StringWriter(32000);
> -
> -    // This relies on the fact that SolrCore.getSolrCore() uses the
> -    // last instantiated SolrCore.
> +
>     updater.doLegacyUpdate(req, writer);
>     return writer.toString();
>   }
> @@ -321,7 +370,17 @@
>    * Shuts down and frees any resources
>    */
>   public void close() {
> -    core.close();
> +    if (container != null) {
> +      for (SolrCore c : container.getCores()) {
> +        if (c.getOpenCount() > 1)
> +          throw new RuntimeException("SolrCore.getOpenCount()=="+core.getOpenCount());
> +      }
> +    }
> +
> +    if (container != null) {
> +      container.shutdown();
> +      container = null;
> +    }
>   }
>
>   /**
>
> Modified: lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java (original)
> +++ lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java Mon Aug 18 08:08:28 2008
> @@ -24,13 +24,14 @@
>  import org.apache.solr.util.AbstractSolrTestCase;
>  import org.apache.solr.util.plugin.SolrCoreAware;
>
> +import java.util.concurrent.*;
> +import java.util.*;
>  public class SolrCoreTest extends AbstractSolrTestCase {
>
>   public String getSchemaFile() { return "schema.xml"; }
>   public String getSolrConfigFile() { return "solrconfig.xml"; }
> -
> +
>   public void testRequestHandlerRegistry() {
> -    // property values defined in build.xml
>     SolrCore core = h.getCore();
>
>     EmptyRequestHandler handler1 = new EmptyRequestHandler();
> @@ -46,7 +47,8 @@
>   }
>
>   public void testClose() throws Exception {
> -    SolrCore core = h.getCore();
> +    final CoreContainer cores = h.getCoreContainer();
> +    SolrCore core = cores.getCore("");
>
>     ClosingRequestHandler handler1 = new ClosingRequestHandler();
>     handler1.inform( core );
> @@ -56,10 +58,116 @@
>     assertNull( old ); // should not be anything...
>     assertEquals( core.getRequestHandlers().get( path ), handler1 );
>     core.close();
> +    cores.shutdown();
>     assertTrue("Handler not closed", handler1.closed == true);
>   }
> +
> +  public void testRefCount() throws Exception {
> +    SolrCore core = h.getCore();
> +    assertTrue("Refcount != 1", core.getOpenCount() == 1);
> +
> +    final CoreContainer cores = h.getCoreContainer();
> +    SolrCore c1 = cores.getCore("");
> +    assertTrue("Refcount != 2", core.getOpenCount() == 2);
> +
> +    ClosingRequestHandler handler1 = new ClosingRequestHandler();
> +    handler1.inform( core );
> +
> +    String path = "/this/is A path /that won't be registered!";
> +    SolrRequestHandler old = core.registerRequestHandler( path, handler1 );
> +    assertNull( old ); // should not be anything...
> +    assertEquals( core.getRequestHandlers().get( path ), handler1 );
> +
> +    SolrCore c2 = cores.getCore("");
> +    c1.close();
> +    assertTrue("Refcount < 1", core.getOpenCount() >= 1);
> +    assertTrue("Handler is closed", handler1.closed == false);
> +
> +    c1 = cores.getCore("");
> +    assertTrue("Refcount < 2", core.getOpenCount() >= 2);
> +    assertTrue("Handler is closed", handler1.closed == false);
> +
> +    c2.close();
> +    assertTrue("Refcount < 1", core.getOpenCount() >= 1);
> +    assertTrue("Handler is closed", handler1.closed == false);
> +
> +    c1.close();
> +    cores.shutdown();
> +    assertTrue("Refcount != 0", core.getOpenCount() == 0);
> +    assertTrue("Handler not closed", core.isClosed() && handler1.closed == true);
> +  }
> +
> +
> +  public void testRefCountMT() throws Exception {
> +    SolrCore core = h.getCore();
> +    assertTrue("Refcount != 1", core.getOpenCount() == 1);
> +
> +    final ClosingRequestHandler handler1 = new ClosingRequestHandler();
> +    handler1.inform(core);
> +    String path = "/this/is A path /that won't be registered!";
> +    SolrRequestHandler old = core.registerRequestHandler(path, handler1);
> +    assertNull(old); // should not be anything...
> +    assertEquals(core.getRequestHandlers().get(path), handler1);
> +
> +    final int LOOP = 100;
> +    final int MT = 16;
> +    ExecutorService service = Executors.newFixedThreadPool(MT);
> +    List<Callable<Integer>> callees = new ArrayList<Callable<Integer>>(MT);
> +    final CoreContainer cores = h.getCoreContainer();
> +    for (int i = 0; i < MT; ++i) {
> +      Callable<Integer> call = new Callable<Integer>() {
> +        void yield(int n) {
> +          try {
> +            Thread.sleep(0, (n % 13 + 1) * 10);
> +          } catch (InterruptedException xint) {
> +          }
> +        }
> +
> +        public Integer call() {
> +          SolrCore core = null;
> +          int r = 0;
> +          try {
> +            for (int l = 0; l < LOOP; ++l) {
> +              r += 1;
> +              core = cores.getCore("");
> +              // sprinkle concurrency hinting...
> +              yield(l);
> +              assertTrue("Refcount < 1", core.getOpenCount() >= 1);
> +              yield(l);
> +              assertTrue("Refcount > 17", core.getOpenCount() <= 17);
> +              yield(l);
> +              assertTrue("Handler is closed", handler1.closed == false);
> +              yield(l);
> +              core.close();
> +              core = null;
> +              yield(l);
> +            }
> +            return r;
> +          } finally {
> +            if (core != null)
> +              core.close();
> +          }
> +        }
> +      };
> +      callees.add(call);
> +    }
> +
> +    List<Future<Integer>> results = service.invokeAll(callees);
> +    for (Future<Integer> result : results) {
> +      assertTrue("loop=" + result.get() +" < " + LOOP, result.get() >= LOOP);
> +    }
> +
> +    cores.shutdown();
> +    assertTrue("Refcount != 0", core.getOpenCount() == 0);
> +    assertTrue("Handler not closed", core.isClosed() && handler1.closed == true);
> +
> +    service.shutdown();
> +    assertTrue("Running for too long...", service.awaitTermination(60, TimeUnit.SECONDS));
> +  }
>  }
>
> +
> +
>  class ClosingRequestHandler extends EmptyRequestHandler implements SolrCoreAware {
>   boolean closed = false;
>
>
> Modified: lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java (original)
> +++ lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java Mon Aug 18 08:08:28 2008
> @@ -285,6 +285,9 @@
>         if( solrReq != null ) {
>           solrReq.close();
>         }
> +        if (core != null) {
> +          core.close();
> +        }
>       }
>     }
>
>
> Modified: lucene/solr/trunk/src/webapp/web/admin/index.jsp
> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/web/admin/index.jsp?rev=686780&r1=686779&r2=686780&view=diff
> ==============================================================================
> --- lucene/solr/trunk/src/webapp/web/admin/index.jsp (original)
> +++ lucene/solr/trunk/src/webapp/web/admin/index.jsp Mon Aug 18 08:08:28 2008
> @@ -21,6 +21,8 @@
>  <%-- $Name:  $ --%>
>
>  <%@ page import="java.util.Date" %>
> +<%@ page import="java.util.List" %>
> +<%@ page import="java.util.Collection" %>
>
>  <%-- jsp:include page="header.jsp"/ --%>
>  <%-- do a verbatim include so we can use the local vars --%>
> @@ -52,15 +54,12 @@
>  </tr>
>
>  <%-- List the cores (that arent this one) so we can switch --%>
> -<% org.apache.solr.core.CoreContainer multicore = (org.apache.solr.core.CoreContainer)request.getAttribute("org.apache.solr.CoreContainer");
> -  if (multicore!=null) {
> -  java.util.Collection<SolrCore> cores = multicore.getCores();
> -if (cores.size() > 1) {%><tr><td><strong>Cores:</strong><br></td><td><%
> -  java.util.Iterator<SolrCore> icore = cores.iterator();
> -  while (icore.hasNext()) {
> -    SolrCore acore = icore.next();
> -    if (acore == core) continue;
> -    %>[<a href="../../<%=acore.getName()%>/admin/"><%=acore.getName()%></a>]<%
> +<% org.apache.solr.core.CoreContainer cores = (org.apache.solr.core.CoreContainer)request.getAttribute("org.apache.solr.CoreContainer");
> +  if (cores!=null) {
> +    Collection<String> names = cores.getCoreNames();
> +    if (names.size() > 1) {%><tr><td><strong>Cores:</strong><br></td><td><%
> +    for (String name : names) {
> +    %>[<a href="../../<%=name%>/admin/"><%=name%></a>]<%
>   }%></td></tr><%
>  }}%>
>
>
>
>



-- 
--Noble Paul

Re: svn commit: r686780 - in /lucene/solr/trunk: ./ client/java/solrj/src/org/apache/solr/client/solrj/embedded/ client/java/solrj/test/org/apache/solr/client/solrj/embedded/ src/java/org/apache/solr/core/ src/java/org/apache/solr/handler/admin/ src/

Posted by Yonik Seeley <yo...@apache.org>.
On Mon, Aug 18, 2008 at 11:31 AM, Noble Paul നോബിള്‍ नोब्ळ्
<no...@gmail.com> wrote:
> do we really need the get to be synchronized (as I posted on the issue) ?

Yes, it would not be thread safe without it.

Things *could* be written in a lockless manner, but more would have to
change (i.e. we can't just remove "synchronized")

-Yonik


> On Mon, Aug 18, 2008 at 8:38 PM,  <yo...@apache.org> wrote:
>> Author: yonik
>> Date: Mon Aug 18 08:08:28 2008
>> New Revision: 686780
>>
>> URL: http://svn.apache.org/viewvc?rev=686780&view=rev
>> Log:
>> SOLR-647: refcount cores
>>
>> Modified:
>>    lucene/solr/trunk/CHANGES.txt
>>    lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
>>    lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java
>>    lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java
>>    lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
>>    lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java
>>    lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java
>>    lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
>>    lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java
>>    lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java
>>    lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java
>>    lucene/solr/trunk/src/webapp/web/admin/index.jsp
>>
>> Modified: lucene/solr/trunk/CHANGES.txt
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/CHANGES.txt?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/CHANGES.txt (original)
>> +++ lucene/solr/trunk/CHANGES.txt Mon Aug 18 08:08:28 2008
>> @@ -358,6 +358,9 @@
>>    1.3 release.  Speciffically, solr.xml has replaced multicore.xml, and uses a slightly
>>    different syntax.  The solrj classes: MultiCore{Request/Response/Params} have been
>>    renamed:  CoreAdmin{Request/Response/Params}  (hossman, ryan, Henri Biestro)
>> +
>> + 3. SOLR-647: reference count the SolrCore uses to prevent a premature
>> +    close while a core is still in use.  (Henri Biestro, Noble Paul, yonik)
>>
>>  Optimizations
>>  1. SOLR-276: improve JSON writer speed. (yonik)
>>
>> Modified: lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java (original)
>> +++ lucene/solr/trunk/client/java/solrj/src/org/apache/solr/client/solrj/embedded/EmbeddedSolrServer.java Mon Aug 18 08:08:28 2008
>> @@ -36,6 +36,7 @@
>>  import org.apache.solr.common.util.NamedList;
>>  import org.apache.solr.core.CoreContainer;
>>  import org.apache.solr.core.SolrCore;
>> +import org.apache.solr.core.CoreDescriptor;
>>  import org.apache.solr.request.BinaryResponseWriter;
>>  import org.apache.solr.request.QueryResponseWriter;
>>  import org.apache.solr.request.SolrQueryRequest;
>> @@ -54,38 +55,46 @@
>>  */
>>  public class EmbeddedSolrServer extends SolrServer
>>  {
>> -
>> -  protected final CoreContainer multicore; // either cores
>> -  protected final SolrCore core; // or single core
>> -  protected final String coreName;  // use CoreContainer registry
>> -
>> +  protected final CoreContainer coreContainer;
>> +  protected final String coreName;
>>   private final SolrRequestParsers _parser;
>>
>> +  /**
>> +   * Use the other constructor using a CoreContainer and a name.
>> +   * @param core
>> +   * @deprecated
>> +   */
>> +  @Deprecated
>>   public EmbeddedSolrServer( SolrCore core )
>>   {
>>     if ( core == null ) {
>>       throw new NullPointerException("SolrCore instance required");
>>     }
>> -    this.core = core;
>> -    if (core.getCoreDescriptor() != null) {
>> -      this.multicore = core.getCoreDescriptor().getMultiCore();
>> -      this.coreName = core.getCoreDescriptor().getName();
>> -    } else {
>> -      this.multicore = null;
>> -      this.coreName = null;
>> -    }
>> +    CoreDescriptor dcore = core.getCoreDescriptor();
>> +    if (dcore == null)
>> +      throw new NullPointerException("CoreDescriptor required");
>> +
>> +    CoreContainer cores = dcore.getCoreContainer();
>> +    if (cores == null)
>> +      throw new NullPointerException("CoreContainer required");
>> +
>> +    coreName = dcore.getName();
>> +    coreContainer = cores;
>>     _parser = new SolrRequestParsers( null );
>>   }
>>
>> -  public EmbeddedSolrServer(  CoreContainer multicore, String coreName )
>> +  /**
>> +   * Creates a SolrServer.
>> +   * @param coreContainer the core container
>> +   * @param coreName the core name
>> +   */
>> +  public EmbeddedSolrServer(  CoreContainer coreContainer, String coreName )
>>   {
>> -    if ( multicore == null ) {
>> +    if ( coreContainer == null ) {
>>       throw new NullPointerException("CoreContainer instance required");
>>     }
>> -    this.core = null;
>> -    this.multicore = multicore;
>> +    this.coreContainer = coreContainer;
>>     this.coreName = coreName == null? "" : coreName;
>> -
>>     _parser = new SolrRequestParsers( null );
>>   }
>>
>> @@ -98,15 +107,10 @@
>>     }
>>
>>     // Check for cores action
>> -    SolrCore core = this.core;
>> -    if( core == null )
>> -      core = multicore.getCore( coreName );
>> -    // solr-647
>> -    //else
>> -    //  core = core.open();
>> +    SolrCore core =  coreContainer.getCore( coreName );
>>     if( core == null ) {
>>       throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,
>> -          coreName == null? "No core": "No such core: " + coreName );
>> +                               "No such core: " + coreName );
>>     }
>>
>>     SolrParams params = request.getParams();
>> @@ -126,14 +130,13 @@
>>       }
>>       // Perhaps the path is to manage the cores
>>       if( handler == null &&
>> -          multicore != null &&
>> -          path.equals( multicore.getAdminPath() ) ) {
>> -        handler = multicore.getMultiCoreHandler();
>> +          coreContainer != null &&
>> +          path.equals( coreContainer.getAdminPath() ) ) {
>> +        handler = coreContainer.getMultiCoreHandler();
>>       }
>>     }
>>     if( handler == null ) {
>> -      // solr-647
>> -      // core.close();
>> +      core.close();
>>       throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "unknown handler: "+path );
>>     }
>>
>> @@ -158,8 +161,7 @@
>>       throw new SolrServerException( ex );
>>     }
>>     finally {
>> -      // solr-647
>> -      // core.close();
>> +      core.close();
>>     }
>>   }
>>
>>
>> Modified: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java (original)
>> +++ lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/LargeVolumeEmbeddedTest.java Mon Aug 18 08:08:28 2008
>> @@ -45,6 +45,6 @@
>>   @Override
>>   protected SolrServer createNewSolrServer()
>>   {
>> -    return new EmbeddedSolrServer( h.getCore() );
>> +    return new EmbeddedSolrServer( h.getCoreContainer(), "" );
>>   }
>>  }
>>
>> Modified: lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java (original)
>> +++ lucene/solr/trunk/client/java/solrj/test/org/apache/solr/client/solrj/embedded/SolrExampleEmbeddedTest.java Mon Aug 18 08:08:28 2008
>> @@ -47,6 +47,6 @@
>>   @Override
>>   protected SolrServer createNewSolrServer()
>>   {
>> -    return new EmbeddedSolrServer( h.getCore() );
>> +    return new EmbeddedSolrServer( h.getCoreContainer(), "" );
>>   }
>>  }
>>
>> Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java (original)
>> +++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreContainer.java Mon Aug 18 08:08:28 2008
>> @@ -25,9 +25,7 @@
>>  import java.io.OutputStreamWriter;
>>  import java.io.Writer;
>>  import java.nio.channels.FileChannel;
>> -import java.util.Collection;
>> -import java.util.LinkedHashMap;
>> -import java.util.Map;
>> +import java.util.*;
>>  import java.util.logging.Logger;
>>
>>  import javax.xml.parsers.ParserConfigurationException;
>> @@ -36,6 +34,7 @@
>>  import org.apache.solr.common.SolrException;
>>  import org.apache.solr.common.util.DOMUtil;
>>  import org.apache.solr.common.util.XML;
>> +import org.apache.solr.common.util.StrUtils;
>>  import org.apache.solr.handler.admin.CoreAdminHandler;
>>  import org.apache.solr.schema.IndexSchema;
>>  import org.w3c.dom.Node;
>> @@ -51,7 +50,7 @@
>>  {
>>   protected static Logger log = Logger.getLogger(CoreContainer.class.getName());
>>
>> -  protected final Map<String, CoreDescriptor> cores = new LinkedHashMap<String, CoreDescriptor>();
>> +  protected final Map<String, SolrCore> cores = new LinkedHashMap<String, SolrCore>();
>>   protected boolean persistent = false;
>>   protected String adminPath = null;
>>   protected String managementPath = null;
>> @@ -69,8 +68,7 @@
>>   public static class Initializer {
>>     protected String solrConfigFilename = null;
>>     protected boolean abortOnConfigurationError = true;
>> -    protected String managementPath = null;
>> -
>> +
>>     public boolean isAbortOnConfigurationError() {
>>       return abortOnConfigurationError;
>>     }
>> @@ -86,14 +84,6 @@
>>     public void setSolrConfigFilename(String solrConfigFilename) {
>>       this.solrConfigFilename = solrConfigFilename;
>>     }
>> -
>> -    public String getManagementPath() {
>> -      return managementPath;
>> -    }
>> -
>> -    public void setManagementPath(String managementPath) {
>> -      this.managementPath = managementPath;
>> -    }
>>
>>     // core container instantiation
>>     public CoreContainer initialize() throws IOException, ParserConfigurationException, SAXException {
>> @@ -116,16 +106,13 @@
>>         solrConfigFilename = cores.getConfigFile().getName();
>>       } else {
>>         // perform compatibility init
>> -        cores = new CoreContainer();
>> -        cores.loader = new SolrResourceLoader(instanceDir);
>> +        cores = new CoreContainer(new SolrResourceLoader(instanceDir));
>>         SolrConfig cfg = solrConfigFilename == null ? new SolrConfig() : new SolrConfig(solrConfigFilename);
>> -        CoreDescriptor dcore = new CoreDescriptor(cores);
>> -        dcore.init("", cfg.getResourceLoader().getInstanceDir());
>> +        CoreDescriptor dcore = new CoreDescriptor(cores, "", cfg.getResourceLoader().getInstanceDir());
>>         SolrCore singlecore = new SolrCore(null, null, cfg, null, dcore);
>> -        dcore.setCore(singlecore);
>>         abortOnConfigurationError = cfg.getBool(
>>                 "abortOnConfigurationError", abortOnConfigurationError);
>> -        cores.register(dcore);
>> +        cores.register("", singlecore, false);
>>         cores.setPersistent(false);
>>         solrConfigFilename = cfg.getName();
>>       }
>> @@ -147,6 +134,14 @@
>>     this.load(dir, configFile);
>>   }
>>
>> +  /**
>> +   * Minimal CoreContainer constructor.
>> +   * @param loader the CoreContainer resource loader
>> +   */
>> +  public CoreContainer(SolrResourceLoader loader) {
>> +    this.loader = loader;
>> +  }
>> +
>>   //-------------------------------------------------------------------
>>   // Initialization / Cleanup
>>   //-------------------------------------------------------------------
>> @@ -165,54 +160,60 @@
>>     FileInputStream cfgis = new FileInputStream(configFile);
>>     try {
>>       Config cfg = new Config(loader, null, cfgis, null);
>> -
>> +
>>       persistent = cfg.getBool( "solr/@persistent", false );
>>       libDir     = cfg.get(     "solr/@sharedLib", null);
>>       adminPath  = cfg.get(     "solr/cores/@adminPath", null );
>>       managementPath  = cfg.get("solr/cores/@managementPath", null );
>> -
>> +
>>       if (libDir != null) {
>>         // relative dir to conf
>>         File f = new File(dir, libDir);
>> -        libDir = f.getPath();
>> +        libDir = f.getPath();
>>         log.info( "loading shared library: "+f.getAbsolutePath() );
>>         libLoader = SolrResourceLoader.createClassLoader(f, null);
>>       }
>> -
>> +
>>       if( adminPath != null ) {
>>         coreAdminHandler = this.createMultiCoreHandler();
>>       }
>> -
>> +
>>       NodeList nodes = (NodeList)cfg.evaluate("solr/cores/core", XPathConstants.NODESET);
>> -      synchronized (cores) {
>> -        for (int i=0; i<nodes.getLength(); i++) {
>> -          Node node = nodes.item(i);
>> -          try {
>> -            CoreDescriptor p = new CoreDescriptor(this);
>> -            p.init(DOMUtil.getAttr(node, "name", null), DOMUtil.getAttr(node, "instanceDir", null));
>> -            // deal with optional settings
>> -            String opt = DOMUtil.getAttr(node, "config", null);
>> -            if (opt != null) {
>> -              p.setConfigName(opt);
>> -            }
>> -            opt = DOMUtil.getAttr(node, "schema", null);
>> -            if (opt != null) {
>> -              p.setSchemaName(opt);
>> -            }
>> -            CoreDescriptor old = cores.get(p.getName());
>> -            if (old != null && old.getName() != null && old.getName().equals(p.getName())) {
>> -              throw new RuntimeException( cfg.getName() +
>> -                " registers multiple cores to the same name: " + p.name);
>> -            }
>> -            p.setCore(create(p));
>> +
>> +      for (int i=0; i<nodes.getLength(); i++) {
>> +        Node node = nodes.item(i);
>> +        try {
>> +          String names = DOMUtil.getAttr(node, "name", null);
>> +          List<String> aliases = StrUtils.splitSmart(names,',');
>> +          String name = aliases.get(0);
>> +          CoreDescriptor p = new CoreDescriptor(this, name, DOMUtil.getAttr(node, "instanceDir", null));
>> +
>> +          // deal with optional settings
>> +          String opt = DOMUtil.getAttr(node, "config", null);
>> +          if (opt != null) {
>> +            p.setConfigName(opt);
>>           }
>> -          catch (Throwable ex) {
>> -            SolrConfig.severeErrors.add( ex );
>> -            SolrException.logOnce(log,null,ex);
>> +          opt = DOMUtil.getAttr(node, "schema", null);
>> +          if (opt != null) {
>> +            p.setSchemaName(opt);
>>           }
>> +
>> +          SolrCore core = create(p);
>> +
>> +          for (int a=1; a<aliases.size(); a++) {
>> +            core.open();
>> +            register(aliases.get(i), core, false);
>> +          }
>> +
>> +          register(name, core, false);
>> +        }
>> +        catch (Throwable ex) {
>> +          SolrConfig.severeErrors.add( ex );
>> +          SolrException.logOnce(log,null,ex);
>>         }
>>       }
>>     }
>> +
>>     finally {
>>       if (cfgis != null) {
>>         try { cfgis.close(); } catch (Exception xany) {}
>> @@ -225,11 +226,8 @@
>>    */
>>   public void shutdown() {
>>     synchronized(cores) {
>> -      for(CoreDescriptor descriptor : cores.values()) {
>> -        SolrCore core = descriptor.getCore();
>> -        if( core != null ) {
>> -          core.close();
>> -        }
>> +      for(SolrCore core : cores.values()) {
>> +        core.close();
>>       }
>>       cores.clear();
>>     }
>> @@ -239,40 +237,44 @@
>>   protected void finalize() {
>>     shutdown();
>>   }
>> -
>> -  // ---------------- CoreDescriptor related methods ---------------
>> +
>>   /**
>>    * Registers a SolrCore descriptor in the registry.
>> -   * @param descr the Solr core descriptor
>> -   * @return a previous descriptor having the same name if it existed, null otherwise
>> +   * @return a previous core having the same name if it existed and returnPrev==true
>>    */
>> -  public CoreDescriptor register( CoreDescriptor descr ) {
>> -    if( descr == null ) {
>> +  public SolrCore register(String name, SolrCore core, boolean returnPrev) {
>> +    if( core == null ) {
>>       throw new RuntimeException( "Can not register a null core." );
>>     }
>> -    String name = descr.getName();
>> -    if( name == null ||
>> +    if( name == null ||
>>         name.indexOf( '/'  ) >= 0 ||
>>         name.indexOf( '\\' ) >= 0 ){
>>       throw new RuntimeException( "Invalid core name: "+name );
>>     }
>>
>> -    CoreDescriptor old = null;
>> +    SolrCore old = null;
>>     synchronized (cores) {
>> -      old = cores.put(name, descr);
>> +      old = cores.put(name, core);
>> +      core.setName(name);
>>     }
>> -    if( old == null ) {
>> +
>> +
>> +    if( old == null || old == core) {
>>       log.info( "registering core: "+name );
>>       return null;
>> -    }
>> +    }
>>     else {
>>       log.info( "replacing core: "+name );
>> +      if (!returnPrev) {
>> +        old.close();
>> +      }
>>       return old;
>>     }
>>   }
>>
>> +
>>   /**
>> -   * Creates a new core based on a descriptor.
>> +   * Creates a new core based on a descriptor but does not register it.
>>    *
>>    * @param dcore a core descriptor
>>    * @return the newly created core
>> @@ -293,10 +295,6 @@
>>     SolrConfig config = new SolrConfig(solrLoader, dcore.getConfigName(), null);
>>     IndexSchema schema = new IndexSchema(config, dcore.getSchemaName(), null);
>>     SolrCore core = new SolrCore(dcore.getName(), null, config, schema, dcore);
>> -    dcore.setCore(core);
>> -
>> -    // Register the new core
>> -    CoreDescriptor old = this.register(dcore);
>>     return core;
>>   }
>>
>> @@ -304,37 +302,39 @@
>>    * @return a Collection of registered SolrCores
>>    */
>>   public Collection<SolrCore> getCores() {
>> -    java.util.List<SolrCore> l = new java.util.ArrayList<SolrCore>();
>> +    List<SolrCore> lst = new ArrayList<SolrCore>();
>>     synchronized (cores) {
>> -      for(CoreDescriptor descr : this.cores.values()) {
>> -        if (descr.getCore() != null)
>> -          l.add(descr.getCore());
>> -      }
>> +      lst.addAll(this.cores.values());
>>     }
>> -    return l;
>> +    return lst;
>>   }
>> -
>> +
>>   /**
>> -   * @return a Collection of registered CoreDescriptors
>> +   * @return a Collection of the names that cores are mapped to
>>    */
>> -  public Collection<CoreDescriptor> getDescriptors() {
>> -   java.util.List<CoreDescriptor> l = new java.util.ArrayList<CoreDescriptor>();
>> -   synchronized (cores) {
>> -     l.addAll(cores.values());
>> -   }
>> -   return l;
>> +  public Collection<String> getCoreNames() {
>> +    List<String> lst = new ArrayList<String>();
>> +    synchronized (cores) {
>> +      lst.addAll(this.cores.keySet());
>> +    }
>> +    return lst;
>>   }
>>
>>   /**
>> -   * @return the CoreDescriptor registered under that name
>> +   * @return a Collection of the names that a specific core is mapped to.
>>    */
>> -  public CoreDescriptor getDescriptor(String name) {
>> -    synchronized(cores) {
>> -      return cores.get( name );
>> +  public Collection<String> getCoreNames(SolrCore core) {
>> +    List<String> lst = new ArrayList<String>();
>> +    synchronized (cores) {
>> +      for (Map.Entry<String,SolrCore> entry : cores.entrySet()) {
>> +        if (core == entry.getValue()) {
>> +          lst.add(entry.getKey());
>> +        }
>> +      }
>>     }
>> +    return lst;
>>   }
>> -
>> -
>> +
>>   // ---------------- Core name related methods ---------------
>>   /**
>>    * Recreates a SolrCore.
>> @@ -348,12 +348,14 @@
>>    */
>>
>>   public void reload(String name) throws ParserConfigurationException, IOException, SAXException {
>> +    SolrCore core;
>>     synchronized(cores) {
>> -      CoreDescriptor dcore = cores.get(name);
>> -      if (dcore == null)
>> -        throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
>> -      create(new CoreDescriptor(dcore));
>> +      core = cores.get(name);
>>     }
>> +    if (core == null)
>> +      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + name );
>> +
>> +    register(name, create(core.getCoreDescriptor()), false);
>>   }
>>
>>
>> @@ -367,36 +369,27 @@
>>       throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Can not swap unnamed cores." );
>>     }
>>     synchronized( cores ) {
>> -      CoreDescriptor c0 = cores.get(n0);
>> +      SolrCore c0 = cores.get(n0);
>> +      SolrCore c1 = cores.get(n1);
>>       if (c0 == null)
>>         throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n0 );
>> -      CoreDescriptor c1 = cores.get(n1);
>>       if (c1 == null)
>>         throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "No such core: " + n1 );
>>       cores.put(n0, c1);
>>       cores.put(n1, c0);
>> -      c0.setName( n1 );
>> -      if (c0.getCore() != null)
>> -        c0.getCore().setName(n1);
>> -      c1.setName( n0 );
>> -      if (c1.getCore() != null)
>> -        c1.getCore().setName(n0);
>> -      log.info( "swaped: "+c0.getName() + " with " + c1.getName() );
>> +
>> +      c0.setName(n1);
>> +      c1.setName(n0);
>>     }
>> +
>> +
>> +    log.info("swaped: "+n0 + " with " + n1);
>>   }
>>
>> -  /** Removes & closes a registered core. */
>> -  public void remove( String name ) {
>> +  /** Removes and returns registered core w/o decrementing it's reference count */
>> +  public SolrCore remove( String name ) {
>>     synchronized(cores) {
>> -      CoreDescriptor dcore = cores.remove( name );
>> -      if (dcore == null) {
>> -        return;
>> -      }
>> -
>> -      SolrCore core = dcore.getCore();
>> -      if (core != null) {
>> -        core.close();
>> -      }
>> +      return cores.remove( name );
>>     }
>>   }
>>
>> @@ -408,15 +401,10 @@
>>    */
>>   public SolrCore getCore(String name) {
>>     synchronized(cores) {
>> -      CoreDescriptor dcore = cores.get(name);
>> -       SolrCore core = null;
>> -      if (dcore != null)
>> -        core = dcore.getCore();
>> -       return core;
>> -// solr-647
>> -//      if (core != null)
>> -//        return core.open();
>> -//      return null;
>> +      SolrCore core = cores.get(name);
>> +      if (core != null)
>> +        core.open();  // increment the ref count while still synchronized
>> +      return core;
>>     }
>>   }
>>
>> @@ -433,20 +421,17 @@
>>    * Ensures there is a valid core to handle MultiCore admin taks and
>>    * increase its refcount.
>>    * @return the acquired admin core, null if no core is available
>> -   */
>> +   */
>>   public SolrCore getAdminCore() {
>>     synchronized (cores) {
>>       SolrCore core = adminCore != null ? adminCore.get() : null;
>> -//      solr-647
>> -//      if (core != null)
>> -//        core = core.open();
>> -      if (core == null) {
>> -        for (CoreDescriptor descr : this.cores.values()) {
>> -          core = descr.getCore();
>> -//          solr-647
>> -//          if (core != null)
>> -//            core = core.open();
>> -          if (core != null) {
>> +      if (core != null) {
>> +        core.open();
>> +      } else {
>> +        for (SolrCore c : cores.values()) {
>> +          if (c != null) {
>> +            core = c;
>> +            core.open();
>>             break;
>>           }
>>         }
>> @@ -517,7 +502,7 @@
>>   public void persist() {
>>     persistFile(null);
>>   }
>> -
>> +
>>   /** Persists the cores config file in a user provided file. */
>>   public void persistFile(File file) {
>>     File tmpFile = null;
>> @@ -527,7 +512,6 @@
>>         file = tmpFile = File.createTempFile("solr", ".xml", configFile.getParentFile());
>>       }
>>       java.io.FileOutputStream out = new java.io.FileOutputStream(file);
>> -      synchronized(cores) {
>>         Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
>>         persist(writer);
>>         writer.flush();
>> @@ -540,7 +524,6 @@
>>           else
>>             fileCopy(tmpFile, configFile);
>>         }
>> -      }
>>     }
>>     catch(java.io.FileNotFoundException xnf) {
>>       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, xnf);
>> @@ -578,20 +561,35 @@
>>     writer.write('\'');
>>     writer.write(">\n");
>>
>> +    Map<SolrCore, LinkedList<String>> aliases = new HashMap<SolrCore,LinkedList<String>>();
>> +
>>     synchronized(cores) {
>> -      for (Map.Entry<String, CoreDescriptor> entry : cores.entrySet()) {
>> -        persist(writer, entry.getValue());
>> +      for (Map.Entry<String, SolrCore> entry : cores.entrySet()) {
>> +        String name = entry.getKey();
>> +        LinkedList<String> a = aliases.get(entry.getValue());
>> +        if (a==null) a = new LinkedList<String>();
>> +        if (name.equals(entry.getValue().getName())) {
>> +          a.addFirst(name);
>> +        } else {
>> +          a.addLast(name);
>> +        }
>> +        aliases.put(entry.getValue(), a);
>>       }
>>     }
>> +
>> +    for (Map.Entry<SolrCore, LinkedList<String>> entry : aliases.entrySet()) {
>> +      persist(writer, entry.getValue(), entry.getKey().getCoreDescriptor());
>> +    }
>> +
>>     writer.write("</cores>\n");
>>     writer.write("</solr>\n");
>>   }
>>
>>   /** Writes the cores configuration node for a given core. */
>> -  void persist(Writer writer, CoreDescriptor dcore) throws IOException {
>> +  void persist(Writer writer, List<String> aliases, CoreDescriptor dcore) throws IOException {
>>     writer.write("  <core");
>>     writer.write (" name='");
>> -    XML.escapeAttributeValue(dcore.getName(), writer);
>> +    XML.escapeAttributeValue(StrUtils.join(aliases,','), writer);
>>     writer.write("' instanceDir='");
>>     XML.escapeAttributeValue(dcore.getInstanceDir(), writer);
>>     writer.write('\'');
>>
>> Modified: lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java (original)
>> +++ lucene/solr/trunk/src/java/org/apache/solr/core/CoreDescriptor.java Mon Aug 18 08:08:28 2008
>> @@ -28,22 +28,17 @@
>>   protected String instanceDir;
>>   protected String configName;
>>   protected String schemaName;
>> -  protected SolrCore core = null;
>>   private final CoreContainer coreContainer;
>>
>> -  public CoreDescriptor(CoreContainer coreContainer) {
>> +  public CoreDescriptor(CoreContainer coreContainer, String name, String instanceDir) {
>>     this.coreContainer = coreContainer;
>> -  }
>> -
>> -  /** Initialize defaults from instance directory. */
>> -  public void init(String name, String instanceDir) {
>> +    this.name = name;
>>     if (name == null) {
>>       throw new RuntimeException("Core needs a name");
>>     }
>>     if (instanceDir == null) {
>>       throw new NullPointerException("Missing required \'instanceDir\'");
>>     }
>> -    this.name = name;
>>     if (!instanceDir.endsWith("/")) instanceDir = instanceDir + "/";
>>     this.instanceDir = instanceDir;
>>     this.configName = getDefaultConfigName();
>> @@ -51,10 +46,10 @@
>>   }
>>
>>   public CoreDescriptor(CoreDescriptor descr) {
>> -    this.name = descr.name;
>>     this.instanceDir = descr.instanceDir;
>>     this.configName = descr.configName;
>>     this.schemaName = descr.schemaName;
>> +    this.name = descr.name;
>>     coreContainer = descr.coreContainer;
>>   }
>>
>> @@ -72,17 +67,7 @@
>>   public String getDefaultDataDir() {
>>     return this.instanceDir + "data/";
>>   }
>> -
>> -  /**@return the core name. */
>> -  public String getName() {
>> -    return name;
>> -  }
>> -
>> -  /** Sets the core name. */
>> -  public void setName(String name) {
>> -    this.name = name;
>> -  }
>> -
>> +
>>   /**@return the core instance directory. */
>>   public String getInstanceDir() {
>>     return instanceDir;
>> @@ -111,16 +96,13 @@
>>   public String getSchemaName() {
>>     return this.schemaName;
>>   }
>> -
>> -  public SolrCore getCore() {
>> -    return core;
>> -  }
>> -
>> -  public void setCore(SolrCore core) {
>> -    this.core = core;
>> +
>> +  /**@return the initial core name */
>> +  public String getName() {
>> +    return this.name;
>>   }
>>
>> -  public CoreContainer getMultiCore() {
>> +  public CoreContainer getCoreContainer() {
>>     return coreContainer;
>>   }
>>  }
>>
>> Modified: lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java (original)
>> +++ lucene/solr/trunk/src/java/org/apache/solr/core/SolrCore.java Mon Aug 18 08:08:28 2008
>> @@ -62,13 +62,15 @@
>>  import java.io.IOException;
>>  import java.util.*;
>>  import java.util.concurrent.*;
>> +import java.util.concurrent.atomic.AtomicInteger;
>>  import java.util.logging.Logger;
>> +import java.net.URL;
>>
>>
>>  /**
>>  * @version $Id$
>>  */
>> -public final class SolrCore {
>> +public final class SolrCore implements SolrInfoMBean {
>>   public static final String version="1.0";
>>
>>   public static Logger log = Logger.getLogger(SolrCore.class.getName());
>> @@ -374,7 +376,7 @@
>>    * @since solr 1.0
>>    */
>>   public SolrCore(String dataDir, IndexSchema schema) throws ParserConfigurationException, IOException, SAXException {
>> -    this( null, dataDir, new SolrConfig(), schema, null );
>> +    this(null, dataDir, new SolrConfig(), schema, null );
>>   }
>>
>>   /**
>> @@ -479,8 +481,9 @@
>>         latch.countDown();
>>       }
>>     } // end synchronized
>> +
>> +    infoRegistry.put("core", this);
>>   }
>> -
>>
>>
>>   /**
>> @@ -569,16 +572,39 @@
>>     }
>>     return chain;
>>   }
>> +
>> +  // this core current usage count
>> +  private final AtomicInteger refCount = new AtomicInteger(1);
>>
>> +  final void open() {
>> +    refCount.incrementAndGet();
>> +  }
>> +
>>   /**
>>    * Close all resources allocated by the core.
>>    *  1. searcher
>>    *  2. updateHandler
>>    *  3. all CloseHooks will be notified
>>    *  4. All MBeans will be unregistered from MBeanServer if JMX was enabled
>> +   * <p>
>> +   * This should always be called when the core is obtained through:
>> +   * @see CoreContainer.getCore
>> +   * @see CoreContainer.getAdminCore
>> +   * </p>
>> +   * The actual close is performed if the core usage count is 1.
>> +   * (A core is created with a usage count of 1).
>> +   * If usage count is > 1, the usage count is decreased by 1.
>> +   * If usage count is &lt; 0, this is an error and a runtime exception is thrown.
>>    */
>>   public void close() {
>> -    log.info(logid+" CLOSING SolrCore!");
>> +    int count = refCount.decrementAndGet();
>> +    if (count > 0) return;
>> +    if (count < 0) {
>> +      //throw new RuntimeException("Too many closes on " + this);
>> +      log.severe("Too many close {count:"+count+"} on " + this + ". Please report this exception to solr-user@lucene.apache.org");
>> +      return;
>> +    }
>> +    log.info(logid+" CLOSING SolrCore " + this);
>>     try {
>>       infoRegistry.clear();
>>     } catch (Exception e) {
>> @@ -602,16 +628,22 @@
>>     if( closeHooks != null ) {
>>        for( CloseHook hook : closeHooks ) {
>>          hook.close( this );
>> -       }
>> +      }
>>     }
>>   }
>>
>> +  /** Current core usage count. */
>> +  public int getOpenCount() {
>> +    return refCount.get();
>> +  }
>> +
>> +  /** Whether this core is closed. */
>>   public boolean isClosed() {
>> -    return _searcher == null;
>> +      return refCount.get() <= 0;
>>   }
>>
>> -  @Override
>> -  protected void finalize() { close(); }
>> +  // this can cause an extra close
>> +  // protected void finalize() { close(); }
>>
>>   private List<CloseHook> closeHooks = null;
>>
>> @@ -1380,6 +1412,45 @@
>>   public CoreDescriptor getCoreDescriptor() {
>>     return coreDescriptor;
>>   }
>> +
>> +
>> +  /////////////////////////////////////////////////////////////////////
>> +  // SolrInfoMBean stuff: Statistics and Module Info
>> +  /////////////////////////////////////////////////////////////////////
>> +
>> +  public String getVersion() {
>> +    return SolrCore.version;
>> +  }
>> +
>> +  public String getDescription() {
>> +    return "SolrCore";
>> +  }
>> +
>> +  public Category getCategory() {
>> +    return Category.CORE;
>> +  }
>> +
>> +  public String getSourceId() {
>> +    return "$Id:$";
>> +  }
>> +
>> +  public String getSource() {
>> +    return "$URL:$";
>> +  }
>> +
>> +  public URL[] getDocs() {
>> +    return null;
>> +  }
>> +
>> +  public NamedList getStatistics() {
>> +    NamedList lst = new SimpleOrderedMap();
>> +    lst.add("coreName", name==null ? "(null)" : name);
>> +    lst.add("startTime", new Date(startTime));
>> +    lst.add("refCount", getOpenCount());
>> +    lst.add("aliases", getCoreDescriptor().getCoreContainer().getCoreNames(this));
>> +    return lst;
>> +  }
>> +
>>  }
>>
>>
>>
>> Modified: lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java (original)
>> +++ lucene/solr/trunk/src/java/org/apache/solr/handler/admin/CoreAdminHandler.java Mon Aug 18 08:08:28 2008
>> @@ -90,9 +90,8 @@
>>
>>     switch(action) {
>>       case CREATE: {
>> -        CoreDescriptor dcore = new CoreDescriptor(cores);
>> -        dcore.init(params.get(CoreAdminParams.NAME),
>> -                  params.get(CoreAdminParams.INSTANCE_DIR));
>> +        String name = params.get(CoreAdminParams.NAME);
>> +        CoreDescriptor dcore = new CoreDescriptor(cores, name, params.get(CoreAdminParams.INSTANCE_DIR));
>>
>>         // fillup optional parameters
>>         String opts = params.get(CoreAdminParams.CONFIG);
>> @@ -104,6 +103,7 @@
>>           dcore.setSchemaName(opts);
>>
>>         SolrCore core = cores.create(dcore);
>> +        cores.register(name, core,false);
>>         rsp.add("core", core.getName());
>>         do_persist = cores.isPersistent();
>>         break;
>> @@ -112,9 +112,8 @@
>>       case STATUS: {
>>         NamedList<Object> status = new SimpleOrderedMap<Object>();
>>         if( cname == null ) {
>> -          for (CoreDescriptor d : cores.getDescriptors()) {
>> -            cname = d.getName();
>> -            status.add(d.getName(), getCoreStatus( cores, cname  ) );
>> +          for (SolrCore core : cores.getCores()) {
>> +            status.add(core.getName(), getCoreStatus( cores, cname  ) );
>>           }
>>         }
>>         else {
>> @@ -172,8 +171,7 @@
>>         info.add("index", LukeRequestHandler.getIndexInfo(searcher.get().getReader(), false));
>>         searcher.decref();
>>       } finally {
>> -        // solr-647
>> -        // core.close();
>> +        core.close();
>>       }
>>     }
>>     return info;
>>
>> Modified: lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java (original)
>> +++ lucene/solr/trunk/src/java/org/apache/solr/util/TestHarness.java Mon Aug 18 08:08:28 2008
>> @@ -21,6 +21,9 @@
>>  import org.apache.solr.common.util.XML;
>>  import org.apache.solr.core.SolrConfig;
>>  import org.apache.solr.core.SolrCore;
>> +import org.apache.solr.core.CoreContainer;
>> +import org.apache.solr.core.CoreDescriptor;
>> +import org.apache.solr.core.SolrResourceLoader;
>>  import org.apache.solr.handler.XmlUpdateRequestHandler;
>>  import org.apache.solr.request.LocalSolrQueryRequest;
>>  import org.apache.solr.request.QueryResponseWriter;
>> @@ -32,6 +35,7 @@
>>
>>  import javax.xml.parsers.DocumentBuilder;
>>  import javax.xml.parsers.DocumentBuilderFactory;
>> +import javax.xml.parsers.ParserConfigurationException;
>>  import javax.xml.xpath.XPath;
>>  import javax.xml.xpath.XPathConstants;
>>  import javax.xml.xpath.XPathExpressionException;
>> @@ -60,7 +64,7 @@
>>  * @version $Id:$
>>  */
>>  public class TestHarness {
>> -
>> +  protected CoreContainer container;
>>   private SolrCore core;
>>   private XPath xpath = XPathFactory.newInstance().newXPath();
>>   private DocumentBuilder builder;
>> @@ -123,8 +127,19 @@
>>   public TestHarness( String dataDirectory,
>>                       SolrConfig solrConfig,
>>                       IndexSchema indexSchema) {
>> +      this("", new Initializer("", dataDirectory, solrConfig, indexSchema));
>> +  }
>> +
>> +  public TestHarness(String coreName, CoreContainer.Initializer init) {
>>     try {
>> -      core = new SolrCore( null, dataDirectory, solrConfig, indexSchema, null);
>> +      container = init.initialize();
>> +      if (coreName == null)
>> +        coreName = "";
>> +      // get the core & decrease its refcount:
>> +      // the container holds the core for the harness lifetime
>> +      core = container.getCore(coreName);
>> +      if (core != null)
>> +        core.close();
>>       builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
>>
>>       updater = new XmlUpdateRequestHandler();
>> @@ -133,6 +148,42 @@
>>       throw new RuntimeException(e);
>>     }
>>   }
>> +
>> +  // Creates a container based on infos needed to create one core
>> +  static class Initializer extends CoreContainer.Initializer {
>> +    String coreName;
>> +    String dataDirectory;
>> +    SolrConfig solrConfig;
>> +    IndexSchema indexSchema;
>> +    public Initializer(String coreName,
>> +                      String dataDirectory,
>> +                      SolrConfig solrConfig,
>> +                      IndexSchema indexSchema) {
>> +      if (coreName == null)
>> +        coreName = "";
>> +      this.coreName = coreName;
>> +      this.dataDirectory = dataDirectory;
>> +      this.solrConfig = solrConfig;
>> +      this.indexSchema = indexSchema;
>> +    }
>> +    public String getCoreName() {
>> +      return coreName;
>> +    }
>> +    @Override
>> +    public CoreContainer initialize() {
>> +      CoreContainer container = new CoreContainer(new SolrResourceLoader(SolrResourceLoader.locateInstanceDir()));
>> +      CoreDescriptor dcore = new CoreDescriptor(container, coreName, solrConfig.getResourceLoader().getInstanceDir());
>> +      dcore.setConfigName(solrConfig.getResourceName());
>> +      dcore.setSchemaName(indexSchema.getResourceName());
>> +      SolrCore core = new SolrCore( null, dataDirectory, solrConfig, indexSchema, dcore);
>> +      container.register(coreName, core, false);
>> +      return container;
>> +    }
>> +  }
>> +
>> +  public CoreContainer getCoreContainer() {
>> +    return container;
>> +  }
>>
>>   public SolrCore getCore() {
>>     return core;
>> @@ -152,9 +203,7 @@
>>
>>     StringReader req = new StringReader(xml);
>>     StringWriter writer = new StringWriter(32000);
>> -
>> -    // This relies on the fact that SolrCore.getSolrCore() uses the
>> -    // last instantiated SolrCore.
>> +
>>     updater.doLegacyUpdate(req, writer);
>>     return writer.toString();
>>   }
>> @@ -321,7 +370,17 @@
>>    * Shuts down and frees any resources
>>    */
>>   public void close() {
>> -    core.close();
>> +    if (container != null) {
>> +      for (SolrCore c : container.getCores()) {
>> +        if (c.getOpenCount() > 1)
>> +          throw new RuntimeException("SolrCore.getOpenCount()=="+core.getOpenCount());
>> +      }
>> +    }
>> +
>> +    if (container != null) {
>> +      container.shutdown();
>> +      container = null;
>> +    }
>>   }
>>
>>   /**
>>
>> Modified: lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java (original)
>> +++ lucene/solr/trunk/src/test/org/apache/solr/core/SolrCoreTest.java Mon Aug 18 08:08:28 2008
>> @@ -24,13 +24,14 @@
>>  import org.apache.solr.util.AbstractSolrTestCase;
>>  import org.apache.solr.util.plugin.SolrCoreAware;
>>
>> +import java.util.concurrent.*;
>> +import java.util.*;
>>  public class SolrCoreTest extends AbstractSolrTestCase {
>>
>>   public String getSchemaFile() { return "schema.xml"; }
>>   public String getSolrConfigFile() { return "solrconfig.xml"; }
>> -
>> +
>>   public void testRequestHandlerRegistry() {
>> -    // property values defined in build.xml
>>     SolrCore core = h.getCore();
>>
>>     EmptyRequestHandler handler1 = new EmptyRequestHandler();
>> @@ -46,7 +47,8 @@
>>   }
>>
>>   public void testClose() throws Exception {
>> -    SolrCore core = h.getCore();
>> +    final CoreContainer cores = h.getCoreContainer();
>> +    SolrCore core = cores.getCore("");
>>
>>     ClosingRequestHandler handler1 = new ClosingRequestHandler();
>>     handler1.inform( core );
>> @@ -56,10 +58,116 @@
>>     assertNull( old ); // should not be anything...
>>     assertEquals( core.getRequestHandlers().get( path ), handler1 );
>>     core.close();
>> +    cores.shutdown();
>>     assertTrue("Handler not closed", handler1.closed == true);
>>   }
>> +
>> +  public void testRefCount() throws Exception {
>> +    SolrCore core = h.getCore();
>> +    assertTrue("Refcount != 1", core.getOpenCount() == 1);
>> +
>> +    final CoreContainer cores = h.getCoreContainer();
>> +    SolrCore c1 = cores.getCore("");
>> +    assertTrue("Refcount != 2", core.getOpenCount() == 2);
>> +
>> +    ClosingRequestHandler handler1 = new ClosingRequestHandler();
>> +    handler1.inform( core );
>> +
>> +    String path = "/this/is A path /that won't be registered!";
>> +    SolrRequestHandler old = core.registerRequestHandler( path, handler1 );
>> +    assertNull( old ); // should not be anything...
>> +    assertEquals( core.getRequestHandlers().get( path ), handler1 );
>> +
>> +    SolrCore c2 = cores.getCore("");
>> +    c1.close();
>> +    assertTrue("Refcount < 1", core.getOpenCount() >= 1);
>> +    assertTrue("Handler is closed", handler1.closed == false);
>> +
>> +    c1 = cores.getCore("");
>> +    assertTrue("Refcount < 2", core.getOpenCount() >= 2);
>> +    assertTrue("Handler is closed", handler1.closed == false);
>> +
>> +    c2.close();
>> +    assertTrue("Refcount < 1", core.getOpenCount() >= 1);
>> +    assertTrue("Handler is closed", handler1.closed == false);
>> +
>> +    c1.close();
>> +    cores.shutdown();
>> +    assertTrue("Refcount != 0", core.getOpenCount() == 0);
>> +    assertTrue("Handler not closed", core.isClosed() && handler1.closed == true);
>> +  }
>> +
>> +
>> +  public void testRefCountMT() throws Exception {
>> +    SolrCore core = h.getCore();
>> +    assertTrue("Refcount != 1", core.getOpenCount() == 1);
>> +
>> +    final ClosingRequestHandler handler1 = new ClosingRequestHandler();
>> +    handler1.inform(core);
>> +    String path = "/this/is A path /that won't be registered!";
>> +    SolrRequestHandler old = core.registerRequestHandler(path, handler1);
>> +    assertNull(old); // should not be anything...
>> +    assertEquals(core.getRequestHandlers().get(path), handler1);
>> +
>> +    final int LOOP = 100;
>> +    final int MT = 16;
>> +    ExecutorService service = Executors.newFixedThreadPool(MT);
>> +    List<Callable<Integer>> callees = new ArrayList<Callable<Integer>>(MT);
>> +    final CoreContainer cores = h.getCoreContainer();
>> +    for (int i = 0; i < MT; ++i) {
>> +      Callable<Integer> call = new Callable<Integer>() {
>> +        void yield(int n) {
>> +          try {
>> +            Thread.sleep(0, (n % 13 + 1) * 10);
>> +          } catch (InterruptedException xint) {
>> +          }
>> +        }
>> +
>> +        public Integer call() {
>> +          SolrCore core = null;
>> +          int r = 0;
>> +          try {
>> +            for (int l = 0; l < LOOP; ++l) {
>> +              r += 1;
>> +              core = cores.getCore("");
>> +              // sprinkle concurrency hinting...
>> +              yield(l);
>> +              assertTrue("Refcount < 1", core.getOpenCount() >= 1);
>> +              yield(l);
>> +              assertTrue("Refcount > 17", core.getOpenCount() <= 17);
>> +              yield(l);
>> +              assertTrue("Handler is closed", handler1.closed == false);
>> +              yield(l);
>> +              core.close();
>> +              core = null;
>> +              yield(l);
>> +            }
>> +            return r;
>> +          } finally {
>> +            if (core != null)
>> +              core.close();
>> +          }
>> +        }
>> +      };
>> +      callees.add(call);
>> +    }
>> +
>> +    List<Future<Integer>> results = service.invokeAll(callees);
>> +    for (Future<Integer> result : results) {
>> +      assertTrue("loop=" + result.get() +" < " + LOOP, result.get() >= LOOP);
>> +    }
>> +
>> +    cores.shutdown();
>> +    assertTrue("Refcount != 0", core.getOpenCount() == 0);
>> +    assertTrue("Handler not closed", core.isClosed() && handler1.closed == true);
>> +
>> +    service.shutdown();
>> +    assertTrue("Running for too long...", service.awaitTermination(60, TimeUnit.SECONDS));
>> +  }
>>  }
>>
>> +
>> +
>>  class ClosingRequestHandler extends EmptyRequestHandler implements SolrCoreAware {
>>   boolean closed = false;
>>
>>
>> Modified: lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java (original)
>> +++ lucene/solr/trunk/src/webapp/src/org/apache/solr/servlet/SolrDispatchFilter.java Mon Aug 18 08:08:28 2008
>> @@ -285,6 +285,9 @@
>>         if( solrReq != null ) {
>>           solrReq.close();
>>         }
>> +        if (core != null) {
>> +          core.close();
>> +        }
>>       }
>>     }
>>
>>
>> Modified: lucene/solr/trunk/src/webapp/web/admin/index.jsp
>> URL: http://svn.apache.org/viewvc/lucene/solr/trunk/src/webapp/web/admin/index.jsp?rev=686780&r1=686779&r2=686780&view=diff
>> ==============================================================================
>> --- lucene/solr/trunk/src/webapp/web/admin/index.jsp (original)
>> +++ lucene/solr/trunk/src/webapp/web/admin/index.jsp Mon Aug 18 08:08:28 2008
>> @@ -21,6 +21,8 @@
>>  <%-- $Name:  $ --%>
>>
>>  <%@ page import="java.util.Date" %>
>> +<%@ page import="java.util.List" %>
>> +<%@ page import="java.util.Collection" %>
>>
>>  <%-- jsp:include page="header.jsp"/ --%>
>>  <%-- do a verbatim include so we can use the local vars --%>
>> @@ -52,15 +54,12 @@
>>  </tr>
>>
>>  <%-- List the cores (that arent this one) so we can switch --%>
>> -<% org.apache.solr.core.CoreContainer multicore = (org.apache.solr.core.CoreContainer)request.getAttribute("org.apache.solr.CoreContainer");
>> -  if (multicore!=null) {
>> -  java.util.Collection<SolrCore> cores = multicore.getCores();
>> -if (cores.size() > 1) {%><tr><td><strong>Cores:</strong><br></td><td><%
>> -  java.util.Iterator<SolrCore> icore = cores.iterator();
>> -  while (icore.hasNext()) {
>> -    SolrCore acore = icore.next();
>> -    if (acore == core) continue;
>> -    %>[<a href="../../<%=acore.getName()%>/admin/"><%=acore.getName()%></a>]<%
>> +<% org.apache.solr.core.CoreContainer cores = (org.apache.solr.core.CoreContainer)request.getAttribute("org.apache.solr.CoreContainer");
>> +  if (cores!=null) {
>> +    Collection<String> names = cores.getCoreNames();
>> +    if (names.size() > 1) {%><tr><td><strong>Cores:</strong><br></td><td><%
>> +    for (String name : names) {
>> +    %>[<a href="../../<%=name%>/admin/"><%=name%></a>]<%
>>   }%></td></tr><%
>>  }}%>
>>
>>
>>
>>
>
>
>
> --
> --Noble Paul
>