You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2013/05/30 09:53:46 UTC

svn commit: r1487777 [42/50] - in /lucene/dev/branches/security: ./ dev-tools/ dev-tools/eclipse/dot.settings/ dev-tools/idea/.idea/ dev-tools/idea/.idea/libraries/ dev-tools/idea/lucene/replicator/ dev-tools/maven/ dev-tools/maven/lucene/ dev-tools/ma...

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrIndexSearcher.java Thu May 30 07:53:18 2013
@@ -20,7 +20,17 @@ package org.apache.solr.search;
 import java.io.Closeable;
 import java.io.IOException;
 import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.atomic.AtomicLong;
 
 import org.apache.lucene.document.Document;
@@ -33,23 +43,55 @@ import org.apache.lucene.document.LazyDo
 import org.apache.lucene.document.LongField;
 import org.apache.lucene.document.StoredField;
 import org.apache.lucene.document.TextField;
-import org.apache.lucene.index.*;
-import org.apache.lucene.search.*;
+import org.apache.lucene.index.AtomicReader;
+import org.apache.lucene.index.AtomicReaderContext;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.DocsEnum;
+import org.apache.lucene.index.FieldInfo;
+import org.apache.lucene.index.FieldInfos;
+import org.apache.lucene.index.Fields;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.MultiDocsEnum;
+import org.apache.lucene.index.SlowCompositeReaderWrapper;
+import org.apache.lucene.index.StorableField;
+import org.apache.lucene.index.StoredDocument;
+import org.apache.lucene.index.StoredFieldVisitor;
+import org.apache.lucene.index.Term;
+import org.apache.lucene.index.Terms;
+import org.apache.lucene.index.TermsEnum;
+import org.apache.lucene.search.Collector;
+import org.apache.lucene.search.DocIdSet;
+import org.apache.lucene.search.DocIdSetIterator;
+import org.apache.lucene.search.Explanation;
+import org.apache.lucene.search.Filter;
+import org.apache.lucene.search.IndexSearcher;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.Query;
+import org.apache.lucene.search.ScoreDoc;
+import org.apache.lucene.search.Scorer;
+import org.apache.lucene.search.Sort;
+import org.apache.lucene.search.SortField;
+import org.apache.lucene.search.TermQuery;
+import org.apache.lucene.search.TimeLimitingCollector;
+import org.apache.lucene.search.TopDocs;
+import org.apache.lucene.search.TopDocsCollector;
+import org.apache.lucene.search.TopFieldCollector;
+import org.apache.lucene.search.TopScoreDocCollector;
+import org.apache.lucene.search.Weight;
 import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.FSDirectory;
-import org.apache.lucene.store.NRTCachingDirectory;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.OpenBitSet;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
 import org.apache.solr.core.DirectoryFactory;
+import org.apache.solr.core.DirectoryFactory.DirContext;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.core.SolrInfoMBean;
-import org.apache.solr.core.DirectoryFactory.DirContext;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestInfo;
@@ -57,6 +99,7 @@ import org.apache.solr.request.UnInverte
 import org.apache.solr.response.SolrQueryResponse;
 import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.SchemaField;
+import org.apache.solr.spelling.QueryConverter;
 import org.apache.solr.update.SolrIndexConfig;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -117,26 +160,43 @@ public class SolrIndexSearcher extends I
   private DirectoryFactory directoryFactory;
   
   private final AtomicReader atomicReader;
-  private String path; 
+  private String path;
+  private final boolean reserveDirectory;
+  private final boolean createdDirectory; 
+  
+  private static DirectoryReader getReader(SolrCore core, SolrIndexConfig config, DirectoryFactory directoryFactory, String path) throws IOException {
+    DirectoryReader reader = null;
+    Directory dir = directoryFactory.get(path, DirContext.DEFAULT, config.lockType);
+    try {
+      reader = core.getIndexReaderFactory().newReader(dir, core);
+    } catch (Throwable t) {
+      directoryFactory.release(dir);
+      throw new SolrException(ErrorCode.SERVER_ERROR, "Error opening Reader", t);
+    }
+    return reader;
+  }
 
   public SolrIndexSearcher(SolrCore core, String path, IndexSchema schema, SolrIndexConfig config, String name, boolean enableCache, DirectoryFactory directoryFactory) throws IOException {
     // we don't need to reserve the directory because we get it from the factory
-    this(core, path, schema,name, core.getIndexReaderFactory().newReader(directoryFactory.get(path, DirContext.DEFAULT, config.lockType), core), true, enableCache, false, directoryFactory);
+    this(core, path, schema, config, name, null, true, enableCache, false, directoryFactory);
   }
 
-  public SolrIndexSearcher(SolrCore core, String path, IndexSchema schema, String name, DirectoryReader r, boolean closeReader, boolean enableCache, boolean reserveDirectory, DirectoryFactory directoryFactory) throws IOException {
-    super(r);
+  public SolrIndexSearcher(SolrCore core, String path, IndexSchema schema, SolrIndexConfig config, String name, DirectoryReader r, boolean closeReader, boolean enableCache, boolean reserveDirectory, DirectoryFactory directoryFactory) throws IOException {
+    super(r == null ? getReader(core, config, directoryFactory, path) : r);
+
     this.path = path;
     this.directoryFactory = directoryFactory;
-    this.reader = r;
-    this.atomicReader = SlowCompositeReaderWrapper.wrap(r);
+    this.reader = (DirectoryReader) super.readerContext.reader();
+    this.atomicReader = SlowCompositeReaderWrapper.wrap(this.reader);
     this.core = core;
     this.schema = schema;
     this.name = "Searcher@" + Integer.toHexString(hashCode()) + (name!=null ? " "+name : "");
     log.info("Opening " + this.name);
 
-    Directory dir = r.directory();
+    Directory dir = this.reader.directory();
     
+    this.reserveDirectory = reserveDirectory;
+    this.createdDirectory = r == null;
     if (reserveDirectory) {
       // keep the directory from being released while we use it
       directoryFactory.incRef(dir);
@@ -281,8 +341,12 @@ public class SolrIndexSearcher extends I
       cache.close();
     }
 
-
-    directoryFactory.release(getIndexReader().directory());
+    if (reserveDirectory) {
+      directoryFactory.release(getIndexReader().directory());
+    }
+    if (createdDirectory) {
+      directoryFactory.release(getIndexReader().directory());
+    }
    
     
     // do this at the end so it only gets done if there are no exceptions
@@ -1172,7 +1236,7 @@ public class SolrIndexSearcher extends I
   public static final int GET_DOCSET            = 0x40000000;
   static final int NO_CHECK_FILTERCACHE  = 0x20000000;
   static final int NO_SET_QCACHE         = 0x10000000;
-
+  public static final int TERMINATE_EARLY = 0x04;
   public static final int GET_DOCLIST           =        0x02; // get the documents actually returned in a response
   public static final int GET_SCORES             =       0x01;
 
@@ -1331,7 +1395,8 @@ public class SolrIndexSearcher extends I
     float[] scores;
 
     boolean needScores = (cmd.getFlags() & GET_SCORES) != 0;
-
+    boolean terminateEarly = (cmd.getFlags() & TERMINATE_EARLY) == TERMINATE_EARLY;
+    
     Query query = QueryUtils.makeQueryable(cmd.getQuery());
 
     ProcessedFilter pf = getProcessedFilter(cmd.getFilter(), cmd.getFilterList());
@@ -1383,7 +1448,9 @@ public class SolrIndexSearcher extends I
           }
         };
       }
-      
+      if (terminateEarly) {
+        collector = new EarlyTerminatingCollector(collector, cmd.len);
+      }
       if( timeAllowed > 0 ) {
         collector = new TimeLimitingCollector(collector, TimeLimitingCollector.getGlobalCounter(), timeAllowed);
       }
@@ -1418,6 +1485,9 @@ public class SolrIndexSearcher extends I
         topCollector = TopFieldCollector.create(weightSort(cmd.getSort()), len, false, needScores, needScores, true);
       }
       Collector collector = topCollector;
+      if (terminateEarly) {
+        collector = new EarlyTerminatingCollector(collector, cmd.len);
+      }
       if( timeAllowed > 0 ) {
         collector = new TimeLimitingCollector(collector, TimeLimitingCollector.getGlobalCounter(), timeAllowed);
       }
@@ -1466,6 +1536,7 @@ public class SolrIndexSearcher extends I
     DocSet set;
 
     boolean needScores = (cmd.getFlags() & GET_SCORES) != 0;
+    boolean terminateEarly = (cmd.getFlags() & TERMINATE_EARLY) == TERMINATE_EARLY;
     int maxDoc = maxDoc();
     int smallSetSize = maxDoc>>6;
 
@@ -1505,7 +1576,9 @@ public class SolrIndexSearcher extends I
            }
          });
        }
-
+       if (terminateEarly) {
+         collector = new EarlyTerminatingCollector(collector, cmd.len);
+       }
        if( timeAllowed > 0 ) {
          collector = new TimeLimitingCollector(collector, TimeLimitingCollector.getGlobalCounter(), timeAllowed);
        }
@@ -1541,7 +1614,9 @@ public class SolrIndexSearcher extends I
 
       DocSetCollector setCollector = new DocSetDelegateCollector(maxDoc>>6, maxDoc, topCollector);
       Collector collector = setCollector;
-
+      if (terminateEarly) {
+        collector = new EarlyTerminatingCollector(collector, cmd.len);
+      }
       if( timeAllowed > 0 ) {
         collector = new TimeLimitingCollector(collector, TimeLimitingCollector.getGlobalCounter(), timeAllowed );
       }
