You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by mi...@apache.org on 2011/06/26 15:34:00 UTC

svn commit: r1139788 [1/2] - in /lucene/dev/trunk: lucene/ lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/ lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/ lucene/contrib/memory/src/java/org/apache/l...

Author: mikemccand
Date: Sun Jun 26 13:33:58 2011
New Revision: 1139788

URL: http://svn.apache.org/viewvc?rev=1139788&view=rev
Log:
LUCENE-3225: add TermsEnum.seekExact(BytesRef); renamne existing methods to seekCeil/seekExact

Modified:
    lucene/dev/trunk/lucene/CHANGES.txt
    lucene/dev/trunk/lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedTermsEnum.java
    lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java
    lucene/dev/trunk/lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java
    lucene/dev/trunk/lucene/contrib/misc/src/java/org/apache/lucene/misc/HighFreqTerms.java
    lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java
    lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestNRTManager.java
    lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/codecs/appending/TestAppendingCodec.java
    lucene/dev/trunk/lucene/contrib/queries/src/java/org/apache/lucene/search/TermsFilter.java
    lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndPrefixQuery.java
    lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTermQuery.java
    lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTruncQuery.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/CheckIndex.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocTermOrds.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/FilterIndexReader.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/MultiTermsEnum.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermState.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/Terms.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermsEnum.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/BlockTermsReader.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/memory/MemoryCodec.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/simpletext/SimpleTextFieldsReader.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FilteredTermsEnum.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/PerReaderTermState.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/BytesRefFSTEnum.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FST.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FSTEnum.java
    lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/IntsRefFSTEnum.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/TestExternalCodecs.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/Test2BTerms.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestCodecs.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDirectoryReader.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDocTermOrds.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFilterIndexReader.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFlex.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriterUnicode.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestPerSegmentDeletes.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSegmentTermDocs.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSegmentTermEnum.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestStressAdvance.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestTermdocPerf.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/codecs/preflex/TestSurrogates.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/search/TestFieldCache.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/search/TestMultiPhraseQuery.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/search/TestPhrasePrefixQuery.java
    lucene/dev/trunk/lucene/src/test/org/apache/lucene/util/fst/TestFSTs.java
    lucene/dev/trunk/modules/suggest/src/java/org/apache/lucene/search/spell/SpellChecker.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/TermVectorComponent.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/handler/component/TermsComponent.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/request/PerSegmentSingleValuedFaceting.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/request/SimpleFacets.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/request/UnInvertedField.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/search/JoinQParserPlugin.java
    lucene/dev/trunk/solr/src/java/org/apache/solr/search/function/FileFloatSource.java
    lucene/dev/trunk/solr/src/test/org/apache/solr/request/TestFaceting.java

Modified: lucene/dev/trunk/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/CHANGES.txt?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/CHANGES.txt (original)
+++ lucene/dev/trunk/lucene/CHANGES.txt Sun Jun 26 13:33:58 2011
@@ -288,6 +288,13 @@ API Changes
   SortField.Type.  In be consistent, CachedArrayCreator.getSortTypeID() has
   been changed CachedArrayCreator.getSortType(). (Chris Male)
 
+* LUCENE-3225: Add TermsEnum.seekExact for faster seeking when you
+  don't need the ceiling term; renamed existing seek methods to either
+  seekCeil or seekExact; changed seekExact(ord) to return no value.
+  Fixed MemoryCodec and SimpleTextCodec to optimize the seekExact
+  case, and fixed places in Lucene to use seekExact when possible.
+  (Mike McCandless)
+
 New features
 
 * LUCENE-2604: Added RegexpQuery support to QueryParser. Regular expressions

Modified: lucene/dev/trunk/lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedTermsEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedTermsEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedTermsEnum.java (original)
+++ lucene/dev/trunk/lucene/contrib/instantiated/src/java/org/apache/lucene/store/instantiated/InstantiatedTermsEnum.java Sun Jun 26 13:33:58 2011
@@ -44,7 +44,20 @@ public class InstantiatedTermsEnum exten
   }
 
   @Override
-  public SeekStatus seek(BytesRef text, boolean useCache) {
+  public boolean seekExact(BytesRef text, boolean useCache) {
+    final Term t = new Term(field, text);
+    int loc = Arrays.binarySearch(terms, t, InstantiatedTerm.termComparator);
+    if (loc < 0) {
+      return false;
+    } else {
+      upto = loc;
+      br.copy(text);
+      return true;
+    }
+  }
+
+  @Override
+  public SeekStatus seekCeil(BytesRef text, boolean useCache) {
     final Term t = new Term(field, text);
     int loc = Arrays.binarySearch(terms, t, InstantiatedTerm.termComparator);
     if (loc < 0) {
@@ -63,17 +76,10 @@ public class InstantiatedTermsEnum exten
   }
 
   @Override
-  public SeekStatus seek(long ord) {
+  public void seekExact(long ord) {
+    assert (start + (int) ord) < terms.length;
     upto = start + (int) ord;
-    if (upto >= terms.length) {
-      return SeekStatus.END;
-    }
-
-    if (terms[upto].field().equals(field)) {
-      return SeekStatus.FOUND;
-    } else {
-      return SeekStatus.END;
-    }
+    assert field.equals(terms[upto].field());
   }
 
   @Override
@@ -140,9 +146,9 @@ public class InstantiatedTermsEnum exten
   }
 
   @Override
-  public void seek(BytesRef term, TermState state) throws IOException {
+  public void seekExact(BytesRef term, TermState state) throws IOException {
     assert state != null && state instanceof OrdTermState;
-    seek(((OrdTermState)state).ord); // just use the ord for simplicity
+    seekExact(((OrdTermState)state).ord); // just use the ord for simplicity
   }
 }
 

Modified: lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java (original)
+++ lucene/dev/trunk/lucene/contrib/instantiated/src/test/org/apache/lucene/store/instantiated/TestIndicesEquals.java Sun Jun 26 13:33:58 2011
@@ -133,9 +133,9 @@ public class TestIndicesEquals extends L
 
     Term t = new Term("c", "danny");
     TermsEnum aprioriTermEnum = MultiFields.getTerms(aprioriReader, t.field()).iterator();
-    aprioriTermEnum.seek(new BytesRef(t.text()));
+    aprioriTermEnum.seekCeil(new BytesRef(t.text()));
     TermsEnum testTermEnum = MultiFields.getTerms(testReader, t.field()).iterator();
-    testTermEnum.seek(new BytesRef(t.text()));
+    testTermEnum.seekCeil(new BytesRef(t.text()));
     assertEquals(aprioriTermEnum.term(), testTermEnum.term());
 
     DocsEnum aprioriTermDocs = aprioriTermEnum.docs(MultiFields.getDeletedDocs(aprioriReader), null);

Modified: lucene/dev/trunk/lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java (original)
+++ lucene/dev/trunk/lucene/contrib/memory/src/java/org/apache/lucene/index/memory/MemoryIndex.java Sun Jun 26 13:33:58 2011
@@ -860,7 +860,18 @@ public class MemoryIndex {
       }
 
       @Override
-      public SeekStatus seek(BytesRef text, boolean useCache) {
+      public boolean seekExact(BytesRef text, boolean useCache) {
+        termUpto = Arrays.binarySearch(info.sortedTerms, text, termComparator);
+        if (termUpto >= 0) {
+          br.copy(info.sortedTerms[termUpto].getKey());
+          return true;
+        } else {
+          return false;
+        }
+      }
+
+      @Override
+      public SeekStatus seekCeil(BytesRef text, boolean useCache) {
         termUpto = Arrays.binarySearch(info.sortedTerms, text, termComparator);
         if (termUpto < 0) { // not found; choose successor
           termUpto = -termUpto -1;
@@ -877,13 +888,9 @@ public class MemoryIndex {
       }
 
       @Override
-      public SeekStatus seek(long ord) {
+      public void seekExact(long ord) {
+        assert ord < info.sortedTerms.length;
         termUpto = (int) ord;
-        if (ord < info.sortedTerms.length) {
-          return SeekStatus.FOUND;
-        } else {
-          return SeekStatus.END;
-        }
       }
       
       @Override
@@ -939,9 +946,9 @@ public class MemoryIndex {
       }
 
       @Override
-      public void seek(BytesRef term, TermState state) throws IOException {
+      public void seekExact(BytesRef term, TermState state) throws IOException {
         assert state != null;
-        this.seek(((OrdTermState)state).ord);
+        this.seekExact(((OrdTermState)state).ord);
       }
 
       @Override

Modified: lucene/dev/trunk/lucene/contrib/misc/src/java/org/apache/lucene/misc/HighFreqTerms.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/misc/src/java/org/apache/lucene/misc/HighFreqTerms.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/misc/src/java/org/apache/lucene/misc/HighFreqTerms.java (original)
+++ lucene/dev/trunk/lucene/contrib/misc/src/java/org/apache/lucene/misc/HighFreqTerms.java Sun Jun 26 13:33:58 2011
@@ -186,7 +186,7 @@ public class HighFreqTerms {
     }
 
     TermsEnum termsEnum = terms.iterator();
-    if (termsEnum.seek(termText) != TermsEnum.SeekStatus.FOUND) {
+    if (termsEnum.seekCeil(termText) != TermsEnum.SeekStatus.FOUND) {
       return 0;
     }
 

Modified: lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java (original)
+++ lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestMultiPassIndexSplitter.java Sun Jun 26 13:33:58 2011
@@ -73,7 +73,7 @@ public class TestMultiPassIndexSplitter 
     Document doc = ir.document(0);
     assertEquals("0", doc.get("id"));
     TermsEnum te = MultiFields.getTerms(ir, "id").iterator();
-    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seek(new BytesRef("1")));
+    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seekCeil(new BytesRef("1")));
     assertNotSame("1", te.term().utf8ToString());
     ir.close();
     ir = IndexReader.open(dirs[1], true);
@@ -81,7 +81,7 @@ public class TestMultiPassIndexSplitter 
     doc = ir.document(0);
     assertEquals("1", doc.get("id"));
     te = MultiFields.getTerms(ir, "id").iterator();
-    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seek(new BytesRef("0")));
+    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seekCeil(new BytesRef("0")));
 
     assertNotSame("0", te.term().utf8ToString());
     ir.close();
@@ -91,10 +91,10 @@ public class TestMultiPassIndexSplitter 
     assertEquals("2", doc.get("id"));
 
     te = MultiFields.getTerms(ir, "id").iterator();
-    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seek(new BytesRef("1")));
+    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seekCeil(new BytesRef("1")));
     assertNotSame("1", te.term());
 
-    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seek(new BytesRef("0")));
+    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seekCeil(new BytesRef("0")));
     assertNotSame("0", te.term().utf8ToString());
     ir.close();
     for (Directory d : dirs)
