You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by si...@apache.org on 2010/10/20 14:44:39 UTC

svn commit: r1025539 [8/10] - in /lucene/dev/branches/docvalues: ./ lucene/ lucene/contrib/ lucene/contrib/benchmark/src/java/org/apache/lucene/benchmark/byTask/tasks/ lucene/contrib/highlighter/src/test/ lucene/contrib/instantiated/src/test/org/apache...

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/NumericFieldCacheSource.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/NumericFieldCacheSource.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/NumericFieldCacheSource.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/NumericFieldCacheSource.java Wed Oct 20 12:44:28 2010
@@ -22,7 +22,7 @@ import org.apache.lucene.search.cache.Ca
 
 /**
  * 
- * @version $Id: FieldCacheSource.java 794328 2009-07-15 17:21:04Z shalin $
+ * @version $Id$
  */
 public abstract class NumericFieldCacheSource<T extends CachedArray> extends FieldCacheSource {
   protected final CachedArrayCreator<T> creator;

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/NumericFieldCacheSource.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/ShortFieldSource.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/VectorValueSource.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/distance/GeohashFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/distance/GeohashHaversineFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/distance/HaversineFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/distance/SquaredEuclideanFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/distance/StringDistanceFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/search/function/distance/VectorDistanceFunction.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/AbstractLuceneSpellChecker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/DirectSolrSpellChecker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/FileBasedSpellChecker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/IndexBasedSpellChecker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/PossibilityIterator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/QueryConverter.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/RankedSpellPossibility.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SolrSpellChecker.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollation.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollation.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollation.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollation.java Wed Oct 20 12:44:28 2010
@@ -20,49 +20,49 @@ package org.apache.solr.spelling;
 import org.apache.solr.common.util.NamedList;
 
 public class SpellCheckCollation implements Comparable<SpellCheckCollation> {
-	private NamedList<String> misspellingsAndCorrections;
-	private int hits;
-	private int internalRank;
-	private String collationQuery;
-	
-	public int compareTo(SpellCheckCollation scc) {
-		int c = new Integer(internalRank).compareTo(scc.internalRank);
-		if (c == 0) {
-			return collationQuery.compareTo(scc.collationQuery);
-		}
-		return c;
-	}
-
-	public NamedList<String> getMisspellingsAndCorrections() {
-		return misspellingsAndCorrections;
-	}
-
-	public void setMisspellingsAndCorrections(
-			NamedList<String> misspellingsAndCorrections) {
-		this.misspellingsAndCorrections = misspellingsAndCorrections;
-	}
-
-	public int getHits() {
-		return hits;
-	}
-
-	public void setHits(int hits) {
-		this.hits = hits;
-	}
-
-	public String getCollationQuery() {
-		return collationQuery;
-	}
-
-	public void setCollationQuery(String collationQuery) {
-		this.collationQuery = collationQuery;
-	}
-	
-	public int getInternalRank() {
-		return internalRank;
-	}
-
-	public void setInternalRank(int internalRank) {
-		this.internalRank = internalRank;
-	}
+  private NamedList<String> misspellingsAndCorrections;
+  private int hits;
+  private int internalRank;
+  private String collationQuery;
+
+  public int compareTo(SpellCheckCollation scc) {
+    int c = new Integer(internalRank).compareTo(scc.internalRank);
+    if (c == 0) {
+      return collationQuery.compareTo(scc.collationQuery);
+    }
+    return c;
+  }
+
+  public NamedList<String> getMisspellingsAndCorrections() {
+    return misspellingsAndCorrections;
+  }
+
+  public void setMisspellingsAndCorrections(
+      NamedList<String> misspellingsAndCorrections) {
+    this.misspellingsAndCorrections = misspellingsAndCorrections;
+  }
+
+  public int getHits() {
+    return hits;
+  }
+
+  public void setHits(int hits) {
+    this.hits = hits;
+  }
+
+  public String getCollationQuery() {
+    return collationQuery;
+  }
+
+  public void setCollationQuery(String collationQuery) {
+    this.collationQuery = collationQuery;
+  }
+
+  public int getInternalRank() {
+    return internalRank;
+  }
+
+  public void setInternalRank(int internalRank) {
+    this.internalRank = internalRank;
+  }
 }

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollation.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollator.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollator.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollator.java Wed Oct 20 12:44:28 2010
@@ -29,6 +29,7 @@ import org.apache.solr.handler.component
 import org.apache.solr.handler.component.ResponseBuilder;
 import org.apache.solr.handler.component.SearchComponent;
 import org.apache.solr.handler.component.SearchHandler;
+import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequestBase;
 import org.apache.solr.response.SolrQueryResponse;
 import org.mortbay.log.Log;
@@ -36,107 +37,107 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class SpellCheckCollator {
-	private static final Logger LOG = LoggerFactory.getLogger(SpellCheckCollator.class);
+  private static final Logger LOG = LoggerFactory.getLogger(SpellCheckCollator.class);
 
-	public List<SpellCheckCollation> collate(SpellingResult result, String originalQuery, ResponseBuilder ultimateResponse,
-			int maxCollations, int maxTries) {
-		List<SpellCheckCollation> collations = new ArrayList<SpellCheckCollation>();
-
-		QueryComponent queryComponent = null;
-		if (ultimateResponse.components != null) {
-			for (SearchComponent sc : ultimateResponse.components) {
-				if (sc instanceof QueryComponent) {
-					queryComponent = (QueryComponent) sc;
-					break;
-				}
-			}
-		}
-		
-		boolean verifyCandidateWithQuery = true;
-		if (maxTries < 1) {
-			maxTries = 1;
-			verifyCandidateWithQuery = false;
-		}
-		if (queryComponent == null && verifyCandidateWithQuery) {
-			LOG.warn("Could not find an instance of QueryComponent.  Disabling collation verification against the index.");
-			maxTries = 1;
-			verifyCandidateWithQuery = false;
-		}
-		
-		int tryNo = 0;
-		int collNo = 0;
-		PossibilityIterator possibilityIter = new PossibilityIterator(result.getSuggestions());
-		while (tryNo < maxTries && collNo < maxCollations && possibilityIter.hasNext()) {
-
-			RankedSpellPossibility possibility = possibilityIter.next();
-			String collationQueryStr = getCollation(originalQuery, possibility.getCorrections());
-			int hits = 0;
-					
-			if (verifyCandidateWithQuery) {
-				tryNo++;
-
-				ResponseBuilder checkResponse = new ResponseBuilder();
-				checkResponse.setQparser(ultimateResponse.getQparser());				
-				checkResponse.setFilters(ultimateResponse.getFilters());
-				checkResponse.setQueryString(collationQueryStr);				
-				checkResponse.components = Arrays.asList(new SearchComponent[] { queryComponent });
-				
-				ModifiableSolrParams params = new ModifiableSolrParams(ultimateResponse.req.getParams());
-				params.remove(CommonParams.Q);
-				params.add(CommonParams.Q, collationQueryStr);
-				params.remove(CommonParams.START);
-				params.remove(CommonParams.ROWS);
-				params.add(CommonParams.FL, "id");
-				params.add(CommonParams.ROWS, "0");
-				//Would rather have found a concrete class to use...
-				checkResponse.req = new SolrQueryRequestBase(ultimateResponse.req.getCore(), params) { };
-				checkResponse.rsp = new SolrQueryResponse();
-				
-				try {
-					queryComponent.prepare(checkResponse);
-					queryComponent.process(checkResponse);				
-					hits = (Integer) checkResponse.rsp.getToLog().get("hits");					
-				} catch (Exception e) {
-					Log.warn("Exception trying to re-query to check if a spell check possibility would return any hits.", e);
-				}
-			}
-			if (hits > 0 || !verifyCandidateWithQuery) {
-				collNo++;
-				SpellCheckCollation collation = new SpellCheckCollation();
-				collation.setCollationQuery(collationQueryStr);
-				collation.setHits(hits);
-				collation.setInternalRank(possibility.getRank());
-
-				NamedList<String> misspellingsAndCorrections = new NamedList<String>();
-				for (SpellCheckCorrection corr : possibility.getCorrections()) {
-					misspellingsAndCorrections.add(corr.getOriginal().toString(), corr.getCorrection());
-				}
-				collation.setMisspellingsAndCorrections(misspellingsAndCorrections);
-				collations.add(collation);
-			}
-			if (LOG.isDebugEnabled()) {
-				LOG.debug("Collation: " + collationQueryStr + (verifyCandidateWithQuery ? (" will return " + hits + " hits.") : ""));
-			}		
-		}
-		return collations;
-	}
-
-	private String getCollation(String origQuery,
-			List<SpellCheckCorrection> corrections) {
-		StringBuilder collation = new StringBuilder(origQuery);
-		int offset = 0;
-		for (SpellCheckCorrection correction : corrections) {
-			Token tok = correction.getOriginal();
-			// we are replacing the query in order, but injected terms might cause
-			// illegal offsets due to previous replacements.
-			if (tok.getPositionIncrement() == 0)
-				continue;
-			collation.replace(tok.startOffset() + offset, tok.endOffset() + offset,
-					correction.getCorrection());
-			offset += correction.getCorrection().length()
-					- (tok.endOffset() - tok.startOffset());
-		}
-		return collation.toString();
-	}
+  public List<SpellCheckCollation> collate(SpellingResult result, String originalQuery, ResponseBuilder ultimateResponse,
+                                           int maxCollations, int maxTries) {
+    List<SpellCheckCollation> collations = new ArrayList<SpellCheckCollation>();
+
+    QueryComponent queryComponent = null;
+    if (ultimateResponse.components != null) {
+      for (SearchComponent sc : ultimateResponse.components) {
+        if (sc instanceof QueryComponent) {
+          queryComponent = (QueryComponent) sc;
+          break;
+        }
+      }
+    }
+
+    boolean verifyCandidateWithQuery = true;
+    if (maxTries < 1) {
+      maxTries = 1;
+      verifyCandidateWithQuery = false;
+    }
+    if (queryComponent == null && verifyCandidateWithQuery) {
+      LOG.info("Could not find an instance of QueryComponent.  Disabling collation verification against the index.");
+      maxTries = 1;
+      verifyCandidateWithQuery = false;
+    }
+
+    int tryNo = 0;
+    int collNo = 0;
+    PossibilityIterator possibilityIter = new PossibilityIterator(result.getSuggestions());
+    while (tryNo < maxTries && collNo < maxCollations && possibilityIter.hasNext()) {
+
+      RankedSpellPossibility possibility = possibilityIter.next();
+      String collationQueryStr = getCollation(originalQuery, possibility.getCorrections());
+      int hits = 0;
+
+      if (verifyCandidateWithQuery) {
+        tryNo++;
+
+        ResponseBuilder checkResponse = new ResponseBuilder();
+        checkResponse.setQparser(ultimateResponse.getQparser());
+        checkResponse.setFilters(ultimateResponse.getFilters());
+        checkResponse.setQueryString(collationQueryStr);
+        checkResponse.components = Arrays.asList(new SearchComponent[] { queryComponent });
+
+        ModifiableSolrParams params = new ModifiableSolrParams(ultimateResponse.req.getParams());
+        params.set(CommonParams.Q, collationQueryStr);
+        params.remove(CommonParams.START);
+        params.set(CommonParams.FL, "id");
+        params.set(CommonParams.ROWS, "0");
+        // creating a request here... make sure to close it!
+        checkResponse.req = new LocalSolrQueryRequest(ultimateResponse.req.getCore(), params);
+        checkResponse.rsp = new SolrQueryResponse();
+
+        try {
+          queryComponent.prepare(checkResponse);
+          queryComponent.process(checkResponse);
+          hits = (Integer) checkResponse.rsp.getToLog().get("hits");
+        } catch (Exception e) {
+          Log.warn("Exception trying to re-query to check if a spell check possibility would return any hits.", e);
+        } finally {
+          checkResponse.req.close();  
+        }
+      }
+      if (hits > 0 || !verifyCandidateWithQuery) {
+        collNo++;
+        SpellCheckCollation collation = new SpellCheckCollation();
+        collation.setCollationQuery(collationQueryStr);
+        collation.setHits(hits);
+        collation.setInternalRank(possibility.getRank());
+
+        NamedList<String> misspellingsAndCorrections = new NamedList<String>();
+        for (SpellCheckCorrection corr : possibility.getCorrections()) {
+          misspellingsAndCorrections.add(corr.getOriginal().toString(), corr.getCorrection());
+        }
+        collation.setMisspellingsAndCorrections(misspellingsAndCorrections);
+        collations.add(collation);
+      }
+      if (LOG.isDebugEnabled()) {
+        LOG.debug("Collation: " + collationQueryStr + (verifyCandidateWithQuery ? (" will return " + hits + " hits.") : ""));
+      }
+    }
+    return collations;
+  }
+
+  private String getCollation(String origQuery,
+                              List<SpellCheckCorrection> corrections) {
+    StringBuilder collation = new StringBuilder(origQuery);
+    int offset = 0;
+    for (SpellCheckCorrection correction : corrections) {
+      Token tok = correction.getOriginal();
+      // we are replacing the query in order, but injected terms might cause
+      // illegal offsets due to previous replacements.
+      if (tok.getPositionIncrement() == 0)
+        continue;
+      collation.replace(tok.startOffset() + offset, tok.endOffset() + offset,
+          correction.getCorrection());
+      offset += correction.getCorrection().length()
+          - (tok.endOffset() - tok.startOffset());
+    }
+    return collation.toString();
+  }
 
 }

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCollator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCorrection.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCorrection.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCorrection.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCorrection.java Wed Oct 20 12:44:28 2010
@@ -19,32 +19,32 @@ package org.apache.solr.spelling;
 import org.apache.lucene.analysis.Token;
 
 public class SpellCheckCorrection {
-	private Token original;
-	private String correction;
-	private int numberOfOccurences;
-
-	public Token getOriginal() {
-		return original;
-	}
-
-	public void setOriginal(Token original) {
-		this.original = original;
-	}
-
-	public String getCorrection() {
-		return correction;
-	}
-
-	public void setCorrection(String correction) {
-		this.correction = correction;
-	}
-
-	public int getNumberOfOccurences() {
-		return numberOfOccurences;
-	}
-
-	public void setNumberOfOccurences(int numberOfOccurences) {
-		this.numberOfOccurences = numberOfOccurences;
-	}
+  private Token original;
+  private String correction;
+  private int numberOfOccurences;
+
+  public Token getOriginal() {
+    return original;
+  }
+
+  public void setOriginal(Token original) {
+    this.original = original;
+  }
+
+  public String getCorrection() {
+    return correction;
+  }
+
+  public void setCorrection(String correction) {
+    this.correction = correction;
+  }
+
+  public int getNumberOfOccurences() {
+    return numberOfOccurences;
+  }
+
+  public void setNumberOfOccurences(int numberOfOccurences) {
+    this.numberOfOccurences = numberOfOccurences;
+  }
 
 }

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellCheckCorrection.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellingOptions.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellingQueryConverter.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/SpellingResult.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/BufferingTermFreqIteratorWrapper.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/BufferingTermFreqIteratorWrapper.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/BufferingTermFreqIteratorWrapper.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/BufferingTermFreqIteratorWrapper.java Wed Oct 20 12:44:28 2010
@@ -21,7 +21,6 @@ public class BufferingTermFreqIteratorWr
       this.freq = freq;
     }
     
