Save This Page
Home » apache-solr-1.3.0 » org.apache.solr » core » [javadoc | source]
    1   /**
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.solr.core;
   19   
   20   import java.io.File;
   21   import java.io.IOException;
   22   import java.util.ArrayList;
   23   import java.util.HashMap;
   24   import java.util.List;
   25   import java.util.Map;
   26   import java.util.concurrent.Callable;
   27   import java.util.concurrent.ExecutorService;
   28   import java.util.concurrent.Executors;
   29   import java.util.concurrent.Future;
   30   import java.util.logging.Logger;
   31   
   32   import javax.xml.xpath.XPathConstants;
   33   
   34   import org.apache.lucene.index.IndexReader;
   35   import org.apache.lucene.index.IndexWriter;
   36   import org.apache.lucene.search.BooleanQuery;
   37   import org.apache.lucene.store.Directory;
   38   import org.apache.lucene.store.FSDirectory;
   39   import org.apache.solr.request.JSONResponseWriter;
   40   import org.apache.solr.request.PythonResponseWriter;
   41   import org.apache.solr.request.QueryResponseWriter;
   42   import org.apache.solr.request.RubyResponseWriter;
   43   import org.apache.solr.request.SolrParams;
   44   import org.apache.solr.request.SolrQueryRequest;
   45   import org.apache.solr.request.SolrQueryResponse;
   46   import org.apache.solr.request.SolrRequestHandler;
   47   import org.apache.solr.request.XMLResponseWriter;
   48   import org.apache.solr.request.SolrParams.EchoParamStyle;
   49   import org.apache.solr.schema.IndexSchema;
   50   import org.apache.solr.search.SolrIndexSearcher;
   51   import org.apache.solr.update.DirectUpdateHandler;
   52   import org.apache.solr.update.SolrIndexConfig;
   53   import org.apache.solr.update.SolrIndexWriter;
   54   import org.apache.solr.update.UpdateHandler;
   55   import org.apache.solr.util.DOMUtil;
   56   import org.apache.solr.util.NamedList;
   57   import org.apache.solr.util.RefCounted;
   58   import org.apache.solr.util.SimpleOrderedMap;
   59   import org.w3c.dom.Element;
   60   import org.w3c.dom.Node;
   61   import org.w3c.dom.NodeList;
   62   
   63   
   64   /**
   65    * @author yonik
   66    * @author <a href='mailto:mbaranczak@epublishing.com'> Mike Baranczak </a> 
   67    * @version $Id: SolrCore.java 542679 2007-05-29 22:28:21Z ryan $
   68    */
   69   
   70   public final class SolrCore {
   71     public static final String version="1.0";  
   72   
   73     public static Logger log = Logger.getLogger(SolrCore.class.getName());
   74   
   75     private final IndexSchema schema;
   76     private final String dataDir;
   77     private final String index_path;
   78     private final UpdateHandler updateHandler;
   79     private static final long startTime = System.currentTimeMillis();
   80     private final RequestHandlers reqHandlers = new RequestHandlers();
   81   
   82     public long getStartTime() { return startTime; }
   83   
   84     public static SolrIndexConfig mainIndexConfig = new SolrIndexConfig("mainIndex");
   85   
   86     static {
   87       BooleanQuery.setMaxClauseCount(SolrConfig.config.getInt("query/maxBooleanClauses",BooleanQuery.getMaxClauseCount()));
   88       if (mainIndexConfig.writeLockTimeout != -1) IndexWriter.setDefaultWriteLockTimeout(mainIndexConfig.writeLockTimeout);
   89     }
   90   
   91   
   92     public static List<SolrEventListener> parseListener(String path) {
   93       List<SolrEventListener> lst = new ArrayList<SolrEventListener>();
   94       log.info("Searching for listeners: " +path);
   95       NodeList nodes = (NodeList)SolrConfig.config.evaluate(path, XPathConstants.NODESET);
   96       if (nodes!=null) {
   97         for (int i=0; i<nodes.getLength(); i++) {
   98           Node node = nodes.item(i);
   99             String className = DOMUtil.getAttr(node,"class");
  100             SolrEventListener listener = (SolrEventListener)Config.newInstance(className);
  101             listener.init(DOMUtil.childNodesToNamedList(node));
  102             lst.add(listener);
  103             log.info("added SolrEventListener: " + listener);
  104         }
  105       }
  106       return lst;
  107     }
  108   
  109     List<SolrEventListener> firstSearcherListeners;
  110     List<SolrEventListener> newSearcherListeners;
  111     private void parseListeners() {
  112       firstSearcherListeners = parseListener("//listener[@event=\"firstSearcher\"]");
  113       newSearcherListeners = parseListener("//listener[@event=\"newSearcher\"]");
  114     }
  115   
  116     public IndexSchema getSchema() { return schema; }
  117     public String getDataDir() { return dataDir; }
  118     public String getIndexDir() { return index_path; }
  119   
  120     // gets a non-caching searcher
  121     public SolrIndexSearcher newSearcher(String name) throws IOException {
  122       return new SolrIndexSearcher(schema, name,getIndexDir(),false);
  123     }
  124   
  125   
  126     void initIndex() {
  127       try {
  128         File dirFile = new File(getIndexDir());
  129         boolean indexExists = dirFile.canRead();
  130   
  131         boolean removeLocks = SolrConfig.config.getBool("mainIndex/unlockOnStartup", false);
  132         if (removeLocks) {
  133           // to remove locks, the directory must already exist... so we create it
  134           // if it didn't exist already...
  135           Directory dir = FSDirectory.getDirectory(dirFile, !indexExists);
  136           if (IndexReader.isLocked(dir)) {
  137             log.warning("WARNING: Solr index directory '" + getIndexDir() + "' is locked.  Unlocking...");
  138             IndexReader.unlock(dir);
  139           }
  140         }
  141   
  142         // Create the index if it doesn't exist. Note that indexExists was tested *before*
  143         // lock removal, since that will result in the creation of the directory.
  144         if(!indexExists) {
  145           log.warning("Solr index directory '" + dirFile + "' doesn't exist."
  146                   + " Creating new index...");
  147   
  148           SolrIndexWriter writer = new SolrIndexWriter("SolrCore.initIndex",getIndexDir(), true, schema, mainIndexConfig);
  149           writer.close();
  150   
  151         }
  152   
  153       } catch (IOException e) {
  154         throw new RuntimeException(e);
  155       }
  156     }
  157   
  158   
  159     private UpdateHandler createUpdateHandler(String className) {
  160       try {
  161         Class handlerClass = Config.findClass(className);
  162         java.lang.reflect.Constructor cons = handlerClass.getConstructor(new Class[]{SolrCore.class});
  163         return (UpdateHandler)cons.newInstance(new Object[]{this});
  164       } catch (SolrException e) {
  165         throw e;
  166       } catch (Exception e) {
  167         throw new SolrException( SolrException.ErrorCode.SERVER_ERROR,"Error Instantiating Update Handler "+className, e);
  168       }
  169     }
  170   
  171   
  172     // Singleton for now...
  173     private static SolrCore core;
  174   
  175     public static SolrCore getSolrCore() {
  176       synchronized (SolrCore.class) {
  177         if (core==null) core = new SolrCore(null,null);
  178         return core;
  179       }
  180     }
  181   
  182   
  183     public SolrCore(String dataDir, IndexSchema schema) {
  184       synchronized (SolrCore.class) {
  185         // this is for backward compatibility (and also the reason
  186         // the sync block is needed)
  187         core = this;   // set singleton
  188   
  189         if (dataDir ==null) {
  190           dataDir = SolrConfig.config.get("dataDir",Config.getInstanceDir()+"data");
  191         }
  192   
  193         log.info("Opening new SolrCore at " + Config.getInstanceDir() + ", dataDir="+dataDir);
  194   
  195         if (schema==null) {
  196           schema = new IndexSchema("schema.xml");
  197         }
  198   
  199         this.schema = schema;
  200         this.dataDir = dataDir;
  201         this.index_path = dataDir + "/" + "index";
  202   
  203         this.maxWarmingSearchers = SolrConfig.config.getInt("query/maxWarmingSearchers",Integer.MAX_VALUE);
  204   
  205         parseListeners();
  206   
  207         initIndex();
  208         
  209         initWriters();
  210         
  211         reqHandlers.initHandlersFromConfig( SolrConfig.config );
  212   
  213         try {
  214           // Open the searcher *before* the handler so we don't end up opening
  215           // one in the middle.
  216           getSearcher(false,false,null);
  217   
  218           updateHandler = createUpdateHandler(
  219                   SolrConfig.config.get("updateHandler/@class", DirectUpdateHandler.class.getName())
  220           );
  221   
  222         } catch (IOException e) {
  223           throw new RuntimeException(e);
  224         }
  225       }
  226     }
  227   
  228     public void close() {
  229       log.info("CLOSING SolrCore!");
  230       try {
  231         closeSearcher();
  232       } catch (Exception e) {
  233         SolrException.log(log,e);
  234       }
  235       try {
  236         searcherExecutor.shutdown();
  237       } catch (Exception e) {
  238         SolrException.log(log,e);
  239       }
  240       try {
  241         updateHandler.close();
  242       } catch (Exception e) {
  243         SolrException.log(log,e);
  244       }
  245     }
  246   
  247     @Override
  248     protected void finalize() { close(); }
  249   
  250   
  251     ////////////////////////////////////////////////////////////////////////////////
  252     // Request Handler
  253     ////////////////////////////////////////////////////////////////////////////////
  254   
  255     /**
  256      * Get the request handler registered to a given name.  
  257      * 
  258      * This function is thread safe.
  259      */
  260     public SolrRequestHandler getRequestHandler(String handlerName) {
  261       return reqHandlers.get(handlerName);
  262     }
  263     
  264     /**
  265      * Returns an unmodifieable Map containing the registered handlers
  266      */
  267     public Map<String,SolrRequestHandler> getRequestHandlers() {
  268       return reqHandlers.getRequestHandlers();
  269     }
  270   
  271     /**
  272      * Registers a handler at the specified location.  If one exists there, it will be replaced.
  273      * To remove a handler, register <code>null</code> at its path
  274      * 
  275      * Once registered the handler can be accessed through:
  276      * <pre>
  277      *   http://${host}:${port}/${context}/${handlerName}
  278      * or:  
  279      *   http://${host}:${port}/${context}/select?qt=${handlerName}
  280      * </pre>  
  281      * 
  282      * Handlers <em>must</em> be initalized before getting registered.  Registered
  283      * handlers can immediatly accept requests.
  284      * 
  285      * This call is thread safe.
  286      *  
  287      * @return the previous <code>SolrRequestHandler</code> registered to this name <code>null</code> if none.
  288      */
  289     public SolrRequestHandler registerRequestHandler(String handlerName, SolrRequestHandler handler) {
  290       return reqHandlers.register(handlerName,handler);
  291     }
  292     
  293     
  294     ////////////////////////////////////////////////////////////////////////////////
  295     // Update Handler
  296     ////////////////////////////////////////////////////////////////////////////////
  297   
  298     /**
  299      * RequestHandlers need access to the updateHandler so they can all talk to the
  300      * same RAM indexer.  
  301      */
  302     public UpdateHandler getUpdateHandler()
  303     {
  304       return updateHandler;
  305     }
  306   
  307     ////////////////////////////////////////////////////////////////////////////////
  308     // Searcher Control
  309     ////////////////////////////////////////////////////////////////////////////////
  310   
  311     // The current searcher used to service queries.
  312     // Don't access this directly!!!! use getSearcher() to
  313     // get it (and it will increment the ref count at the same time)
  314     private RefCounted<SolrIndexSearcher> _searcher;
  315   
  316     final ExecutorService searcherExecutor = Executors.newSingleThreadExecutor();
  317     private int onDeckSearchers;  // number of searchers preparing
  318     private Object searcherLock = new Object();  // the sync object for the searcher
  319     private final int maxWarmingSearchers;  // max number of on-deck searchers allowed
  320   
  321   
  322     public RefCounted<SolrIndexSearcher> getSearcher() {
  323       try {
  324         return getSearcher(false,true,null);
  325       } catch (IOException e) {
  326         SolrException.log(log,null,e);
  327         return null;
  328       }
  329     }
  330   
  331     /**
  332      * Get a {@link SolrIndexSearcher} or start the process of creating a new one.
  333      * <p>
  334      * The registered searcher is the default searcher used to service queries.
  335      * A searcher will normally be registered after all of the warming
  336      * and event handlers (newSearcher or firstSearcher events) have run.
  337      * In the case where there is no registered searcher, the newly created searcher will
  338      * be registered before running the event handlers (a slow searcher is better than no searcher).
  339      *
  340      * <p>
  341      * If <tt>forceNew==true</tt> then
  342      *  A new searcher will be opened and registered regardless of whether there is already
  343      *    a registered searcher or other searchers in the process of being created.
  344      * <p>
  345      * If <tt>forceNew==false</tt> then:<ul>
  346      *   <li>If a searcher is already registered, that searcher will be returned</li>
  347      *   <li>If no searcher is currently registered, but at least one is in the process of being created, then
  348      * this call will block until the first searcher is registered</li>
  349      *   <li>If no searcher is currently registered, and no searchers in the process of being registered, a new
  350      * searcher will be created.</li>
  351      * </ul>
  352      * <p>
  353      * If <tt>returnSearcher==true</tt> then a {@link RefCounted}&lt;{@link SolrIndexSearcher}&gt; will be returned with
  354      * the reference count incremented.  It <b>must</b> be decremented when no longer needed.
  355      * <p>
  356      * If <tt>waitSearcher!=null</tt> and a new {@link SolrIndexSearcher} was created,
  357      * then it is filled in with a Future that will return after the searcher is registered.  The Future may be set to
  358      * <tt>null</tt> in which case the SolrIndexSearcher created has already been registered at the time
  359      * this method returned.
  360      * <p>
  361      * @param forceNew           if true, force the open of a new index searcher regardless if there is already one open.
  362      * @param returnSearcher     if true, returns a {@link SolrIndexSearcher} holder with the refcount already incremented.
  363      * @param waitSearcher       if non-null, will be filled in with a {@link Future} that will return after the new searcher is registered.
  364      * @throws IOException
  365      */
  366     public RefCounted<SolrIndexSearcher> getSearcher(boolean forceNew, boolean returnSearcher, final Future[] waitSearcher) throws IOException {
  367       // it may take some time to open an index.... we may need to make
  368       // sure that two threads aren't trying to open one at the same time
  369       // if it isn't necessary.
  370   
  371       synchronized (searcherLock) {
  372         // see if we can return the current searcher
  373         if (_searcher!=null && !forceNew) {
  374           if (returnSearcher) {
  375             _searcher.incref();
  376             return _searcher;
  377           } else {
  378             return null;
  379           }
  380         }
  381   
  382         // check to see if we can wait for someone else's searcher to be set
  383         if (onDeckSearchers>0 && !forceNew && _searcher==null) {
  384           try {
  385             searcherLock.wait();
  386           } catch (InterruptedException e) {
  387             log.info(SolrException.toStr(e));
  388           }
  389         }
  390   
  391         // check again: see if we can return right now
  392         if (_searcher!=null && !forceNew) {
  393           if (returnSearcher) {
  394             _searcher.incref();
  395             return _searcher;
  396           } else {
  397             return null;
  398           }
  399         }
  400   
  401         // At this point, we know we need to open a new searcher...
  402         // first: increment count to signal other threads that we are
  403         //        opening a new searcher.
  404         onDeckSearchers++;
  405         if (onDeckSearchers < 1) {
  406           // should never happen... just a sanity check
  407           log.severe("ERROR!!! onDeckSearchers is " + onDeckSearchers);
  408           onDeckSearchers=1;  // reset
  409         } else if (onDeckSearchers > maxWarmingSearchers) {
  410           onDeckSearchers--;
  411           String msg="Error opening new searcher. exceeded limit of maxWarmingSearchers="+maxWarmingSearchers + ", try again later.";
  412           log.warning(msg);
  413           // HTTP 503==service unavailable, or 409==Conflict
  414           throw new SolrException(SolrException.ErrorCode.SERVICE_UNAVAILABLE,msg,true);
  415         } else if (onDeckSearchers > 1) {
  416           log.info("PERFORMANCE WARNING: Overlapping onDeckSearchers=" + onDeckSearchers);
  417         }
  418       }
  419   
  420       // open the index synchronously
  421       // if this fails, we need to decrement onDeckSearchers again.
  422       SolrIndexSearcher tmp;
  423       try {
  424         tmp = new SolrIndexSearcher(schema, "main", index_path, true);
  425       } catch (Throwable th) {
  426         synchronized(searcherLock) {
  427           onDeckSearchers--;
  428           // notify another waiter to continue... it may succeed
  429           // and wake any others.
  430           searcherLock.notify();
  431         }
  432         // need to close the searcher here??? we shouldn't have to.
  433         throw new RuntimeException(th);
  434       }
  435   
  436       final SolrIndexSearcher newSearcher=tmp;
  437   
  438       RefCounted<SolrIndexSearcher> currSearcherHolder=null;
  439       final RefCounted<SolrIndexSearcher> newSearchHolder=newHolder(newSearcher);
  440       if (returnSearcher) newSearchHolder.incref();
  441   
  442       // a signal to decrement onDeckSearchers if something goes wrong.
  443       final boolean[] decrementOnDeckCount=new boolean[1];
  444       decrementOnDeckCount[0]=true;
  445   
  446       try {
  447   
  448         boolean alreadyRegistered = false;
  449         synchronized (searcherLock) {
  450           if (_searcher == null) {
  451             // if there isn't a current searcher then we may
  452             // want to register this one before warming is complete instead of waiting.
  453             if (SolrConfig.config.getBool("query/useColdSearcher",false)) {
  454               registerSearcher(newSearchHolder);
  455               decrementOnDeckCount[0]=false;
  456               alreadyRegistered=true;
  457             }
  458           } else {
  459             // get a reference to the current searcher for purposes of autowarming.
  460             currSearcherHolder=_searcher;
  461             currSearcherHolder.incref();
  462           }
  463         }
  464   
  465   
  466         final SolrIndexSearcher currSearcher = currSearcherHolder==null ? null : currSearcherHolder.get();
  467   
  468         //
  469         // Note! if we registered the new searcher (but didn't increment it's
  470         // reference count because returnSearcher==false, it's possible for
  471         // someone else to register another searcher, and thus cause newSearcher
  472         // to close while we are warming.
  473         //
  474         // Should we protect against that by incrementing the reference count?
  475         // Maybe we should just let it fail?   After all, if returnSearcher==false
  476         // and newSearcher has been de-registered, what's the point of continuing?
  477         //
  478   
  479         Future future=null;
  480   
  481         // warm the new searcher based on the current searcher.
  482         // should this go before the other event handlers or after?
  483         if (currSearcher != null) {
  484           future = searcherExecutor.submit(
  485                   new Callable() {
  486                     public Object call() throws Exception {
  487                       try {
  488                         newSearcher.warm(currSearcher);
  489                       } catch (Throwable e) {
  490                         SolrException.logOnce(log,null,e);
  491                       }
  492                       return null;
  493                     }
  494                   }
  495           );
  496         }
  497   
  498         if (currSearcher==null && firstSearcherListeners.size() > 0) {
  499           future = searcherExecutor.submit(
  500                   new Callable() {
  501                     public Object call() throws Exception {
  502                       try {
  503                         for (SolrEventListener listener : firstSearcherListeners) {
  504                           listener.newSearcher(newSearcher,null);
  505                         }
  506                       } catch (Throwable e) {
  507                         SolrException.logOnce(log,null,e);
  508                       }
  509                       return null;
  510                     }
  511                   }
  512           );
  513         }
  514   
  515         if (currSearcher!=null && newSearcherListeners.size() > 0) {
  516           future = searcherExecutor.submit(
  517                   new Callable() {
  518                     public Object call() throws Exception {
  519                       try {
  520                         for (SolrEventListener listener : newSearcherListeners) {
  521                           listener.newSearcher(newSearcher,null);
  522                         }
  523                       } catch (Throwable e) {
  524                         SolrException.logOnce(log,null,e);
  525                       }
  526                       return null;
  527                     }
  528                   }
  529           );
  530         }
  531   
  532         // WARNING: this code assumes a single threaded executor (that all tasks
  533         // queued will finish first).
  534         final RefCounted<SolrIndexSearcher> currSearcherHolderF = currSearcherHolder;
  535         if (!alreadyRegistered) {
  536           future = searcherExecutor.submit(
  537                   new Callable() {
  538                     public Object call() throws Exception {
  539                       try {
  540                         // signal that we no longer need to decrement
  541                         // the count *before* registering the searcher since
  542                         // registerSearcher will decrement even if it errors.
  543                         decrementOnDeckCount[0]=false;
  544                         registerSearcher(newSearchHolder);
  545                       } catch (Throwable e) {
  546                         SolrException.logOnce(log,null,e);
  547                       } finally {
  548                         // we are all done with the old searcher we used
  549                         // for warming...
  550                         if (currSearcherHolderF!=null) currSearcherHolderF.decref();
  551                       }
  552                       return null;
  553                     }
  554                   }
  555           );
  556         }
  557   
  558         if (waitSearcher != null) {
  559           waitSearcher[0] = future;
  560         }
  561   
  562         // Return the searcher as the warming tasks run in parallel
  563         // callers may wait on the waitSearcher future returned.
  564         return returnSearcher ? newSearchHolder : null;
  565   
  566       }
  567       catch (Exception e) {
  568         SolrException.logOnce(log,null,e);
  569         if (currSearcherHolder != null) currSearcherHolder.decref();
  570   
  571         synchronized (searcherLock) {
  572           if (decrementOnDeckCount[0]) {
  573             onDeckSearchers--;
  574           }
  575           if (onDeckSearchers < 0) {
  576             // sanity check... should never happen
  577             log.severe("ERROR!!! onDeckSearchers after decrement=" + onDeckSearchers);
  578             onDeckSearchers=0; // try and recover
  579           }
  580           // if we failed, we need to wake up at least one waiter to continue the process
  581           searcherLock.notify();
  582         }
  583   
  584         // since the indexreader was already opened, assume we can continue on
  585         // even though we got an exception.
  586         return returnSearcher ? newSearchHolder : null;
  587       }
  588   
  589     }
  590   
  591   
  592     private RefCounted<SolrIndexSearcher> newHolder(SolrIndexSearcher newSearcher) {
  593       RefCounted<SolrIndexSearcher> holder = new RefCounted<SolrIndexSearcher>(newSearcher)
  594       {
  595         public void close() {
  596           try {
  597             resource.close();
  598           } catch (IOException e) {
  599             log.severe("Error closing searcher:" + SolrException.toStr(e));
  600           }
  601         }
  602       };
  603       holder.incref();  // set ref count to 1 to account for this._searcher
  604       return holder;
  605     }
  606   
  607   
  608     // Take control of newSearcherHolder (which should have a reference count of at
  609     // least 1 already.  If the caller wishes to use the newSearcherHolder directly
  610     // after registering it, then they should increment the reference count *before*
  611     // calling this method.
  612     //
  613     // onDeckSearchers will also be decremented (it should have been incremented
  614     // as a result of opening a new searcher).
  615     private void registerSearcher(RefCounted<SolrIndexSearcher> newSearcherHolder) throws IOException {
  616       synchronized (searcherLock) {
  617         try {
  618           if (_searcher != null) {
  619             _searcher.decref();   // dec refcount for this._searcher
  620             _searcher=null;
  621           }
  622   
  623           _searcher = newSearcherHolder;
  624           SolrIndexSearcher newSearcher = newSearcherHolder.get();
  625   
  626           newSearcher.register(); // register subitems (caches)
  627           log.info("Registered new searcher " + newSearcher);
  628   
  629         } catch (Throwable e) {
  630           log(e);
  631         } finally {
  632           // wake up anyone waiting for a searcher
  633           // even in the face of errors.
  634           onDeckSearchers--;
  635           searcherLock.notifyAll();
  636         }
  637       }
  638     }
  639   
  640   
  641   
  642     public void closeSearcher() {
  643       log.info("Closing main searcher on request.");
  644       synchronized (searcherLock) {
  645         if (_searcher != null) {
  646           _searcher.decref();   // dec refcount for this._searcher
  647           _searcher=null;
  648           SolrInfoRegistry.getRegistry().remove("currentSearcher");
  649         }
  650       }
  651     }
  652   
  653   
  654     public void execute(SolrRequestHandler handler, SolrQueryRequest req, SolrQueryResponse rsp) {
  655       // setup response header and handle request
  656       final NamedList<Object> responseHeader = new SimpleOrderedMap<Object>();
  657       rsp.add("responseHeader", responseHeader);
  658       handler.handleRequest(req,rsp);
  659       setResponseHeaderValues(handler,responseHeader,req,rsp);
  660   
  661       log.info(req.getContext().get("path") + " "
  662               + req.getParamString()+ " 0 "+
  663          (int)(rsp.getEndTime() - req.getStartTime()));
  664     }
  665   
  666     @Deprecated
  667     public void execute(SolrQueryRequest req, SolrQueryResponse rsp) {
  668       SolrRequestHandler handler = getRequestHandler(req.getQueryType());
  669       if (handler==null) {
  670         log.warning("Unknown Request Handler '" + req.getQueryType() +"' :" + req);
  671         throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"Unknown Request Handler '" + req.getQueryType() + "'", true);
  672       }
  673       execute(handler, req, rsp);
  674     }
  675     
  676     protected void setResponseHeaderValues(SolrRequestHandler handler, NamedList<Object> responseHeader,SolrQueryRequest req, SolrQueryResponse rsp) {
  677       // TODO should check that responseHeader has not been replaced by handler
  678       
  679       final int qtime=(int)(rsp.getEndTime() - req.getStartTime());
  680       responseHeader.add("status",rsp.getException()==null ? 0 : 500);
  681       responseHeader.add("QTime",qtime);
  682           
  683       SolrParams params = req.getParams();
  684       if( params.getBool(SolrParams.HEADER_ECHO_HANDLER, false) ) {
  685         responseHeader.add("handler", handler.getName() );
  686       }
  687       
  688       // Values for echoParams... false/true/all or false/explicit/all ???
  689       String ep = params.get( SolrParams.HEADER_ECHO_PARAMS, null );
  690       if( ep != null ) {
  691         EchoParamStyle echoParams = EchoParamStyle.get( ep );
  692         if( echoParams == null ) {
  693           throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"Invalid value '" + ep + "' for " + SolrParams.HEADER_ECHO_PARAMS 
  694               + " parameter, use '" + EchoParamStyle.EXPLICIT + "' or '" + EchoParamStyle.ALL + "'" );
  695         }
  696         if( echoParams == EchoParamStyle.EXPLICIT ) {
  697           responseHeader.add("params", req.getOriginalParams().toNamedList());
  698         }
  699         else if( echoParams == EchoParamStyle.ALL ) {
  700           responseHeader.add("params", req.getParams().toNamedList());
  701         }
  702       }
  703     }
  704   
  705   
  706     final public static void log(Throwable e) {
  707       SolrException.logOnce(log,null,e);
  708     }
  709   
  710     
  711     
  712     private QueryResponseWriter defaultResponseWriter;
  713     private final Map<String, QueryResponseWriter> responseWriters = new HashMap<String, QueryResponseWriter>();
  714     
  715     /** Configure the query response writers. There will always be a default writer; additional 
  716      * writers may also be configured. */
  717     private void initWriters() {
  718       String xpath = "queryResponseWriter";
  719       NodeList nodes = (NodeList) SolrConfig.config.evaluate(xpath, XPathConstants.NODESET);
  720       int length = nodes.getLength();
  721       for (int i=0; i<length; i++) {
  722         Element elm = (Element) nodes.item(i);
  723         
  724         try {
  725           String name = DOMUtil.getAttr(elm,"name", xpath+" config");
  726           String className = DOMUtil.getAttr(elm,"class", xpath+" config");
  727           log.info("adding queryResponseWriter "+name+"="+className);
  728             
  729           QueryResponseWriter writer = (QueryResponseWriter) Config.newInstance(className);
  730           writer.init(DOMUtil.childNodesToNamedList(elm));
  731           responseWriters.put(name, writer);
  732         } catch (Exception ex) {
  733           SolrConfig.severeErrors.add( ex );
  734           SolrException.logOnce(log,null, ex);
  735           // if a writer can't be created, skip it and continue
  736         }
  737       }
  738   
  739       // configure the default response writer; this one should never be null
  740       if (responseWriters.containsKey("standard")) {
  741         defaultResponseWriter = responseWriters.get("standard");
  742       }
  743       if (defaultResponseWriter == null) {
  744         defaultResponseWriter = new XMLResponseWriter();
  745       }
  746   
  747       // make JSON response writers available by default
  748       if (responseWriters.get("json")==null) {
  749         responseWriters.put("json", new JSONResponseWriter());
  750       }
  751       if (responseWriters.get("python")==null) {
  752         responseWriters.put("python", new PythonResponseWriter());
  753       }
  754       if (responseWriters.get("ruby")==null) {
  755         responseWriters.put("ruby", new RubyResponseWriter());
  756       }
  757   
  758     }
  759     
  760     /** Finds a writer by name, or returns the default writer if not found. */
  761     public final QueryResponseWriter getQueryResponseWriter(String writerName) {
  762       if (writerName != null) {
  763           QueryResponseWriter writer = responseWriters.get(writerName);
  764           if (writer != null) {
  765               return writer;
  766           }
  767       }
  768       return defaultResponseWriter;
  769     }
  770   
  771     /** Returns the appropriate writer for a request. If the request specifies a writer via the
  772      * 'wt' parameter, attempts to find that one; otherwise return the default writer.
  773      */
  774     public final QueryResponseWriter getQueryResponseWriter(SolrQueryRequest request) {
  775       return getQueryResponseWriter(request.getParam("wt")); 
  776     }
  777   }
  778   
  779   
  780   

Save This Page
Home » apache-solr-1.3.0 » org.apache.solr » core » [javadoc | source]