@@ -132,7 +132,7 @@ public class TestMultiPassIndexSplitter 
     // make sure the deleted doc is not here
     TermsEnum te = MultiFields.getTerms(ir, "id").iterator();
     Term t = new Term("id", (NUM_DOCS - 1) + "");
-    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seek(new BytesRef(t.text())));
+    assertEquals(TermsEnum.SeekStatus.NOT_FOUND, te.seekCeil(new BytesRef(t.text())));
     assertNotSame(t.text(), te.term().utf8ToString());
     ir.close();
     for (Directory d : dirs)

Modified: lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestNRTManager.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestNRTManager.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestNRTManager.java (original)
+++ lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/TestNRTManager.java Sun Jun 26 13:33:58 2011
@@ -526,7 +526,7 @@ public class TestNRTManager extends Luce
                           //System.out.println("trigger " + trigger);
                           shift = random.nextInt(trigger);
                         }
-                        termsEnum.seek(new BytesRef(""));
+                        termsEnum.seekCeil(new BytesRef(""));
                         continue;
                       }
                       seenTermCount++;

Modified: lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/codecs/appending/TestAppendingCodec.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/codecs/appending/TestAppendingCodec.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/codecs/appending/TestAppendingCodec.java (original)
+++ lucene/dev/trunk/lucene/contrib/misc/src/test/org/apache/lucene/index/codecs/appending/TestAppendingCodec.java Sun Jun 26 13:33:58 2011
@@ -154,14 +154,14 @@ public class TestAppendingCodec extends 
     Terms terms = fields.terms("f");
     assertNotNull(terms);
     TermsEnum te = terms.iterator();
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("quick")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("brown")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("fox")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("jumped")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("over")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("lazy")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("dog")));
-    assertEquals(SeekStatus.FOUND, te.seek(new BytesRef("the")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("quick")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("brown")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("fox")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("jumped")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("over")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("lazy")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("dog")));
+    assertEquals(SeekStatus.FOUND, te.seekCeil(new BytesRef("the")));
     DocsEnum de = te.docs(null, null);
     assertTrue(de.advance(0) != DocsEnum.NO_MORE_DOCS);
     assertEquals(2, de.freq());