-    @Override
     public int compareTo(Entry o) {
       return word.compareTo(o.word);
     }    
@@ -42,24 +41,20 @@ public class BufferingTermFreqIteratorWr
     curPos = 0;
   }
 
-  @Override
   public float freq() {
     return curEntry.freq;
   }
 
-  @Override
   public boolean hasNext() {
     return curPos < entries.size();
   }
 
-  @Override
   public String next() {
     curEntry = entries.get(curPos);
     curPos++;
     return curEntry.word;
   }
 
-  @Override
   public void remove() {
     throw new UnsupportedOperationException("remove is not supported");
   }

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/BufferingTermFreqIteratorWrapper.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/FileDictionary.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Lookup.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Lookup.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Lookup.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Lookup.java Wed Oct 20 12:44:28 2010
@@ -16,7 +16,7 @@ public abstract class Lookup {
   /**
    * Result of a lookup.
    */
-  public static final class LookupResult {
+  public static final class LookupResult implements Comparable<LookupResult> {
     String key;
     float value;
     
@@ -28,6 +28,11 @@ public abstract class Lookup {
     public String toString() {
       return key + "/" + value;
     }
+
+    /** Compare alphabetically. */
+    public int compareTo(LookupResult o) {
+      return this.key.compareTo(o.key);
+    }
   }
   
   public static final class LookupPriorityQueue extends PriorityQueue<LookupResult> {

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Lookup.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/SortedTermFreqIteratorWrapper.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Suggester.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Suggester.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Suggester.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Suggester.java Wed Oct 20 12:44:28 2010
@@ -1,9 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.apache.solr.spelling.suggest;
 
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
+import java.util.Collections;
 import java.util.List;
 
 import org.apache.lucene.analysis.Token;
@@ -58,7 +76,7 @@ public class Suggester extends SolrSpell
     LOG.info("init: " + config);
     String name = super.init(config, core);
     threshold = config.get(THRESHOLD_TOKEN_FREQUENCY) == null ? 0.0f
-            : (Float) config.get(THRESHOLD_TOKEN_FREQUENCY);
+            : Float.valueOf((String)config.get(THRESHOLD_TOKEN_FREQUENCY));
     sourceLocation = (String) config.get(LOCATION);
     field = (String)config.get(FIELD);
     lookupImpl = (String)config.get(LOOKUP_IMPL);
@@ -149,6 +167,9 @@ public class Suggester extends SolrSpell
       if (suggestions == null) {
         continue;
       }
+      if (!options.onlyMorePopular) {
+        Collections.sort(suggestions);
+      }
       for (LookupResult lr : suggestions) {
         res.add(t, lr.key, ((Number)lr.value).intValue());
       }

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/Suggester.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/UnsortedTermFreqIteratorWrapper.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/jaspell/JaspellLookup.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/jaspell/JaspellTernarySearchTrie.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/tst/TSTAutocomplete.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/tst/TSTLookup.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/spelling/suggest/tst/TernaryTreeNode.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/update/processor/UpdateRequestProcessorChain.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/BitSetIterator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/BitUtil.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/BoundedTreeSet.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/DateMathParser.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/DateMathParser.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/DateMathParser.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/DateMathParser.java Wed Oct 20 12:44:28 2010
@@ -73,7 +73,7 @@ import java.util.regex.Pattern;
  * inspecting the keySet of <code>CALENDAR_UNITS</code>.
  * </p>
  *
- * @version $Id:$
+ * @version $Id$
  */
 public class DateMathParser  {
 

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/DateMathParser.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/HighFrequencyDictionary.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/HighlightingUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/OpenBitSet.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/SimplePostTool.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/SolrPluginUtils.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/SortedIterator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TermFreqIterator.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TermFreqIterator.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TermFreqIterator.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TermFreqIterator.java Wed Oct 20 12:44:28 2010
@@ -13,22 +13,18 @@ public interface TermFreqIterator extend
       this.wrapped = wrapped;
     }
 
-    @Override
     public float freq() {
       return 1.0f;
     }
 
-    @Override
     public boolean hasNext() {
       return wrapped.hasNext();
     }
 
-    @Override
     public String next() {
       return wrapped.next().toString();
     }
 
-    @Override
     public void remove() {
       throw new UnsupportedOperationException();
     }

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TermFreqIterator.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TestHarness.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TestHarness.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TestHarness.java (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TestHarness.java Wed Oct 20 12:44:28 2010
@@ -65,7 +65,7 @@ import java.util.Map;
  * distribution, in order to encourage plugin writers to create unit 
  * tests for their plugins.
  *
- * @version $Id:$
+ * @version $Id$
  */
 public class TestHarness {
   protected CoreContainer container;
@@ -175,12 +175,21 @@ public class TestHarness {
     }
     @Override
     public CoreContainer initialize() {
-      CoreContainer container = new CoreContainer(new SolrResourceLoader(SolrResourceLoader.locateSolrHome()));
+      CoreContainer container = new CoreContainer(new SolrResourceLoader(SolrResourceLoader.locateSolrHome())) {
+        {
+          hostPort = System.getProperty("hostPort");
+          hostContext = "solr";
+          defaultCoreName = "collection1";
+          initZooKeeper(System.getProperty("zkHost"), 10000);
+        }
+      };
+      
       CoreDescriptor dcore = new CoreDescriptor(container, coreName, solrConfig.getResourceLoader().getInstanceDir());
       dcore.setConfigName(solrConfig.getResourceName());
       dcore.setSchemaName(indexSchema.getResourceName());
-      SolrCore core = new SolrCore( null, dataDirectory, solrConfig, indexSchema, dcore);
+      SolrCore core = new SolrCore("collection1", dataDirectory, solrConfig, indexSchema, dcore);
       container.register(coreName, core, false);
+
       return container;
     }
   }
@@ -308,7 +317,7 @@ public class TestHarness {
   }
 
   /**
-   * Processes a "query" using a user constructed SolrQueryRequest
+   * Processes a "query" using a user constructed SolrQueryRequest, and closes the request at the end.
    *
    * @param handler the name of the request handler to process the request
    * @param req the Query to process, will be closed.
@@ -318,17 +327,22 @@ public class TestHarness {
    * @see LocalSolrQueryRequest
    */
   public String query(String handler, SolrQueryRequest req) throws IOException, Exception {
-    SolrQueryResponse rsp = queryAndResponse(handler, req);
+    try {
+      SolrQueryResponse rsp = queryAndResponse(handler, req);
 
-    StringWriter sw = new StringWriter(32000);
-    QueryResponseWriter responseWriter = core.getQueryResponseWriter(req);
-    responseWriter.write(sw,req,rsp);
+      StringWriter sw = new StringWriter(32000);
+      QueryResponseWriter responseWriter = core.getQueryResponseWriter(req);
+      responseWriter.write(sw,req,rsp);
 
-    req.close();
+      req.close();
 
-    return sw.toString();
+      return sw.toString();
+    } finally {
+      req.close();
+    }
   }
 
+  /** It is the users responsibility to close the request object when done with it */
   public SolrQueryResponse queryAndResponse(String handler, SolrQueryRequest req) throws Exception {
     SolrQueryResponse rsp = new SolrQueryResponse();
     core.execute(core.getRequestHandler(handler),req,rsp);

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/TestHarness.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Modified: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/doc-files/min-should-match.html
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/doc-files/min-should-match.html?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/doc-files/min-should-match.html (original)
+++ lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/doc-files/min-should-match.html Wed Oct 20 12:44:28 2010
@@ -119,7 +119,7 @@ DisMaxRequestHandler. 
 
 <hr>
 <pre>
-$Id:$
+$Id$
 $Source:$
 </pre>
 

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/doc-files/min-should-match.html
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/plugin/PluginInfoInitialized.java
------------------------------------------------------------------------------
--- svn:keywords (original)
+++ svn:keywords Wed Oct 20 12:44:28 2010
@@ -1 +1 @@
-Id
+Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/java/org/apache/solr/util/xslt/TransformerProvider.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: lucene/dev/branches/docvalues/solr/src/maven/solr-core-pom.xml.template
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Oct 20 12:44:28 2010
@@ -1,3 +1,4 @@
 /lucene/dev/branches/branch_3x/solr/src/maven/solr-core-pom.xml.template:949730,961612,979161,980654,982195,987811,988512
 /lucene/dev/branches/preflexfixes/solr/src/maven/solr-core-pom.xml.template:967125-979432
+/lucene/dev/trunk/solr/src/maven/solr-core-pom.xml.template:1021635-1024556,1025532-1025536
 /lucene/solr/trunk/src/maven/solr-core-pom.xml.template:922950-923910,923912-925091

Propchange: lucene/dev/branches/docvalues/solr/src/maven/solr-solrj-pom.xml.template
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Oct 20 12:44:28 2010
@@ -1,3 +1,4 @@
 /lucene/dev/branches/branch_3x/solr/src/maven/solr-solrj-pom.xml.template:949730,961612,979161,980654,982195,987811,988512
 /lucene/dev/branches/preflexfixes/solr/src/maven/solr-solrj-pom.xml.template:967125-979432
+/lucene/dev/trunk/solr/src/maven/solr-solrj-pom.xml.template:1021635-1024556,1025532-1025536
 /lucene/solr/trunk/src/maven/solr-solrj-pom.xml.template:922950-923910,923912-925091

Propchange: lucene/dev/branches/docvalues/solr/src/solrj/org/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Oct 20 12:44:28 2010
@@ -1,3 +1,4 @@
 /lucene/dev/branches/branch_3x/solr/src/solrj/org:949730,961612,979161,980654,982195,987811,988512
 /lucene/dev/branches/preflexfixes/solr/src/solrj/org:967125-979432
+/lucene/dev/trunk/solr/src/solrj/org:1021635-1024556,1025532-1025536
 /lucene/solr/trunk/src/solrj/org:922950-923910,923912-925091

Modified: lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java (original)
+++ lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/impl/LBHttpSolrServer.java Wed Oct 20 12:44:28 2010
@@ -18,6 +18,9 @@ package org.apache.solr.client.solrj.imp
 
 import org.apache.commons.httpclient.HttpClient;
 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.DefaultMethodRetryHandler;
+import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
+import org.apache.commons.httpclient.params.HttpMethodParams;
 import org.apache.solr.client.solrj.*;
 import org.apache.solr.client.solrj.response.QueryResponse;
 import org.apache.solr.common.util.NamedList;
@@ -27,26 +30,24 @@ import java.io.IOException;
 import java.lang.ref.WeakReference;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
+import java.util.concurrent.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.*;
 
 /**
- * LBHttpSolrServer or "LoadBalanced HttpSolrServer" is just a wrapper to CommonsHttpSolrServer. This is useful when you
+ * LBHttpSolrServer or "LoadBalanced HttpSolrServer" is a load balancing wrapper to CommonsHttpSolrServer. This is useful when you
  * have multiple SolrServers and the requests need to be Load Balanced among them. This should <b>NOT</b> be used for
  * indexing. Also see the <a href="http://wiki.apache.org/solr/LBHttpSolrServer">wiki</a> page.
  * <p/>
  * It offers automatic failover when a server goes down and it detects when the server comes back up.
  * <p/>
- * Load balancing is done using a simple roundrobin on the list of servers.
+ * Load balancing is done using a simple round-robin on the list of servers.
  * <p/>
  * If a request to a server fails by an IOException due to a connection timeout or read timeout then the host is taken
  * off the list of live servers and moved to a 'dead server list' and the request is resent to the next live server.
  * This process is continued till it tries all the live servers. If atleast one server is alive, the request succeeds,
- * andif not it fails.
+ * and if not it fails.
  * <blockquote><pre>
  * SolrServer lbHttpSolrServer = new LBHttpSolrServer("http://host1:8080/solr/","http://host2:8080/solr","http://host2:8080/solr");
  * //or if you wish to pass the HttpClient do as follows
@@ -57,22 +58,33 @@ import java.util.concurrent.locks.Reentr
  * This interval can be set using {@link #setAliveCheckInterval} , the default is set to one minute.
  * <p/>
  * <b>When to use this?</b><br/> This can be used as a software load balancer when you do not wish to setup an external
- * load balancer. The code is relatively new and the API is currently experimental. Alternatives to this code are to use
+ * load balancer. Alternatives to this code are to use
  * a dedicated hardware load balancer or using Apache httpd with mod_proxy_balancer as a load balancer. See <a
  * href="http://en.wikipedia.org/wiki/Load_balancing_(computing)">Load balancing on Wikipedia</a>
  *
  * @since solr 1.4
  */
 public class LBHttpSolrServer extends SolrServer {
-  private final CopyOnWriteArrayList<ServerWrapper> aliveServers = new CopyOnWriteArrayList<ServerWrapper>();
-  private final CopyOnWriteArrayList<ServerWrapper> zombieServers = new CopyOnWriteArrayList<ServerWrapper>();
+
+
+  // keys to the maps are currently of the form "http://localhost:8983/solr"
+  // which should be equivalent to CommonsHttpSolrServer.getBaseURL()
+  private final Map<String, ServerWrapper> aliveServers = new LinkedHashMap<String, ServerWrapper>();
+  // access to aliveServers should be synchronized on itself
+  
+  private final Map<String, ServerWrapper> zombieServers = new ConcurrentHashMap<String, ServerWrapper>();
+
+  // changes to aliveServers are reflected in this array, no need to synchronize
+  private volatile ServerWrapper[] aliveServerList = new ServerWrapper[0];
+
+
   private ScheduledExecutorService aliveCheckExecutor;
 
   private HttpClient httpClient;
   private final AtomicInteger counter = new AtomicInteger(-1);
 
-  private ReentrantLock checkLock = new ReentrantLock();
   private static final SolrQuery solrQuery = new SolrQuery("*:*");
+  private static final BinaryResponseParser binaryParser = new BinaryResponseParser();
 
   static {
     solrQuery.setRows(0);
@@ -81,8 +93,13 @@ public class LBHttpSolrServer extends So
   private static class ServerWrapper {
     final CommonsHttpSolrServer solrServer;
 
-    // Used only by the thread in aliveCheckExecutor
-    long lastUsed, lastChecked;
+    long lastUsed;     // last time used for a real request
+    long lastChecked;  // last time checked for liveness
+
+    // "standard" servers are used by default.  They normally live in the alive list
+    // and move to the zombie list when unavailable.  When they become available again,
+    // they move back to the alive list.
+    boolean standard = true;
 
     int failedPings = 0;
 
@@ -93,35 +110,225 @@ public class LBHttpSolrServer extends So
     public String toString() {
       return solrServer.getBaseURL();
     }
+
+    public String getKey() {
+      return solrServer.getBaseURL();
+    }
+
+    @Override
+    public int hashCode() {
+      return this.getKey().hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+      if (this == obj) return true;
+      if (!(obj instanceof ServerWrapper)) return false;
+      return this.getKey().equals(((ServerWrapper)obj).getKey());
+    }
+  }
+
+  public static class Req {
+    protected SolrRequest request;
+    protected List<String> servers;
+    protected int numDeadServersToTry;
+
+    public Req(SolrRequest request, List<String> servers) {
+      this.request = request;
+      this.servers = servers;
+      this.numDeadServersToTry = servers.size();
+    }
+
+    public SolrRequest getRequest() {
+      return request;
+    }
+    public List<String> getServers() {
+      return servers;
+    }
+
+    /** @return the number of dead servers to try if there are no live servers left */
+    public int getNumDeadServersToTry() {
+      return numDeadServersToTry;
+    }
+
+    /** @return The number of dead servers to try if there are no live servers left.
+     * Defaults to the number of servers in this request. */
+    public void setNumDeadServersToTry(int numDeadServersToTry) {
+      this.numDeadServersToTry = numDeadServersToTry;
+    }
+  }
+
+  public static class Rsp {
+    protected String server;
+    protected NamedList<Object> rsp;
+
+    /** The response from the server */
+    public NamedList<Object> getResponse() {
+      return rsp;
+    }
+
+    /** The server that returned the response */
+    public String getServer() {
+      return server;
+    }
   }
 
   public LBHttpSolrServer(String... solrServerUrls) throws MalformedURLException {
     this(new HttpClient(new MultiThreadedHttpConnectionManager()), solrServerUrls);
+
+    DefaultHttpMethodRetryHandler retryhandler = new DefaultHttpMethodRetryHandler(0, false);
+    httpClient.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, retryhandler);
   }
 
+  /** The provided httpClient should use a multi-threaded connection manager */ 
   public LBHttpSolrServer(HttpClient httpClient, String... solrServerUrl)
           throws MalformedURLException {
     this(httpClient, new BinaryResponseParser(), solrServerUrl);
   }
 
+  /** The provided httpClient should use a multi-threaded connection manager */  
   public LBHttpSolrServer(HttpClient httpClient, ResponseParser parser, String... solrServerUrl)
           throws MalformedURLException {
     this.httpClient = httpClient;
     for (String s : solrServerUrl) {
-      aliveServers.add(new ServerWrapper(new CommonsHttpSolrServer(s, httpClient, parser)));
+      ServerWrapper wrapper = new ServerWrapper(makeServer(s));
+      aliveServers.put(wrapper.getKey(), wrapper);
     }
+    updateAliveList();
   }
 
-  public void addSolrServer(String server) throws MalformedURLException {
-    CommonsHttpSolrServer solrServer = new CommonsHttpSolrServer(server, httpClient);
-    checkLock.lock();
-    try {
-      aliveServers.add(new ServerWrapper(solrServer));
-    } finally {
-      checkLock.unlock();
+  public static String normalize(String server) {
+    if (server.endsWith("/"))
+      server = server.substring(0, server.length() - 1);
+    return server;
+  }
+
+  protected CommonsHttpSolrServer makeServer(String server) throws MalformedURLException {
+    return new CommonsHttpSolrServer(server, httpClient, binaryParser);
+  }
+
+
+
+  /**
+   * Tries to query a live server from the list provided in Req. Servers in the dead pool are skipped.
+   * If a request fails due to an IOException, the server is moved to the dead pool for a certain period of
+   * time, or until a test request on that server succeeds.
+   *
+   * Servers are queried in the exact order given (except servers currently in the dead pool are skipped).
+   * If no live servers from the provided list remain to be tried, a number of previously skipped dead servers will be tried.
+   * Req.getNumDeadServersToTry() controls how many dead servers will be tried.
+   *
+   * If no live servers are found a SolrServerException is thrown.
+   *
+   * @param req contains both the request as well as the list of servers to query
+   *
+   * @return the result of the request
+   *
+   * @throws SolrServerException
+   * @throws IOException
+   */
+  public Rsp request(Req req) throws SolrServerException, IOException {
+    Rsp rsp = new Rsp();
+    Exception ex = null;
+
+    List<ServerWrapper> skipped = new ArrayList<ServerWrapper>(req.getNumDeadServersToTry());
+
+    for (String serverStr : req.getServers()) {
+      serverStr = normalize(serverStr);
+      // if the server is currently a zombie, just skip to the next one
+      ServerWrapper wrapper = zombieServers.get(serverStr);
+      if (wrapper != null) {
+        // System.out.println("ZOMBIE SERVER QUERIED: " + serverStr);
+        if (skipped.size() < req.getNumDeadServersToTry())
+          skipped.add(wrapper);
+        continue;
+      }
+      rsp.server = serverStr;
+      CommonsHttpSolrServer server = makeServer(serverStr);
+
+      try {
+        rsp.rsp = server.request(req.getRequest());
+        return rsp; // SUCCESS
+      } catch (SolrException e) {
+        // Server is alive but the request was malformed or invalid
+        throw e;
+      } catch (SolrServerException e) {
+        if (e.getRootCause() instanceof IOException) {
+          ex = e;
+          wrapper = new ServerWrapper(server);
+          wrapper.lastUsed = System.currentTimeMillis();
+          wrapper.standard = false;
+          zombieServers.put(wrapper.getKey(), wrapper);
+          startAliveCheckExecutor();
+        } else {
+          throw e;
+        }
+      } catch (Exception e) {
+        throw new SolrServerException(e);
+      }
+    }
+
+    // try the servers we previously skipped
+    for (ServerWrapper wrapper : skipped) {
+      try {
+        rsp.rsp = wrapper.solrServer.request(req.getRequest());
+        zombieServers.remove(wrapper.getKey());
+        return rsp; // SUCCESS
+      } catch (SolrException e) {
+        // Server is alive but the request was malformed or invalid
+        zombieServers.remove(wrapper.getKey());
+        throw e;
+      } catch (SolrServerException e) {
+        if (e.getRootCause() instanceof IOException) {
+          ex = e;
+          // already a zombie, no need to re-add
+        } else {
+          throw e;
+        }
+      } catch (Exception e) {
+        throw new SolrServerException(e);
+      }
+    }
+
+
+    if (ex == null) {
+      throw new SolrServerException("No live SolrServers available to handle this request");
+    } else {
+      throw new SolrServerException("No live SolrServers available to handle this request", ex);
+    }
+
+  }  
+
+
+
+  private void updateAliveList() {
+    synchronized (aliveServers) {
+      aliveServerList = aliveServers.values().toArray(new ServerWrapper[aliveServers.size()]);
+    }
+  }
+
+  private ServerWrapper removeFromAlive(String key) {
+    synchronized (aliveServers) {
+      ServerWrapper wrapper = aliveServers.remove(key);
+      if (wrapper != null)
+        updateAliveList();
+      return wrapper;
+    }
+  }
+
+  private void addToAlive(ServerWrapper wrapper) {
+    synchronized (aliveServers) {
+      ServerWrapper prev = aliveServers.put(wrapper.getKey(), wrapper);
+      // TODO: warn if there was a previous entry?
+      updateAliveList();
     }
   }
 
+  public void addSolrServer(String server) throws MalformedURLException {
+    CommonsHttpSolrServer solrServer = makeServer(server);
+    addToAlive(new ServerWrapper(solrServer));
+  }
+
   public String removeSolrServer(String server) {
     try {
       server = new URL(server).toExternalForm();
@@ -131,25 +338,11 @@ public class LBHttpSolrServer extends So
     if (server.endsWith("/")) {
       server = server.substring(0, server.length() - 1);
     }
-    this.checkLock.lock();
-    try {
-      for (ServerWrapper serverWrapper : aliveServers) {
-        if (serverWrapper.solrServer.getBaseURL().equals(server)) {
-          aliveServers.remove(serverWrapper);
-          return serverWrapper.solrServer.getBaseURL();
-        }
-      }
-      if (zombieServers.isEmpty()) return null;
 
-      for (ServerWrapper serverWrapper : zombieServers) {
-        if (serverWrapper.solrServer.getBaseURL().equals(server)) {
-          zombieServers.remove(serverWrapper);
-          return serverWrapper.solrServer.getBaseURL();
-        }
-      }
-    } finally {
-      checkLock.unlock();
-    }
+    // there is a small race condition here - if the server is in the process of being moved between
+    // lists, we could fail to remove it.
+    removeFromAlive(server);
+    zombieServers.remove(server);
     return null;
   }
 
@@ -173,9 +366,10 @@ public class LBHttpSolrServer extends So
   }
 
   /**
-   * Tries to query a live server. If no live servers are found it throws a SolrServerException. If the request failed
-   * due to IOException then the live server is moved to dead pool and the request is retried on another live server if
-   * available. If all live servers are exhausted then a SolrServerException is thrown.
+   * Tries to query a live server. A SolrServerException is thrown if all servers are dead.
+   * If the request failed due to IOException then the live server is moved to dead pool and the request is
+   * retried on another live server.  After live servers are exhausted, any servers previously marked as dead
+   * will be tried before failing the request.
    *
    * @param request the SolrRequest.
    *
@@ -186,41 +380,69 @@ public class LBHttpSolrServer extends So
    */
   public NamedList<Object> request(final SolrRequest request)
           throws SolrServerException, IOException {
-    int count = counter.incrementAndGet();
-    int attempts = 0;
-    Exception ex;
-    int startSize = aliveServers.size();
-    while (true) {
-      int size = aliveServers.size();
-      if (size < 1) throw new SolrServerException("No live SolrServers available to handle this request");
-      ServerWrapper solrServer;
+    Exception ex = null;
+    ServerWrapper[] serverList = aliveServerList;
+    
+    int maxTries = serverList.length;
+    Map<String,ServerWrapper> justFailed = null;
+
+    for (int attempts=0; attempts<maxTries; attempts++) {
+      int count = counter.incrementAndGet();      
+      ServerWrapper wrapper = serverList[count % serverList.length];
+      wrapper.lastUsed = System.currentTimeMillis();
+
       try {
-        solrServer = aliveServers.get(count % size);
-      } catch (IndexOutOfBoundsException e) {
-        //this list changes dynamically. so it is expected to get IndexOutOfBoundsException
-        continue;
+        return wrapper.solrServer.request(request);
+      } catch (SolrException e) {
+        // Server is alive but the request was malformed or invalid
+        throw e;
+      } catch (SolrServerException e) {
+        if (e.getRootCause() instanceof IOException) {
+          ex = e;
+          moveAliveToDead(wrapper);
+          if (justFailed == null) justFailed = new HashMap<String,ServerWrapper>();
+          justFailed.put(wrapper.getKey(), wrapper);
+        } else {
+          throw e;
+        }
+      } catch (Exception e) {
+        throw new SolrServerException(e);
       }
+    }
+
+
+    // try other standard servers that we didn't try just now
+    for (ServerWrapper wrapper : zombieServers.values()) {
+      if (wrapper.standard==false || justFailed!=null && justFailed.containsKey(wrapper.getKey())) continue;
       try {
-        return solrServer.solrServer.request(request);
+        NamedList<Object> rsp = wrapper.solrServer.request(request);
+        // remove from zombie list *before* adding to alive to avoid a race that could lose a server
+        zombieServers.remove(wrapper.getKey());
+        addToAlive(wrapper);
+        return rsp;
       } catch (SolrException e) {
         // Server is alive but the request was malformed or invalid
         throw e;
       } catch (SolrServerException e) {
         if (e.getRootCause() instanceof IOException) {
           ex = e;
-          moveAliveToDead(solrServer);
+          // still dead
         } else {
           throw e;
         }
       } catch (Exception e) {
         throw new SolrServerException(e);
       }
-      attempts++;
-      if (attempts >= startSize)
-        throw new SolrServerException("No live SolrServers available to handle this request", ex);
     }
-  }
 
+
+    if (ex == null) {
+      throw new SolrServerException("No live SolrServers available to handle this request");
+    } else {
+      throw new SolrServerException("No live SolrServers available to handle this request", ex);
+    }
+  }
+  
   /**
    * Takes up one dead server and check for aliveness. The check is done in a roundrobin. Each server is checked for
    * aliveness once in 'x' millis where x is decided by the setAliveCheckinterval() or it is defaulted to 1 minute
@@ -229,39 +451,44 @@ public class LBHttpSolrServer extends So
    */
   private void checkAZombieServer(ServerWrapper zombieServer) {
     long currTime = System.currentTimeMillis();
-    checkLock.lock();
     try {
       zombieServer.lastChecked = currTime;
       QueryResponse resp = zombieServer.solrServer.query(solrQuery);
       if (resp.getStatus() == 0) {
-        //server has come back up
-        zombieServer.lastUsed = currTime;
-        zombieServers.remove(zombieServer);
-        aliveServers.add(zombieServer);
-        zombieServer.failedPings = 0;
+        // server has come back up.
+        // make sure to remove from zombies before adding to alive to avoid a race condition
+        // where another thread could mark it down, move it back to zombie, and then we delete
+        // from zombie and lose it forever.
+        ServerWrapper wrapper = zombieServers.remove(zombieServer.getKey());
+        if (wrapper != null) {
+          wrapper.failedPings = 0;
+          if (wrapper.standard) {
+            addToAlive(wrapper);
+          }
+        } else {
+          // something else already moved the server from zombie to alive
+        }
       }
     } catch (Exception e) {
+      //Expected. The server is still down.
       zombieServer.failedPings++;
-      //Expected . The server is still down
-    } finally {
-      checkLock.unlock();
-    }
-  }
 
-  private void moveAliveToDead(ServerWrapper solrServer) {
-    checkLock.lock();
-    try {
-      boolean result = aliveServers.remove(solrServer);
-      if (result) {
-        if (zombieServers.addIfAbsent(solrServer)) {
-          startAliveCheckExecutor();
-        }
+      // If the server doesn't belong in the standard set belonging to this load balancer
+      // then simply drop it after a certain number of failed pings.
+      if (!zombieServer.standard && zombieServer.failedPings >= NONSTANDARD_PING_LIMIT) {
+        zombieServers.remove(zombieServer.getKey());
       }
-    } finally {
-      checkLock.unlock();
     }
   }
 
+  private void moveAliveToDead(ServerWrapper wrapper) {
+    wrapper = removeFromAlive(wrapper.getKey());
+    if (wrapper == null)
+      return;  // another thread already detected the failure and removed it
+    zombieServers.put(wrapper.getKey(), wrapper);
+    startAliveCheckExecutor();
+  }
+
   private int interval = CHECK_INTERVAL;
 
   /**
@@ -279,6 +506,8 @@ public class LBHttpSolrServer extends So
   }
 
   private void startAliveCheckExecutor() {
+    // double-checked locking, but it's OK because we don't *do* anything with aliveCheckExecutor
+    // if it's not null.
     if (aliveCheckExecutor == null) {
       synchronized (this) {
         if (aliveCheckExecutor == null) {
@@ -291,13 +520,13 @@ public class LBHttpSolrServer extends So
     }
   }
 
-  private static Runnable getAliveCheckRunner(final WeakReference<LBHttpSolrServer> lbHttpSolrServer) {
+  private static Runnable getAliveCheckRunner(final WeakReference<LBHttpSolrServer> lbRef) {
     return new Runnable() {
       public void run() {
-        LBHttpSolrServer solrServer = lbHttpSolrServer.get();
-        if (solrServer != null && solrServer.zombieServers != null) {
-          for (ServerWrapper zombieServer : solrServer.zombieServers) {
-            solrServer.checkAZombieServer(zombieServer);
+        LBHttpSolrServer lb = lbRef.get();
+        if (lb != null && lb.zombieServers != null) {
+          for (ServerWrapper zombieServer : lb.zombieServers.values()) {
+            lb.checkAZombieServer(zombieServer);
           }
         }
       }
@@ -317,5 +546,7 @@ public class LBHttpSolrServer extends So
     }
   }
 
+  // defaults
   private static final int CHECK_INTERVAL = 60 * 1000; //1 minute between checks
+  private static final int NONSTANDARD_PING_LIMIT = 5;  // number of times we'll ping dead servers not in the server list
 }

Modified: lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/response/QueryResponse.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/response/QueryResponse.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/response/QueryResponse.java (original)
+++ lucene/dev/branches/docvalues/solr/src/solrj/org/apache/solr/client/solrj/response/QueryResponse.java Wed Oct 20 12:44:28 2010
@@ -204,7 +204,7 @@ public class QueryResponse extends SolrR
       _facetFields = new ArrayList<FacetField>( ff.size() );
       _limitingFacets = new ArrayList<FacetField>( ff.size() );
       
-      long minsize = _results.getNumFound();
+      long minsize = _results == null ? Long.MAX_VALUE :_results.getNumFound();
       for( Map.Entry<String,NamedList<Number>> facet : ff ) {
         FacetField f = new FacetField( facet.getKey() );
         for( Map.Entry<String, Number> entry : facet.getValue() ) {

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BaseDistributedSearchTestCase.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BaseDistributedSearchTestCase.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BaseDistributedSearchTestCase.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BaseDistributedSearchTestCase.java Wed Oct 20 12:44:28 2010
@@ -1,6 +1,20 @@
 package org.apache.solr;
 
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+
 import junit.framework.TestCase;
+
 import org.apache.solr.client.solrj.SolrServer;
 import org.apache.solr.client.solrj.SolrServerException;
 import org.apache.solr.client.solrj.embedded.JettySolrRunner;
@@ -17,10 +31,6 @@ import org.junit.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.io.File;
-import java.io.IOException;
-import java.util.*;
-
 /**
  * Helper base class for distributed search test cases
  *
@@ -44,6 +54,10 @@ public abstract class BaseDistributedSea
   protected List<JettySolrRunner> jettys = new ArrayList<JettySolrRunner>();
   protected String context = "/solr";
   protected String shards;
+  protected String[] shardsArr;
+  // Some ISPs redirect to their own web site for domains that don't exist, causing this to fail
+  // protected String[] deadServers = {"does_not_exist_54321.com:33331/solr","localhost:33332/solr"};
+  protected String[] deadServers = {"[::1]:33332/solr"};
   protected File testDir;
   protected SolrServer controlClient;
 
@@ -130,40 +144,79 @@ public abstract class BaseDistributedSea
     super.tearDown();
   }
 
-  private void createServers(int numShards) throws Exception {
-    controlJetty = createJetty(testDir, "control");
+  protected void createServers(int numShards) throws Exception {
+    controlJetty = createJetty(testDir, testDir + "/control/data");
     controlClient = createNewSolrServer(controlJetty.getLocalPort());
 
+    shardsArr = new String[numShards];
     StringBuilder sb = new StringBuilder();
-    for (int i = 1; i <= numShards; i++) {
+    for (int i = 0; i < numShards; i++) {
       if (sb.length() > 0) sb.append(',');
-      JettySolrRunner j = createJetty(testDir, "shard" + i);
+      JettySolrRunner j = createJetty(testDir, testDir + "/shard" + i + "/data");
       jettys.add(j);
       clients.add(createNewSolrServer(j.getLocalPort()));
-      sb.append("localhost:").append(j.getLocalPort()).append(context);
+      String shardStr = "localhost:" + j.getLocalPort() + context;
+      shardsArr[i] = shardStr;
+      sb.append(shardStr);
     }
 
     shards = sb.toString();
   }
 
+
+  protected void setDistributedParams(ModifiableSolrParams params) {
+    params.set("shards", getShardsString());
+  }
+
+  protected String getShardsString() {
+    if (deadServers == null) return shards;
+    
+    StringBuilder sb = new StringBuilder();
+    for (String shard : shardsArr) {
+      if (sb.length() > 0) sb.append(',');
+      int nDeadServers = r.nextInt(deadServers.length+1);
+      if (nDeadServers > 0) {
+        List<String> replicas = new ArrayList<String>(Arrays.asList(deadServers));
+        Collections.shuffle(replicas, r);
+        replicas.add(r.nextInt(nDeadServers+1), shard);
+        for (int i=0; i<nDeadServers+1; i++) {
+          if (i!=0) sb.append('|');
+          sb.append(replicas.get(i));
+        }
+      } else {
+        sb.append(shard);
+      }
+    }
+
+    return sb.toString();
+  }
+
   protected void destroyServers() throws Exception {
     controlJetty.stop();
     for (JettySolrRunner jetty : jettys) jetty.stop();
     clients.clear();
     jettys.clear();
   }
+  
+  public JettySolrRunner createJetty(File baseDir, String dataDir) throws Exception {
+    return createJetty(baseDir, dataDir, null, null);
+  }
 
-  public static JettySolrRunner createJetty(File baseDir, String dataDirName) throws Exception {
-    File subDir = new File(baseDir, dataDirName);
-    subDir.mkdirs();
-    System.setProperty("solr.data.dir", subDir.toString());
-
-    JettySolrRunner jetty = new JettySolrRunner("/solr", 0);
-
+  public JettySolrRunner createJetty(File baseDir, String dataDir, String shardId) throws Exception {
+    return createJetty(baseDir, dataDir, shardId, null);
+  }
+  
+  public JettySolrRunner createJetty(File baseDir, String dataDir, String shardList, String solrConfigOverride) throws Exception {
+    System.setProperty("solr.data.dir", dataDir);
+    JettySolrRunner jetty = new JettySolrRunner("/solr", 0, solrConfigOverride);
+    if(shardList != null) {
+      System.setProperty("shard", shardList);
+    }
     jetty.start();
+    System.clearProperty("shard");
     return jetty;
   }
-
+  
   protected SolrServer createNewSolrServer(int port) {
     try {
       // setup the server...
@@ -230,6 +283,14 @@ public abstract class BaseDistributedSea
     for (SolrServer client : clients) client.commit();
   }
 
+  protected QueryResponse queryServer(ModifiableSolrParams params) throws SolrServerException {
+    // query a random server
+    int which = r.nextInt(clients.size());
+    SolrServer client = clients.get(which);
+    QueryResponse rsp = client.query(params);
+    return rsp;
+  }
+
   protected void query(Object... q) throws Exception {
     final ModifiableSolrParams params = new ModifiableSolrParams();
 
@@ -239,11 +300,9 @@ public abstract class BaseDistributedSea
 
     final QueryResponse controlRsp = controlClient.query(params);
 
-    // query a random server
-    params.set("shards", shards);
-    int which = r.nextInt(clients.size());
-    SolrServer client = clients.get(which);
-    QueryResponse rsp = client.query(params);
+    setDistributedParams(params);
+
+    QueryResponse rsp = queryServer(params);
 
     compareResponses(rsp, controlRsp);
 

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BasicFunctionalityTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BasicFunctionalityTest.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BasicFunctionalityTest.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/BasicFunctionalityTest.java Wed Oct 20 12:44:28 2010
@@ -237,12 +237,12 @@ public class BasicFunctionalityTest exte
       };
     handler.init(new NamedList());
     SolrQueryResponse rsp = new SolrQueryResponse();
+    SolrQueryRequest req = req();
     h.getCore().execute(handler, 
-                        new LocalSolrQueryRequest(h.getCore(),
-                                                  new NamedList()),
+                        req,
                         rsp);
     assertNotNull("should have found an exception", rsp.getException());
-                        
+    req.close();                    
   }
 
   @Test
@@ -303,11 +303,13 @@ public class BasicFunctionalityTest exte
     rsp.add("\"quoted\"", "\"value\"");
 
     StringWriter writer = new StringWriter(32000);
-    XMLWriter.writeResponse(writer,req("foo"),rsp);
+    SolrQueryRequest req = req("foo");
+    XMLWriter.writeResponse(writer,req,rsp);
 
     DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
     builder.parse(new ByteArrayInputStream
                   (writer.toString().getBytes("UTF-8")));
+    req.close();
   }
 
   @Test
@@ -327,6 +329,7 @@ public class BasicFunctionalityTest exte
     assertEquals(2, arrayParams.length);
     assertEquals("array", arrayParams[0]);
     assertEquals("value", arrayParams[1]);
+    req.close();
   }
 
   @Test
@@ -442,7 +445,7 @@ public class BasicFunctionalityTest exte
     assertEquals("SSS", p.get("ss"));
     assertEquals("XXX", p.get("xx"));
 
-    
+    req.close();
   }
 
   @Test
@@ -566,6 +569,7 @@ public class BasicFunctionalityTest exte
     // ensure field is not lazy
     assertTrue( d.getFieldable("test_hlt") instanceof Field );
     assertTrue( d.getFieldable("title") instanceof Field );
+    req.close();
   }
 
   @Test
@@ -588,6 +592,7 @@ public class BasicFunctionalityTest exte
     // ensure field is lazy
     assertTrue( !( d.getFieldable("test_hlt") instanceof Field ) );
     assertTrue( d.getFieldable("title") instanceof Field );
+    req.close();
   } 
             
 

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/JSONTestUtil.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/JSONTestUtil.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/JSONTestUtil.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/JSONTestUtil.java Wed Oct 20 12:44:28 2010
@@ -53,10 +53,12 @@ public class JSONTestUtil {
   
   public static String matchObj(String path, Object input, Object expected) throws Exception {
     CollectionTester tester = new CollectionTester(input);
-    if (!tester.seek(path)) {
+    boolean reversed = path.startsWith("!");
+    String positivePath = reversed ? path.substring(1) : path;
+    if (!tester.seek(positivePath) ^ reversed) {
       return "Path not found: " + path;
     }
-    if (expected != null && !tester.match(expected)) {
+    if (expected != null && (!tester.match(expected) ^ reversed)) {
       return tester.err + " @ " + tester.getPath();
     }
     return null;

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/SolrTestCaseJ4.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/SolrTestCaseJ4.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/SolrTestCaseJ4.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/SolrTestCaseJ4.java Wed Oct 20 12:44:28 2010
@@ -27,7 +27,9 @@ import org.apache.solr.common.params.Mod
 import org.apache.solr.common.params.SolrParams;
 import org.apache.solr.common.util.XML;
 import org.apache.solr.core.SolrConfig;
+import org.apache.solr.request.LocalSolrQueryRequest;
 import org.apache.solr.request.SolrQueryRequest;
+import org.apache.solr.search.SolrIndexSearcher;
 import org.apache.solr.util.TestHarness;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -85,6 +87,7 @@ public abstract class SolrTestCaseJ4 ext
   /** Call initCore in @BeforeClass to instantiate a solr core in your test class.
    * deleteCore will be called for you via SolrTestCaseJ4 @AfterClass */
   public static void initCore(String config, String schema, String solrHome) throws Exception {
+    startTrackingSearchers();
     configString = config;
     schemaString = schema;
     if (solrHome != null) {
@@ -93,6 +96,26 @@ public abstract class SolrTestCaseJ4 ext
     initCore();
   }
 
+
+  static long numOpens;
+  static long numCloses;
+  protected static void startTrackingSearchers() {
+    numOpens = SolrIndexSearcher.numOpens.get();
+    numCloses = SolrIndexSearcher.numCloses.get();
+  }
+
+  protected static void endTrackingSearchers() {
+     long endNumOpens = SolrIndexSearcher.numOpens.get();
+     long endNumCloses = SolrIndexSearcher.numCloses.get();
+
+     if (endNumOpens-numOpens != endNumCloses-numCloses) {
+       String msg = "ERROR: SolrIndexSearcher opens=" + (endNumOpens-numOpens) + " closes=" + (endNumCloses-numCloses);
+       log.error(msg);
+       // TODO: make this fail if we manage to clean up
+       // fail(msg);
+     }
+  }
+
   /** Causes an exception matching the regex pattern to not be logged. */
   public static void ignoreException(String pattern) {
     if (SolrException.ignorePatterns == null)
@@ -196,8 +219,9 @@ public abstract class SolrTestCaseJ4 ext
     if (factoryProp == null) {
       System.setProperty("solr.directoryFactory","solr.RAMDirectoryFactory");
     }
-
-    createTempDir();
+    if (dataDir == null) {
+      createTempDir();
+    }
 
     // other  methods like starting a jetty instance need these too
     System.setProperty("solr.test.sys.prop1", "propone");
@@ -260,7 +284,9 @@ public abstract class SolrTestCaseJ4 ext
     solrConfig = null;
     h = null;
     lrf = null;
-    configString = schemaString = null;    
+    configString = schemaString = null;
+
+    endTrackingSearchers();
   }
 
 
@@ -328,14 +354,18 @@ public abstract class SolrTestCaseJ4 ext
       String results = h.validateXPath(response, tests);
 
       if (null != results) {
-        fail(m + "query failed XPath: " + results +
-             "\n xml response was: " + response +
-             "\n request was: " + req.getParamString());
+        String msg = "REQUEST FAILED: xpath=" + results
+            + "\n\txml response was: " + response
+            + "\n\trequest was:" + req.getParamString();
+
+        log.error(msg);
+        throw new RuntimeException(msg);
       }
 
     } catch (XPathExpressionException e1) {
       throw new RuntimeException("XPath is invalid", e1);
     } catch (Exception e2) {
+      SolrException.log(log,"REQUEST FAILED: " + req.getParamString(), e2);
       throw new RuntimeException("Exception during query", e2);
     }
   }
@@ -524,6 +554,14 @@ public abstract class SolrTestCaseJ4 ext
     return d;
   }
 
+  public static ModifiableSolrParams params(String... params) {
+    ModifiableSolrParams msp = new ModifiableSolrParams();
+    for (int i=0; i<params.length; i+=2) {
+      msp.add(params[i], params[i+1]);
+    }
+    return msp;
+  }
+
   /**
    * Generates a SolrQueryRequest using the LocalRequestFactory
    * @see #lrf
@@ -548,6 +586,17 @@ public abstract class SolrTestCaseJ4 ext
     return lrf.makeRequest(allParams);
   }
 
+  /**
+   * Generates a SolrQueryRequest
+   */
+  public static SolrQueryRequest req(SolrParams params, String... moreParams) {
+    ModifiableSolrParams mp = new ModifiableSolrParams(params);
+    for (int i=0; i<moreParams.length; i+=2) {
+      mp.add(moreParams[i], moreParams[i+1]);
+    }
+    return new LocalSolrQueryRequest(h.getCore(), mp);
+  }
+
   /** Neccessary to make method signatures un-ambiguous */
   public static class Doc {
     public String xml;

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/TestPluginEnable.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/TestPluginEnable.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/TestPluginEnable.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/TestPluginEnable.java Wed Oct 20 12:44:28 2010
@@ -1,32 +1,24 @@
 package org.apache.solr;
 
 import org.apache.solr.client.solrj.SolrServerException;
-import org.apache.solr.util.AbstractSolrTestCase;
-
+import org.junit.BeforeClass;
+import org.junit.Test;
 /**
  * <p> Test disabling components</p>
  *
  * @version $Id$
  * @since solr 1.4
  */
-public class TestPluginEnable extends AbstractSolrTestCase {
-
-
+public class TestPluginEnable extends SolrTestCaseJ4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-enableplugin.xml", "schema-replication1.xml");
+  }
+  
+  @Test
   public void testSimple() throws SolrServerException {
     assertNull(h.getCore().getRequestHandler("disabled"));
     assertNotNull(h.getCore().getRequestHandler("enabled"));
 
   }
-
-
-  @Override
-  public String getSchemaFile() {
-    return "schema-replication1.xml";
-  }
-
-  @Override
-  public String getSolrConfigFile() {
-    return "solrconfig-enableplugin.xml";
-  }
-
 }

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestLuceneMatchVersion.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestLuceneMatchVersion.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestLuceneMatchVersion.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestLuceneMatchVersion.java Wed Oct 20 12:44:28 2010
@@ -20,6 +20,7 @@ import java.io.StringReader;
 import java.lang.reflect.Field;
 
 import org.apache.lucene.analysis.standard.StandardTokenizer;
+import org.apache.solr.SolrTestCaseJ4;
 import org.apache.solr.core.Config;
 import org.apache.solr.schema.IndexSchema;
 import org.apache.solr.schema.FieldType;
@@ -27,20 +28,16 @@ import org.apache.solr.util.AbstractSolr
 import org.apache.lucene.analysis.Analyzer;
 import org.apache.lucene.analysis.standard.StandardAnalyzer;
 import org.apache.lucene.util.Version;
+import org.junit.BeforeClass;
 
 /**
  * Tests for luceneMatchVersion property for analyzers
  */
-public class TestLuceneMatchVersion extends AbstractSolrTestCase {
+public class TestLuceneMatchVersion extends SolrTestCaseJ4 {
 
-  @Override
-  public String getSchemaFile() {
-    return "schema-luceneMatchVersion.xml";
-  }
-  
-  @Override
-  public String getSolrConfigFile() {
-    return "solrconfig.xml";
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig.xml","schema-luceneMatchVersion.xml");
   }
   
   // this must match the solrconfig.xml version for this test

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestThaiWordFilterFactory.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestThaiWordFilterFactory.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestThaiWordFilterFactory.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/analysis/TestThaiWordFilterFactory.java Wed Oct 20 12:44:28 2010
@@ -24,7 +24,6 @@ import org.apache.lucene.analysis.TokenS
 import org.apache.lucene.analysis.Tokenizer;
 import org.apache.lucene.analysis.core.WhitespaceTokenizer;
 import org.apache.lucene.analysis.th.ThaiWordFilter;
-import org.junit.Assume;
 
 /**
  * Simple tests to ensure the Thai word filter factory is working.
@@ -34,7 +33,7 @@ public class TestThaiWordFilterFactory e
    * Ensure the filter actually decomposes text.
    */
   public void testWordBreak() throws Exception {
-    Assume.assumeTrue(ThaiWordFilter.DBBI_AVAILABLE);
+    assumeTrue("JRE does not support Thai dictionary-based BreakIterator", ThaiWordFilter.DBBI_AVAILABLE);
     Reader reader = new StringReader("การที่ได้ต้องแสดงว่างานดี");
     Tokenizer tokenizer = new WhitespaceTokenizer(DEFAULT_VERSION, reader);
     ThaiWordFilterFactory factory = new ThaiWordFilterFactory();

Propchange: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Wed Oct 20 12:44:28 2010
@@ -1,3 +1,4 @@
 /lucene/dev/branches/branch_3x/solr/src/test/org/apache/solr/client:949730,961612,979161,980654,982195,987811,988512
 /lucene/dev/branches/preflexfixes/solr/src/test/org/apache/solr/client:967125-979432
+/lucene/dev/trunk/solr/src/test/org/apache/solr/client:1021635-1024556,1025532-1025536
 /lucene/solr/trunk/src/test/org/apache/solr/client:922950-923910,923912-925091

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/SolrExampleTests.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/SolrExampleTests.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/SolrExampleTests.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/SolrExampleTests.java Wed Oct 20 12:44:28 2010
@@ -650,9 +650,9 @@ abstract public class SolrExampleTests e
     counts = p.getPivot();
   //  p.write(System.out, 5 );
     assertEquals( 1, counts.size() );
-    assertEquals( "inStock", counts.get(0).getField() );
-    assertEquals( "true",    counts.get(0).getValue() );
-    assertEquals(  2,       counts.get(0).getCount() );
+    assertEquals( "inStock",    counts.get(0).getField() );
+    assertEquals( Boolean.TRUE, counts.get(0).getValue() );
+    assertEquals(  2,           counts.get(0).getCount() );
   }
   
   public static SolrInputDocument makeTestDoc( Object ... kvp )

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java Wed Oct 20 12:44:28 2010
@@ -45,10 +45,12 @@ import java.util.Set;
  */
 public class TestLBHttpSolrServer extends LuceneTestCase {
   SolrInstance[] solr = new SolrInstance[3];
-  HttpClient httpClient = new HttpClient();
+  HttpClient httpClient;
 
   public void setUp() throws Exception {
     super.setUp();
+    httpClient = new HttpClient();
+    httpClient.getParams().setParameter("http.connection.timeout", new Integer(1000));
     for (int i = 0; i < solr.length; i++) {
       solr[i] = new SolrInstance("solr" + i, 0);
       solr[i].setUp();

Modified: lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/core/AlternateDirectoryTest.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/core/AlternateDirectoryTest.java?rev=1025539&r1=1025538&r2=1025539&view=diff
==============================================================================
--- lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/core/AlternateDirectoryTest.java (original)
+++ lucene/dev/branches/docvalues/solr/src/test/org/apache/solr/core/AlternateDirectoryTest.java Wed Oct 20 12:44:28 2010
@@ -18,17 +18,18 @@ package org.apache.solr.core;
 
 import java.io.File;
 import java.io.IOException;
-import org.apache.lucene.store.FSDirectory;
-import org.apache.solr.util.AbstractSolrTestCase;
-
-public class AlternateDirectoryTest extends AbstractSolrTestCase {
 
-  public String getSchemaFile() {
-    return "schema.xml";
-  }
-
-  public String getSolrConfigFile() {
-    return "solrconfig-altdirectory.xml";
+import org.apache.lucene.index.IndexReader;
+import org.apache.lucene.store.Directory;
+import org.apache.lucene.store.FSDirectory;
+import org.apache.solr.SolrTestCaseJ4;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class AlternateDirectoryTest extends SolrTestCaseJ4 {
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    initCore("solrconfig-altdirectory.xml", "schema.xml");
   }
 
   /**
@@ -36,12 +37,15 @@ public class AlternateDirectoryTest exte
    * 
    * @throws Exception
    */
+  @Test
   public void testAltDirectoryUsed() throws Exception {
+    assertQ(req("q","*:*","qt","standard"));
     assertTrue(TestFSDirectoryFactory.openCalled);
+    assertTrue(TestIndexReaderFactory.newReaderCalled);
   }
 
   static public class TestFSDirectoryFactory extends DirectoryFactory {
-    public static boolean openCalled = false;
+    public static volatile boolean openCalled = false;
 
     public FSDirectory open(String path) throws IOException {
       openCalled = true;
@@ -50,4 +54,15 @@ public class AlternateDirectoryTest exte
 
   }
 
+
+  static public class TestIndexReaderFactory extends IndexReaderFactory {
+    static volatile boolean newReaderCalled = false;
+
+    public IndexReader newReader(Directory indexDir, boolean readOnly)
+        throws IOException {
+      TestIndexReaderFactory.newReaderCalled = true;
+      return IndexReader.open(indexDir, readOnly);
+    }
+  }
+
 }