@@ -2307,6 +2382,11 @@ class FilterImpl extends Filter {
     public int advance(int target) throws IOException {
       return doNext(first.advance(target));
     }
+
+    @Override
+    public long cost() {
+      return first.cost();
+    }
   }
 
   private static class DualFilterIterator extends DocIdSetIterator {
@@ -2344,6 +2424,11 @@ class FilterImpl extends Filter {
         if (other == doc) return doc;
       }
     }
+
+    @Override
+    public long cost() {
+      return Math.min(a.cost(), b.cost());
+    }
   }
 
 }

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SolrReturnFields.java Thu May 30 07:53:18 2013
@@ -52,14 +52,14 @@ public class SolrReturnFields extends Re
   private final List<String> globs = new ArrayList<String>(1);
 
   // The lucene field names to request from the SolrIndexSearcher
-  // Order is important for CSVResponseWriter
-  private final Set<String> fields = new LinkedHashSet<String>();
+  private final Set<String> fields = new HashSet<String>();
 
   // Field names that are OK to include in the response.
   // This will include pseudo fields, lucene fields, and matching globs
   private Set<String> okFieldNames = new HashSet<String>();
 
   // The list of explicitly requested fields
+  // Order is important for CSVResponseWriter
   private Set<String> reqFieldNames = null;
   
   protected DocTransformer transformer;
@@ -122,7 +122,7 @@ public class SolrReturnFields extends Re
           if(from.equals(rename.getName(j))) {
             rename.setName(j, to); // copy from the current target
             if(reqFieldNames==null) {
-              reqFieldNames = new HashSet<String>();
+              reqFieldNames = new LinkedHashSet<String>();
             }
             reqFieldNames.add(to); // don't rename our current target
           }
@@ -360,12 +360,16 @@ public class SolrReturnFields extends Re
 
   private void addField(String field, String key, DocTransformers augmenters, SolrQueryRequest req)
   {
+    if(reqFieldNames==null) {
+      reqFieldNames = new LinkedHashSet<String>();
+    }
+    
     if(key==null) {
-      if(reqFieldNames==null) {
-        reqFieldNames = new HashSet<String>();
-      }
       reqFieldNames.add(field);
     }
+    else {
+      reqFieldNames.add(key);
+    }
 
     fields.add(field); // need to put in the map to maintain order for things like CSVResponseWriter
     okFieldNames.add( field );
@@ -386,6 +390,19 @@ public class SolrReturnFields extends Re
   }
 
   @Override
+  public Set<String> getRequestedFieldNames() {
+    if(_wantsAllFields || reqFieldNames==null || reqFieldNames.isEmpty()) {
+      return null;
+    }
+    return reqFieldNames;
+  }
+  
+  @Override
+  public boolean hasPatternMatching() {
+    return !globs.isEmpty();
+  }
+
+  @Override
   public boolean wantsField(String name)
   {
     if( _wantsAllFields || okFieldNames.contains( name ) ){

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SortedIntDocSet.java Thu May 30 07:53:18 2013
@@ -755,6 +755,10 @@ public class SortedIntDocSet extends Doc
                 }
               }
 
+              @Override
+              public long cost() {
+                return docs.length;
+              }
             };
           }
 

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SwitchQParserPlugin.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SwitchQParserPlugin.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SwitchQParserPlugin.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/SwitchQParserPlugin.java Thu May 30 07:53:18 2013
@@ -82,6 +82,57 @@ import org.apache.commons.lang.StringUti
  *                             v=$shipping}&lt;/str&gt;
  *   &lt;/lst&gt;
  * &lt;/requestHandler&gt;</pre>
+ *
+ * <p>
+ * A slightly more interesting variant of the <code>shipping</code> example above, would be
+ * to combine the switch parser with the frange parser, to allow the client to specify an 
+ * arbitrary "max shipping" amount that will be used to build a filter if and only if a 
+ * value is specified.  Example:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;requestHandler name="/select" class="solr.SearchHandler"&gt;
+ *   &lt;lst name="invariants"&gt;
+ *     &lt;str name="shipping_fq"&gt;{!frange u=$shipping}shipping_cost&lt;/str&gt;
+ *   &lt;/lst&gt;
+ *   &lt;lst name="defaults"&gt;
+ *     &lt;str name="shipping"&gt;any&lt;/str&gt;
+ *   &lt;/lst&gt;
+ *   &lt;lst name="appends"&gt;
+ *     &lt;str name="fq"&gt;{!switch case='*:*'
+ *                             case.any='*:*'
+ *                             default=$shipping_fq
+ *                             v=$shipping}&lt;/str&gt;
+ *   &lt;/lst&gt;
+ * &lt;/requestHandler&gt;</pre>
+ *
+ * <p>
+ * With the above configuration a client that specifies <code>shipping=any</code>, or 
+ * does not specify a <code>shipping</code> param at all, will not have the results 
+ * filtered.  But if a client specifies a numeric value (ie: <code>shipping=10</code>, 
+ * <code>shipping=5</code>, etc..) then the results will be limited to documents whose 
+ * <code>shipping_cost</code> field has a value less then that number.
+ * </p>
+ *
+ * <p>
+ * A similar use case would be to combine the switch parser with the bbox parser to 
+ * support an optional geographic filter that is applied if and only if the client 
+ * specifies a <code>location</code> param containing a lat,lon pair to be used as 
+ * the center of the bounding box:
+ * </p>
+ * <pre class="prettyprint">
+ * &lt;requestHandler name="/select" class="solr.SearchHandler"&gt;
+ *   &lt;lst name="invariants"&gt;
+ *     &lt;str name="bbox_fq"&gt;{!bbox pt=$location sfield=geo d=$dist}&lt;/str&gt;
+ *   &lt;/lst&gt;
+ *   &lt;lst name="defaults"&gt;
+ *     &lt;str name="dist"&gt;100&lt;/str&gt;
+ *   &lt;/lst&gt;
+ *   &lt;lst name="appends"&gt;
+ *     &lt;str name="fq"&gt;{!switch case='*:*' 
+ *                             default=$bbox_fq 
+ *                             v=$location}&lt;/str&gt;
+ *   &lt;/lst&gt;
+ * &lt;/requestHandler&gt;</pre>
  */
 public class SwitchQParserPlugin extends QParserPlugin {
   public static String NAME = "switch";

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/requestfactory/TopGroupsShardRequestFactory.java Thu May 30 07:53:18 2013
@@ -27,6 +27,7 @@ import org.apache.solr.common.params.Sha
 import org.apache.solr.handler.component.ResponseBuilder;
 import org.apache.solr.handler.component.ShardRequest;
 import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.search.Grouping;
 import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.search.grouping.distributed.ShardRequestFactory;
@@ -112,12 +113,13 @@ public class TopGroupsShardRequestFactor
     }
 
     sreq.params.set(GroupParams.GROUP_DISTRIBUTED_SECOND, "true");