Modified: lucene/dev/trunk/lucene/contrib/queries/src/java/org/apache/lucene/search/TermsFilter.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/queries/src/java/org/apache/lucene/search/TermsFilter.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/queries/src/java/org/apache/lucene/search/TermsFilter.java (original)
+++ lucene/dev/trunk/lucene/contrib/queries/src/java/org/apache/lucene/search/TermsFilter.java Sun Jun 26 13:33:58 2011
@@ -79,7 +79,7 @@ public class TermsFilter extends Filter
 
         if (terms != null) {
           br.copy(term.bytes());
-          if (termsEnum.seek(br) == TermsEnum.SeekStatus.FOUND) {
+          if (termsEnum.seekCeil(br) == TermsEnum.SeekStatus.FOUND) {
             docs = termsEnum.docs(delDocs, docs);
             while(docs.nextDoc() != DocsEnum.NO_MORE_DOCS) {
               result.set(docs.docID());

Modified: lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndPrefixQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndPrefixQuery.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndPrefixQuery.java (original)
+++ lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndPrefixQuery.java Sun Jun 26 13:33:58 2011
@@ -63,7 +63,7 @@ public class SrndPrefixQuery extends Sim
       TermsEnum termsEnum = terms.iterator();
 
       boolean skip = false;
-      TermsEnum.SeekStatus status = termsEnum.seek(new BytesRef(getPrefix()));
+      TermsEnum.SeekStatus status = termsEnum.seekCeil(new BytesRef(getPrefix()));
       if (status == TermsEnum.SeekStatus.FOUND) {
         mtv.visitMatchingTerm(getLucenePrefixTerm(fieldName));
       } else if (status == TermsEnum.SeekStatus.NOT_FOUND) {

Modified: lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTermQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTermQuery.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTermQuery.java (original)
+++ lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTermQuery.java Sun Jun 26 13:33:58 2011
@@ -53,7 +53,7 @@ public class SrndTermQuery extends Simpl
     if (terms != null) {
       TermsEnum termsEnum = terms.iterator();
 
-      TermsEnum.SeekStatus status = termsEnum.seek(new BytesRef(getTermText()));
+      TermsEnum.SeekStatus status = termsEnum.seekCeil(new BytesRef(getTermText()));
       if (status == TermsEnum.SeekStatus.FOUND) {
         mtv.visitMatchingTerm(getLuceneTerm(fieldName));
       }

Modified: lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTruncQuery.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTruncQuery.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTruncQuery.java (original)
+++ lucene/dev/trunk/lucene/contrib/queryparser/src/java/org/apache/lucene/queryParser/surround/query/SrndTruncQuery.java Sun Jun 26 13:33:58 2011
@@ -95,7 +95,7 @@ public class SrndTruncQuery extends Simp
       try {
         TermsEnum termsEnum = terms.iterator();
 
-        TermsEnum.SeekStatus status = termsEnum.seek(prefixRef);
+        TermsEnum.SeekStatus status = termsEnum.seekCeil(prefixRef);
         BytesRef text;
         if (status == TermsEnum.SeekStatus.FOUND) {
           text = prefixRef;

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/BufferedDeletesStream.java Sun Jun 26 13:33:58 2011
@@ -398,7 +398,7 @@ class BufferedDeletesStream {
 
       // System.out.println("  term=" + term);
 
-      if (termsEnum.seek(term.bytes(), false) == TermsEnum.SeekStatus.FOUND) {
+      if (termsEnum.seekExact(term.bytes(), false)) {
         DocsEnum docsEnum = termsEnum.docs(reader.getDeletedDocs(), docs);
 
         if (docsEnum != null) {

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/CheckIndex.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/CheckIndex.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/CheckIndex.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/CheckIndex.java Sun Jun 26 13:33:58 2011
@@ -881,7 +881,7 @@ public class CheckIndex {
 
         // Test seek to last term:
         if (lastTerm != null) {
-          if (terms.seek(lastTerm) != TermsEnum.SeekStatus.FOUND) {
+          if (terms.seekCeil(lastTerm) != TermsEnum.SeekStatus.FOUND) {
             throw new RuntimeException("seek to last term " + lastTerm + " failed");
           }
 
@@ -908,14 +908,14 @@ public class CheckIndex {
             // Seek by ord
             for(int i=seekCount-1;i>=0;i--) {
               long ord = i*(termCount/seekCount);
-              terms.seek(ord);
+              terms.seekExact(ord);
               seekTerms[i] = new BytesRef(terms.term());
             }
 
             // Seek by term
             long totDocCount = 0;
             for(int i=seekCount-1;i>=0;i--) {
-              if (terms.seek(seekTerms[i]) != TermsEnum.SeekStatus.FOUND) {
+              if (terms.seekCeil(seekTerms[i]) != TermsEnum.SeekStatus.FOUND) {
                 throw new RuntimeException("seek to existing term " + seekTerms[i] + " failed");
               }
               

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocTermOrds.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocTermOrds.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocTermOrds.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocTermOrds.java Sun Jun 26 13:33:58 2011
@@ -237,7 +237,7 @@ public class DocTermOrds {
     final TermsEnum te = terms.iterator();
     final BytesRef seekStart = termPrefix != null ? termPrefix : new BytesRef();
     //System.out.println("seekStart=" + seekStart.utf8ToString());
-    if (te.seek(seekStart) == TermsEnum.SeekStatus.END) {
+    if (te.seekCeil(seekStart) == TermsEnum.SeekStatus.END) {
       // No terms match
       return;
     }
@@ -693,7 +693,7 @@ public class DocTermOrds {
     }
 
     @Override
-    public SeekStatus seek(BytesRef target, boolean useCache) throws IOException {
+    public SeekStatus seekCeil(BytesRef target, boolean useCache) throws IOException {
 
       // already here
       if (term != null && term.equals(target)) {
@@ -704,7 +704,7 @@ public class DocTermOrds {
 
       if (startIdx >= 0) {
         // we hit the term exactly... lucky us!
-        TermsEnum.SeekStatus seekStatus = termsEnum.seek(target);
+        TermsEnum.SeekStatus seekStatus = termsEnum.seekCeil(target);
         assert seekStatus == TermsEnum.SeekStatus.FOUND;
         ord = startIdx << indexIntervalBits;
         setTerm();
@@ -717,7 +717,7 @@ public class DocTermOrds {
     
       if (startIdx == 0) {
         // our target occurs *before* the first term
-        TermsEnum.SeekStatus seekStatus = termsEnum.seek(target);
+        TermsEnum.SeekStatus seekStatus = termsEnum.seekCeil(target);
         assert seekStatus == TermsEnum.SeekStatus.NOT_FOUND;
         ord = 0;
         setTerm();
@@ -733,7 +733,7 @@ public class DocTermOrds {
         // so we don't need to seek.
       } else {
         // seek to the right block
-        TermsEnum.SeekStatus seekStatus = termsEnum.seek(indexedTermsArray[startIdx]);
+        TermsEnum.SeekStatus seekStatus = termsEnum.seekCeil(indexedTermsArray[startIdx]);
         assert seekStatus == TermsEnum.SeekStatus.FOUND;
         ord = startIdx << indexIntervalBits;
         setTerm();
@@ -754,16 +754,16 @@ public class DocTermOrds {
     }
 
     @Override
-    public SeekStatus seek(long targetOrd) throws IOException {
+    public void seekExact(long targetOrd) throws IOException {
       int delta = (int) (targetOrd - ordBase - ord);
-      //System.out.println("  seek(ord) targetOrd=" + targetOrd + " delta=" + delta + " ord=" + ord);
+      //System.out.println("  seek(ord) targetOrd=" + targetOrd + " delta=" + delta + " ord=" + ord + " ii=" + indexInterval);
       if (delta < 0 || delta > indexInterval) {
         final int idx = (int) (targetOrd >>> indexIntervalBits);
         final BytesRef base = indexedTermsArray[idx];
         //System.out.println("  do seek term=" + base.utf8ToString());
         ord = idx << indexIntervalBits;
         delta = (int) (targetOrd - ord);
-        final TermsEnum.SeekStatus seekStatus = termsEnum.seek(base, true);
+        final TermsEnum.SeekStatus seekStatus = termsEnum.seekCeil(base, true);
         assert seekStatus == TermsEnum.SeekStatus.FOUND;
       } else {
         //System.out.println("seek w/in block");
@@ -772,15 +772,14 @@ public class DocTermOrds {
       while (--delta >= 0) {
         BytesRef br = termsEnum.next();
         if (br == null) {
-          term = null;
-          return null;
+          assert false;
+          return;
         }
         ord++;
       }
 
       setTerm();
-      return term == null ? SeekStatus.END : SeekStatus.FOUND;
-      //System.out.println("  return term=" + term.utf8ToString());
+      assert term != null;
     }
 
     private BytesRef setTerm() throws IOException {
@@ -794,8 +793,7 @@ public class DocTermOrds {
   }
 
   public BytesRef lookupTerm(TermsEnum termsEnum, int ord) throws IOException {
-    TermsEnum.SeekStatus status = termsEnum.seek(ord);
-    assert status == TermsEnum.SeekStatus.FOUND;
+    termsEnum.seekExact(ord);
     return termsEnum.term();
   }
 }

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/DocumentsWriterFlushControl.java Sun Jun 26 13:33:58 2011
@@ -99,7 +99,7 @@ public final class DocumentsWriterFlushC
       final long ram = flushBytes + activeBytes;
       final long ramBufferBytes = (long) (maxConfiguredRamBuffer * 1024 * 1024);
       // take peakDelta into account - worst case is that all flushing, pending and blocked DWPT had maxMem and the last doc had the peakDelta 
-      final long expected = (long)(2 * (ramBufferBytes)) + ((numPending + numFlushingDWPT() + numBlockedFlushes()) * peakDelta);
+      final long expected = (2 * (ramBufferBytes)) + ((numPending + numFlushingDWPT() + numBlockedFlushes()) * peakDelta);
       if (peakDelta < (ramBufferBytes >> 1)) {
         /*
          * if we are indexing with very low maxRamBuffer like 0.1MB memory can

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/FilterIndexReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/FilterIndexReader.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/FilterIndexReader.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/FilterIndexReader.java Sun Jun 26 13:33:58 2011
@@ -132,13 +132,18 @@ public class FilterIndexReader extends I
     public FilterTermsEnum(TermsEnum in) { this.in = in; }
 
     @Override
-    public SeekStatus seek(BytesRef text, boolean useCache) throws IOException {
-      return in.seek(text, useCache);
+    public boolean seekExact(BytesRef text, boolean useCache) throws IOException {
+      return in.seekExact(text, useCache);
     }
 
     @Override
-    public SeekStatus seek(long ord) throws IOException {
-      return in.seek(ord);
+    public SeekStatus seekCeil(BytesRef text, boolean useCache) throws IOException {
+      return in.seekCeil(text, useCache);
+    }
+
+    @Override
+    public void seekExact(long ord) throws IOException {
+      in.seekExact(ord);
     }
 
     @Override
@@ -182,8 +187,8 @@ public class FilterIndexReader extends I
     }
 
     @Override
-    public void seek(BytesRef term, TermState state) throws IOException {
-      in.seek(term, state);
+    public void seekExact(BytesRef term, TermState state) throws IOException {
+      in.seekExact(term, state);
     }
 
     @Override

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/MultiTermsEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/MultiTermsEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/MultiTermsEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/MultiTermsEnum.java Sun Jun 26 13:33:58 2011
@@ -139,7 +139,7 @@ public final class MultiTermsEnum extend
   }
 
   @Override
-  public SeekStatus seek(BytesRef term, boolean useCache) throws IOException {
+  public boolean seekExact(BytesRef term, boolean useCache) throws IOException {
     queue.clear();
     numTop = 0;
 
@@ -147,6 +147,56 @@ public final class MultiTermsEnum extend
     if (lastSeek != null && termComp.compare(lastSeek, term) <= 0) {
       seekOpt = true;
     }
+
+    lastSeek = null;
+
+    for(int i=0;i<numSubs;i++) {
+      final boolean status;
+      // LUCENE-2130: if we had just seek'd already, prior
+      // to this seek, and the new seek term is after the
+      // previous one, don't try to re-seek this sub if its
+      // current term is already beyond this new seek term.
+      // Doing so is a waste because this sub will simply
+      // seek to the same spot.
+      if (seekOpt) {
+        final BytesRef curTerm = currentSubs[i].current;
+        if (curTerm != null) {
+          final int cmp = termComp.compare(term, curTerm);
+          if (cmp == 0) {
+            status = true;
+          } else if (cmp < 0) {
+            status = false;
+          } else {
+            status = currentSubs[i].terms.seekExact(term, useCache);
+          }
+        } else {
+          status = false;
+        }
+      } else {
+        status = currentSubs[i].terms.seekExact(term, useCache);
+      }
+
+      if (status) {
+        top[numTop++] = currentSubs[i];
+        current = currentSubs[i].current = currentSubs[i].terms.term();
+      }
+    }
+
+    // if at least one sub had exact match to the requested
+    // term then we found match
+    return numTop > 0;
+  }
+
+  @Override
+  public SeekStatus seekCeil(BytesRef term, boolean useCache) throws IOException {
+    queue.clear();
+    numTop = 0;
+
+    boolean seekOpt = false;
+    if (lastSeek != null && termComp.compare(lastSeek, term) <= 0) {
+      seekOpt = true;
+    }
+
     lastSeekScratch.copy(term);
     lastSeek = lastSeekScratch;
 
@@ -167,25 +217,27 @@ public final class MultiTermsEnum extend
           } else if (cmp < 0) {
             status = SeekStatus.NOT_FOUND;
           } else {
-            status = currentSubs[i].terms.seek(term, useCache);
+            status = currentSubs[i].terms.seekCeil(term, useCache);
           }
         } else {
           status = SeekStatus.END;
         }
       } else {
-        status = currentSubs[i].terms.seek(term, useCache);
+        status = currentSubs[i].terms.seekCeil(term, useCache);
       }
 
       if (status == SeekStatus.FOUND) {
         top[numTop++] = currentSubs[i];
         current = currentSubs[i].current = currentSubs[i].terms.term();
-      } else if (status == SeekStatus.NOT_FOUND) {
-        currentSubs[i].current = currentSubs[i].terms.term();
-        assert currentSubs[i].current != null;
-        queue.add(currentSubs[i]);
       } else {
-        // enum exhausted
-        currentSubs[i].current = null;
+        if (status == SeekStatus.NOT_FOUND) {
+          currentSubs[i].current = currentSubs[i].terms.term();
+          assert currentSubs[i].current != null;
+          queue.add(currentSubs[i]);
+        } else {
+          // enum exhausted
+          currentSubs[i].current = null;
+        }
       }
     }
 
@@ -204,7 +256,7 @@ public final class MultiTermsEnum extend
   }
 
   @Override
-  public SeekStatus seek(long ord) throws IOException {
+  public void seekExact(long ord) throws IOException {
     throw new UnsupportedOperationException();
   }
 

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermState.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermState.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermState.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermState.java Sun Jun 26 13:33:58 2011
@@ -21,7 +21,7 @@ package org.apache.lucene.index;
  * Encapsulates all required internal state to position the associated
  * {@link TermsEnum} without re-seeking.
  * 
- * @see TermsEnum#seek(org.apache.lucene.util.BytesRef, TermState)
+ * @see TermsEnum#seekExact(org.apache.lucene.util.BytesRef, TermState)
  * @see TermsEnum#termState()
  * @lucene.experimental
  */

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/Terms.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/Terms.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/Terms.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/Terms.java Sun Jun 26 13:33:58 2011
@@ -50,7 +50,7 @@ public abstract class Terms {
    *  exist. */
   public int docFreq(BytesRef text) throws IOException {
     final TermsEnum termsEnum = getThreadTermsEnum();
-    if (termsEnum.seek(text) == TermsEnum.SeekStatus.FOUND) {
+    if (termsEnum.seekExact(text, true)) {
       return termsEnum.docFreq();
     } else {
       return 0;
@@ -62,7 +62,7 @@ public abstract class Terms {
    *  exist. */
   public long totalTermFreq(BytesRef text) throws IOException {
     final TermsEnum termsEnum = getThreadTermsEnum();
-    if (termsEnum.seek(text) == TermsEnum.SeekStatus.FOUND) {
+    if (termsEnum.seekExact(text, true)) {
       return termsEnum.totalTermFreq();
     } else {
       return 0;
@@ -73,7 +73,7 @@ public abstract class Terms {
    *  method may return null if the term does not exist. */
   public DocsEnum docs(Bits skipDocs, BytesRef text, DocsEnum reuse) throws IOException {
     final TermsEnum termsEnum = getThreadTermsEnum();
-    if (termsEnum.seek(text) == TermsEnum.SeekStatus.FOUND) {
+    if (termsEnum.seekExact(text, true)) {
       return termsEnum.docs(skipDocs, reuse);
     } else {
       return null;
@@ -85,7 +85,7 @@ public abstract class Terms {
    *  exists, or positions were not indexed. */ 
   public DocsAndPositionsEnum docsAndPositions(Bits skipDocs, BytesRef text, DocsAndPositionsEnum reuse) throws IOException {
     final TermsEnum termsEnum = getThreadTermsEnum();
-    if (termsEnum.seek(text) == TermsEnum.SeekStatus.FOUND) {
+    if (termsEnum.seekExact(text, true)) {
       return termsEnum.docsAndPositions(skipDocs, reuse);
     } else {
       return null;
@@ -97,10 +97,10 @@ public abstract class Terms {
    * This method may return <code>null</code> if the term does not exist.
    * 
    * @see TermsEnum#termState()
-   * @see TermsEnum#seek(BytesRef, TermState) */
+   * @see TermsEnum#seekExact(BytesRef, TermState) */
   public DocsEnum docs(Bits skipDocs, BytesRef term, TermState termState, DocsEnum reuse) throws IOException {
     final TermsEnum termsEnum = getThreadTermsEnum();
-    termsEnum.seek(term, termState);
+    termsEnum.seekExact(term, termState);
     return termsEnum.docs(skipDocs, reuse);
   }
 
@@ -110,10 +110,10 @@ public abstract class Terms {
    * not indexed.
    * 
    * @see TermsEnum#termState()
-   * @see TermsEnum#seek(BytesRef, TermState) */
+   * @see TermsEnum#seekExact(BytesRef, TermState) */
   public DocsAndPositionsEnum docsAndPositions(Bits skipDocs, BytesRef term, TermState termState, DocsAndPositionsEnum reuse) throws IOException {
     final TermsEnum termsEnum = getThreadTermsEnum();
-    termsEnum.seek(term, termState);
+    termsEnum.seekExact(term, termState);
     return termsEnum.docsAndPositions(skipDocs, reuse);
   }
 

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermsEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermsEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermsEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/TermsEnum.java Sun Jun 26 13:33:58 2011
@@ -24,18 +24,20 @@ import org.apache.lucene.util.AttributeS
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 
-/** Iterator to seek ({@link #seek}) or step through ({@link
- * #next} terms, obtain frequency information ({@link
- * #docFreq}), and obtain a {@link DocsEnum} or {@link
+/** Iterator to seek ({@link #seekCeil(BytesRef)}, {@link
+ * #seekExact(BytesRef,boolean)}) or step through ({@link
+ * #next} terms to obtain frequency information ({@link
+ * #docFreq}), {@link DocsEnum} or {@link
  * DocsAndPositionsEnum} for the current term ({@link
  * #docs}.
  * 
  * <p>Term enumerations are always ordered by
  * {@link #getComparator}.  Each term in the enumeration is
- * greater than all that precede it.</p>
+ * greater than the one before it.</p>
  *
- * <p>On obtaining a TermsEnum, you must first call
- * {@link #next} or {@link #seek}.
+ * <p>The TermsEnum is unpositioned when you first obtain it
+ * and you must first successfully call {@link #next} or one
+ * of the <code>seek</code> methods.
  *
  * @lucene.experimental */
 public abstract class TermsEnum {
@@ -48,31 +50,41 @@ public abstract class TermsEnum {
     return atts;
   }
   
-  /** Represents returned result from {@link #seek}.
+  /** Represents returned result from {@link #seekCeil}.
    *  If status is FOUND, then the precise term was found.
    *  If status is NOT_FOUND, then a different term was
    *  found.  If the status is END, the end of the iteration
    *  was hit. */
   public static enum SeekStatus {END, FOUND, NOT_FOUND};
 
-  /** Expert: just like {@link #seek(BytesRef)} but allows
+  /** Attemps to seek to the exact term, returning
+   *  true if the term is found.  If this returns false, the
+   *  enum is unpositioned.  For some codecs, seekExact may
+   *  be substantially faster than {@link #seekCeil}. */
+  public boolean seekExact(BytesRef text, boolean useCache) throws IOException {
+    return seekCeil(text, useCache) == SeekStatus.FOUND;
+  }
+
+  /** Expert: just like {@link #seekCeil(BytesRef)} but allows
    *  you to control whether the implementation should
    *  attempt to use its term cache (if it uses one). */
-  public abstract SeekStatus seek(BytesRef text, boolean useCache) throws IOException;
+  public abstract SeekStatus seekCeil(BytesRef text, boolean useCache) throws IOException;
 
-  /** Seeks to the specified term.  Returns SeekStatus to
+  /** Seeks to the specified term, if it exists, or to the
+   *  next (ceiling) term.  Returns SeekStatus to
    *  indicate whether exact term was found, a different
    *  term was found, or EOF was hit.  The target term may
-   *  be before or after the current term. */
-  public final SeekStatus seek(BytesRef text) throws IOException {
-    return seek(text, true);
+   *  be before or after the current term.  If this returns
+   *  SeekStatus.END, the enum is unpositioned. */
+  public final SeekStatus seekCeil(BytesRef text) throws IOException {
+    return seekCeil(text, true);
   }
 
   /** Seeks to the specified term by ordinal (position) as
    *  previously returned by {@link #ord}.  The target ord
-   *  may be before or after the current ord.  See {@link
-   *  #seek(BytesRef)}. */
-  public abstract SeekStatus seek(long ord) throws IOException;
+   *  may be before or after the current ord, and must be
+   *  within bounds. */
+  public abstract void seekExact(long ord) throws IOException;
 
   /**
    * Expert: Seeks a specific position by {@link TermState} previously obtained
@@ -82,8 +94,7 @@ public abstract class TermsEnum {
    * <p>
    * Seeking by {@link TermState} should only be used iff the enum the state was
    * obtained from and the enum the state is used for seeking are obtained from
-   * the same {@link IndexReader}, otherwise a {@link #seek(BytesRef, TermState)} call can
-   * leave the enum in undefined state.
+   * the same {@link IndexReader}.
    * <p>
    * NOTE: Using this method with an incompatible {@link TermState} might leave
    * this {@link TermsEnum} in undefined state. On a segment level
@@ -97,32 +108,30 @@ public abstract class TermsEnum {
    * @param term the term the TermState corresponds to
    * @param state the {@link TermState}
    * */
-  public void seek(BytesRef term, TermState state) throws IOException {
-    seek(term);
+  public void seekExact(BytesRef term, TermState state) throws IOException {
+    if (!seekExact(term, true)) {
+      throw new IllegalArgumentException("term=" + term + " does not exist");
+    }
   }
 
-  /** Increments the enumeration to the next element.
+  /** Increments the enumeration to the next term.
    *  Returns the resulting term, or null if the end was
-   *  hit.  The returned BytesRef may be re-used across calls
-   *  to next. */
+   *  hit (which means the enum is unpositioned).  The
+   *  returned BytesRef may be re-used across calls to next. */
   public abstract BytesRef next() throws IOException;
 
-  /** Returns current term. Do not call this before calling
-   *  next() for the first time, after next() returns null
-   *  or after seek returns {@link SeekStatus#END}.*/
+  /** Returns current term. Do not call this when the enum
+   *  is unpositioned. */
   public abstract BytesRef term() throws IOException;
 
   /** Returns ordinal position for current term.  This is an
    *  optional method (the codec may throw {@link
    *  UnsupportedOperationException}).  Do not call this
-   *  before calling {@link #next} for the first time or after
-   *  {@link #next} returns null or {@link #seek} returns
-   *  END; */
+   *  when the enum is unpositioned. */
   public abstract long ord() throws IOException;
 
   /** Returns the number of documents containing the current
-   *  term.  Do not call this before calling next() for the
-   *  first time, after next() returns null or seek returns
+   *  term.  Do not call this when the enum is unpositioned.
    *  {@link SeekStatus#END}.*/
   public abstract int docFreq() throws IOException;
 
@@ -135,9 +144,8 @@ public abstract class TermsEnum {
   public abstract long totalTermFreq() throws IOException;
 
   /** Get {@link DocsEnum} for the current term.  Do not
-   *  call this before calling {@link #next} or {@link
-   *  #seek} for the first time.  This method will not
-   *  return null.
+   *  call this when the enum is unpositioned.  This method
+   *  will not return null.
    *  
    * @param skipDocs set bits are documents that should not
    * be returned
@@ -145,10 +153,9 @@ public abstract class TermsEnum {
   public abstract DocsEnum docs(Bits skipDocs, DocsEnum reuse) throws IOException;
 
   /** Get {@link DocsAndPositionsEnum} for the current term.
-   *  Do not call this before calling {@link #next} or
-   *  {@link #seek} for the first time.  This method will
-   *  only return null if positions were not indexed into
-   *  the postings by this codec. */
+   *  Do not call this when the enum is unpositioned.
+   *  This method will only return null if positions were
+   *  not indexed into the postings by this codec. */
   public abstract DocsAndPositionsEnum docsAndPositions(Bits skipDocs, DocsAndPositionsEnum reuse) throws IOException;
 
   /**
@@ -160,7 +167,7 @@ public abstract class TermsEnum {
    * {@link AttributeSource} states separately
    * 
    * @see TermState
-   * @see #seek(BytesRef, TermState)
+   * @see #seekExact(BytesRef, TermState)
    */
   public TermState termState() throws IOException {
     return new TermState() {
@@ -186,10 +193,10 @@ public abstract class TermsEnum {
    */
   public static final TermsEnum EMPTY = new TermsEnum() {    
     @Override
-    public SeekStatus seek(BytesRef term, boolean useCache) { return SeekStatus.END; }
+    public SeekStatus seekCeil(BytesRef term, boolean useCache) { return SeekStatus.END; }
     
     @Override
-    public SeekStatus seek(long ord) { return SeekStatus.END; }
+    public void seekExact(long ord) {}
     
     @Override
     public BytesRef term() {
@@ -242,7 +249,7 @@ public abstract class TermsEnum {
     }
 
     @Override
-    public void seek(BytesRef term, TermState state) throws IOException {
+    public void seekExact(BytesRef term, TermState state) throws IOException {
       throw new IllegalStateException("this method should never be called");
     }
   };

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/BlockTermsReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/BlockTermsReader.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/BlockTermsReader.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/BlockTermsReader.java Sun Jun 26 13:33:58 2011
@@ -302,7 +302,7 @@ public class BlockTermsReader extends Fi
          only valid if didIndexNext is true: */
       private BytesRef nextIndexTerm;
 
-      /* True after seek(TermState), do defer seeking.  If the app then
+      /* True after seekExact(TermState), do defer seeking.  If the app then
          calls next() (which is not "typical"), then we'll do the real seek */
       private boolean seekPending;
 
@@ -348,7 +348,7 @@ public class BlockTermsReader extends Fi
       // return NOT_FOUND so it's a waste for us to fill in
       // the term that was actually NOT_FOUND
       @Override
-      public SeekStatus seek(final BytesRef target, final boolean useCache) throws IOException {
+      public SeekStatus seekCeil(final BytesRef target, final boolean useCache) throws IOException {
 
         if (indexEnum == null) {
           throw new IllegalStateException("terms index was not loaded");
@@ -376,7 +376,7 @@ public class BlockTermsReader extends Fi
           if (cachedState != null) {
             seekPending = true;
             //System.out.println("  cached!");
-            seek(target, cachedState);
+            seekExact(target, cachedState);
             //System.out.println("  term=" + term.utf8ToString());
             return SeekStatus.FOUND;
           }
@@ -711,7 +711,7 @@ public class BlockTermsReader extends Fi
       }
 
       @Override
-      public void seek(BytesRef target, TermState otherState) throws IOException {
+      public void seekExact(BytesRef target, TermState otherState) throws IOException {
         //System.out.println("BTR.seek termState target=" + target.utf8ToString() + " " + target + " this=" + this);
         assert otherState != null && otherState instanceof BlockTermState;
         assert !doOrd || ((BlockTermState) otherState).ord < numTerms;
@@ -731,16 +731,13 @@ public class BlockTermsReader extends Fi
       }
 
       @Override
-      public SeekStatus seek(long ord) throws IOException {
+      public void seekExact(long ord) throws IOException {
         //System.out.println("BTR.seek by ord ord=" + ord);
         if (indexEnum == null) {
           throw new IllegalStateException("terms index was not loaded");
         }
 
-        if (ord >= numTerms) {
-          state.ord = numTerms-1;
-          return SeekStatus.END;
-        }
+        assert ord < numTerms;
 
         // TODO: if ord is in same terms block and
         // after current ord, we should avoid this seek just
@@ -768,9 +765,6 @@ public class BlockTermsReader extends Fi
           left--;
           assert indexIsCurrent;
         }
-
-        // always found
-        return SeekStatus.FOUND;
       }
 
       @Override

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/memory/MemoryCodec.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/memory/MemoryCodec.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/memory/MemoryCodec.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/memory/MemoryCodec.java Sun Jun 26 13:33:58 2011
@@ -561,7 +561,15 @@ public class MemoryCodec extends Codec {
     }
 
     @Override
-    public SeekStatus seek(BytesRef text, boolean useCache /* ignored */) throws IOException {
+    public boolean seekExact(BytesRef text, boolean useCache /* ignored */) throws IOException {
+      if (VERBOSE) System.out.println("te.seekExact text=" + field.name + ":" + text.utf8ToString() + " this=" + this);
+      current = fstEnum.seekExact(text);
+      didDecode = false;
+      return current != null;
+    }
+
+    @Override
+    public SeekStatus seekCeil(BytesRef text, boolean useCache /* ignored */) throws IOException {
       if (VERBOSE) System.out.println("te.seek text=" + field.name + ":" + text.utf8ToString() + " this=" + this);
       current = fstEnum.seekCeil(text);
       if (current == null) {
@@ -656,7 +664,7 @@ public class MemoryCodec extends Codec {
     }
 
     @Override
-    public SeekStatus seek(long ord) {
+    public void seekExact(long ord) {
       // NOTE: we could add this...
       throw new UnsupportedOperationException();
     }

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/preflex/PreFlexFields.java Sun Jun 26 13:33:58 2011
@@ -746,7 +746,7 @@ public class PreFlexFields extends Field
     }
 
     @Override
-    public SeekStatus seek(long ord) throws IOException {
+    public void seekExact(long ord) throws IOException {
       throw new UnsupportedOperationException();
     }
 
@@ -756,7 +756,7 @@ public class PreFlexFields extends Field
     }
 
     @Override
-    public SeekStatus seek(BytesRef term, boolean useCache) throws IOException {
+    public SeekStatus seekCeil(BytesRef term, boolean useCache) throws IOException {
       if (DEBUG_SURROGATES) {
         System.out.println("TE.seek target=" + UnicodeUtil.toHexString(term.utf8ToString()));
       }

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/simpletext/SimpleTextFieldsReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/simpletext/SimpleTextFieldsReader.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/simpletext/SimpleTextFieldsReader.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/index/codecs/simpletext/SimpleTextFieldsReader.java Sun Jun 26 13:33:58 2011
@@ -128,7 +128,23 @@ class SimpleTextFieldsReader extends Fie
     }
 
     @Override
-    public SeekStatus seek(BytesRef text, boolean useCache /* ignored */) throws IOException {
+    public boolean seekExact(BytesRef text, boolean useCache /* ignored */) throws IOException {
+
+      final BytesRefFSTEnum.InputOutput<PairOutputs.Pair<Long,PairOutputs.Pair<Long,Long>>> result = fstEnum.seekExact(text);
+      if (result != null) {
+        PairOutputs.Pair<Long,PairOutputs.Pair<Long,Long>> pair1 = result.output;
+        PairOutputs.Pair<Long,Long> pair2 = pair1.output2;
+        docsStart = pair1.output1;
+        docFreq = pair2.output1.intValue();
+        totalTermFreq = pair2.output2;
+        return true;
+      } else {
+        return false;
+      }
+    }
+
+    @Override
+    public SeekStatus seekCeil(BytesRef text, boolean useCache /* ignored */) throws IOException {
 
       //System.out.println("seek to text=" + text.utf8ToString());
       final BytesRefFSTEnum.InputOutput<PairOutputs.Pair<Long,PairOutputs.Pair<Long,Long>>> result = fstEnum.seekCeil(text);
@@ -180,7 +196,7 @@ class SimpleTextFieldsReader extends Fie
     }
 
     @Override
-    public SeekStatus seek(long ord) {
+    public void seekExact(long ord) {
       throw new UnsupportedOperationException();
     }
 

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FilteredTermsEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FilteredTermsEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FilteredTermsEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FilteredTermsEnum.java Sun Jun 26 13:33:58 2011
@@ -135,7 +135,7 @@ public abstract class FilteredTermsEnum 
    * @throws UnsupportedOperationException
    */
   @Override
-  public SeekStatus seek(BytesRef term, boolean useCache) throws IOException {
+  public boolean seekExact(BytesRef term, boolean useCache) throws IOException {
     throw new UnsupportedOperationException(getClass().getName()+" does not support seeking");
   }
 
@@ -143,7 +143,15 @@ public abstract class FilteredTermsEnum 
    * @throws UnsupportedOperationException
    */
   @Override
-  public SeekStatus seek(long ord) throws IOException {
+  public SeekStatus seekCeil(BytesRef term, boolean useCache) throws IOException {
+    throw new UnsupportedOperationException(getClass().getName()+" does not support seeking");
+  }
+
+  /** This enum does not support seeking!
+   * @throws UnsupportedOperationException
+   */
+  @Override
+  public void seekExact(long ord) throws IOException {
     throw new UnsupportedOperationException(getClass().getName()+" does not support seeking");
   }
 
@@ -166,7 +174,7 @@ public abstract class FilteredTermsEnum 
    * @throws UnsupportedOperationException
    */
   @Override
-  public void seek(BytesRef term, TermState state) throws IOException {
+  public void seekExact(BytesRef term, TermState state) throws IOException {
     throw new UnsupportedOperationException(getClass().getName()+" does not support seeking");
   }
   
@@ -189,7 +197,7 @@ public abstract class FilteredTermsEnum 
         final BytesRef t = nextSeekTerm(actualTerm);
         // Make sure we always seek forward:
         assert actualTerm == null || t == null || getComparator().compare(t, actualTerm) > 0: "curTerm=" + actualTerm + " seekTerm=" + t;
-        if (t == null || tenum.seek(t, false) == SeekStatus.END) {
+        if (t == null || tenum.seekCeil(t, false) == SeekStatus.END) {
           // no more terms to seek to or enum exhausted
           return null;
         }

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/FuzzyTermsEnum.java Sun Jun 26 13:33:58 2011
@@ -263,8 +263,8 @@ public final class FuzzyTermsEnum extend
   }
   
   @Override
-  public void seek(BytesRef term, TermState state) throws IOException {
-    actualEnum.seek(term, state);
+  public void seekExact(BytesRef term, TermState state) throws IOException {
+    actualEnum.seekExact(term, state);
   }
   
   @Override
@@ -283,13 +283,18 @@ public final class FuzzyTermsEnum extend
   }
   
   @Override
-  public SeekStatus seek(BytesRef text, boolean useCache) throws IOException {
-    return actualEnum.seek(text, useCache);
+  public boolean seekExact(BytesRef text, boolean useCache) throws IOException {
+    return actualEnum.seekExact(text, useCache);
+  }
+
+  @Override
+  public SeekStatus seekCeil(BytesRef text, boolean useCache) throws IOException {
+    return actualEnum.seekCeil(text, useCache);
   }
   
   @Override
-  public SeekStatus seek(long ord) throws IOException {
-    return actualEnum.seek(ord);
+  public void seekExact(long ord) throws IOException {
+    actualEnum.seekExact(ord);
   }
   
   @Override

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java Sun Jun 26 13:33:58 2011
@@ -239,13 +239,13 @@ public class DocTermsIndexCreator extend
       }
 
       @Override
-      public SeekStatus seek(BytesRef text, boolean useCache) throws IOException {
+      public SeekStatus seekCeil(BytesRef text, boolean useCache /* ignored */) throws IOException {
         int low = 1;
         int high = numOrd-1;
         
         while (low <= high) {
           int mid = (low + high) >>> 1;
-          seek(mid);
+          seekExact(mid);
           int cmp = term.compareTo(text);
 
           if (cmp < 0)
@@ -259,19 +259,17 @@ public class DocTermsIndexCreator extend
         if (low == numOrd) {
           return SeekStatus.END;
         } else {
-          seek(low);
+          seekExact(low);
           return SeekStatus.NOT_FOUND;
         }
       }
 
-      @Override
-      public SeekStatus seek(long ord) throws IOException {
+      public void seekExact(long ord) throws IOException {
         assert(ord >= 0 && ord <= numOrd);
         // TODO: if gap is small, could iterate from current position?  Or let user decide that?
         currentBlockNumber = bytes.fillAndGetIndex(term, termOrdToBytesOffset.get((int)ord));
         end = blockEnds[currentBlockNumber];
         currentOrd = (int)ord;
-        return SeekStatus.FOUND;
       }
 
       @Override
@@ -339,9 +337,9 @@ public class DocTermsIndexCreator extend
       }
 
       @Override
-      public void seek(BytesRef term, TermState state) throws IOException {
+      public void seekExact(BytesRef term, TermState state) throws IOException {
         assert state != null && state instanceof OrdTermState;
-        this.seek(((OrdTermState)state).ord);
+        this.seekExact(((OrdTermState)state).ord);
       }
 
       @Override

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/PerReaderTermState.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/PerReaderTermState.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/PerReaderTermState.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/PerReaderTermState.java Sun Jun 26 13:33:58 2011
@@ -28,7 +28,6 @@ import org.apache.lucene.index.Terms;
 import org.apache.lucene.index.TermsEnum;
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.IndexReader.ReaderContext;
-import org.apache.lucene.index.TermsEnum.SeekStatus;
 
 /**
  * Maintains a {@link IndexReader} {@link TermState} view over
@@ -90,7 +89,7 @@ public final class PerReaderTermState {
         final Terms terms = fields.terms(field);
         if (terms != null) {
           final TermsEnum termsEnum = terms.getThreadTermsEnum(); // thread-private don't share!
-          if (SeekStatus.FOUND == termsEnum.seek(bytes, cache)) { 
+          if (termsEnum.seekExact(bytes, cache)) { 
             final TermState termState = termsEnum.termState();
             perReaderTermState.register(termState, leaves[i].ord, termsEnum.docFreq());
           }

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/BytesRefFSTEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/BytesRefFSTEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/BytesRefFSTEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/BytesRefFSTEnum.java Sun Jun 26 13:33:58 2011
@@ -71,6 +71,21 @@ public final class BytesRefFSTEnum<T> ex
     return setResult();
   }
 
+  /** Seeks to exactly this term, returning null if the term
+   *  doesn't exist.  This is faster than using {@link
+   *  #seekFloor} or {@link #seekCeil} because it
+   *  short-circuits as soon the match is not found. */
+  public InputOutput<T> seekExact(BytesRef target) throws IOException {
+    this.target = target;
+    targetLength = target.length;
+    if (super.doSeekExact()) {
+      assert upto == 1+target.length;
+      return setResult();
+    } else {
+      return null;
+    }
+  }
+
   @Override
   protected int getTargetLabel() {
     if (upto-1 == target.length) {

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FST.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FST.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FST.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FST.java Sun Jun 26 13:33:58 2011
@@ -704,6 +704,12 @@ public class FST<T> {
 
     if (labelToMatch == END_LABEL) {
       if (follow.isFinal()) {
+        if (follow.target <= 0) {
+          arc.flags = BIT_LAST_ARC;
+        } else {
+          arc.flags = 0;
+          arc.nextArc = follow.target;
+        }
         arc.output = follow.nextFinalOutput;
         arc.label = END_LABEL;
         return arc;

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FSTEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FSTEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FSTEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/FSTEnum.java Sun Jun 26 13:33:58 2011
@@ -73,6 +73,7 @@ abstract class FSTEnum<T> {
       final int cmp = getCurrentLabel() - getTargetLabel();
       if (cmp < 0) {
         // seek forward
+        //System.out.println("    seek fwd");
         break;
       } else if (cmp > 0) {
         // seek backwards -- reset this arc to the first arc
@@ -83,6 +84,7 @@ abstract class FSTEnum<T> {
       }
       upto++;
     }
+    //System.out.println("  fall through upto=" + upto);
   }
 
   protected void doNext() throws IOException {
@@ -352,7 +354,7 @@ abstract class FSTEnum<T> {
           //System.out.println(" hasFloor arcIdx=" + (arc.arcIdx+1));
           fst.readNextRealArc(arc);
           assert arc.isLast() || fst.readNextArcLabel(arc) > targetLabel;
-          assert arc.label < targetLabel;
+          assert arc.label < targetLabel: "arc.label=" + arc.label + " vs targetLabel=" + targetLabel;
           pushLast();
           return;
         }        
@@ -410,6 +412,48 @@ abstract class FSTEnum<T> {
     }
   }
 
+  /** Seeks to exactly target term. */
+  protected boolean doSeekExact() throws IOException {
+
+    // TODO: possibly caller could/should provide common
+    // prefix length?  ie this work may be redundant if
+    // caller is in fact intersecting against its own
+    // automaton
+
+    //System.out.println("FE: seek exact upto=" + upto);
+
+    // Save time by starting at the end of the shared prefix
+    // b/w our current term & the target:
+    rewindPrefix();
+
+    //System.out.println("FE: after rewind upto=" + upto);
+    FST.Arc<T> arc = getArc(upto-1);
+    int targetLabel = getTargetLabel();
+
+    while(true) {
+      //System.out.println("  cycle target=" + (targetLabel == -1 ? "-1" : (char) targetLabel));
+      final FST.Arc<T> nextArc = fst.findTargetArc(targetLabel, arc, getArc(upto));
+      if (nextArc == null) {
+        // short circuit
+        //upto--;
+        //upto = 0;
+        fst.readFirstTargetArc(arc, getArc(upto));
+        //System.out.println("  no match upto=" + upto);
+        return false;
+      }
+      // Match -- recurse:
+      output[upto] = fst.outputs.add(output[upto-1], nextArc.output);
+      if (targetLabel == FST.END_LABEL) {
+        //System.out.println("  return found; upto=" + upto + " output=" + output[upto] + " nextArc=" + nextArc.isLast());
+        return true;
+      }
+      setCurrentLabel(targetLabel);
+      incr();
+      targetLabel = getTargetLabel();
+      arc = nextArc;
+    }
+  }
+
   private void incr() {
     upto++;
     grow();

Modified: lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/IntsRefFSTEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/IntsRefFSTEnum.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/IntsRefFSTEnum.java (original)
+++ lucene/dev/trunk/lucene/src/java/org/apache/lucene/util/fst/IntsRefFSTEnum.java Sun Jun 26 13:33:58 2011
@@ -71,6 +71,21 @@ public final class IntsRefFSTEnum<T> ext
     return setResult();
   }
 
+  /** Seeks to exactly this term, returning null if the term
+   *  doesn't exist.  This is faster than using {@link
+   *  #seekFloor} or {@link #seekCeil} because it
+   *  short-circuits as soon the match is not found. */
+  public InputOutput<T> seekExact(IntsRef target) throws IOException {
+    this.target = target;
+    targetLength = target.length;
+    if (super.doSeekExact()) {
+      assert upto == 1+target.length;
+      return setResult();
+    } else {
+      return null;
+    }
+  }
+
   @Override
   protected int getTargetLabel() {
     if (upto-1 == target.length) {

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/TestExternalCodecs.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/TestExternalCodecs.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/TestExternalCodecs.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/TestExternalCodecs.java Sun Jun 26 13:33:58 2011
@@ -305,7 +305,7 @@ public class TestExternalCodecs extends 
       }
 
       @Override
-      public SeekStatus seek(BytesRef term, boolean useCache) {
+      public SeekStatus seekCeil(BytesRef term, boolean useCache) {
         current = term.utf8ToString();
         it = null;
         if (ramField.termToDocs.containsKey(current)) {
@@ -320,7 +320,7 @@ public class TestExternalCodecs extends 
       }
 
       @Override
-      public SeekStatus seek(long ord) {
+      public void seekExact(long ord) {
         throw new UnsupportedOperationException();
       }
 

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/Test2BTerms.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/Test2BTerms.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/Test2BTerms.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/Test2BTerms.java Sun Jun 26 13:33:58 2011
@@ -255,7 +255,7 @@ public class Test2BTerms extends LuceneT
       final long t1 = System.currentTimeMillis();
       System.out.println("  took " + (t1-t0) + " millis");
 
-      TermsEnum.SeekStatus result = termsEnum.seek(term);
+      TermsEnum.SeekStatus result = termsEnum.seekCeil(term);
       if (result != TermsEnum.SeekStatus.FOUND) {
         if (result == TermsEnum.SeekStatus.END) {
           System.out.println("  FAILED: got END");

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java Sun Jun 26 13:33:58 2011
@@ -632,24 +632,24 @@ public class TestBackwardsCompatibility 
 
       // should be found exactly
       assertEquals(TermsEnum.SeekStatus.FOUND,
-                   terms.seek(aaaTerm));
+                   terms.seekCeil(aaaTerm));
       assertEquals(35, countDocs(terms.docs(null, null)));
       assertNull(terms.next());
 
       // should hit end of field
       assertEquals(TermsEnum.SeekStatus.END,
-                   terms.seek(new BytesRef("bbb")));
+                   terms.seekCeil(new BytesRef("bbb")));
       assertNull(terms.next());
 
       // should seek to aaa
       assertEquals(TermsEnum.SeekStatus.NOT_FOUND,
-                   terms.seek(new BytesRef("a")));
+                   terms.seekCeil(new BytesRef("a")));
       assertTrue(terms.term().bytesEquals(aaaTerm));
       assertEquals(35, countDocs(terms.docs(null, null)));
       assertNull(terms.next());
 
       assertEquals(TermsEnum.SeekStatus.FOUND,
-                   terms.seek(aaaTerm));
+                   terms.seekCeil(aaaTerm));
       assertEquals(35, countDocs(terms.docs(null, null)));
       assertNull(terms.next());
 

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestCodecs.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestCodecs.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestCodecs.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestCodecs.java Sun Jun 26 13:33:58 2011
@@ -266,7 +266,7 @@ public class TestCodecs extends LuceneTe
     assertNull(termsEnum.next());
 
     for(int i=0;i<NUM_TERMS;i++) {
-      assertEquals(termsEnum.seek(new BytesRef(terms[i].text2)), TermsEnum.SeekStatus.FOUND);
+      assertEquals(termsEnum.seekCeil(new BytesRef(terms[i].text2)), TermsEnum.SeekStatus.FOUND);
     }
 
     assertNull(fieldsEnum.next());
@@ -461,7 +461,7 @@ public class TestCodecs extends LuceneTe
 
         // Test random seek:
         TermData term = field.terms[TestCodecs.random.nextInt(field.terms.length)];
-        TermsEnum.SeekStatus status = termsEnum.seek(new BytesRef(term.text2));
+        TermsEnum.SeekStatus status = termsEnum.seekCeil(new BytesRef(term.text2));
         assertEquals(status, TermsEnum.SeekStatus.FOUND);
         assertEquals(term.docs.length, termsEnum.docFreq());
         if (field.omitTF) {
@@ -473,13 +473,14 @@ public class TestCodecs extends LuceneTe
         // Test random seek by ord:
         final int idx = TestCodecs.random.nextInt(field.terms.length);
         term = field.terms[idx];
+        boolean success = false;
         try {
-          status = termsEnum.seek(idx);
+          termsEnum.seekExact(idx);
+          success = true;
         } catch (UnsupportedOperationException uoe) {
           // ok -- skip it
-          status = null;
         }
-        if (status != null) {
+        if (success) {
           assertEquals(status, TermsEnum.SeekStatus.FOUND);
           assertTrue(termsEnum.term().bytesEquals(new BytesRef(term.text2)));
           assertEquals(term.docs.length, termsEnum.docFreq());
@@ -493,21 +494,21 @@ public class TestCodecs extends LuceneTe
         // Test seek to non-existent terms:
         for(int i=0;i<100;i++) {
           final String text2 = _TestUtil.randomUnicodeString(random) + ".";
-          status = termsEnum.seek(new BytesRef(text2));
+          status = termsEnum.seekCeil(new BytesRef(text2));
           assertTrue(status == TermsEnum.SeekStatus.NOT_FOUND ||
                      status == TermsEnum.SeekStatus.END);
         }
 
         // Seek to each term, backwards:
         for(int i=field.terms.length-1;i>=0;i--) {
-          assertEquals(Thread.currentThread().getName() + ": field=" + field.fieldInfo.name + " term=" + field.terms[i].text2, TermsEnum.SeekStatus.FOUND, termsEnum.seek(new BytesRef(field.terms[i].text2)));
+          assertEquals(Thread.currentThread().getName() + ": field=" + field.fieldInfo.name + " term=" + field.terms[i].text2, TermsEnum.SeekStatus.FOUND, termsEnum.seekCeil(new BytesRef(field.terms[i].text2)));
           assertEquals(field.terms[i].docs.length, termsEnum.docFreq());
         }
 
         // Seek to each term by ord, backwards
         for(int i=field.terms.length-1;i>=0;i--) {
           try {
-            assertEquals(Thread.currentThread().getName() + ": field=" + field.fieldInfo.name + " term=" + field.terms[i].text2, TermsEnum.SeekStatus.FOUND, termsEnum.seek(i));
+            termsEnum.seekExact(i);
             assertEquals(field.terms[i].docs.length, termsEnum.docFreq());
             assertTrue(termsEnum.term().bytesEquals(new BytesRef(field.terms[i].text2)));
           } catch (UnsupportedOperationException uoe) {
@@ -515,7 +516,7 @@ public class TestCodecs extends LuceneTe
         }
 
         // Seek to non-existent empty-string term
-        status = termsEnum.seek(new BytesRef(""));
+        status = termsEnum.seekCeil(new BytesRef(""));
         assertNotNull(status);
         //assertEquals(TermsEnum.SeekStatus.NOT_FOUND, status);
 
@@ -523,7 +524,7 @@ public class TestCodecs extends LuceneTe
         assertTrue(termsEnum.term().bytesEquals(new BytesRef(field.terms[0].text2)));
 
         // Test docs enum
-        termsEnum.seek(new BytesRef(""));
+        termsEnum.seekCeil(new BytesRef(""));
         upto = 0;
         do {
           term = field.terms[upto];

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDirectoryReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDirectoryReader.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDirectoryReader.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDirectoryReader.java Sun Jun 26 13:33:58 2011
@@ -166,14 +166,14 @@ public class TestDirectoryReader extends
 
     // test mixing up TermDocs and TermEnums from different readers.
     TermsEnum te2 = MultiFields.getTerms(mr2, "body").iterator();
-    te2.seek(new BytesRef("wow"));
+    te2.seekCeil(new BytesRef("wow"));
     DocsEnum td = MultiFields.getTermDocsEnum(mr2,
                                               MultiFields.getDeletedDocs(mr2),
                                               "body",
                                               te2.term());
 
     TermsEnum te3 = MultiFields.getTerms(mr3, "body").iterator();
-    te3.seek(new BytesRef("wow"));
+    te3.seekCeil(new BytesRef("wow"));
     td = te3.docs(MultiFields.getDeletedDocs(mr3),
                   td);
     

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDocTermOrds.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDocTermOrds.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDocTermOrds.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestDocTermOrds.java Sun Jun 26 13:33:58 2011
@@ -479,7 +479,7 @@ public class TestDocTermOrds extends Luc
         Terms terms = MultiFields.getTerms(r, "field");
         if (terms != null) {
           TermsEnum termsEnum = terms.iterator();
-          TermsEnum.SeekStatus result = termsEnum.seek(prefixRef, false);
+          TermsEnum.SeekStatus result = termsEnum.seekCeil(prefixRef, false);
           if (result != TermsEnum.SeekStatus.END) {
             assertFalse("term=" + termsEnum.term().utf8ToString() + " matches prefix=" + prefixRef.utf8ToString(), termsEnum.term().startsWith(prefixRef));
           } else {
@@ -494,7 +494,7 @@ public class TestDocTermOrds extends Luc
 
     if (VERBOSE) {
       System.out.println("TEST: TERMS:");
-      te.seek(0);
+      te.seekExact(0);
       while(true) {
         System.out.println("  ord=" + te.ord() + " term=" + te.term().utf8ToString());
         if (te.next() == null) {
@@ -515,7 +515,7 @@ public class TestDocTermOrds extends Luc
       while(true) {
         final int chunk = iter.read(buffer);
         for(int idx=0;idx<chunk;idx++) {
-          assertEquals(TermsEnum.SeekStatus.FOUND, te.seek((long) buffer[idx]));
+          te.seekExact((long) buffer[idx]);
           final BytesRef expected = termsArray[answers[upto++]];
           if (VERBOSE) {
             System.out.println("  exp=" + expected.utf8ToString() + " actual=" + te.term().utf8ToString());

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFilterIndexReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFilterIndexReader.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFilterIndexReader.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFilterIndexReader.java Sun Jun 26 13:33:58 2011
@@ -155,7 +155,7 @@ public class TestFilterIndexReader exten
       assertTrue(terms.term().utf8ToString().indexOf('e') != -1);
     }
     
-    assertEquals(TermsEnum.SeekStatus.FOUND, terms.seek(new BytesRef("one")));
+    assertEquals(TermsEnum.SeekStatus.FOUND, terms.seekCeil(new BytesRef("one")));
     
     DocsAndPositionsEnum positions = terms.docsAndPositions(MultiFields.getDeletedDocs(reader),
                                                             null);

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFlex.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFlex.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFlex.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestFlex.java Sun Jun 26 13:33:58 2011
@@ -53,7 +53,7 @@ public class TestFlex extends LuceneTest
       IndexReader r = w.getReader();
       
       TermsEnum terms = MultiFields.getTerms(r, "field3").iterator();
-      assertEquals(TermsEnum.SeekStatus.END, terms.seek(new BytesRef("abc")));
+      assertEquals(TermsEnum.SeekStatus.END, terms.seekCeil(new BytesRef("abc")));
       r.close();
     }
 

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriterUnicode.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriterUnicode.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriterUnicode.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestIndexWriterUnicode.java Sun Jun 26 13:33:58 2011
@@ -163,7 +163,7 @@ public class TestIndexWriterUnicode exte
       BytesRef tr = new BytesRef(it.next());
       assertEquals("seek failed for term=" + termDesc(tr.utf8ToString()),
                    TermsEnum.SeekStatus.FOUND,
-                   terms.seek(tr));
+                   terms.seekCeil(tr));
     }
   }
 

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestNRTThreads.java Sun Jun 26 13:33:58 2011
@@ -430,7 +430,7 @@ public class TestNRTThreads extends Luce
                       trigger = totTermCount.get()/10;
                       //System.out.println("trigger " + trigger);
                       shift = random.nextInt(trigger);
-                      termsEnum.seek(new BytesRef(""));
+                      termsEnum.seekCeil(new BytesRef(""));
                       continue;
                     }
                     seenTermCount++;

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestPerSegmentDeletes.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestPerSegmentDeletes.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestPerSegmentDeletes.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestPerSegmentDeletes.java Sun Jun 26 13:33:58 2011
@@ -24,7 +24,6 @@ import java.util.Random;
 import java.util.Map;
 
 import org.apache.lucene.analysis.MockAnalyzer;
-import org.apache.lucene.index.TermsEnum.SeekStatus;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.MockDirectoryWrapper;
 import org.apache.lucene.store.RAMDirectory;
@@ -225,8 +224,7 @@ public class TestPerSegmentDeletes exten
     Fields fields = MultiFields.getFields(reader);
     Terms cterms = fields.terms(term.field);
     TermsEnum ctermsEnum = cterms.iterator();
-    SeekStatus ss = ctermsEnum.seek(new BytesRef(term.text()), false);
-    if (ss.equals(SeekStatus.FOUND)) {
+    if (ctermsEnum.seekExact(new BytesRef(term.text()), false)) {
       DocsEnum docsEnum = ctermsEnum.docs(bits, null);
       return toArray(docsEnum);
     }

Modified: lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSegmentTermDocs.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSegmentTermDocs.java?rev=1139788&r1=1139787&r2=1139788&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSegmentTermDocs.java (original)
+++ lucene/dev/trunk/lucene/src/test/org/apache/lucene/index/TestSegmentTermDocs.java Sun Jun 26 13:33:58 2011
@@ -60,7 +60,7 @@ public class TestSegmentTermDocs extends
     assertEquals(indexDivisor, reader.getTermInfosIndexDivisor());
 
     TermsEnum terms = reader.fields().terms(DocHelper.TEXT_FIELD_2_KEY).iterator();
-    terms.seek(new BytesRef("field"));
+    terms.seekCeil(new BytesRef("field"));
     DocsEnum termDocs = terms.docs(reader.getDeletedDocs(), null);
     if (termDocs.nextDoc() != DocsEnum.NO_MORE_DOCS)    {
       int docId = termDocs.docID();