+    final IndexSchema schema = rb.req.getSearcher().getSchema();
     for (Map.Entry<String, Collection<SearchGroup<BytesRef>>> entry : rb.mergedSearchGroups.entrySet()) {
       for (SearchGroup<BytesRef> searchGroup : entry.getValue()) {
         String groupValue;
         if (searchGroup.groupValue != null) {
           String rawGroupValue = searchGroup.groupValue.utf8ToString();
-          FieldType fieldType = rb.req.getSearcher().getSchema().getField(entry.getKey()).getType();
+          FieldType fieldType = schema.getField(entry.getKey()).getType();
           groupValue = fieldType.indexedToReadable(rawGroupValue);
         } else {
           groupValue = GROUP_NULL_VALUE;
@@ -127,9 +129,9 @@ public class TopGroupsShardRequestFactor
     }
 
     if ((rb.getFieldFlags() & SolrIndexSearcher.GET_SCORES) != 0 || rb.getSortSpec().includesScore()) {
-      sreq.params.set(CommonParams.FL, rb.req.getSchema().getUniqueKeyField().getName() + ",score");
+      sreq.params.set(CommonParams.FL, schema.getUniqueKeyField().getName() + ",score");
     } else {
-      sreq.params.set(CommonParams.FL, rb.req.getSchema().getUniqueKeyField().getName());
+      sreq.params.set(CommonParams.FL, schema.getUniqueKeyField().getName());
     }
     
     int origTimeAllowed = sreq.params.getInt(CommonParams.TIME_ALLOWED, -1);

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/distributed/shardresultserializer/TopGroupsResultTransformer.java Thu May 30 07:53:18 2013
@@ -32,6 +32,7 @@ import org.apache.solr.common.util.Named
 import org.apache.solr.handler.component.ResponseBuilder;
 import org.apache.solr.handler.component.ShardDoc;
 import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.SchemaField;
 import org.apache.solr.search.grouping.Command;
 import org.apache.solr.search.grouping.distributed.command.QueryCommand;
@@ -66,11 +67,12 @@ public class TopGroupsResultTransformer 
   @Override
   public NamedList transform(List<Command> data) throws IOException {
     NamedList<NamedList> result = new NamedList<NamedList>();
+    final IndexSchema schema = rb.req.getSearcher().getSchema();
     for (Command command : data) {
       NamedList commandResult;
       if (TopGroupsFieldCommand.class.isInstance(command)) {
         TopGroupsFieldCommand fieldCommand = (TopGroupsFieldCommand) command;
-        SchemaField groupField = rb.req.getSearcher().getSchema().getField(fieldCommand.getKey());
+        SchemaField groupField = schema.getField(fieldCommand.getKey());
         commandResult = serializeTopGroups(fieldCommand.result(), groupField);
       } else if (QueryCommand.class.isInstance(command)) {
         QueryCommand queryCommand = (QueryCommand) command;
@@ -184,7 +186,8 @@ public class TopGroupsResultTransformer 
     }
     CharsRef spare = new CharsRef();
 
-    SchemaField uniqueField = rb.req.getSearcher().getSchema().getUniqueKeyField();
+    final IndexSchema schema = rb.req.getSearcher().getSchema();
+    SchemaField uniqueField = schema.getUniqueKeyField();
     for (GroupDocs<BytesRef> searchGroup : data.groups) {
       NamedList<Object> groupResult = new NamedList<Object>();
       groupResult.add("totalHits", searchGroup.totalHits);
@@ -211,7 +214,7 @@ public class TopGroupsResultTransformer 
         for (int j = 0; j < fieldDoc.fields.length; j++) {
           Object sortValue  = fieldDoc.fields[j];
           Sort sortWithinGroup = rb.getGroupingSpec().getSortWithinGroup();
-          SchemaField field = sortWithinGroup.getSort()[j].getField() != null ? rb.req.getSearcher().getSchema().getFieldOrNull(sortWithinGroup.getSort()[j].getField()) : null;
+          SchemaField field = sortWithinGroup.getSort()[j].getField() != null ? schema.getFieldOrNull(sortWithinGroup.getSort()[j].getField()) : null;
           if (field != null) {
             FieldType fieldType = field.getType();
             if (sortValue instanceof BytesRef) {
@@ -244,7 +247,8 @@ public class TopGroupsResultTransformer 
     List<NamedList> documents = new ArrayList<NamedList>();
     queryResult.add("documents", documents);
 
-    SchemaField uniqueField = rb.req.getSearcher().getSchema().getUniqueKeyField();
+    final IndexSchema schema = rb.req.getSearcher().getSchema();
+    SchemaField uniqueField = schema.getUniqueKeyField();
     CharsRef spare = new CharsRef();
     for (ScoreDoc scoreDoc : result.getTopDocs().scoreDocs) {
       NamedList<Object> document = new NamedList<Object>();
@@ -264,7 +268,8 @@ public class TopGroupsResultTransformer 
       for (int j = 0; j < fieldDoc.fields.length; j++) {
         Object sortValue  = fieldDoc.fields[j];
         Sort groupSort = rb.getGroupingSpec().getGroupSort();
-        SchemaField field = groupSort.getSort()[j].getField() != null ? rb.req.getSearcher().getSchema().getFieldOrNull(groupSort.getSort()[j].getField()) : null;
+        SchemaField field = groupSort.getSort()[j].getField() != null 
+                          ? schema.getFieldOrNull(groupSort.getSort()[j].getField()) : null;
         if (field != null) {
           FieldType fieldType = field.getType();
           if (sortValue instanceof BytesRef) {

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/grouping/endresulttransformer/GroupedEndResultTransformer.java Thu May 30 07:53:18 2013
@@ -50,7 +50,7 @@ public class GroupedEndResultTransformer
    */
   @Override
   public void transform(Map<String, ?> result, ResponseBuilder rb, SolrDocumentSource solrDocumentSource) {
-    NamedList<Object> commands = new NamedList<Object>();
+    NamedList<Object> commands = new SimpleOrderedMap<Object>();
     for (Map.Entry<String, ?> entry : result.entrySet()) {
       Object value = entry.getValue();
       if (TopGroups.class.isInstance(value)) {

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/similarities/SchemaSimilarityFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/similarities/SchemaSimilarityFactory.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/similarities/SchemaSimilarityFactory.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/search/similarities/SchemaSimilarityFactory.java Thu May 30 07:53:18 2013
@@ -20,14 +20,15 @@ package org.apache.solr.search.similarit
 import org.apache.lucene.search.similarities.DefaultSimilarity;
 import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper;
 import org.apache.lucene.search.similarities.Similarity;
+import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.core.SolrCore;
 import org.apache.solr.schema.FieldType;
-import org.apache.solr.schema.IndexSchema;
-import org.apache.solr.schema.SchemaAware;
 import org.apache.solr.schema.SimilarityFactory;
+import org.apache.solr.util.plugin.SolrCoreAware;
 
 /**
  * SimilarityFactory that returns a {@link PerFieldSimilarityWrapper}
- * that delegates to the field type, if its configured, otherwise
+ * that delegates to the field type, if it's configured, otherwise
  * {@link DefaultSimilarity}.
  *
  * <p>
@@ -42,16 +43,23 @@ import org.apache.solr.schema.Similarity
  *
  * @see FieldType#getSimilarity
  */
-public class SchemaSimilarityFactory extends SimilarityFactory implements SchemaAware {
+public class SchemaSimilarityFactory extends SimilarityFactory implements SolrCoreAware {
   private Similarity similarity;
   private Similarity defaultSimilarity = new DefaultSimilarity();
+  private volatile SolrCore core;
+
+  @Override
+  public void inform(SolrCore core) {
+    this.core = core;
+  }
   
   @Override
-  public void inform(final IndexSchema schema) {
+  public void init(SolrParams args) {
+    super.init(args);
     similarity = new PerFieldSimilarityWrapper() {
       @Override
       public Similarity get(String name) {
-        FieldType fieldType = schema.getFieldTypeNoEx(name);
+        FieldType fieldType = core.getLatestSchema().getFieldTypeNoEx(name);
         if (fieldType == null) {
           return defaultSimilarity;
         } else {
@@ -64,7 +72,7 @@ public class SchemaSimilarityFactory ext
 
   @Override
   public Similarity getSimilarity() {
-    assert similarity != null : "inform must be called first";
+    assert core != null : "inform must be called first";
     return similarity;
   }
 }

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/LoadAdminUiServlet.java Thu May 30 07:53:18 2013
@@ -30,6 +30,7 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.solr.core.CoreContainer;
+import org.apache.solr.core.SolrCore;
 
 /**
  * A simple servlet to load the Solr Admin UI
@@ -53,14 +54,17 @@ public final class LoadAdminUiServlet ex
         Writer out = new OutputStreamWriter(response.getOutputStream(), "UTF-8");
 
         String html = IOUtils.toString(in, "UTF-8");
+        Package pack = SolrCore.class.getPackage();
 
         String[] search = new String[] { 
             "${contextPath}", 
-            "${adminPath}" 
+            "${adminPath}",
+            "${version}" 
         };
         String[] replace = new String[] {
             StringEscapeUtils.escapeJavaScript(request.getContextPath()),
-            StringEscapeUtils.escapeJavaScript(cores.getAdminPath())
+            StringEscapeUtils.escapeJavaScript(cores.getAdminPath()),
+            StringEscapeUtils.escapeJavaScript(pack.getSpecificationVersion())
         };
         
         out.write( StringUtils.replaceEach(html, search, replace) );

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrDispatchFilter.java Thu May 30 07:53:18 2013
@@ -17,8 +17,6 @@
 
 package org.apache.solr.servlet;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -31,6 +29,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
@@ -42,7 +41,6 @@ import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
 import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
 import javax.servlet.ServletRequest;
 import javax.servlet.ServletResponse;
 import javax.servlet.http.HttpServletRequest;
@@ -50,6 +48,8 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.commons.io.IOUtils;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.cloud.Aliases;
 import org.apache.solr.common.cloud.ClusterState;
 import org.apache.solr.common.cloud.Replica;
 import org.apache.solr.common.cloud.Slice;
@@ -58,10 +58,12 @@ import org.apache.solr.common.cloud.ZkNo
 import org.apache.solr.common.cloud.ZkStateReader;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.MapSolrParams;
+import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.ContentStreamBase;
 import org.apache.solr.common.util.NamedList;
 import org.apache.solr.common.util.SimpleOrderedMap;
+import org.apache.solr.common.util.StrUtils;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.SolrConfig;
 import org.apache.solr.core.SolrCore;
@@ -86,7 +88,7 @@ import org.slf4j.LoggerFactory;
  */
 public class SolrDispatchFilter implements Filter
 {
-  final Logger log = LoggerFactory.getLogger(SolrDispatchFilter.class);
+  final Logger log;
 
   protected volatile CoreContainer cores;
 
@@ -96,6 +98,19 @@ public class SolrDispatchFilter implemen
   
   private static final Charset UTF8 = Charset.forName("UTF-8");
 
+  public SolrDispatchFilter() {
+    try {
+      log = LoggerFactory.getLogger(SolrDispatchFilter.class);
+    } catch (NoClassDefFoundError e) {
+      throw new SolrException(
+          ErrorCode.SERVER_ERROR,
+          "Could not find necessary SLF4j logging jars. If using Jetty, the SLF4j logging jars need to go in "
+          +"the jetty lib/ext directory. For other containers, the corresponding directory should be used. "
+          +"For more information, see: http://wiki.apache.org/solr/SolrLogging",
+          e);
+    }
+  }
+  
   @Override
   public void init(FilterConfig config) throws ServletException
   {
@@ -134,9 +149,13 @@ public class SolrDispatchFilter implemen
       cores = null;
     }    
   }
-
+  
   @Override
   public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
+    doFilter(request, response, chain, false);
+  }
+  
+  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, boolean retry) throws IOException, ServletException {
     if( abortErrorMessage != null ) {
       ((HttpServletResponse)response).sendError( 500, abortErrorMessage );
       return;
@@ -149,12 +168,14 @@ public class SolrDispatchFilter implemen
     CoreContainer cores = this.cores;
     SolrCore core = null;
     SolrQueryRequest solrReq = null;
+    Aliases aliases = null;
     
     if( request instanceof HttpServletRequest) {
       HttpServletRequest req = (HttpServletRequest)request;
       HttpServletResponse resp = (HttpServletResponse)response;
       SolrRequestHandler handler = null;
       String corename = "";
+      String origCorename = null;
       try {
         // put the core container in request attribute
         req.setAttribute("org.apache.solr.CoreContainer", cores);
@@ -185,6 +206,8 @@ public class SolrDispatchFilter implemen
           handleAdminRequest(req, response, handler, solrReq);
           return;
         }
+        boolean usingAliases = false;
+        List<String> collectionsList = null;
         // Check for the core admin collections url
         if( path.equals( "/admin/collections" ) ) {
           handler = cores.getCollectionsHandler();
@@ -198,7 +221,24 @@ public class SolrDispatchFilter implemen
           if( idx > 1 ) {
             // try to get the corename as a request parameter first
             corename = path.substring( 1, idx );
+            
+            // look at aliases
+            if (cores.isZooKeeperAware()) {
+              origCorename = corename;
+              ZkStateReader reader = cores.getZkController().getZkStateReader();
+              aliases = reader.getAliases();
+              if (aliases != null && aliases.collectionAliasSize() > 0) {
+                usingAliases = true;
+                String alias = aliases.getCollectionAlias(corename);
+                if (alias != null) {
+                  collectionsList = StrUtils.splitSmart(alias, ",", true);
+                  corename = collectionsList.get(0);
+                }
+              }
+            }
+            
             core = cores.getCore(corename);
+
             if (core != null) {
               path = path.substring( idx );
             }
@@ -221,11 +261,21 @@ public class SolrDispatchFilter implemen
           
           // if we couldn't find it locally, look on other nodes
           if (core == null && idx > 0) {
-            String coreUrl = getRemotCoreUrl(cores, corename);
+            String coreUrl = getRemotCoreUrl(cores, corename, origCorename);
             if (coreUrl != null) {
               path = path.substring( idx );
               remoteQuery(coreUrl + path, req, solrReq, resp);
               return;
+            } else {
+              if (!retry) {
+                // we couldn't find a core to work with, try reloading aliases
+                // TODO: it would be nice if admin ui elements skipped this...
+                ZkStateReader reader = cores.getZkController()
+                    .getZkStateReader();
+                reader.updateAliases();
+                doFilter(request, response, chain, true);
+                return;
+              }
             }
           }
           
@@ -289,6 +339,10 @@ public class SolrDispatchFilter implemen
               solrReq = parser.parse( core, path, req );
             }
 
+            if (usingAliases) {
+              processAliases(solrReq, aliases, collectionsList);
+            }
+            
             final Method reqMethod = Method.getMethod(req.getMethod());
             HttpCacheHeaderUtil.setCacheControlHeader(config, resp, reqMethod);
             // unless we have been explicitly told not to, do cache validation
@@ -328,6 +382,7 @@ public class SolrDispatchFilter implemen
       } 
       finally {
         if( solrReq != null ) {
+          log.debug("Closing out SolrRequest: {}", solrReq);
           solrReq.close();
         }
         if (core != null) {
@@ -341,9 +396,44 @@ public class SolrDispatchFilter implemen
     chain.doFilter(request, response);
   }
   
+  private void processAliases(SolrQueryRequest solrReq, Aliases aliases,
+      List<String> collectionsList) {
+    String collection = solrReq.getParams().get("collection");
+    if (collection != null) {
+      collectionsList = StrUtils.splitSmart(collection, ",", true);
+    }
+    if (collectionsList != null) {
+      Set<String> newCollectionsList = new HashSet<String>(
+          collectionsList.size());
+      for (String col : collectionsList) {
+        String al = aliases.getCollectionAlias(col);
+        if (al != null) {
+          List<String> aliasList = StrUtils.splitSmart(al, ",", true);
+          newCollectionsList.addAll(aliasList);
+        } else {
+          newCollectionsList.add(col);
+        }
+      }
+      if (newCollectionsList.size() > 0) {
+        StringBuilder collectionString = new StringBuilder();
+        Iterator<String> it = newCollectionsList.iterator();
+        int sz = newCollectionsList.size();
+        for (int i = 0; i < sz; i++) {
+          collectionString.append(it.next());
+          if (i < newCollectionsList.size() - 1) {
+            collectionString.append(",");
+          }
+        }
+        ModifiableSolrParams params = new ModifiableSolrParams(
+            solrReq.getParams());
+        params.set("collection", collectionString.toString());
+        solrReq.setParams(params);
+      }
+    }
+  }
+  
   private void remoteQuery(String coreUrl, HttpServletRequest req,
       SolrQueryRequest solrReq, HttpServletResponse resp) throws IOException {
-    
     try {
       String urlstr = coreUrl;
       
@@ -372,6 +462,7 @@ public class SolrDispatchFilter implemen
           os = con.getOutputStream(); // side effect: method is switched to POST
           try {
             IOUtils.copyLarge(is, os);
+            os.flush();
           } finally {
             IOUtils.closeQuietly(os);
             IOUtils.closeQuietly(is);  // TODO: I thought we weren't supposed to explicitly close servlet streams
@@ -394,6 +485,7 @@ public class SolrDispatchFilter implemen
         os = resp.getOutputStream();
         try {
           IOUtils.copyLarge(is, os);
+          os.flush();
         } finally {
           IOUtils.closeQuietly(os);   // TODO: I thought we weren't supposed to explicitly close servlet streams
           IOUtils.closeQuietly(is);
@@ -409,9 +501,9 @@ public class SolrDispatchFilter implemen
     
   }
   
-  private String getRemotCoreUrl(CoreContainer cores, String collectionName) {
+  private String getRemotCoreUrl(CoreContainer cores, String collectionName, String origCorename) {
     ClusterState clusterState = cores.getZkController().getClusterState();
-    Collection<Slice> slices = clusterState.getSlices(collectionName);
+    Collection<Slice> slices = clusterState.getActiveSlices(collectionName);
     boolean byCoreName = false;
     if (slices == null) {
       // look by core name
@@ -419,7 +511,7 @@ public class SolrDispatchFilter implemen
       Set<String> collections = clusterState.getCollections();
       for (String collection : collections) {
         slices = new ArrayList<Slice>();
-        slices.addAll(clusterState.getSlices(collection));
+        slices.addAll(clusterState.getActiveSlices(collection));
       }
     }
     
@@ -444,9 +536,14 @@ public class SolrDispatchFilter implemen
             // don't count a local core
             continue;
           }
-          String coreUrl = coreNodeProps.getCoreUrl();
-          if (coreUrl.endsWith("/")) {
-            coreUrl = coreUrl.substring(0, coreUrl.length() - 1);
+          String coreUrl;
+          if (origCorename != null) {
+            coreUrl = coreNodeProps.getBaseUrl() + "/" + origCorename;
+          } else {
+            coreUrl = coreNodeProps.getCoreUrl();
+            if (coreUrl.endsWith("/")) {
+              coreUrl = coreUrl.substring(0, coreUrl.length() - 1);
+            }
           }
 
           return coreUrl;
@@ -461,7 +558,7 @@ public class SolrDispatchFilter implemen
     ZkStateReader zkStateReader = cores.getZkController().getZkStateReader();
     
     ClusterState clusterState = zkStateReader.getClusterState();
-    Map<String,Slice> slices = clusterState.getSlicesMap(collection);
+    Map<String,Slice> slices = clusterState.getActiveSlicesMap(collection);
     if (slices == null) {
       return null;
     }

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/SolrRequestParsers.java Thu May 30 07:53:18 2013
@@ -44,6 +44,7 @@ import org.apache.commons.fileupload.dis
 import org.apache.commons.fileupload.servlet.ServletFileUpload;
 import org.apache.lucene.util.IOUtils;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.common.params.CommonParams;
 import org.apache.solr.common.params.MultiMapSolrParams;
 import org.apache.solr.common.params.SolrParams;
@@ -72,7 +73,8 @@ public class SolrRequestParsers 
   private final boolean enableRemoteStreams;
   private StandardRequestParser standard;
   private boolean handleSelect = true;
-  
+  private boolean addHttpRequestToContext;
+
   /** Default instance for e.g. admin requests. Limits to 2 MB uploads and does not allow remote streams. */
   public static final SolrRequestParsers DEFAULT = new SolrRequestParsers();
   
@@ -86,6 +88,7 @@ public class SolrRequestParsers 
       multipartUploadLimitKB = formUploadLimitKB = Integer.MAX_VALUE; 
       enableRemoteStreams = true;
       handleSelect = true;
+      addHttpRequestToContext = false;
     } else {
       multipartUploadLimitKB = globalConfig.getInt( 
           "requestDispatcher/requestParsers/@multipartUploadLimitInKB", 2048 );
@@ -99,6 +102,9 @@ public class SolrRequestParsers 
       // Let this filter take care of /select?xxx format
       handleSelect = globalConfig.getBool( 
           "requestDispatcher/@handleSelect", true ); 
+      
+      addHttpRequestToContext = globalConfig.getBool( 
+          "requestDispatcher/requestParsers/@addHttpRequestToContext", false ); 
     }
     init(multipartUploadLimitKB, formUploadLimitKB);
   }
@@ -106,6 +112,7 @@ public class SolrRequestParsers 
   private SolrRequestParsers() {
     enableRemoteStreams = false;
     handleSelect = false;
+    addHttpRequestToContext = false;
     init(2048, 2048);
   }
 
@@ -139,6 +146,10 @@ public class SolrRequestParsers 
     // Handlers and login will want to know the path. If it contains a ':'
     // the handler could use it for RESTful URLs
     sreq.getContext().put( "path", path );
+    
+    if(addHttpRequestToContext) {
+      sreq.getContext().put("httpRequest", req);
+    }
     return sreq;
   }
   
@@ -151,7 +162,7 @@ public class SolrRequestParsers 
     String[] strs = params.getParams( CommonParams.STREAM_URL );
     if( strs != null ) {
       if( !enableRemoteStreams ) {
-        throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Remote Streaming is disabled." );
+        throw new SolrException( ErrorCode.BAD_REQUEST, "Remote Streaming is disabled." );
       }
       for( final String url : strs ) {
         ContentStreamBase stream = new ContentStreamBase.URLStream( new URL(url) );
@@ -166,7 +177,7 @@ public class SolrRequestParsers 
     strs = params.getParams( CommonParams.STREAM_FILE );
     if( strs != null ) {
       if( !enableRemoteStreams ) {
-        throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Remote Streaming is disabled." );
+        throw new SolrException( ErrorCode.BAD_REQUEST, "Remote Streaming is disabled." );
       }
       for( final String file : strs ) {
         ContentStreamBase stream = new ContentStreamBase.FileStream( new File(file) );
@@ -222,7 +233,7 @@ public class SolrRequestParsers 
             if (pos < len) {
               final char ch = queryString.charAt(pos);
               if (ch > 127) {
-                throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "URLDecoder: The query string contains a not-%-escaped byte > 127 at position " + pos);
+                throw new SolrException(ErrorCode.BAD_REQUEST, "URLDecoder: The query string contains a not-%-escaped byte > 127 at position " + pos);
               }
               pos++;
               return ch;
@@ -233,7 +244,7 @@ public class SolrRequestParsers 
         };
         parseFormDataContent(in, Long.MAX_VALUE, IOUtils.CHARSET_UTF_8, map);
       } catch (IOException ioe) {
-        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, ioe);
+        throw new SolrException(ErrorCode.BAD_REQUEST, ioe);
       }
     }
   }
@@ -263,7 +274,7 @@ public class SolrRequestParsers 
             final String key = decodeChars(keyStream, keyPos, charsetDecoder), value = decodeChars(valueStream, valuePos, charsetDecoder);
             MultiMapSolrParams.addParam(key, value, map);
           } else if (valueStream.size() > 0) {
-            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded invalid: missing key");
+            throw new SolrException(ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded invalid: missing key");
           }
           keyStream.reset();
           valueStream.reset();
@@ -295,7 +306,7 @@ public class SolrRequestParsers 
       }
       len++;
       if (len > maxLen) {
-        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content exceeds upload limit of " + (maxLen/1024L) + " KB");
+        throw new SolrException(ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content exceeds upload limit of " + (maxLen/1024L) + " KB");
       }
     }
     return len;
@@ -305,7 +316,7 @@ public class SolrRequestParsers 
     try {
       return charsetDecoder.decode(ByteBuffer.wrap(stream.buffer(), 0, stream.size())).toString();
     } catch (CharacterCodingException cce) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+      throw new SolrException(ErrorCode.BAD_REQUEST,
         "URLDecoder: Invalid character encoding detected after position " + position +
         " of query string / form data (while parsing as " + charsetDecoder.charset().name() + ")"
       );
@@ -321,7 +332,7 @@ public class SolrRequestParsers 
   
   private static int digit16(int b) {
     if (b == -1) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "URLDecoder: Incomplete trailing escape (%) pattern");
+      throw new SolrException(ErrorCode.BAD_REQUEST, "URLDecoder: Incomplete trailing escape (%) pattern");
     }
     if (b >= '0' && b <= '9') {
       return b - '0';
@@ -332,7 +343,7 @@ public class SolrRequestParsers 
     if (b >= 'a' && b <= 'f') {
       return b - ('a' - 10);
     }
-    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "URLDecoder: Invalid digit (" + ((char) b) + ") in escape (%) pattern");
+    throw new SolrException(ErrorCode.BAD_REQUEST, "URLDecoder: Invalid digit (" + ((char) b) + ") in escape (%) pattern");
   }
   
   public boolean isHandleSelect() {
@@ -342,6 +353,14 @@ public class SolrRequestParsers 
   public void setHandleSelect(boolean handleSelect) {
     this.handleSelect = handleSelect;
   }
+  
+  public boolean isAddRequestHeadersToContext() {
+    return addHttpRequestToContext;
+  }
+
+  public void setAddRequestHeadersToContext(boolean addRequestHeadersToContext) {
+    this.addHttpRequestToContext = addRequestHeadersToContext;
+  }
 }
 
 //-----------------------------------------------------------------
@@ -453,7 +472,7 @@ class MultipartRequestParser implements 
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
     if( !ServletFileUpload.isMultipartContent(req) ) {
-      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Not multipart content! "+req.getContentType() );
+      throw new SolrException( ErrorCode.BAD_REQUEST, "Not multipart content! "+req.getContentType() );
     }
     
     MultiMapSolrParams params = SolrRequestParsers.parseQueryString( req.getQueryString() );
@@ -508,7 +527,7 @@ class FormDataRequestParser implements S
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
     if (!isFormData(req)) {
-      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Not application/x-www-form-urlencoded content: "+req.getContentType() );
+      throw new SolrException( ErrorCode.BAD_REQUEST, "Not application/x-www-form-urlencoded content: "+req.getContentType() );
     }
     
     final Map<String,String[]> map = new HashMap<String, String[]>();
@@ -523,7 +542,7 @@ class FormDataRequestParser implements S
     final long totalLength = req.getContentLength();
     final long maxLength = ((long) uploadLimitKB) * 1024L;
     if (totalLength > maxLength) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content length (" +
+      throw new SolrException(ErrorCode.BAD_REQUEST, "application/x-www-form-urlencoded content length (" +
         totalLength + " bytes) exceeds upload limit of " + uploadLimitKB + " KB");
     }
     
@@ -538,7 +557,7 @@ class FormDataRequestParser implements S
         throw getParameterIncompatibilityException();
       }
     } catch (IOException ioe) {
-      throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, ioe);
+      throw new SolrException(ErrorCode.BAD_REQUEST, ioe);
     } catch (IllegalStateException ise) {
       throw (SolrException) getParameterIncompatibilityException().initCause(ise);
     } finally {
@@ -549,7 +568,7 @@ class FormDataRequestParser implements S
   }
   
   private SolrException getParameterIncompatibilityException() {
-    return new SolrException(SolrException.ErrorCode.SERVER_ERROR,
+    return new SolrException(ErrorCode.SERVER_ERROR,
       "Solr requires that request parameters sent using application/x-www-form-urlencoded " +
       "content-type can be read through the request input stream. Unfortunately, the " +
       "stream was empty / not available. This may be caused by another servlet filter calling " +
@@ -595,7 +614,8 @@ class StandardRequestParser implements S
       final HttpServletRequest req, ArrayList<ContentStream> streams ) throws Exception
   {
     String method = req.getMethod().toUpperCase(Locale.ROOT);
-    if ("GET".equals(method) || "HEAD".equals(method)) {
+    if ("GET".equals(method) || "HEAD".equals(method) 
+        || ("PUT".equals(method) && req.getRequestURI().contains("/schema"))) {
       return SolrRequestParsers.parseQueryString(req.getQueryString());
     }
     if ("POST".equals( method ) ) {
@@ -607,7 +627,7 @@ class StandardRequestParser implements S
       }
       return raw.parseParamsAndFillStreams(req, streams);
     }
-    throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Unsupported method: "+method );
+    throw new SolrException(ErrorCode.BAD_REQUEST, "Unsupported method: " + method + " for request " + req);
   }
 }
 

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/servlet/ZookeeperInfoServlet.java Thu May 30 07:53:18 2013
@@ -32,8 +32,8 @@ import javax.servlet.http.HttpServletRes
 
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.IOUtils;
-import org.apache.noggit.CharArr;
-import org.apache.noggit.JSONWriter;
+import org.noggit.CharArr;
+import org.noggit.JSONWriter;
 import org.apache.solr.cloud.ZkController;
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.cloud.SolrZkClient;

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/FileBasedSpellChecker.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/FileBasedSpellChecker.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/FileBasedSpellChecker.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/FileBasedSpellChecker.java Thu May 30 07:53:18 2013
@@ -21,7 +21,13 @@ import java.io.InputStreamReader;
 import java.util.List;
 
 import org.apache.lucene.document.Field;
-import org.apache.lucene.index.*;
+import org.apache.lucene.index.DirectoryReader;
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.index.IndexWriter;
+import org.apache.lucene.index.IndexWriterConfig;
+import org.apache.lucene.index.LogByteSizeMergePolicy;
+import org.apache.lucene.index.LogMergePolicy;
+import org.apache.solr.schema.IndexSchema;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -60,7 +66,7 @@ public class FileBasedSpellChecker exten
 
   @Override
   public void build(SolrCore core, SolrIndexSearcher searcher) throws IOException {
-    loadExternalFileDictionary(core);
+    loadExternalFileDictionary(core, searcher);
     spellChecker.clearIndex();
     // TODO: you should be able to specify the IWC params?
     // TODO: if we enable this, codec gets angry since field won't exist in the schema
@@ -76,12 +82,12 @@ public class FileBasedSpellChecker exten
     return null;
   }
 
-  private void loadExternalFileDictionary(SolrCore core) {
+  private void loadExternalFileDictionary(SolrCore core, SolrIndexSearcher searcher) {
     try {
-
+      IndexSchema schema = null == searcher ? core.getLatestSchema() : searcher.getSchema();
       // Get the field's analyzer
-      if (fieldTypeName != null && core.getSchema().getFieldTypeNoEx(fieldTypeName) != null) {
-        FieldType fieldType = core.getSchema().getFieldTypes().get(fieldTypeName);
+      if (fieldTypeName != null && schema.getFieldTypeNoEx(fieldTypeName) != null) {
+        FieldType fieldType = schema.getFieldTypes().get(fieldTypeName);
         // Do index-time analysis using the given fieldType's analyzer
         RAMDirectory ramDir = new RAMDirectory();
 

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SolrSpellChecker.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SolrSpellChecker.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SolrSpellChecker.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SolrSpellChecker.java Thu May 30 07:53:18 2013
@@ -29,6 +29,7 @@ import org.apache.solr.common.util.Named
 import org.apache.solr.core.SolrCore;
 import org.apache.solr.handler.component.SpellCheckMergeData;
 import org.apache.solr.schema.FieldType;
+import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.search.SolrIndexSearcher;
 
 import java.io.IOException;
@@ -63,12 +64,13 @@ public abstract class SolrSpellChecker {
       name = DEFAULT_DICTIONARY_NAME;
     }
     field = (String)config.get(FIELD);
-    if (field != null && core.getSchema().getFieldTypeNoEx(field) != null)  {
-      analyzer = core.getSchema().getFieldType(field).getQueryAnalyzer();
+    IndexSchema schema = core.getLatestSchema();
+    if (field != null && schema.getFieldTypeNoEx(field) != null)  {
+      analyzer = schema.getFieldType(field).getQueryAnalyzer();
     }
     fieldTypeName = (String) config.get(FIELD_TYPE);
-    if (core.getSchema().getFieldTypes().containsKey(fieldTypeName))  {
-      FieldType fieldType = core.getSchema().getFieldTypes().get(fieldTypeName);
+    if (schema.getFieldTypes().containsKey(fieldTypeName))  {
+      FieldType fieldType = schema.getFieldTypes().get(fieldTypeName);
       analyzer = fieldType.getQueryAnalyzer();
     }
     if (analyzer == null)   {

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/SpellCheckCollator.java Thu May 30 07:53:18 2013
@@ -22,7 +22,9 @@ import java.util.Iterator;
 import java.util.List;
 
 import org.apache.lucene.analysis.Token;
+import org.apache.lucene.index.IndexReader;
 import org.apache.solr.common.params.CommonParams;
+import org.apache.solr.common.params.DisMaxParams;
 import org.apache.solr.common.params.GroupParams;
 import org.apache.solr.common.params.ModifiableSolrParams;
 import org.apache.solr.common.params.SolrParams;
@@ -33,15 +35,22 @@ import org.apache.solr.handler.component
 import org.apache.solr.handler.component.SearchComponent;
 import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.search.EarlyTerminatingCollectorException;
+import org.apache.solr.search.SolrIndexSearcher;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class SpellCheckCollator {
   private static final Logger LOG = LoggerFactory.getLogger(SpellCheckCollator.class);
-
-  public List<SpellCheckCollation> collate(SpellingResult result, String originalQuery, ResponseBuilder ultimateResponse,
-                                           int maxCollations, int maxTries, int maxEvaluations, boolean suggestionsMayOverlap) {
-    List<SpellCheckCollation> collations = new ArrayList<SpellCheckCollation>();
+  private int maxCollations = 1;
+  private int maxCollationTries = 0;
+  private int maxCollationEvaluations = 10000;
+  private boolean suggestionsMayOverlap = false;
+  private int docCollectionLimit = 0;
+
+  public List<SpellCheckCollation> collate(SpellingResult result,
+      String originalQuery, ResponseBuilder ultimateResponse) {
+  List<SpellCheckCollation> collations = new ArrayList<SpellCheckCollation>();
 
     QueryComponent queryComponent = null;
     if (ultimateResponse.components != null) {
@@ -54,6 +63,7 @@ public class SpellCheckCollator {
     }
 
     boolean verifyCandidateWithQuery = true;
+    int maxTries = maxCollationTries;
     int maxNumberToIterate = maxTries;
     if (maxTries < 1) {
       maxTries = 1;
@@ -65,10 +75,17 @@ public class SpellCheckCollator {
       maxTries = 1;
       verifyCandidateWithQuery = false;
     }
+    docCollectionLimit = docCollectionLimit > 0 ? docCollectionLimit : 0;
+    int maxDocId = -1;
+    if (verifyCandidateWithQuery && docCollectionLimit > 0) {
+      IndexReader reader = ultimateResponse.req.getSearcher().getIndexReader();
+      maxDocId = reader.maxDoc();
+    }
 
     int tryNo = 0;
     int collNo = 0;
-    PossibilityIterator possibilityIter = new PossibilityIterator(result.getSuggestions(), maxNumberToIterate, maxEvaluations, suggestionsMayOverlap);
+    PossibilityIterator possibilityIter = new PossibilityIterator(result.getSuggestions(), 
+        maxNumberToIterate, maxCollationEvaluations, suggestionsMayOverlap);
     while (tryNo < maxTries && collNo < maxCollations && possibilityIter.hasNext()) {
 
       PossibilityIterator.RankedSpellPossibility possibility = possibilityIter.next();
@@ -96,12 +113,25 @@ public class SpellCheckCollator {
         }
         params.set(CommonParams.Q, collationQueryStr);
         params.remove(CommonParams.START);
+        params.set(CommonParams.ROWS, "" + docCollectionLimit);
+        // we don't want any stored fields
         params.set(CommonParams.FL, "id");
-        params.set(CommonParams.ROWS, "0");
+        // we'll sort by doc id to ensure no scoring is done.
+        params.set(CommonParams.SORT, "_docid_ asc");
+        // If a dismax query, don't add unnecessary clauses for scoring
+        params.remove(DisMaxParams.TIE);
+        params.remove(DisMaxParams.PF);
+        params.remove(DisMaxParams.PF2);
+        params.remove(DisMaxParams.PF3);
+        params.remove(DisMaxParams.BQ);
+        params.remove(DisMaxParams.BF);
+        // Collate testing does not support Grouping (see SOLR-2577)
         params.remove(GroupParams.GROUP);
 
         // creating a request here... make sure to close it!
-        ResponseBuilder checkResponse = new ResponseBuilder(new LocalSolrQueryRequest(ultimateResponse.req.getCore(), params),new SolrQueryResponse(), Arrays.<SearchComponent>asList(queryComponent));
+        ResponseBuilder checkResponse = new ResponseBuilder(
+            new LocalSolrQueryRequest(ultimateResponse.req.getCore(), params),
+            new SolrQueryResponse(), Arrays.<SearchComponent> asList(queryComponent)); 
         checkResponse.setQparser(ultimateResponse.getQparser());
         checkResponse.setFilters(ultimateResponse.getFilters());
         checkResponse.setQueryString(collationQueryStr);
@@ -109,8 +139,19 @@ public class SpellCheckCollator {
 
         try {
           queryComponent.prepare(checkResponse);
+          if (docCollectionLimit > 0) {
+            int f = checkResponse.getFieldFlags();
+            checkResponse.setFieldFlags(f |= SolrIndexSearcher.TERMINATE_EARLY);            
+          }
           queryComponent.process(checkResponse);
           hits = (Integer) checkResponse.rsp.getToLog().get("hits");
+        } catch (EarlyTerminatingCollectorException etce) {
+          assert (docCollectionLimit > 0);
+          if (etce.getLastDocId() + 1 == maxDocId) {
+            hits = docCollectionLimit;
+          } else {
+            hits = maxDocId / ((etce.getLastDocId() + 1) / docCollectionLimit);
+          }
         } catch (Exception e) {
           LOG.warn("Exception trying to re-query to check if a spell check possibility would return any hits.", e);
         } finally {
@@ -191,6 +232,27 @@ public class SpellCheckCollator {
       offset += corr.length() - oneForReqOrProhib - (tok.endOffset() - tok.startOffset());      
     }
     return collation.toString();
-  }
-
+  }  
+  public SpellCheckCollator setMaxCollations(int maxCollations) {
+    this.maxCollations = maxCollations;
+    return this;
+  }  
+  public SpellCheckCollator setMaxCollationTries(int maxCollationTries) {
+    this.maxCollationTries = maxCollationTries;
+    return this;
+  }  
+  public SpellCheckCollator setMaxCollationEvaluations(
+      int maxCollationEvaluations) {
+    this.maxCollationEvaluations = maxCollationEvaluations;
+    return this;
+  }  
+  public SpellCheckCollator setSuggestionsMayOverlap(
+      boolean suggestionsMayOverlap) {
+    this.suggestionsMayOverlap = suggestionsMayOverlap;
+    return this;
+  }  
+  public SpellCheckCollator setDocCollectionLimit(int docCollectionLimit) {
+    this.docCollectionLimit = docCollectionLimit;
+    return this;
+  }    
 }

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/AnalyzingLookupFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/AnalyzingLookupFactory.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/AnalyzingLookupFactory.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/AnalyzingLookupFactory.java Thu May 30 07:53:18 2013
@@ -77,7 +77,7 @@ public class AnalyzingLookupFactory exte
     if (fieldTypeName == null) {
       throw new IllegalArgumentException("Error in configuration: " + QUERY_ANALYZER + " parameter is mandatory");
     }
-    FieldType ft = core.getSchema().getFieldTypeByName(fieldTypeName.toString());
+    FieldType ft = core.getLatestSchema().getFieldTypeByName(fieldTypeName.toString());
     Analyzer indexAnalyzer = ft.getAnalyzer();
     Analyzer queryAnalyzer = ft.getQueryAnalyzer();
     

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/FuzzyLookupFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/FuzzyLookupFactory.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/FuzzyLookupFactory.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/spelling/suggest/fst/FuzzyLookupFactory.java Thu May 30 07:53:18 2013
@@ -67,7 +67,7 @@ public class FuzzyLookupFactory extends 
       throw new IllegalArgumentException("Error in configuration: " + AnalyzingLookupFactory.QUERY_ANALYZER + " parameter is mandatory");
     }
     // retrieve index and query analyzers for the field
-    FieldType ft = core.getSchema().getFieldTypeByName(fieldTypeName.toString());
+    FieldType ft = core.getLatestSchema().getFieldTypeByName(fieldTypeName.toString());
     Analyzer indexAnalyzer = ft.getAnalyzer();
     Analyzer queryAnalyzer = ft.getQueryAnalyzer();
     

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DefaultSolrCoreState.java Thu May 30 07:53:18 2013
@@ -22,9 +22,9 @@ import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
 import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.store.AlreadyClosedException;
 import org.apache.solr.cloud.RecoveryStrategy;
 import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrException.ErrorCode;
 import org.apache.solr.core.CoreContainer;
 import org.apache.solr.core.CoreDescriptor;
 import org.apache.solr.core.DirectoryFactory;
@@ -48,7 +48,6 @@ public final class DefaultSolrCoreState 
 
   private volatile boolean recoveryRunning;
   private RecoveryStrategy recoveryStrat;
-  private volatile boolean closed = false;
 
   private RefCounted<IndexWriter> refCntWriter;
 
@@ -71,6 +70,7 @@ public final class DefaultSolrCoreState 
         log.info("closing IndexWriter...");
         indexWriter.close();
       }
+      indexWriter = null;
     } catch (Throwable t) {
       log.error("Error during shutdown of writer.", t);
     } 
@@ -79,17 +79,9 @@ public final class DefaultSolrCoreState 
   @Override
   public RefCounted<IndexWriter> getIndexWriter(SolrCore core)
       throws IOException {
-    
-    if (closed) {
-      throw new RuntimeException("SolrCoreState already closed");
-    }
-    
     synchronized (writerPauseLock) {
-      if (core == null) {
-        // core == null is a signal to just return the current writer, or null
-        // if none.
-        if (refCntWriter != null) refCntWriter.incref();
-        return refCntWriter;
+      if (closed) {
+        throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "SolrCoreState already closed");
       }
       
       while (pauseWriter) {
@@ -98,12 +90,24 @@ public final class DefaultSolrCoreState 
         } catch (InterruptedException e) {}
         
         if (closed) {
-          throw new RuntimeException("Already closed");
+          throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "Already closed");
         }
       }
       
+      if (core == null) {
+        // core == null is a signal to just return the current writer, or null
+        // if none.
+        initRefCntWriter();
+        if (refCntWriter == null) return null;
+        writerFree = false;
+        writerPauseLock.notifyAll();
+        if (refCntWriter != null) refCntWriter.incref();
+        
+        return refCntWriter;
+      }
+      
       if (indexWriter == null) {
-        indexWriter = createMainIndexWriter(core, "DirectUpdateHandler2", false);
+        indexWriter = createMainIndexWriter(core, "DirectUpdateHandler2");
       }
       initRefCntWriter();
       writerFree = false;
@@ -114,7 +118,7 @@ public final class DefaultSolrCoreState 
   }
 
   private void initRefCntWriter() {
-    if (refCntWriter == null) {
+    if (refCntWriter == null && indexWriter != null) {
       refCntWriter = new RefCounted<IndexWriter>(indexWriter) {
         @Override
         public void close() {
@@ -128,13 +132,14 @@ public final class DefaultSolrCoreState 
   }
 
   @Override
-  public synchronized void newIndexWriter(SolrCore core, boolean rollback, boolean forceNewDir) throws IOException {
-    if (closed) {
-      throw new AlreadyClosedException("SolrCoreState already closed");
-    }
+  public synchronized void newIndexWriter(SolrCore core, boolean rollback) throws IOException {
     log.info("Creating new IndexWriter...");
     String coreName = core.getName();
     synchronized (writerPauseLock) {
+      if (closed) {
+        throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "Already closed");
+      }
+      
       // we need to wait for the Writer to fall out of use
       // first lets stop it from being lent out
       pauseWriter = true;
@@ -147,7 +152,7 @@ public final class DefaultSolrCoreState 
         } catch (InterruptedException e) {}
         
         if (closed) {
-          throw new RuntimeException("SolrCoreState already closed");
+          throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE, "SolrCoreState already closed");
         }
       }
 
@@ -171,7 +176,7 @@ public final class DefaultSolrCoreState 
             }
           }
         }
-        indexWriter = createMainIndexWriter(core, "DirectUpdateHandler2", forceNewDir);
+        indexWriter = createMainIndexWriter(core, "DirectUpdateHandler2");
         log.info("New IndexWriter is ready to be used.");
         // we need to null this so it picks up the new writer next get call
         refCntWriter = null;
@@ -185,13 +190,13 @@ public final class DefaultSolrCoreState 
 
   @Override
   public synchronized void rollbackIndexWriter(SolrCore core) throws IOException {
-    newIndexWriter(core, true, true);
+    newIndexWriter(core, true);
   }
   
-  protected SolrIndexWriter createMainIndexWriter(SolrCore core, String name, boolean forceNewDirectory) throws IOException {
+  protected SolrIndexWriter createMainIndexWriter(SolrCore core, String name) throws IOException {
     return SolrIndexWriter.create(name, core.getNewIndexDir(),
-        core.getDirectoryFactory(), false, core.getSchema(),
-        core.getSolrConfig().indexConfig, core.getDeletionPolicy(), core.getCodec(), forceNewDirectory);
+        core.getDirectoryFactory(), false, core.getLatestSchema(),
+        core.getSolrConfig().indexConfig, core.getDeletionPolicy(), core.getCodec());
   }
 
   @Override
@@ -206,12 +211,18 @@ public final class DefaultSolrCoreState 
       return;
     }
     
+    // check before we grab the lock
     if (cc.isShutDown()) {
       log.warn("Skipping recovery because Solr is shutdown");
       return;
     }
     
     synchronized (recoveryLock) {
+      // to be air tight we must also check after lock
+      if (cc.isShutDown()) {
+        log.warn("Skipping recovery because Solr is shutdown");
+        return;
+      }
       log.info("Running recovery - first canceling any ongoing recovery");
       cancelRecovery();
       

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DirectUpdateHandler2.java Thu May 30 07:53:18 2013
@@ -51,6 +51,7 @@ import org.apache.solr.request.LocalSolr
 import org.apache.solr.request.SolrQueryRequest;
 import org.apache.solr.request.SolrRequestInfo;
 import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.SchemaField;
 import org.apache.solr.search.FunctionRangeQuery;
 import org.apache.solr.search.QParser;
@@ -110,7 +111,7 @@ public class DirectUpdateHandler2 extend
   }
   
   public DirectUpdateHandler2(SolrCore core, UpdateHandler updateHandler) {
-    super(core);
+    super(core, updateHandler.getUpdateLog());
     solrCoreState = core.getSolrCoreState();
     
     UpdateHandlerInfo updateHandlerInfo = core.getSolrConfig()
@@ -123,11 +124,6 @@ public class DirectUpdateHandler2 extend
     int softCommitTimeUpperBound = updateHandlerInfo.autoSoftCommmitMaxTime; // getInt("updateHandler/autoSoftCommit/maxTime", -1);
     softCommitTracker = new CommitTracker("Soft", core, softCommitDocsUpperBound, softCommitTimeUpperBound, updateHandlerInfo.openSearcher, true);
     
-    this.ulog = updateHandler.getUpdateLog();
-    if (this.ulog != null) {
-      this.ulog.init(this, core);
-    }
-    
     commitWithinSoftCommit = updateHandlerInfo.commitWithinSoftCommit;
   }
 
@@ -162,6 +158,7 @@ public class DirectUpdateHandler2 extend
       }
       
       try {
+        IndexSchema schema = cmd.getReq().getSchema();
         
         if (cmd.overwrite) {
           
@@ -401,7 +398,7 @@ public class DirectUpdateHandler2 extend
       RefCounted<IndexWriter> iw = solrCoreState.getIndexWriter(core);
       try {
         IndexWriter writer = iw.get();
-        writer.updateDocument(idTerm, luceneDocument, core.getSchema()
+        writer.updateDocument(idTerm, luceneDocument, cmd.getReq().getSchema()
             .getAnalyzer());
         
         for (Query q : dbqList) {
@@ -616,8 +613,8 @@ public class DirectUpdateHandler2 extend
   }
 
   @Override
-  public void newIndexWriter(boolean rollback, boolean forceNewDir) throws IOException {
-    solrCoreState.newIndexWriter(core, rollback, forceNewDir);
+  public void newIndexWriter(boolean rollback) throws IOException {
+    solrCoreState.newIndexWriter(core, rollback);
   }
   
   /**
@@ -749,7 +746,7 @@ public class DirectUpdateHandler2 extend
 
   @Override
   public void split(SplitIndexCommand cmd) throws IOException {
-    // TODO: do a commit first?
+    commit(new CommitUpdateCommand(cmd.req, false));
     SolrIndexSplitter splitter = new SolrIndexSplitter(cmd);
     splitter.split();
   }

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DocumentBuilder.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DocumentBuilder.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DocumentBuilder.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/DocumentBuilder.java Thu May 30 07:53:18 2013
@@ -17,8 +17,6 @@
 
 package org.apache.solr.update;
 
-import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.List;
 
 import org.apache.lucene.document.Document;
@@ -27,154 +25,23 @@ import org.apache.lucene.index.StorableF
 import org.apache.solr.common.SolrException;
 import org.apache.solr.common.SolrInputDocument;
 import org.apache.solr.common.SolrInputField;
-import org.apache.solr.schema.*;
+import org.apache.solr.schema.CopyField;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
+
 
 /**
  *
  */
-
-
-// Not thread safe - by design.  Create a new builder for each thread.
 public class DocumentBuilder {
-  private final IndexSchema schema;
-  private Document doc;
-  private HashMap<String,String> map;
-
-  public DocumentBuilder(IndexSchema schema) {
-    this.schema = schema;
-  }
-
-  public void startDoc() {
-    doc = new Document();
-    map = new HashMap<String,String>();
-  }
-
-  protected void addSingleField(SchemaField sfield, String val, float boost) {
-    //System.out.println("###################ADDING FIELD "+sfield+"="+val);
-
-    // we don't check for a null val ourselves because a solr.FieldType
-    // might actually want to map it to something.  If createField()
-    // returns null, then we don't store the field.
-    List<StorableField> fields = sfield.createFields(val, boost);
-    if (!fields.isEmpty()) {
-      if (!sfield.multiValued()) {
-        String oldValue = map.put(sfield.getName(), val);
-        if (oldValue != null) {
-          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "ERROR: multiple values encountered for non multiValued field " + sfield.getName()
-                  + ": first='" + oldValue + "' second='" + val + "'");
-        }
-      }
-      // Add each field
-      for (StorableField field : fields) {
-        doc.add((Field) field);
-      }
-    }
-
-  }
-
-  /**
-   * Add the specified {@link org.apache.solr.schema.SchemaField} to the document.  Does not invoke the copyField mechanism.
-   * @param sfield The {@link org.apache.solr.schema.SchemaField} to add
-   * @param val The value to add
-   * @param boost The boost factor
-   *
-   * @see #addField(String, String)
-   * @see #addField(String, String, float)
-   * @see #addSingleField(org.apache.solr.schema.SchemaField, String, float)
-   */
-  public void addField(SchemaField sfield, String val, float boost) {
-    addSingleField(sfield,val,boost);
-  }
-
-  /**
-   * Add the Field and value to the document, invoking the copyField mechanism
-   * @param name The name of the field
-   * @param val The value to add
-   *
-   * @see #addField(String, String, float)
-   * @see #addField(org.apache.solr.schema.SchemaField, String, float)
-   * @see #addSingleField(org.apache.solr.schema.SchemaField, String, float)
-   */
-  public void addField(String name, String val) {
-    addField(name, val, 1.0f);
-  }
-
-  /**
-   * Add the Field and value to the document with the specified boost, invoking the copyField mechanism
-   * @param name The name of the field.
-   * @param val The value to add
-   * @param boost The boost
-   *
-   * @see #addField(String, String)
-   * @see #addField(org.apache.solr.schema.SchemaField, String, float)
-   * @see #addSingleField(org.apache.solr.schema.SchemaField, String, float)
-   *
-   */
-  public void addField(String name, String val, float boost) {
-    SchemaField sfield = schema.getFieldOrNull(name);
-    if (sfield != null) {
-      addField(sfield,val,boost);
-    }
-
-    // Check if we should copy this field to any other fields.
-    // This could happen whether it is explicit or not.
-    final List<CopyField> copyFields = schema.getCopyFieldsList(name);
-    if (copyFields != null) {
-      for(CopyField cf : copyFields) {
-        addSingleField(cf.getDestination(), cf.getLimitedValue( val ), boost);
-      }
-    }
-
-    // error if this field name doesn't match anything
-    if (sfield==null && (copyFields==null || copyFields.size()==0)) {
-      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST,"ERROR:unknown field '" + name + "'");
-    }
-  }
-
-  public void endDoc() {
-  }
-
-  // specific to this type of document builder
-  public Document getDoc() throws IllegalArgumentException {
-    
-    // Check for all required fields -- Note, all fields with a
-    // default value are defacto 'required' fields.  
-    List<String> missingFields = null;
-    for (SchemaField field : schema.getRequiredFields()) {
-      if (doc.getField(field.getName() ) == null) {
-        if (field.getDefaultValue() != null) {
-          addField(doc, field, field.getDefaultValue(), 1.0f);
-        } else {
-          if (missingFields==null) {
-            missingFields = new ArrayList<String>(1);
-          }
-          missingFields.add(field.getName());
-        }
-      }
-    }
-  
-    if (missingFields != null) {
-      StringBuilder builder = new StringBuilder();
-      // add the uniqueKey if possible
-      if( schema.getUniqueKeyField() != null ) {
-        String n = schema.getUniqueKeyField().getName();
-        String v = doc.getField( n ).stringValue();
-        builder.append( "Document ["+n+"="+v+"] " );
-      }
-      builder.append("missing required fields: " );
-      for (String field : missingFields) {
-        builder.append(field);
-        builder.append(" ");
-      }
-      throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, builder.toString());
-    }
-    
-    Document ret = doc; doc=null;
-    return ret;
-  }
-
 
   private static void addField(Document doc, SchemaField field, Object val, float boost) {
+    if (val instanceof StorableField) {
+      // set boost to the calculated compound boost
+      ((Field)val).setBoost(boost);
+      doc.add((Field)val);
+      return;
+    }
     for (StorableField f : field.getType().createFields(field, val, boost)) {
       if (f != null) doc.add((Field) f); // null fields are not added
     }

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/PeerSync.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/PeerSync.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/PeerSync.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/PeerSync.java Thu May 30 07:53:18 2013
@@ -51,6 +51,7 @@ import org.apache.solr.response.SolrQuer
 import org.apache.solr.update.processor.DistributedUpdateProcessorFactory;
 import org.apache.solr.update.processor.RunUpdateProcessorFactory;
 import org.apache.solr.update.processor.UpdateRequestProcessor;
+import org.apache.solr.update.processor.UpdateRequestProcessorChain;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -447,13 +448,8 @@ public class PeerSync  {
     SolrQueryRequest req = new LocalSolrQueryRequest(uhandler.core, params);
     SolrQueryResponse rsp = new SolrQueryResponse();
 
-    // TODO: use the standard update processor chain now that it has support to skip processors before the DistributedUpdateProcessor?
-    RunUpdateProcessorFactory runFac = new RunUpdateProcessorFactory();
-    DistributedUpdateProcessorFactory magicFac = new DistributedUpdateProcessorFactory();
-    runFac.init(new NamedList());
-    magicFac.init(new NamedList());
-
-    UpdateRequestProcessor proc = magicFac.getInstance(req, rsp, runFac.getInstance(req, rsp, null));
+    UpdateRequestProcessorChain processorChain = req.getCore().getUpdateProcessingChain(null);
+    UpdateRequestProcessor proc = processorChain.createProcessor(req, rsp);
 
     Collections.sort(updates, updateRecordComparator);
 

Modified: lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/SolrCoreState.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/SolrCoreState.java?rev=1487777&r1=1487776&r2=1487777&view=diff
==============================================================================
--- lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/SolrCoreState.java (original)
+++ lucene/dev/branches/security/solr/core/src/java/org/apache/solr/update/SolrCoreState.java Thu May 30 07:53:18 2013
@@ -37,6 +37,7 @@ import org.slf4j.LoggerFactory;
 public abstract class SolrCoreState {
   public static Logger log = LoggerFactory.getLogger(SolrCoreState.class);
   
+  protected boolean closed = false;
   private final Object deleteLock = new Object();
   
   public Object getUpdateLock() {
@@ -44,10 +45,6 @@ public abstract class SolrCoreState {
   }
   
   private int solrCoreStateRefCnt = 1;
-  
-  public synchronized int getSolrCoreStateRefCnt() {
-    return solrCoreStateRefCnt;
-  }
 
   public void increfSolrCoreState() {
     synchronized (this) {
@@ -58,11 +55,13 @@ public abstract class SolrCoreState {
     }
   }
   
-  public void decrefSolrCoreState(IndexWriterCloser closer) {
+  public boolean decrefSolrCoreState(IndexWriterCloser closer) {
     boolean close = false;
     synchronized (this) {
       solrCoreStateRefCnt--;
+      assert solrCoreStateRefCnt >= 0;
       if (solrCoreStateRefCnt == 0) {
+        closed = true;
         close = true;
       }
     }
@@ -75,6 +74,7 @@ public abstract class SolrCoreState {
         log.error("Error closing SolrCoreState", t);
       }
     }
+    return close;
   }
   
   public abstract Lock getCommitLock();
@@ -86,7 +86,7 @@ public abstract class SolrCoreState {
    * @param rollback close IndexWriter if false, else rollback
    * @throws IOException If there is a low-level I/O error.
    */
-  public abstract void newIndexWriter(SolrCore core, boolean rollback, boolean forceNewDir) throws IOException;
+  public abstract void newIndexWriter(SolrCore core, boolean rollback) throws IOException;
   
   /**
    * Get the current IndexWriter. If a new IndexWriter must be created, use the