Index: solr/core/src/java/org/apache/solr/schema/TrieField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/TrieField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/TrieField.java	(working copy)
@@ -20,16 +20,12 @@
 import org.apache.lucene.document.NumericField;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.*;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.DoubleValuesCreator;
+
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.queries.function.valuesource.DoubleFieldSource;
 import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
 import org.apache.lucene.queries.function.valuesource.IntFieldSource;
 import org.apache.lucene.queries.function.valuesource.LongFieldSource;
-import org.apache.lucene.search.cache.FloatValuesCreator;
-import org.apache.lucene.search.cache.IntValuesCreator;
-import org.apache.lucene.search.cache.LongValuesCreator;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.CharsRef;
 import org.apache.lucene.util.NumericUtils;
@@ -137,7 +133,6 @@
   public SortField getSortField(SchemaField field, boolean top) {
     field.checkSortability();
 
-    int flags = CachedArrayCreator.CACHE_VALUES_AND_BITS;
     Object missingValue = null;
     boolean sortMissingLast  = field.sortMissingLast();
     boolean sortMissingFirst = field.sortMissingFirst();
@@ -150,8 +145,7 @@
         else if( sortMissingFirst ) {
           missingValue = top ? Integer.MAX_VALUE : Integer.MIN_VALUE;
         }
-        return new SortField( new IntValuesCreator( field.getName(), 
-            FieldCache.NUMERIC_UTILS_INT_PARSER, flags ), top).setMissingValue( missingValue );
+        return new SortField( field.getName(), FieldCache.NUMERIC_UTILS_INT_PARSER, top).setMissingValue(missingValue);
       
       case FLOAT:
         if( sortMissingLast ) {
@@ -160,8 +154,7 @@
         else if( sortMissingFirst ) {
           missingValue = top ? Float.POSITIVE_INFINITY : Float.NEGATIVE_INFINITY;
         }
-        return new SortField( new FloatValuesCreator( field.getName(), 
-            FieldCache.NUMERIC_UTILS_FLOAT_PARSER, flags ), top).setMissingValue( missingValue );
+        return new SortField( field.getName(), FieldCache.NUMERIC_UTILS_FLOAT_PARSER, top).setMissingValue(missingValue);
       
       case DATE: // fallthrough
       case LONG:
@@ -171,8 +164,7 @@
         else if( sortMissingFirst ) {
           missingValue = top ? Long.MAX_VALUE : Long.MIN_VALUE;
         }
-        return new SortField( new LongValuesCreator( field.getName(), 
-            FieldCache.NUMERIC_UTILS_LONG_PARSER, flags ), top).setMissingValue( missingValue );
+        return new SortField( field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER, top).setMissingValue(missingValue);
         
       case DOUBLE:
         if( sortMissingLast ) {
@@ -181,8 +173,7 @@
         else if( sortMissingFirst ) {
           missingValue = top ? Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
         }
-        return new SortField( new DoubleValuesCreator( field.getName(), 
-            FieldCache.NUMERIC_UTILS_DOUBLE_PARSER, flags ), top).setMissingValue( missingValue );
+        return new SortField( field.getName(), FieldCache.NUMERIC_UTILS_DOUBLE_PARSER, top).setMissingValue(missingValue);
         
       default:
         throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + field.name);
@@ -192,18 +183,17 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    int flags = CachedArrayCreator.CACHE_VALUES_AND_BITS;
     switch (type) {
       case INTEGER:
-        return new IntFieldSource( new IntValuesCreator( field.getName(), FieldCache.NUMERIC_UTILS_INT_PARSER, flags ) );
+        return new IntFieldSource( field.getName(), FieldCache.NUMERIC_UTILS_INT_PARSER );
       case FLOAT:
-        return new FloatFieldSource( new FloatValuesCreator( field.getName(), FieldCache.NUMERIC_UTILS_FLOAT_PARSER, flags ));
+        return new FloatFieldSource( field.getName(), FieldCache.NUMERIC_UTILS_FLOAT_PARSER );
       case DATE:
-        return new TrieDateFieldSource( new LongValuesCreator( field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER, flags ));        
+        return new TrieDateFieldSource( field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER );        
       case LONG:
-        return new LongFieldSource( new LongValuesCreator( field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER, flags ) );
+        return new LongFieldSource( field.getName(), FieldCache.NUMERIC_UTILS_LONG_PARSER );
       case DOUBLE:
-        return new DoubleFieldSource( new DoubleValuesCreator( field.getName(), FieldCache.NUMERIC_UTILS_DOUBLE_PARSER, flags ));
+        return new DoubleFieldSource( field.getName(), FieldCache.NUMERIC_UTILS_DOUBLE_PARSER );
       default:
         throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, "Unknown type for trie field: " + field.name);
     }
@@ -573,8 +563,8 @@
 
 class TrieDateFieldSource extends LongFieldSource {
 
-  public TrieDateFieldSource(LongValuesCreator creator) {
-    super(creator);
+  public TrieDateFieldSource(String field, FieldCache.LongParser parser) {
+    super(field, parser);
   }
 
   @Override
Index: solr/core/src/java/org/apache/solr/schema/DoubleField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/DoubleField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/DoubleField.java	(working copy)
@@ -21,8 +21,6 @@
 import org.apache.lucene.queries.function.valuesource.DoubleFieldSource;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.DoubleValuesCreator;
 import org.apache.solr.response.TextResponseWriter;
 import org.apache.solr.search.QParser;
 
@@ -48,7 +46,7 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    return new DoubleFieldSource( new DoubleValuesCreator( field.name, null, CachedArrayCreator.CACHE_VALUES_AND_BITS ) );
+    return new DoubleFieldSource(field.name);
   }
 
   @Override
Index: solr/core/src/java/org/apache/solr/schema/ShortField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/ShortField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/ShortField.java	(working copy)
@@ -20,8 +20,6 @@
 import org.apache.lucene.queries.function.valuesource.ShortFieldSource;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.ShortValuesCreator;
 
 import org.apache.solr.response.TextResponseWriter;
 import org.apache.solr.search.QParser;
@@ -51,7 +49,7 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    return new ShortFieldSource(new ShortValuesCreator( field.name, null, CachedArrayCreator.CACHE_VALUES_AND_BITS ) );
+    return new ShortFieldSource(field.name);
   }
 
   @Override
Index: solr/core/src/java/org/apache/solr/schema/LongField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/LongField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/LongField.java	(working copy)
@@ -21,8 +21,6 @@
 import org.apache.lucene.queries.function.valuesource.LongFieldSource;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.LongValuesCreator;
 import org.apache.solr.response.TextResponseWriter;
 import org.apache.solr.search.QParser;
 
@@ -48,7 +46,7 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    return new LongFieldSource( new LongValuesCreator( field.name, null, CachedArrayCreator.CACHE_VALUES_AND_BITS ) );
+    return new LongFieldSource(field.name);
   }
 
   @Override
Index: solr/core/src/java/org/apache/solr/schema/ByteField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/ByteField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/ByteField.java	(working copy)
@@ -20,8 +20,6 @@
 import org.apache.lucene.queries.function.valuesource.ByteFieldSource;
 import org.apache.lucene.index.IndexableField;
 import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.cache.ByteValuesCreator;
-import org.apache.lucene.search.cache.CachedArrayCreator;
 
 import org.apache.solr.response.TextResponseWriter;
 import org.apache.solr.search.QParser;
@@ -48,7 +46,7 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    return new ByteFieldSource( new ByteValuesCreator( field.name, null, CachedArrayCreator.CACHE_VALUES_AND_BITS ) );
+    return new ByteFieldSource(field.name);
   }
 
   @Override
Index: solr/core/src/java/org/apache/solr/schema/FloatField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/FloatField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/FloatField.java	(working copy)
@@ -20,8 +20,6 @@
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
 import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.FloatValuesCreator;
 import org.apache.solr.search.QParser;
 import org.apache.lucene.index.IndexableField;
 import org.apache.solr.response.TextResponseWriter;
@@ -46,7 +44,7 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    return new FloatFieldSource( new FloatValuesCreator( field.name, null, CachedArrayCreator.CACHE_VALUES_AND_BITS ) );
+    return new FloatFieldSource(field.name);
   }
 
   @Override
Index: solr/core/src/java/org/apache/solr/schema/IntField.java
===================================================================
--- solr/core/src/java/org/apache/solr/schema/IntField.java	(revision 1199574)
+++ solr/core/src/java/org/apache/solr/schema/IntField.java	(working copy)
@@ -20,8 +20,6 @@
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.queries.function.valuesource.IntFieldSource;
 import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.IntValuesCreator;
 import org.apache.solr.search.QParser;
 import org.apache.lucene.index.IndexableField;
 import org.apache.solr.response.TextResponseWriter;
@@ -46,7 +44,7 @@
   @Override
   public ValueSource getValueSource(SchemaField field, QParser qparser) {
     field.checkFieldCacheSource(qparser);
-    return new IntFieldSource(new IntValuesCreator( field.name, null, CachedArrayCreator.CACHE_VALUES_AND_BITS ) );
+    return new IntFieldSource(field.name);
   }
 
   @Override
Index: modules/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java
===================================================================
--- modules/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java	(revision 1199574)
+++ modules/queries/src/test/org/apache/lucene/queries/function/TestFieldScoreQuery.java	(working copy)
@@ -27,7 +27,6 @@
 import org.apache.lucene.search.QueryUtils;
 import org.apache.lucene.search.ScoreDoc;
 import org.apache.lucene.search.TopDocs;
-import org.apache.lucene.search.cache.*;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
Index: modules/queries/src/test/org/apache/lucene/queries/function/FunctionTestSetup.java
===================================================================
--- modules/queries/src/test/org/apache/lucene/queries/function/FunctionTestSetup.java	(revision 1199574)
+++ modules/queries/src/test/org/apache/lucene/queries/function/FunctionTestSetup.java	(working copy)
@@ -12,7 +12,6 @@
 import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
 import org.apache.lucene.queries.function.valuesource.IntFieldSource;
 import org.apache.lucene.queries.function.valuesource.ShortFieldSource;
-import org.apache.lucene.search.cache.*;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.util.LuceneTestCase;
 import org.apache.lucene.util._TestUtil;
@@ -54,14 +53,12 @@
   protected static final String INT_FIELD = "iii";
   protected static final String FLOAT_FIELD = "fff";
 
-  private static final int CREATOR_FLAGS = CachedArrayCreator.CACHE_VALUES_AND_BITS;
+  protected ValueSource BYTE_VALUESOURCE = new ByteFieldSource(INT_FIELD);
+  protected ValueSource SHORT_VALUESOURCE = new ShortFieldSource(INT_FIELD);
+  protected ValueSource INT_VALUESOURCE = new IntFieldSource(INT_FIELD);
+  protected ValueSource INT_AS_FLOAT_VALUESOURCE = new FloatFieldSource(INT_FIELD);
+  protected ValueSource FLOAT_VALUESOURCE = new FloatFieldSource(FLOAT_FIELD);
 
-  protected ValueSource BYTE_VALUESOURCE = new ByteFieldSource(new ByteValuesCreator(INT_FIELD, null, CREATOR_FLAGS));
-  protected ValueSource SHORT_VALUESOURCE = new ShortFieldSource(new ShortValuesCreator(INT_FIELD, null, CREATOR_FLAGS));
-  protected ValueSource INT_VALUESOURCE = new IntFieldSource(new IntValuesCreator(INT_FIELD, null, CREATOR_FLAGS));
-  protected ValueSource INT_AS_FLOAT_VALUESOURCE = new FloatFieldSource(new FloatValuesCreator(INT_FIELD, null, CREATOR_FLAGS));
-  protected ValueSource FLOAT_VALUESOURCE = new FloatFieldSource(new FloatValuesCreator(FLOAT_FIELD, null, CREATOR_FLAGS));
-
   private static final String DOC_TEXT_LINES[] = {
           "Well, this is just some plain text we use for creating the ",
           "test documents. It used to be a text from an online collection ",
Index: modules/queries/src/test/org/apache/lucene/queries/TestCustomScoreQuery.java
===================================================================
--- modules/queries/src/test/org/apache/lucene/queries/TestCustomScoreQuery.java	(revision 1199574)
+++ modules/queries/src/test/org/apache/lucene/queries/TestCustomScoreQuery.java	(working copy)
@@ -22,7 +22,6 @@
 import org.apache.lucene.queries.function.ValueSource;
 import org.apache.lucene.queries.function.valuesource.FloatFieldSource;
 import org.apache.lucene.search.*;
-import org.apache.lucene.search.cache.*;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import java.io.IOException;
@@ -77,9 +76,6 @@
   @Test
   public void testCustomScoreFloat() throws Exception {
     // INT field can be parsed as float
-    FloatValuesCreator valuesCreator = new FloatValuesCreator(INT_FIELD, null, CachedArrayCreator.CACHE_VALUES_AND_BITS);
-    FloatFieldSource fieldSource = new FloatFieldSource(valuesCreator);
-
     doTestCustomScore(INT_AS_FLOAT_VALUESOURCE, 1.0);
     doTestCustomScore(INT_AS_FLOAT_VALUESOURCE, 5.0);
 
@@ -237,8 +233,8 @@
   
   // Test that FieldScoreQuery returns docs with expected score.
   private void doTestCustomScore(ValueSource valueSource, double dboost) throws Exception {
-    FunctionQuery functionQuery = new FunctionQuery(valueSource);
     float boost = (float) dboost;
+    FunctionQuery functionQuery = new FunctionQuery(valueSource);
     IndexSearcher s = new IndexSearcher(dir, true);
 
     // regular (boolean) query.
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/DoubleFieldSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/DoubleFieldSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/DoubleFieldSource.java	(working copy)
@@ -17,20 +17,19 @@
 
 package org.apache.lucene.queries.function.valuesource;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.queries.function.DocValues;
 import org.apache.lucene.queries.function.ValueSourceScorer;
 import org.apache.lucene.queries.function.docvalues.DoubleDocValues;
+import org.apache.lucene.search.FieldCache;
 import org.apache.lucene.util.Bits;
-import org.apache.lucene.search.cache.DoubleValuesCreator;
-import org.apache.lucene.search.cache.CachedArray.DoubleValues;
 import org.apache.lucene.util.mutable.MutableValue;
 import org.apache.lucene.util.mutable.MutableValueDouble;
 
-import java.io.IOException;
-import java.util.Map;
-
 /**
  * Obtains float field values from the {@link org.apache.lucene.search.FieldCache}
  * using <code>getFloats()</code>
@@ -39,23 +38,27 @@
  *
  */
 
-public class DoubleFieldSource extends NumericFieldCacheSource<DoubleValues> {
+public class DoubleFieldSource extends FieldCacheSource {
 
-  public DoubleFieldSource(DoubleValuesCreator creator) {
-    super(creator);
+  protected FieldCache.DoubleParser parser;
+
+  public DoubleFieldSource(String field) {
+    this(field, null);
   }
 
-  @Override
+  public DoubleFieldSource(String field, FieldCache.DoubleParser parser) {
+    super(field);
+    this.parser = parser;
+  }
+
   public String description() {
     return "double(" + field + ')';
   }
 
   @Override
   public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
-    final DoubleValues vals = cache.getDoubles(readerContext.reader, field, creator);
-    final double[] arr = vals.values;
-    final Bits valid = vals.valid;
-    
+    final double[] arr = cache.getDoubles(readerContext.reader, field, parser);
+    final Bits valid = cache.getDocsWithField(readerContext.reader, field);
     return new DoubleDocValues(this) {
       @Override
       public double doubleVal(int doc) {
@@ -148,4 +151,18 @@
       };
 
   }
+
+  public boolean equals(Object o) {
+    if (o.getClass() != DoubleFieldSource.class) return false;
+    DoubleFieldSource other = (DoubleFieldSource) o;
+    return super.equals(other)
+      && (this.parser == null ? other.parser == null :
+          this.parser.getClass() == other.parser.getClass());
+  }
+
+  public int hashCode() {
+    int h = parser == null ? Double.class.hashCode() : parser.getClass().hashCode();
+    h += super.hashCode();
+    return h;
+  }
 }
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/NumericFieldCacheSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/NumericFieldCacheSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/NumericFieldCacheSource.java	(working copy)
@@ -1,50 +0,0 @@
-/**
- * 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.lucene.queries.function.valuesource;
-
-import org.apache.lucene.search.cache.CachedArray;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-
-/**
- * 
- *
- */
-public abstract class NumericFieldCacheSource<T extends CachedArray> extends FieldCacheSource {
-  protected final CachedArrayCreator<T> creator;
-
-  public NumericFieldCacheSource( CachedArrayCreator<T> creator ) {
-    super( creator.field );
-    this.creator = creator;
-  }
-
-  @Override
-  public final boolean equals(Object o) {
-    if (o.getClass() != this.getClass()) return false;
-    NumericFieldCacheSource other = (NumericFieldCacheSource) o;
-    return super.equals(other)
-            && (this.creator == null ? other.creator == null :
-            this.creator.getClass() == other.creator.getClass());
-  }
-
-  @Override
-  public final int hashCode() {
-    int h = creator == null ? this.getClass().hashCode() : creator.getClass().hashCode();
-    h += super.hashCode();
-    return h;
-  }
-}
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/ShortFieldSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/ShortFieldSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/ShortFieldSource.java	(working copy)
@@ -16,25 +16,30 @@
  * limitations under the License.
  */
 
-import org.apache.lucene.queries.function.DocValues;
-import org.apache.lucene.search.cache.ShortValuesCreator;
-import org.apache.lucene.search.cache.CachedArray.ShortValues;
-import org.apache.lucene.index.IndexReader.AtomicReaderContext;
-
 import java.io.IOException;
 import java.util.Map;
 
+import org.apache.lucene.index.IndexReader.AtomicReaderContext;
+import org.apache.lucene.queries.function.DocValues;
+import org.apache.lucene.search.FieldCache;
 
+
 /**
  *
  *
  **/
-public class ShortFieldSource extends NumericFieldCacheSource<ShortValues> {
+public class ShortFieldSource extends FieldCacheSource {
 
-  public ShortFieldSource(ShortValuesCreator creator) {
-    super(creator);
+  final FieldCache.ShortParser parser;
+
+  public ShortFieldSource(String field) {
+    this(field, null);
   }
 
+  public ShortFieldSource(String field, FieldCache.ShortParser parser) {
+    super(field);
+    this.parser = parser;
+  }
 
   @Override
   public String description() {
@@ -43,8 +48,7 @@
 
   @Override
   public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
-    final ShortValues vals = cache.getShorts(readerContext.reader, field, creator);
-    final short[] arr = vals.values;
+    final short[] arr = cache.getShorts(readerContext.reader, field, parser);
     
     return new DocValues() {
       @Override
@@ -89,4 +93,19 @@
 
     };
   }
+
+  public boolean equals(Object o) {
+    if (o.getClass() != ShortFieldSource.class) return false;
+    ShortFieldSource
+            other = (ShortFieldSource) o;
+    return super.equals(other)
+      && (this.parser == null ? other.parser == null :
+          this.parser.getClass() == other.parser.getClass());
+  }
+
+  public int hashCode() {
+    int h = parser == null ? Short.class.hashCode() : parser.getClass().hashCode();
+    h += super.hashCode();
+    return h;
+  }
 }
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/LongFieldSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/LongFieldSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/LongFieldSource.java	(working copy)
@@ -17,21 +17,19 @@
 
 package org.apache.lucene.queries.function.valuesource;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.queries.function.DocValues;
 import org.apache.lucene.queries.function.ValueSourceScorer;
 import org.apache.lucene.queries.function.docvalues.LongDocValues;
+import org.apache.lucene.search.FieldCache;
 import org.apache.lucene.util.Bits;
-import org.apache.lucene.search.cache.LongValuesCreator;
-import org.apache.lucene.search.cache.CachedArray.LongValues;
 import org.apache.lucene.util.mutable.MutableValue;
 import org.apache.lucene.util.mutable.MutableValueLong;
 
-
-import java.io.IOException;
-import java.util.Map;
-
 /**
  * Obtains float field values from the {@link org.apache.lucene.search.FieldCache}
  * using <code>getFloats()</code>
@@ -40,12 +38,19 @@
  *
  */
 
-public class LongFieldSource extends NumericFieldCacheSource<LongValues> {
+public class LongFieldSource extends FieldCacheSource {
 
-  public LongFieldSource(LongValuesCreator creator) {
-    super(creator);
+  protected FieldCache.LongParser parser;
+
+  public LongFieldSource(String field) {
+    this(field, null);
   }
 
+  public LongFieldSource(String field, FieldCache.LongParser parser) {
+    super(field);
+    this.parser = parser;
+  }
+
   @Override
   public String description() {
     return "long(" + field + ')';
@@ -61,9 +66,8 @@
 
   @Override
   public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
-    final LongValues vals = cache.getLongs(readerContext.reader, field, creator);
-    final long[] arr = vals.values;
-    final Bits valid = vals.valid;
+    final long[] arr = cache.getLongs(readerContext.reader, field, parser);
+    final Bits valid = cache.getDocsWithField(readerContext.reader, field);
     
     return new LongDocValues(this) {
       @Override
@@ -141,4 +145,17 @@
     return new MutableValueLong();  
   }
 
+  public boolean equals(Object o) {
+    if (o.getClass() != this.getClass()) return false;
+    LongFieldSource other = (LongFieldSource) o;
+    return super.equals(other)
+      && (this.parser == null ? other.parser == null :
+          this.parser.getClass() == other.parser.getClass());
+  }
+
+  public int hashCode() {
+    int h = parser == null ? this.getClass().hashCode() : parser.getClass().hashCode();
+    h += super.hashCode();
+    return h;
+  }
 }
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteFieldSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteFieldSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/ByteFieldSource.java	(working copy)
@@ -16,14 +16,13 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+import java.util.Map;
+
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.queries.function.DocValues;
-import org.apache.lucene.search.cache.ByteValuesCreator;
-import org.apache.lucene.search.cache.CachedArray.ByteValues;
+import org.apache.lucene.search.FieldCache;
 
-import java.io.IOException;
-import java.util.Map;
-
 /**
  * Obtains int field values from the {@link org.apache.lucene.search.FieldCache}
  * using <code>getInts()</code>
@@ -32,12 +31,19 @@
  *
  */
 
-public class ByteFieldSource extends NumericFieldCacheSource<ByteValues> {
+public class ByteFieldSource extends FieldCacheSource {
 
-  public ByteFieldSource(ByteValuesCreator creator) {
-    super(creator);
+  private FieldCache.ByteParser parser;
+
+  public ByteFieldSource(String field) {
+    this(field, null);
   }
 
+  public ByteFieldSource(String field, FieldCache.ByteParser parser) {
+    super(field);
+    this.parser = parser;
+  }
+
   @Override
   public String description() {
     return "byte(" + field + ')';
@@ -45,8 +51,7 @@
 
   @Override
   public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
-    final ByteValues vals = cache.getBytes(readerContext.reader, field, creator);
-    final byte[] arr = vals.values;
+    final byte[] arr = cache.getBytes(readerContext.reader, field, parser);
     
     return new DocValues() {
       @Override
@@ -96,4 +101,19 @@
 
     };
   }
+
+  public boolean equals(Object o) {
+    if (o.getClass() != ByteFieldSource.class) return false;
+    ByteFieldSource
+            other = (ByteFieldSource) o;
+    return super.equals(other)
+      && (this.parser == null ? other.parser == null :
+          this.parser.getClass() == other.parser.getClass());
+  }
+
+  public int hashCode() {
+    int h = parser == null ? Byte.class.hashCode() : parser.getClass().hashCode();
+    h += super.hashCode();
+    return h;
+  }
 }
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatFieldSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatFieldSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/FloatFieldSource.java	(working copy)
@@ -23,9 +23,8 @@
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.queries.function.DocValues;
 import org.apache.lucene.queries.function.docvalues.FloatDocValues;
+import org.apache.lucene.search.FieldCache;
 import org.apache.lucene.util.Bits;
-import org.apache.lucene.search.cache.FloatValuesCreator;
-import org.apache.lucene.search.cache.CachedArray.FloatValues;
 import org.apache.lucene.util.mutable.MutableValue;
 import org.apache.lucene.util.mutable.MutableValueFloat;
 
@@ -37,23 +36,28 @@
  *
  */
 
-public class FloatFieldSource extends NumericFieldCacheSource<FloatValues> {
+public class FloatFieldSource extends FieldCacheSource {
 
-  public FloatFieldSource(FloatValuesCreator creator) {
-    super(creator);
+  protected FieldCache.FloatParser parser;
+
+  public FloatFieldSource(String field) {
+    this(field, null);
   }
 
-  @Override
+  public FloatFieldSource(String field, FieldCache.FloatParser parser) {
+    super(field);
+    this.parser = parser;
+  }
+
   public String description() {
     return "float(" + field + ')';
   }
 
   @Override
   public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
-    final FloatValues vals = cache.getFloats(readerContext.reader, field, creator);
-    final float[] arr = vals.values;
-    final Bits valid = vals.valid;
-    
+    final float[] arr = cache.getFloats(readerContext.reader, field, parser);
+    final Bits valid = cache.getDocsWithField(readerContext.reader, field);
+
     return new FloatDocValues(this) {
       @Override
       public float floatVal(int doc) {
@@ -91,4 +95,18 @@
 
     };
   }
+
+  public boolean equals(Object o) {
+    if (o.getClass() !=  FloatFieldSource.class) return false;
+    FloatFieldSource other = (FloatFieldSource)o;
+    return super.equals(other)
+      && (this.parser==null ? other.parser==null :
+          this.parser.getClass() == other.parser.getClass());
+  }
+
+  public int hashCode() {
+    int h = parser==null ? Float.class.hashCode() : parser.getClass().hashCode();
+    h += super.hashCode();
+    return h;
+  };
 }
Index: modules/queries/src/java/org/apache/lucene/queries/function/valuesource/IntFieldSource.java
===================================================================
--- modules/queries/src/java/org/apache/lucene/queries/function/valuesource/IntFieldSource.java	(revision 1199574)
+++ modules/queries/src/java/org/apache/lucene/queries/function/valuesource/IntFieldSource.java	(working copy)
@@ -17,20 +17,19 @@
 
 package org.apache.lucene.queries.function.valuesource;
 
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexReader.AtomicReaderContext;
 import org.apache.lucene.queries.function.DocValues;
 import org.apache.lucene.queries.function.ValueSourceScorer;
 import org.apache.lucene.queries.function.docvalues.IntDocValues;
+import org.apache.lucene.search.FieldCache;
 import org.apache.lucene.util.Bits;
-import org.apache.lucene.search.cache.IntValuesCreator;
-import org.apache.lucene.search.cache.CachedArray.IntValues;
 import org.apache.lucene.util.mutable.MutableValue;
 import org.apache.lucene.util.mutable.MutableValueInt;
 
-import java.io.IOException;
-import java.util.Map;
-
 /**
  * Obtains int field values from the {@link org.apache.lucene.search.FieldCache}
  * using <code>getInts()</code>
@@ -38,12 +37,18 @@
  *
  */
 
-public class IntFieldSource extends NumericFieldCacheSource<IntValues> {
+public class IntFieldSource extends FieldCacheSource {
+  final FieldCache.IntParser parser;
 
-  public IntFieldSource(IntValuesCreator creator) {
-    super(creator);
+  public IntFieldSource(String field) {
+    this(field, null);
   }
 
+  public IntFieldSource(String field, FieldCache.IntParser parser) {
+    super(field);
+    this.parser = parser;
+  }
+
   @Override
   public String description() {
     return "int(" + field + ')';
@@ -52,9 +57,8 @@
 
   @Override
   public DocValues getValues(Map context, AtomicReaderContext readerContext) throws IOException {
-    final IntValues vals = cache.getInts(readerContext.reader, field, creator);
-    final int[] arr = vals.values;
-    final Bits valid = vals.valid;
+    final int[] arr = cache.getInts(readerContext.reader, field, parser);
+    final Bits valid = cache.getDocsWithField(readerContext.reader, field);
     
     return new IntDocValues(this) {
       final MutableValueInt val = new MutableValueInt();
@@ -155,4 +159,18 @@
       
     };
   }
+
+  public boolean equals(Object o) {
+    if (o.getClass() !=  IntFieldSource.class) return false;
+    IntFieldSource other = (IntFieldSource)o;
+    return super.equals(other)
+      && (this.parser==null ? other.parser==null :
+          this.parser.getClass() == other.parser.getClass());
+  }
+
+  public int hashCode() {
+    int h = parser==null ? Integer.class.hashCode() : parser.getClass().hashCode();
+    h += super.hashCode();
+    return h;
+  };
 }
Index: lucene/src/test/org/apache/lucene/search/cache/TestEntryCreators.java
===================================================================
--- lucene/src/test/org/apache/lucene/search/cache/TestEntryCreators.java	(revision 1199574)
+++ lucene/src/test/org/apache/lucene/search/cache/TestEntryCreators.java	(working copy)
@@ -1,234 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * Copyright 2004 The Apache Software Foundation
- *
- * Licensed 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.
- */
-
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.apache.lucene.analysis.MockAnalyzer;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.FieldType;
-import org.apache.lucene.document.TextField;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.RandomIndexWriter;
-import org.apache.lucene.search.FieldCache.*;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.util.LuceneTestCase;
-import org.apache.lucene.util.FixedBitSet;
-import org.junit.BeforeClass;
-
-import static org.hamcrest.CoreMatchers.*;
-
-public class TestEntryCreators extends LuceneTestCase {
-  protected IndexReader reader;
-  private static int NUM_DOCS;
-  private Directory directory;
-  
-  @BeforeClass
-  public static void beforeClass() throws Exception {
-    NUM_DOCS = atLeast(500);
-  }
-
-  static class NumberTypeTester {
-    String funcName;
-    Class<? extends CachedArrayCreator> creator;
-    Class<? extends Parser> parser;
-    String field;
-    Number[] values;
-    
-    public NumberTypeTester( String f, String func, Class<? extends CachedArrayCreator> creator, Class<? extends Parser> parser ) {
-      field = f;
-      funcName = func;
-      this.creator = creator;
-      this.parser = parser;
-      values = new Number[NUM_DOCS];
-    }
-    @Override
-    public String toString()
-    {
-      return field;
-    }
-  }
-  private NumberTypeTester[] typeTests;
-  
-  
-  @Override
-  public void setUp() throws Exception {
-    super.setUp();
-    directory = newDirectory();
-    RandomIndexWriter writer= new RandomIndexWriter(random, directory, newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random)).setMergePolicy(newLogMergePolicy()));
-
-    typeTests = new NumberTypeTester[] {
-        new NumberTypeTester( "theRandomByte",   "getBytes",   ByteValuesCreator.class,   ByteParser.class ),
-        new NumberTypeTester( "theRandomShort",  "getShorts",  ShortValuesCreator.class,  ShortParser.class  ),
-        new NumberTypeTester( "theRandomInt",    "getInts",    IntValuesCreator.class,    IntParser.class  ),
-        new NumberTypeTester( "theRandomLong",   "getLongs",   LongValuesCreator.class,   LongParser.class  ),
-        new NumberTypeTester( "theRandomFloat",  "getFloats",  FloatValuesCreator.class,  FloatParser.class  ),
-        new NumberTypeTester( "theRandomDouble", "getDoubles", DoubleValuesCreator.class, DoubleParser.class  ),
-    };
-    
-    for (int i = 0; i < NUM_DOCS; i++){
-      Document doc = new Document();
-      
-      // Test the valid bits
-      for( NumberTypeTester tester : typeTests ) {
-        if (random.nextInt(20) != 17 && i > 1) {
-          tester.values[i] = 10 + random.nextInt( 20 ); // get some field overlap
-          FieldType customType = new FieldType(TextField.TYPE_UNSTORED);
-          customType.setTokenized(false);
-          doc.add(newField(tester.field, String.valueOf(tester.values[i]), customType));
-        }
-      }
-      writer.addDocument(doc);
-    }
-
-    reader = writer.getReader();
-    writer.close();
-  }
-
-  @Override
-  public void tearDown() throws Exception {
-    reader.close();
-    directory.close();
-    super.tearDown();
-  }
-
-  public void testKeys() throws IOException {
-    // Check that the keys are unique for different fields
-
-    EntryKey key_1 = new ByteValuesCreator( "field1", null ).getCacheKey();
-    EntryKey key_2 = new ByteValuesCreator( "field2", null ).getCacheKey();
-    assertThat("different fields should have a different key", key_1, not(key_2) );
-
-    key_1 = new ByteValuesCreator(  "field1", null ).getCacheKey();
-    key_2 = new ShortValuesCreator( "field1", null ).getCacheKey();
-    assertThat( "same field different type should have different key", key_1, not( key_2 ) );
-
-    key_1 = new ByteValuesCreator( "ff", null ).getCacheKey();
-    key_2 = new ByteValuesCreator( "ff", null ).getCacheKey();
-    assertThat( "same args should have same key", key_1, is( key_2 ) );
-
-    key_1 = new ByteValuesCreator( "ff", null, ByteValuesCreator.OPTION_CACHE_BITS ^ ByteValuesCreator.OPTION_CACHE_VALUES ).getCacheKey();
-    key_2 = new ByteValuesCreator( "ff", null ).getCacheKey();
-    assertThat( "different options should share same key", key_1, is( key_2 ) );
-
-    key_1 = new IntValuesCreator( "ff", FieldCache.DEFAULT_INT_PARSER ).getCacheKey();
-    key_2 = new IntValuesCreator( "ff", FieldCache.NUMERIC_UTILS_INT_PARSER ).getCacheKey();
-    assertThat( "diferent parser should have same key", key_1, is( key_2 ) );
-  }
-  
-  private CachedArray getWithReflection( FieldCache cache, NumberTypeTester tester, int flags ) throws IOException 
-  {
-    try {
-      Method getXXX = cache.getClass().getMethod( tester.funcName, IndexReader.class, String.class, EntryCreator.class );
-      Constructor constructor = tester.creator.getConstructor( String.class, tester.parser, Integer.TYPE );
-      CachedArrayCreator creator = (CachedArrayCreator)constructor.newInstance( tester.field, null, flags );
-      return (CachedArray) getXXX.invoke(cache, reader, tester.field, creator );
-    }
-    catch( Exception ex ) {
-      throw new RuntimeException( "Reflection failed", ex );
-    }
-  }
-
-  public void testCachedArrays() throws IOException 
-  {
-    FieldCache cache = FieldCache.DEFAULT;
-
-    // Check the Different CachedArray Types
-    CachedArray last = null;
-    CachedArray justbits = null;
-    String field;
-    
-    for( NumberTypeTester tester : typeTests ) {
-      justbits = getWithReflection( cache, tester, CachedArrayCreator.OPTION_CACHE_BITS );
-      assertNull( "should not get values : "+tester, justbits.getRawArray() );
-      assertNotNull( "should get bits : "+tester, justbits.valid );
-      last = getWithReflection( cache, tester, CachedArrayCreator.CACHE_VALUES_AND_BITS );
-      assertEquals( "should use same cached object : "+tester, justbits, last );
-      assertNull( "Validate=false shoudl not regenerate : "+tester, justbits.getRawArray() ); 
-      last = getWithReflection( cache, tester, CachedArrayCreator.CACHE_VALUES_AND_BITS_VALIDATE );
-      assertEquals( "should use same cached object : "+tester, justbits, last );
-      assertNotNull( "Validate=true should add the Array : "+tester, justbits.getRawArray() ); 
-      checkCachedArrayValuesAndBits( tester, last );
-    }
-    
-    // Now switch the the parser (for the same type) and expect an error
-    cache.purgeAllCaches();
-    int flags = CachedArrayCreator.CACHE_VALUES_AND_BITS_VALIDATE;
-    field = "theRandomInt";
-    last = cache.getInts(reader, field, new IntValuesCreator( field, FieldCache.DEFAULT_INT_PARSER, flags ) );
-    checkCachedArrayValuesAndBits( typeTests[2], last );
-    try {
-      cache.getInts(reader, field, new IntValuesCreator( field, FieldCache.NUMERIC_UTILS_INT_PARSER, flags ) );
-      fail( "Should fail if you ask for the same type with a different parser : " + field );
-    } catch( Exception ex ) {} // expected
-
-    field = "theRandomLong";
-    last = cache.getLongs(reader,   field, new LongValuesCreator( field, FieldCache.DEFAULT_LONG_PARSER, flags ) );
-    checkCachedArrayValuesAndBits( typeTests[3], last );
-    try {
-      cache.getLongs(reader, field, new LongValuesCreator( field, FieldCache.NUMERIC_UTILS_LONG_PARSER, flags ) );
-      fail( "Should fail if you ask for the same type with a different parser : " + field );
-    } catch( Exception ex ) {} // expected
-
-    field = "theRandomFloat";
-    last = cache.getFloats(reader,   field, new FloatValuesCreator( field, FieldCache.DEFAULT_FLOAT_PARSER, flags ) );
-    checkCachedArrayValuesAndBits( typeTests[4], last );
-    try {
-      cache.getFloats(reader, field, new FloatValuesCreator( field, FieldCache.NUMERIC_UTILS_FLOAT_PARSER, flags ) );
-      fail( "Should fail if you ask for the same type with a different parser : " + field );
-    } catch( Exception ex ) {} // expected
-
-    field = "theRandomDouble";
-    last = cache.getDoubles(reader,   field, new DoubleValuesCreator( field, FieldCache.DEFAULT_DOUBLE_PARSER, flags ) );
-    checkCachedArrayValuesAndBits( typeTests[5], last );
-    try {
-      cache.getDoubles(reader, field, new DoubleValuesCreator( field, FieldCache.NUMERIC_UTILS_DOUBLE_PARSER, flags ) );
-      fail( "Should fail if you ask for the same type with a different parser : " + field );
-    } catch( Exception ex ) {} // expected
-  }
-
-  private void checkCachedArrayValuesAndBits( NumberTypeTester tester, CachedArray cachedVals )
-  {
-//    for( int i=0; i<NUM_DOCS; i++ ) {
-//      System.out.println( i + "] "+ tester.values[i] + " :: " + cachedVals.valid.get(i) );
-//    }
-    
-    int numDocs =0;
-    Set<Number> distinctTerms = new HashSet<Number>();
-    for( int i=0; i<NUM_DOCS; i++ ) {
-      Number v = tester.values[i];
-      boolean isValid = cachedVals.valid.get(i);
-      if( v != null ) {
-        numDocs++;
-        distinctTerms.add( v );
-        assertTrue( "Valid bit should be true ("+i+"="+tester.values[i]+") "+tester, isValid );        
-      }
-      else {
-        assertFalse( "Valid bit should be false ("+i+") "+tester, isValid );        
-      }
-    }
-    assertEquals( "Cached numTerms does not match : "+tester, distinctTerms.size(), cachedVals.numTerms );
-    assertEquals( "Cached numDocs does not match : "+tester, numDocs, cachedVals.numDocs );
-    assertEquals( "Ordinal should match numDocs : "+tester, numDocs, ((FixedBitSet)cachedVals.valid).cardinality() );
-  }
-
-}
Index: lucene/src/test/org/apache/lucene/search/TestSort.java
===================================================================
--- lucene/src/test/org/apache/lucene/search/TestSort.java	(revision 1199574)
+++ lucene/src/test/org/apache/lucene/search/TestSort.java	(working copy)
@@ -44,13 +44,6 @@
 import org.apache.lucene.index.values.ValueType;
 import org.apache.lucene.search.BooleanClause.Occur;
 import org.apache.lucene.search.FieldValueHitQueue.Entry;
-import org.apache.lucene.search.cache.ByteValuesCreator;
-import org.apache.lucene.search.cache.CachedArrayCreator;
-import org.apache.lucene.search.cache.DoubleValuesCreator;
-import org.apache.lucene.search.cache.FloatValuesCreator;
-import org.apache.lucene.search.cache.IntValuesCreator;
-import org.apache.lucene.search.cache.LongValuesCreator;
-import org.apache.lucene.search.cache.ShortValuesCreator;
 import org.apache.lucene.store.Directory;
 import org.apache.lucene.store.LockObtainFailedException;
 import org.apache.lucene.util.Bits;
@@ -139,7 +132,7 @@
           Field f = new StringField ("int", data[i][2]);
           if (supportsDocValues) {
             f = IndexDocValuesField.build(f, ValueType.VAR_INTS);
-          };
+          }
           doc.add(f);
         }
         if (data[i][3] != null) {
@@ -350,12 +343,12 @@
   }
   
   private static class SortMissingLastTestHelper {
-    CachedArrayCreator<?> creator;
-    Object min;
-    Object max;
+    final SortField sortField;
+    final Object min;
+    final Object max;
     
-    SortMissingLastTestHelper( CachedArrayCreator<?> c, Object min, Object max ) {
-      creator = c;
+    SortMissingLastTestHelper(SortField sortField, Object min, Object max) {
+      this.sortField = sortField;
       this.min = min;
       this.max = max;
     }
@@ -364,27 +357,51 @@
   // test sorts where the type of field is specified
   public void testSortMissingLast() throws Exception {
     
-    SortMissingLastTestHelper[] testers = new SortMissingLastTestHelper[] {
-        new SortMissingLastTestHelper( new ByteValuesCreator(   "byte",   null ), Byte.MIN_VALUE,    Byte.MAX_VALUE ),
-        new SortMissingLastTestHelper( new ShortValuesCreator(  "short",  null ), Short.MIN_VALUE,   Short.MAX_VALUE ),
-        new SortMissingLastTestHelper( new IntValuesCreator(    "int",    null ), Integer.MIN_VALUE, Integer.MAX_VALUE ),
-        new SortMissingLastTestHelper( new LongValuesCreator(   "long",   null ), Long.MIN_VALUE,    Long.MAX_VALUE ),
-        new SortMissingLastTestHelper( new FloatValuesCreator(  "float",  null ), Float.MIN_VALUE,   Float.MAX_VALUE ),
-        new SortMissingLastTestHelper( new DoubleValuesCreator( "double", null ), Double.MIN_VALUE,  Double.MAX_VALUE ),
+    @SuppressWarnings("boxing")
+    SortMissingLastTestHelper[] ascendTesters = new SortMissingLastTestHelper[] {
+        new SortMissingLastTestHelper( new SortField(   "byte",   SortField.Type.BYTE ), Byte.MIN_VALUE,    Byte.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(  "short",  SortField.Type.SHORT ), Short.MIN_VALUE,   Short.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(    "int",    SortField.Type.INT ), Integer.MIN_VALUE, Integer.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(   "long",   SortField.Type.LONG ), Long.MIN_VALUE,    Long.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField(  "float",  SortField.Type.FLOAT ), Float.MIN_VALUE,   Float.MAX_VALUE ),
+        new SortMissingLastTestHelper( new SortField( "double", SortField.Type.DOUBLE ), Double.MIN_VALUE,  Double.MAX_VALUE ),
     };
     
-    for( SortMissingLastTestHelper t : testers ) {
-      sort.setSort (new SortField( t.creator, false ), SortField.FIELD_DOC );
-      assertMatches("creator:"+t.creator, full, queryM, sort, "adbc" );
+    @SuppressWarnings("boxing")
+    SortMissingLastTestHelper[] descendTesters = new SortMissingLastTestHelper[] {
+      new SortMissingLastTestHelper( new SortField(   "byte",   SortField.Type.BYTE, true ), Byte.MIN_VALUE,    Byte.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(  "short",  SortField.Type.SHORT, true ), Short.MIN_VALUE,   Short.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(    "int",    SortField.Type.INT, true ), Integer.MIN_VALUE, Integer.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(   "long",   SortField.Type.LONG, true ), Long.MIN_VALUE,    Long.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField(  "float",  SortField.Type.FLOAT, true ), Float.MIN_VALUE,   Float.MAX_VALUE ),
+      new SortMissingLastTestHelper( new SortField( "double", SortField.Type.DOUBLE, true ), Double.MIN_VALUE,  Double.MAX_VALUE ),
+    };
+    
+    // Default order: ascending
+    for(SortMissingLastTestHelper t : ascendTesters) {
+      sort.setSort(t.sortField, SortField.FIELD_DOC);
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "adbc");
 
-      sort.setSort (new SortField( t.creator, false ).setMissingValue( t.max ), SortField.FIELD_DOC );
-      assertMatches("creator:"+t.creator, full, queryM, sort, "bcad" );
+      sort.setSort(t.sortField.setMissingValue(t.max), SortField.FIELD_DOC);
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "bcad");
 
-      sort.setSort (new SortField( t.creator, false ).setMissingValue( t.min ), SortField.FIELD_DOC );
-      assertMatches("creator:"+t.creator, full, queryM, sort, "adbc" );
+      sort.setSort(t.sortField.setMissingValue(t.min), SortField.FIELD_DOC);
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "adbc");
     }
+    
+    // Reverse order: descending (Note: Order for un-valued documents remains the same due to tie breaker: a,d)
+    for(SortMissingLastTestHelper t : descendTesters) {
+      sort.setSort(t.sortField, SortField.FIELD_DOC);
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "cbad");
+      
+      sort.setSort(t.sortField.setMissingValue( t.max ), SortField.FIELD_DOC);
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "adcb");
+      
+      sort.setSort(t.sortField.setMissingValue( t.min ), SortField.FIELD_DOC);
+      assertMatches("sortField:"+t.sortField, full, queryM, sort, "cbad");
+    }
   }
-  
+
   /**
    * Test String sorting: small queue to many matches, multi field sort, reverse sort
    */
@@ -1064,7 +1081,7 @@
   private void assertMatches(String msg, IndexSearcher searcher, Query query, Sort sort,
       String expectedResult) throws IOException {
     //ScoreDoc[] result = searcher.search (query, null, 1000, sort).scoreDocs;
-    TopDocs hits = searcher.search (query, null, Math.max(1, expectedResult.length()), sort);
+    TopDocs hits = searcher.search(query, null, Math.max(1, expectedResult.length()), sort);
     ScoreDoc[] result = hits.scoreDocs;
     assertEquals(expectedResult.length(),hits.totalHits);
     StringBuilder buff = new StringBuilder(10);
@@ -1076,7 +1093,7 @@
         buff.append (v[j].stringValue());
       }
     }
-    assertEquals (msg, expectedResult, buff.toString());
+    assertEquals(msg, expectedResult, buff.toString());
   }
 
   public void testEmptyStringVsNullStringSort() throws Exception {
Index: lucene/src/java/org/apache/lucene/search/FieldCache.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/FieldCache.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/FieldCache.java	(working copy)
@@ -17,23 +17,21 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+import java.io.PrintStream;
+import java.text.DecimalFormat;
+
+import org.apache.lucene.analysis.NumericTokenStream; // for javadocs
+import org.apache.lucene.document.NumericField; // for javadocs
 import org.apache.lucene.index.DocTermOrds;
 import org.apache.lucene.index.IndexReader;
 import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.cache.EntryCreator;
-import org.apache.lucene.search.cache.CachedArray.*;
+import org.apache.lucene.util.Bits;
+import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.NumericUtils;
 import org.apache.lucene.util.RamUsageEstimator;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.document.NumericField; // for javadocs
-import org.apache.lucene.analysis.NumericTokenStream; // for javadocs
 import org.apache.lucene.util.packed.PackedInts;
 
-import java.io.IOException;
-import java.io.PrintStream;
-
-import java.text.DecimalFormat;
-
 /**
  * Expert: Maintains caches of term values.
  *
@@ -299,6 +297,15 @@
     }
   };
   
+ 
+   /** Checks the internal cache for an appropriate entry, and if none is found,
+    * reads the terms in <code>field</code> and returns a bit set at the size of
+    * <code>reader.maxDoc()</code>, with turned on bits for each docid that 
+    * does have a value for this field.
+    */
+   public Bits getDocsWithField(IndexReader reader, String field) 
+   throws IOException;
+
   /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as a single byte and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -324,19 +331,6 @@
   public byte[] getBytes (IndexReader reader, String field, ByteParser parser)
   throws IOException;
 
-  /** Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as bytes and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   * @param reader  Used to get field values.
-   * @param field   Which field contains the bytes.
-   * @param creator  Used to make the ByteValues
-   * @return The values in the given field for each document.
-   * @throws IOException  If any error occurs.
-   */
-  public ByteValues getBytes(IndexReader reader, String field, EntryCreator<ByteValues> creator ) throws IOException;
-  
-  
   /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as shorts and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -362,20 +356,6 @@
   public short[] getShorts (IndexReader reader, String field, ShortParser parser)
   throws IOException;
   
-  
-  /** Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as shorts and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   * @param reader  Used to get field values.
-   * @param field   Which field contains the shorts.
-   * @param creator  Computes short for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException  If any error occurs.
-   */
-  public ShortValues getShorts(IndexReader reader, String field, EntryCreator<ShortValues> creator ) throws IOException;
-  
-
   /** Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as integers and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -401,19 +381,6 @@
   public int[] getInts (IndexReader reader, String field, IntParser parser)
   throws IOException;
 
-  /** Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as integers and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   * @param reader  Used to get field values.
-   * @param field   Which field contains the integers.
-   * @param creator  Computes integer for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException  If any error occurs.
-   */
-  public IntValues getInts(IndexReader reader, String field, EntryCreator<IntValues> creator ) throws IOException;
-  
-
   /** Checks the internal cache for an appropriate entry, and if
    * none is found, reads the terms in <code>field</code> as floats and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -439,19 +406,6 @@
   public float[] getFloats (IndexReader reader, String field,
                             FloatParser parser) throws IOException;
 
-  /** Checks the internal cache for an appropriate entry, and if
-   * none is found, reads the terms in <code>field</code> as floats and returns an array
-   * of size <code>reader.maxDoc()</code> of the value each document
-   * has in the given field.
-   * @param reader  Used to get field values.
-   * @param field   Which field contains the floats.
-   * @param creator  Computes float for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException  If any error occurs.
-   */
-  public FloatValues getFloats(IndexReader reader, String field, EntryCreator<FloatValues> creator ) throws IOException;
-  
-  
   /**
    * Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as longs and returns an array
@@ -482,21 +436,6 @@
           throws IOException;
 
   /**
-   * Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as longs and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   *
-   * @param reader Used to get field values.
-   * @param field  Which field contains the longs.
-   * @param creator Computes integer for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException If any error occurs.
-   */
-  public LongValues getLongs(IndexReader reader, String field, EntryCreator<LongValues> creator ) throws IOException;
-  
-
-  /**
    * Checks the internal cache for an appropriate entry, and if none is
    * found, reads the terms in <code>field</code> as integers and returns an array
    * of size <code>reader.maxDoc()</code> of the value each document
@@ -525,21 +464,6 @@
   public double[] getDoubles(IndexReader reader, String field, DoubleParser parser)
           throws IOException;
 
-  /**
-   * Checks the internal cache for an appropriate entry, and if none is found,
-   * reads the terms in <code>field</code> as doubles and returns an array of
-   * size <code>reader.maxDoc()</code> of the value each document has in the
-   * given field.
-   *
-   * @param reader Used to get field values.
-   * @param field  Which field contains the doubles.
-   * @param creator Computes integer for string values.
-   * @return The values in the given field for each document.
-   * @throws IOException If any error occurs.
-   */
-  public DoubleValues getDoubles(IndexReader reader, String field, EntryCreator<DoubleValues> creator ) throws IOException;
-  
-  
   /** Returned by {@link #getTerms} */
   public abstract static class DocTerms {
     /** The BytesRef argument must not be null; the method
@@ -644,7 +568,6 @@
   public DocTermsIndex getTermsIndex (IndexReader reader, String field)
   throws IOException;
 
-
   /** Expert: just like {@link
    *  #getTermsIndex(IndexReader,String)}, but you can specify
    *  whether more RAM should be consumed in exchange for
Index: lucene/src/java/org/apache/lucene/search/cache/LongValuesCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/LongValuesCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/LongValuesCreator.java	(working copy)
@@ -1,165 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.FieldCache.LongParser;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.cache.CachedArray.LongValues;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public class LongValuesCreator extends CachedArrayCreator<LongValues>
-{
-  protected LongParser parser;
-
-  public LongValuesCreator( String field, LongParser parser, int options )
-  {
-    super( field, options );
-    this.parser = parser;
-  }
-
-  public LongValuesCreator( String field, LongParser parser )
-  {
-    super( field );
-    this.parser = parser;
-  }
-
-  @Override
-  public Class getArrayType() {
-    return Long.class;
-  }
-
-  @Override
-  public Parser getParser() {
-    return parser;
-  }
-  
-  @Override
-  public SortField.Type getSortType() {
-    return SortField.Type.LONG;
-  }
-
-
-  //--------------------------------------------------------------------------------
-  //--------------------------------------------------------------------------------
-
-  @Override
-  public LongValues create(IndexReader reader) throws IOException {
-    return validate( new LongValues(), reader );
-  }
-
-  @Override
-  public synchronized LongValues validate(LongValues entry, IndexReader reader) throws IOException {
-    boolean ok = false;
-    
-    if( hasOption(OPTION_CACHE_VALUES) ) {
-      ok = true;
-      if( entry.values == null ) {
-        fillLongValues(entry, reader, field);
-      }
-      else {
-        assertSameParser( entry, parser );
-      }
-    }
-    if( hasOption(OPTION_CACHE_BITS) ) {
-      ok = true;
-      if( entry.valid == null ) {
-        fillValidBits(entry, reader, field);
-      }
-    }
-    if( !ok ) {
-      throw new RuntimeException( "the config must cache values and/or bits" );
-    }
-    return entry;
-  }
-
-  protected void fillLongValues( LongValues vals, IndexReader reader, String field ) throws IOException
-  {
-    if( parser == null ) {
-      try {
-        parser = FieldCache.DEFAULT_LONG_PARSER;
-        fillLongValues( vals, reader, field );
-        return;
-      }
-      catch (NumberFormatException ne) {
-        vals.parserHashCode = null; // wipe the previous one
-        parser = FieldCache.NUMERIC_UTILS_LONG_PARSER;
-        fillLongValues( vals, reader, field );
-        return;
-      }
-    }
-    setParserAndResetCounts(vals, parser);
-
-    Terms terms = MultiFields.getTerms(reader, field);
-    int maxDoc = reader.maxDoc();
-    vals.values = null;
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = (hasOption(OPTION_CACHE_BITS)) ? new FixedBitSet( maxDoc ) : null;
-      DocsEnum docs = null;
-      try {
-        while(true) {
-          final BytesRef term = termsEnum.next();
-          if (term == null) {
-            break;
-          }
-          final long termval = parser.parseLong(term);
-          docs = termsEnum.docs(null, docs);
-          while (true) {
-            final int docID = docs.nextDoc();
-            if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-              break;
-            }
-            if(vals.values == null) {
-              vals.values = new long[maxDoc];
-            }
-            vals.values[docID] = termval;
-            vals.numDocs++;
-            if( validBits != null ) {
-              validBits.set( docID );
-            }
-          }
-          vals.numTerms++;
-        }
-      } catch (FieldCache.StopFillCacheException stop) {}
-
-      if( vals.valid == null ) {
-        vals.valid = checkMatchAllBits( validBits, vals.numDocs, maxDoc );
-      }
-    }
-
-    if(vals.values == null) {
-      vals.values = new long[maxDoc];
-    }
-
-    if( vals.valid == null && vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( maxDoc );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/ShortValuesCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/ShortValuesCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/ShortValuesCreator.java	(working copy)
@@ -1,147 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.FieldCache.ShortParser;
-import org.apache.lucene.search.cache.CachedArray.ShortValues;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public class ShortValuesCreator extends CachedArrayCreator<ShortValues>
-{
-  protected ShortParser parser;
-
-  public ShortValuesCreator( String field, ShortParser parser, int options )
-  {
-    super( field, options );
-    this.parser = parser;
-  }
-
-  public ShortValuesCreator( String field, ShortParser parser )
-  {
-    super( field );
-    this.parser = parser;
-  }
-
-  @Override
-  public Class getArrayType() {
-    return Short.class;
-  }
-
-  @Override
-  public Parser getParser() {
-    return parser;
-  }
-  
-  @Override
-  public SortField.Type getSortType() {
-    return SortField.Type.SHORT;
-  }
-
-
-  //--------------------------------------------------------------------------------
-  //--------------------------------------------------------------------------------
-
-  @Override
-  public ShortValues create(IndexReader reader) throws IOException {
-    return validate( new ShortValues(), reader );
-  }
-
-  @Override
-  public synchronized ShortValues validate(ShortValues entry, IndexReader reader) throws IOException {
-    boolean ok = false;
-    
-    if( hasOption(OPTION_CACHE_VALUES) ) {
-      ok = true;
-      if( entry.values == null ) {
-        fillShortValues(entry, reader, field);
-      }
-      else {
-        assertSameParser( entry, parser );
-      }
-    }
-    if( hasOption(OPTION_CACHE_BITS) ) {
-      ok = true;
-      if( entry.valid == null ) {
-        fillValidBits(entry, reader, field);
-      }
-    }
-    if( !ok ) {
-      throw new RuntimeException( "the config must cache values and/or bits" );
-    }
-    return entry;
-  }
-
-  protected void fillShortValues( ShortValues vals, IndexReader reader, String field ) throws IOException
-  {
-    if( parser == null ) {
-      parser = FieldCache.DEFAULT_SHORT_PARSER;
-    }
-    setParserAndResetCounts(vals, parser);
-
-    Terms terms = MultiFields.getTerms(reader, field);
-    int maxDoc = reader.maxDoc();
-    vals.values = new short[maxDoc];
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = (hasOption(OPTION_CACHE_BITS)) ? new FixedBitSet( maxDoc ) : null;
-      DocsEnum docs = null;
-      try {
-        while(true) {
-          final BytesRef term = termsEnum.next();
-          if (term == null) {
-            break;
-          }
-          final short termval = parser.parseShort(term);
-          docs = termsEnum.docs(null, docs);
-          while (true) {
-            final int docID = docs.nextDoc();
-            if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-              break;
-            }
-            vals.values[docID] = termval;
-            vals.numDocs++;
-            if( validBits != null ) {
-              validBits.set( docID );
-            }
-          }
-          vals.numTerms++;
-        }
-      } catch (FieldCache.StopFillCacheException stop) {}
-
-      if( vals.valid == null ) {
-        vals.valid = checkMatchAllBits( validBits, vals.numDocs, maxDoc );
-      }
-    }
-    if( vals.valid == null && vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( maxDoc );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/DocTermsCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/DocTermsCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/DocTermsCreator.java	(working copy)
@@ -1,169 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache.DocTerms;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.PagedBytes;
-import org.apache.lucene.util.packed.GrowableWriter;
-import org.apache.lucene.util.packed.PackedInts;
-
-// TODO: this if DocTermsIndex was already created, we should share it...
-public class DocTermsCreator extends EntryCreatorWithOptions<DocTerms>
-{
-  public static final int FASTER_BUT_MORE_RAM = 2;
-
-  public String field;
-
-  public DocTermsCreator( String field )
-  {
-    super( FASTER_BUT_MORE_RAM ); // By default turn on FASTER_BUT_MORE_RAM
-    if( field == null ) {
-      throw new IllegalArgumentException( "field can not be null" );
-    }
-    this.field = field;
-  }
-
-  public DocTermsCreator( String field, int flags )
-  {
-    super( flags );
-    if( field == null ) {
-      throw new IllegalArgumentException( "field can not be null" );
-    }
-    this.field = field;
-  }
-
-  @Override
-  public SimpleEntryKey getCacheKey() {
-    return new SimpleEntryKey( DocTermsCreator.class, field );
-  }
-
-  @Override
-  public DocTerms create(IndexReader reader) throws IOException {
-
-    Terms terms = MultiFields.getTerms(reader, field);
-
-    final boolean fasterButMoreRAM = hasOption( FASTER_BUT_MORE_RAM );
-    final int termCountHardLimit = reader.maxDoc();
-
-    // Holds the actual term data, expanded.
-    final PagedBytes bytes = new PagedBytes(15);
-
-    int startBPV;
-
-    if (terms != null) {
-      // Try for coarse estimate for number of bits; this
-      // should be an underestimate most of the time, which
-      // is fine -- GrowableWriter will reallocate as needed
-      long numUniqueTerms = 0;
-      try {
-        numUniqueTerms = terms.getUniqueTermCount();
-      } catch (UnsupportedOperationException uoe) {
-        numUniqueTerms = -1;
-      }
-      if (numUniqueTerms != -1) {
-        if (numUniqueTerms > termCountHardLimit) {
-          numUniqueTerms = termCountHardLimit;
-        }
-        startBPV = PackedInts.bitsRequired(numUniqueTerms*4);
-      } else {
-        startBPV = 1;
-      }
-    } else {
-      startBPV = 1;
-    }
-
-    final GrowableWriter docToOffset = new GrowableWriter(startBPV, reader.maxDoc(), fasterButMoreRAM);
-
-    // pointer==0 means not set
-    bytes.copyUsingLengthPrefix(new BytesRef());
-
-    if (terms != null) {
-      int termCount = 0;
-      final TermsEnum termsEnum = terms.iterator();
-      final Bits liveDocs = MultiFields.getLiveDocs(reader);
-      DocsEnum docs = null;
-      while(true) {
-        if (termCount++ == termCountHardLimit) {
-          // app is misusing the API (there is more than
-          // one term per doc); in this case we make best
-          // effort to load what we can (see LUCENE-2142)
-          break;
-        }
-
-        final BytesRef term = termsEnum.next();
-        if (term == null) {
-          break;
-        }
-        final long pointer = bytes.copyUsingLengthPrefix(term);
-        docs = termsEnum.docs(liveDocs, docs);
-        while (true) {
-          final int docID = docs.nextDoc();
-          if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-            break;
-          }
-          docToOffset.set(docID, pointer);
-        }
-      }
-    }
-
-    // maybe an int-only impl?
-    return new DocTermsImpl(bytes.freeze(true), docToOffset.getMutable());
-  }
-
-  @Override
-  public DocTerms validate(DocTerms entry, IndexReader reader) throws IOException {
-    // TODO? nothing? perhaps subsequent call with FASTER_BUT_MORE_RAM?
-    return entry;
-  }
-
-  private static class DocTermsImpl extends DocTerms {
-    private final PagedBytes.Reader bytes;
-    private final PackedInts.Reader docToOffset;
-
-    public DocTermsImpl(PagedBytes.Reader bytes, PackedInts.Reader docToOffset) {
-      this.bytes = bytes;
-      this.docToOffset = docToOffset;
-    }
-
-    @Override
-    public int size() {
-      return docToOffset.size();
-    }
-
-    @Override
-    public boolean exists(int docID) {
-      return docToOffset.get(docID) == 0;
-    }
-
-    @Override
-    public BytesRef getTerm(int docID, BytesRef ret) {
-      final long pointer = docToOffset.get(docID);
-      return bytes.fill(ret, pointer);
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/ByteValuesCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/ByteValuesCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/ByteValuesCreator.java	(working copy)
@@ -1,146 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.FieldCache.ByteParser;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.cache.CachedArray.ByteValues;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public class ByteValuesCreator extends CachedArrayCreator<ByteValues>
-{
-  protected ByteParser parser;
-
-  public ByteValuesCreator( String field, ByteParser parser, int options )
-  {
-    super( field, options );
-    this.parser = parser;
-  }
-
-  public ByteValuesCreator( String field, ByteParser parser )
-  {
-    super( field );
-    this.parser = parser;
-  }
-
-  @Override
-  public Class getArrayType() {
-    return Byte.class;
-  }
-
-  @Override
-  public Parser getParser() {
-    return parser;
-  }
-  
-  @Override
-  public SortField.Type getSortType() {
-    return SortField.Type.BYTE;
-  }
-
-  //--------------------------------------------------------------------------------
-  //--------------------------------------------------------------------------------
-
-  @Override
-  public ByteValues create(IndexReader reader) throws IOException {
-    return validate( new ByteValues(), reader );
-  }
-
-  @Override
-  public synchronized ByteValues validate(ByteValues entry, IndexReader reader) throws IOException {
-    boolean ok = false;
-    
-    if( hasOption(OPTION_CACHE_VALUES) ) {
-      ok = true;
-      if( entry.values == null ) {
-        fillByteValues(entry, reader, field);
-      }
-      else {
-        assertSameParser( entry, parser );
-      }
-    }
-    if( hasOption(OPTION_CACHE_BITS) ) {
-      ok = true;
-      if( entry.valid == null ) {
-        fillValidBits(entry, reader, field);
-      }
-    }
-    if( !ok ) {
-      throw new RuntimeException( "the config must cache values and/or bits" );
-    }
-    return entry;
-  }
-
-  protected void fillByteValues( ByteValues vals, IndexReader reader, String field ) throws IOException
-  {
-    if( parser == null ) {
-      parser = FieldCache.DEFAULT_BYTE_PARSER;
-    }
-    setParserAndResetCounts(vals, parser);
-
-    Terms terms = MultiFields.getTerms(reader, field);
-    int maxDoc = reader.maxDoc();
-    vals.values = new byte[maxDoc];
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = (hasOption(OPTION_CACHE_BITS)) ? new FixedBitSet( maxDoc ) : null;
-      DocsEnum docs = null;
-      try {
-        while(true) {
-          final BytesRef term = termsEnum.next();
-          if (term == null) {
-            break;
-          }
-          final byte termval = parser.parseByte(term);
-          docs = termsEnum.docs(null, docs);
-          while (true) {
-            final int docID = docs.nextDoc();
-            if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-              break;
-            }
-            vals.values[docID] = termval;
-            vals.numDocs++;
-            if( validBits != null ) {
-              validBits.set( docID );
-            }
-          }
-          vals.numTerms++;
-        }
-      } catch (FieldCache.StopFillCacheException stop) {}
-
-      if( vals.valid == null ) {
-        vals.valid = checkMatchAllBits( validBits, vals.numDocs, maxDoc );
-      }
-    }
-    if( vals.valid == null && vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( maxDoc );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/FloatValuesCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/FloatValuesCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/FloatValuesCreator.java	(working copy)
@@ -1,165 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.FieldCache.FloatParser;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.cache.CachedArray.FloatValues;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public class FloatValuesCreator extends CachedArrayCreator<FloatValues>
-{
-  protected FloatParser parser;
-
-  public FloatValuesCreator( String field, FloatParser parser, int options )
-  {
-    super( field, options );
-    this.parser = parser;
-  }
-
-  public FloatValuesCreator( String field, FloatParser parser )
-  {
-    super( field );
-    this.parser = parser;
-  }
-
-  @Override
-  public Class getArrayType() {
-    return Float.class;
-  }
-
-  @Override
-  public Parser getParser() {
-    return parser;
-  }
-  
-  @Override
-  public SortField.Type getSortType() {
-    return SortField.Type.FLOAT;
-  }
-
-
-  //--------------------------------------------------------------------------------
-  //--------------------------------------------------------------------------------
-
-  @Override
-  public FloatValues create(IndexReader reader) throws IOException {
-    return validate( new FloatValues(), reader );
-  }
-
-  @Override
-  public synchronized FloatValues validate(FloatValues entry, IndexReader reader) throws IOException {
-    boolean ok = false;
-    
-    if( hasOption(OPTION_CACHE_VALUES) ) {
-      ok = true;
-      if( entry.values == null ) {
-        fillFloatValues(entry, reader, field);
-      }
-      else {
-        assertSameParser( entry, parser );
-      }
-    }
-    if( hasOption(OPTION_CACHE_BITS) ) {
-      ok = true;
-      if( entry.valid == null ) {
-        fillValidBits(entry, reader, field);
-      }
-    }
-    if( !ok ) {
-      throw new RuntimeException( "the config must cache values and/or bits" );
-    }
-    return entry;
-  }
-
-  protected void fillFloatValues( FloatValues vals, IndexReader reader, String field ) throws IOException
-  {
-    if( parser == null ) {
-      try {
-        parser = FieldCache.DEFAULT_FLOAT_PARSER;
-        fillFloatValues( vals, reader, field );
-        return;
-      }
-      catch (NumberFormatException ne) {
-        vals.parserHashCode = null; // wipe the previous one
-        parser = FieldCache.NUMERIC_UTILS_FLOAT_PARSER;
-        fillFloatValues( vals, reader, field );
-        return;
-      }
-    }
-    setParserAndResetCounts(vals, parser);
-
-    Terms terms = MultiFields.getTerms(reader, field);
-    int maxDoc = reader.maxDoc();
-    vals.values = null;
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = (hasOption(OPTION_CACHE_BITS)) ? new FixedBitSet( maxDoc ) : null;
-      DocsEnum docs = null;
-      try {
-        while(true) {
-          final BytesRef term = termsEnum.next();
-          if (term == null) {
-            break;
-          }
-          final float termval = parser.parseFloat(term);
-          docs = termsEnum.docs(null, docs);
-          while (true) {
-            final int docID = docs.nextDoc();
-            if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-              break;
-            }
-            if(vals.values == null) {
-              vals.values = new float[maxDoc];
-            }
-            vals.values[docID] = termval;
-            vals.numDocs++;
-            if( validBits != null ) {
-              validBits.set( docID );
-            }
-          }
-          vals.numTerms++;
-        }
-      } catch (FieldCache.StopFillCacheException stop) {}
-
-      if( vals.valid == null ) {
-        vals.valid = checkMatchAllBits( validBits, vals.numDocs, maxDoc );
-      }
-    }
-
-    if(vals.values == null) {
-      vals.values = new float[maxDoc];
-    }
-
-    if( vals.valid == null && vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( maxDoc );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/DocTermOrdsCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/DocTermOrdsCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/DocTermOrdsCreator.java	(working copy)
@@ -1,51 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/*
- * 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.
- */
-
-import org.apache.lucene.index.DocTermOrds;
-import org.apache.lucene.index.IndexReader;
-
-import java.io.IOException;
-
-/**
- * Creates {@link DocTermOrds} instances.
- */
-public class DocTermOrdsCreator extends EntryCreatorWithOptions<DocTermOrds> {
-
-  private final String field;
-
-  public DocTermOrdsCreator(String field, int flag) {
-    super(flag);
-    this.field = field;
-  }
-
-  @Override
-  public DocTermOrds create(IndexReader reader) throws IOException {
-    return new DocTermOrds(reader, field);
-  }
-
-  @Override
-  public DocTermOrds validate(DocTermOrds entry, IndexReader reader) throws IOException {
-    return entry;
-  }
-
-  @Override
-  public EntryKey getCacheKey() {
-    return new SimpleEntryKey(DocTermOrdsCreator.class, field);
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/CachedArray.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/CachedArray.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/CachedArray.java	(working copy)
@@ -1,78 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import org.apache.lucene.util.Bits;
-
-public abstract class CachedArray 
-{
-  public Integer parserHashCode; // a flag to make sure you don't change what you are asking for in subsequent requests
-  public int numDocs;
-  public int numTerms;
-
-  /**
-   * NOTE: these Bits may have false positives for deleted documents.  That is,
-   * Documents that are deleted may be marked as valid but the array value is not.
-   */
-  public Bits valid;
-
-  public CachedArray() {
-    this.parserHashCode = null;
-    this.numDocs = 0;
-    this.numTerms = 0;
-  }
-  
-  /**
-   * @return the native array
-   */
-  public abstract Object getRawArray();
-
-  //-------------------------------------------------------------
-  // Concrete Values
-  //-------------------------------------------------------------
-
-  public static class ByteValues extends CachedArray {
-    public byte[] values = null;
-    @Override public byte[] getRawArray() { return values; }
-  };
-
-  public static class ShortValues extends CachedArray {
-    public short[] values = null;
-    @Override public short[] getRawArray() { return values; }
-  };
-
-  public static class IntValues extends CachedArray {
-    public int[] values = null;
-    @Override public int[] getRawArray() { return values; }
-  };
-
-  public static class FloatValues extends CachedArray {
-    public float[] values = null;
-    @Override public float[] getRawArray() { return values; }
-  };
-
-  public static class LongValues extends CachedArray {
-    public long[] values = null;
-    @Override public long[] getRawArray() { return values; }
-  };
-
-  public static class DoubleValues extends CachedArray {
-    public double[] values = null;
-    @Override public double[] getRawArray() { return values; }
-  };
-}
Index: lucene/src/java/org/apache/lucene/search/cache/DoubleValuesCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/DoubleValuesCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/DoubleValuesCreator.java	(working copy)
@@ -1,164 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.FieldCache.DoubleParser;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.cache.CachedArray.DoubleValues;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public class DoubleValuesCreator extends CachedArrayCreator<DoubleValues>
-{
-  protected DoubleParser parser;
-
-  public DoubleValuesCreator( String field, DoubleParser parser, int options )
-  {
-    super( field, options );
-    this.parser = parser;
-  }
-
-  public DoubleValuesCreator( String field, DoubleParser parser )
-  {
-    super( field );
-    this.parser = parser;
-  }
-
-  @Override
-  public Class getArrayType() {
-    return Double.class;
-  }
-
-  @Override
-  public Parser getParser() {
-    return parser;
-  }
-  
-  @Override
-  public SortField.Type getSortType() {
-    return SortField.Type.DOUBLE;
-  }
-
-  //--------------------------------------------------------------------------------
-  //--------------------------------------------------------------------------------
-
-  @Override
-  public DoubleValues create(IndexReader reader) throws IOException {
-    return validate( new DoubleValues(), reader );
-  }
-
-  @Override
-  public synchronized DoubleValues validate(DoubleValues entry, IndexReader reader) throws IOException {
-    boolean ok = false;
-    
-    if( hasOption(OPTION_CACHE_VALUES) ) {
-      ok = true;
-      if( entry.values == null ) {
-        fillDoubleValues(entry, reader, field);
-      }
-      else {
-        assertSameParser( entry, parser );
-      }
-    }
-    if( hasOption(OPTION_CACHE_BITS) ) {
-      ok = true;
-      if( entry.valid == null ) {
-        fillValidBits(entry, reader, field);
-      }
-    }
-    if( !ok ) {
-      throw new RuntimeException( "the config must cache values and/or bits" );
-    }
-    return entry;
-  }
-
-  protected void fillDoubleValues( DoubleValues vals, IndexReader reader, String field ) throws IOException
-  {
-    if( parser == null ) {
-      try {
-        parser = FieldCache.DEFAULT_DOUBLE_PARSER;
-        fillDoubleValues( vals, reader, field );
-        return;
-      }
-      catch (NumberFormatException ne) {
-        vals.parserHashCode = null; // wipe the previous one
-        parser = FieldCache.NUMERIC_UTILS_DOUBLE_PARSER;
-        fillDoubleValues( vals, reader, field );
-        return;
-      }
-    }
-    setParserAndResetCounts(vals, parser);
-
-    Terms terms = MultiFields.getTerms(reader, field);
-    int maxDoc = reader.maxDoc();
-    vals.values = null;
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = (hasOption(OPTION_CACHE_BITS)) ? new FixedBitSet( maxDoc ) : null;
-      DocsEnum docs = null;
-      try {
-        while(true) {
-          final BytesRef term = termsEnum.next();
-          if (term == null) {
-            break;
-          }
-          final double termval = parser.parseDouble(term);
-          docs = termsEnum.docs(null, docs);
-          while (true) {
-            final int docID = docs.nextDoc();
-            if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-              break;
-            }
-            if(vals.values == null) {
-              vals.values = new double[maxDoc];
-            }
-            vals.values[docID] = termval;
-            vals.numDocs++;
-            if( validBits != null ) {
-              validBits.set( docID );
-            }
-          }
-          vals.numTerms++;
-        }
-      } catch (FieldCache.StopFillCacheException stop) {}
-
-      if( vals.valid == null ) {
-        vals.valid = checkMatchAllBits( validBits, vals.numDocs, maxDoc );
-      }
-    }
-
-    if(vals.values == null) {
-      vals.values = new double[maxDoc];
-    }
-
-    if( vals.valid == null && vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( maxDoc );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/EntryKey.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/EntryKey.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/EntryKey.java	(working copy)
@@ -1,26 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-
-/**
- * A Simple marker class -- Perhaps it could/should just be an Object
- */
-public abstract class EntryKey {
-
-}
Index: lucene/src/java/org/apache/lucene/search/cache/package.html
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/package.html	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/package.html	(working copy)
@@ -1,25 +0,0 @@
-<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
-<!--
- 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.
--->
-<html>
-<head>
-   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-</head>
-<body>
-Fieldcache
-</body>
-</html>
Index: lucene/src/java/org/apache/lucene/search/cache/EntryCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/EntryCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/EntryCreator.java	(working copy)
@@ -1,72 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.IndexReader;
-
-/**
- * Create Cached Values for a given key
- * 
- * @lucene.experimental
- */
-public abstract class EntryCreator<T>
-{
-  public abstract T create( IndexReader reader ) throws IOException;
-  public abstract T validate( T entry, IndexReader reader ) throws IOException;
-
-  /**
-   * Indicate if a cached cached value should be checked before usage.
-   * This is useful if an application wants to support subsequent calls
-   * to the same cached object that may alter the cached object.  If
-   * an application wants to avoid this (synchronized) check, it should
-   * return 'false'
-   *
-   * @return 'true' if the Cache should call 'validate' before returning a cached object
-   */
-  public boolean shouldValidate() {
-    return true;
-  }
-
-  /**
-   * @return A key to identify valid cache entries for subsequent requests
-   */
-  public abstract EntryKey getCacheKey();
-  
-
-  //------------------------------------------------------------------------
-  // The Following code is a hack to make things work while the 
-  // EntryCreator is stored in in the FieldCache.  
-  // When the FieldCache is replaced with a simpler map LUCENE-2665
-  // This can be removed
-  //------------------------------------------------------------------------
-
-  @Override
-  public boolean equals(Object obj) {
-    if( obj instanceof EntryCreator ) {
-      return getCacheKey().equals( ((EntryCreator)obj).getCacheKey() );
-    }
-    return false;
-  }
-
-  @Override
-  public int hashCode() {
-    return getCacheKey().hashCode();
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/SimpleEntryKey.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/SimpleEntryKey.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/SimpleEntryKey.java	(working copy)
@@ -1,77 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-
-public class SimpleEntryKey extends EntryKey
-{
-  public final Class clazz;
-  public final Object[] args;
-  public final int hash;
-
-  public SimpleEntryKey( Class clazz, Object ... args ) {
-    this.clazz = clazz;
-    this.args = args;
-
-    int hash = clazz.hashCode();
-    if( args != null ) {
-      for( Object obj : args ) {
-        hash ^= obj.hashCode();
-      }
-    }
-    this.hash = hash;
-  }
-
-  @Override
-  public boolean equals(Object obj) {
-    if( obj instanceof SimpleEntryKey ) {
-      SimpleEntryKey key = (SimpleEntryKey)obj;
-      if( key.hash != hash ||
-          key.clazz != clazz ||
-          key.args.length != args.length ) {
-        return false;
-      }
-
-      // In the off chance that the hash etc is all the same
-      // we should actually check the values
-      for( int i=0; i<args.length; i++ ) {
-        if( !args[i].equals( key.args[i] ) ) {
-          return false;
-        }
-      }
-      return true;
-    }
-    return false;
-  }
-
-  @Override
-  public int hashCode() {
-    return hash;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder str = new StringBuilder();
-    str.append( '[' ).append( clazz.getName() ).append( ':' );
-    for( Object v : args ) {
-      str.append( v ).append( ':' );
-    }
-    str.append( hash ).append( ']' );
-    return str.toString();
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/CachedArrayCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/CachedArrayCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/CachedArrayCreator.java	(working copy)
@@ -1,152 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public abstract class CachedArrayCreator<T extends CachedArray> extends EntryCreatorWithOptions<T>
-{
-  public static final int OPTION_VALIDATE     = 1;
-  public static final int OPTION_CACHE_VALUES = 2;
-  public static final int OPTION_CACHE_BITS   = 4;
-  
-  // Composite Options Fields
-  public static final int CACHE_VALUES_AND_BITS = OPTION_CACHE_VALUES ^ OPTION_CACHE_BITS;
-  public static final int CACHE_VALUES_AND_BITS_VALIDATE = OPTION_CACHE_VALUES ^ OPTION_CACHE_BITS ^ OPTION_VALIDATE;
-
-  public final String field;
-
-  public CachedArrayCreator( String field )
-  {
-    super( OPTION_CACHE_VALUES ^ OPTION_VALIDATE );
-    if( field == null ) {
-      throw new IllegalArgumentException( "field can not be null" );
-    }
-    this.field = field;
-  }
-
-  public CachedArrayCreator( String field, int flags )
-  {
-    super( flags );
-    if( field == null ) {
-      throw new IllegalArgumentException( "field can not be null" );
-    }
-    this.field = field;
-  }
-
-  /**
-   * Note that the 'flags' are not part of the key -- subsequent calls to the cache
-   * with different options will use the same cache entry.
-   */
-  @Override
-  public EntryKey getCacheKey() {
-    return new SimpleEntryKey( CachedArray.class, getArrayType(), field );
-    //return new Integer( CachedArrayCreator.class.hashCode() ^ getArrayType().hashCode() ^ field.hashCode() );
-  }
-  
-  /** Return the type that the array will hold */
-  public abstract Class getArrayType();
-  public abstract Parser getParser();
-  public abstract SortField.Type getSortType();
-
-  protected void setParserAndResetCounts(T value, Parser parser)
-  {
-    int parserHashCode = parser.hashCode();
-    if( value.parserHashCode != null && value.parserHashCode != parserHashCode ) {
-      throw new RuntimeException( "Parser changed in subsequent call.  "
-          +value.parserHashCode+" != "+parserHashCode + " :: " + parser );
-    }
-    value.parserHashCode = parserHashCode;
-    value.numDocs = value.numTerms = 0;
-  }
-
-  protected void assertSameParser(T value, Parser parser)
-  {
-    if( parser != null && value.parserHashCode != null ) {
-      int parserHashCode = parser.hashCode();
-      if(  value.parserHashCode != parserHashCode ) {
-        throw new RuntimeException( "Parser changed in subsequent call.  "
-            +value.parserHashCode+" != "+parserHashCode + " :: " + parser );
-      }
-    }
-  }
-
-  /**
-   * Utility function to help check what bits are valid
-   */
-  protected Bits checkMatchAllBits( FixedBitSet valid, int numDocs, int maxDocs )
-  {
-    if( numDocs != maxDocs ) {
-      if( hasOption( OPTION_CACHE_BITS ) ) {
-        for( int i=0; i<maxDocs; i++ ) {
-          if( !valid.get(i) ) {
-            return valid;
-          }
-        }
-      }
-      else {
-        return null;
-      }
-    }
-    return new Bits.MatchAllBits( maxDocs );
-  }
-
-  public void fillValidBits( T vals, IndexReader reader, String field ) throws IOException
-  {
-    vals.numDocs = vals.numTerms = 0;
-    Terms terms = MultiFields.getTerms(reader, field);
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = new FixedBitSet( reader.maxDoc() );
-      DocsEnum docs = null;
-      while(true) {
-        final BytesRef term = termsEnum.next();
-        if (term == null) {
-          break;
-        }
-        docs = termsEnum.docs(null, docs);
-        while (true) {
-          final int docID = docs.nextDoc();
-          if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-            break;
-          }
-          validBits.set( docID );
-          vals.numDocs++;
-        }
-        vals.numTerms++;
-      }
-
-      vals.valid = checkMatchAllBits( validBits, vals.numDocs, reader.maxDoc() );
-    }
-    if( vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( reader.maxDoc() );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/DocTermsIndexCreator.java	(working copy)
@@ -1,353 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-import java.util.Comparator;
-
-import org.apache.lucene.index.DocsAndPositionsEnum;
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.OrdTermState;
-import org.apache.lucene.index.TermState;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache.DocTermsIndex;
-import org.apache.lucene.util.ArrayUtil;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.PagedBytes;
-import org.apache.lucene.util.packed.GrowableWriter;
-import org.apache.lucene.util.packed.PackedInts;
-
-public class DocTermsIndexCreator extends EntryCreatorWithOptions<DocTermsIndex>
-{
-  public static final int FASTER_BUT_MORE_RAM = 2;
-
-  public String field;
-
-  public DocTermsIndexCreator( String field )
-  {
-    super( FASTER_BUT_MORE_RAM ); // By default turn on FASTER_BUT_MORE_RAM
-    if( field == null ) {
-      throw new IllegalArgumentException( "field can not be null" );
-    }
-    this.field = field;
-  }
-
-  public DocTermsIndexCreator( String field, int flags )
-  {
-    super( flags );
-    if( field == null ) {
-      throw new IllegalArgumentException( "field can not be null" );
-    }
-    this.field = field;
-  }
-
-  @Override
-  public EntryKey getCacheKey() {
-    return new SimpleEntryKey( DocTermsIndexCreator.class, field );
-  }
-
-  @Override
-  public DocTermsIndex create(IndexReader reader) throws IOException
-  {
-    Terms terms = MultiFields.getTerms(reader, field);
-
-    final boolean fasterButMoreRAM = hasOption(FASTER_BUT_MORE_RAM);
-
-    final PagedBytes bytes = new PagedBytes(15);
-
-    int startBytesBPV;
-    int startTermsBPV;
-    int startNumUniqueTerms;
-
-    int maxDoc = reader.maxDoc();
-    final int termCountHardLimit;
-    if (maxDoc == Integer.MAX_VALUE) {
-      termCountHardLimit = Integer.MAX_VALUE;
-    } else {
-      termCountHardLimit = maxDoc+1;
-    }
-
-    if (terms != null) {
-      // Try for coarse estimate for number of bits; this
-      // should be an underestimate most of the time, which
-      // is fine -- GrowableWriter will reallocate as needed
-      long numUniqueTerms = 0;
-      try {
-        numUniqueTerms = terms.getUniqueTermCount();
-      } catch (UnsupportedOperationException uoe) {
-        numUniqueTerms = -1;
-      }
-      if (numUniqueTerms != -1) {
-
-        if (numUniqueTerms > termCountHardLimit) {
-          // app is misusing the API (there is more than
-          // one term per doc); in this case we make best
-          // effort to load what we can (see LUCENE-2142)
-          numUniqueTerms = termCountHardLimit;
-        }
-
-        startBytesBPV = PackedInts.bitsRequired(numUniqueTerms*4);
-        startTermsBPV = PackedInts.bitsRequired(numUniqueTerms);
-
-        startNumUniqueTerms = (int) numUniqueTerms;
-      } else {
-        startBytesBPV = 1;
-        startTermsBPV = 1;
-        startNumUniqueTerms = 1;
-      }
-    } else {
-      startBytesBPV = 1;
-      startTermsBPV = 1;
-      startNumUniqueTerms = 1;
-    }
-
-    GrowableWriter termOrdToBytesOffset = new GrowableWriter(startBytesBPV, 1+startNumUniqueTerms, fasterButMoreRAM);
-    final GrowableWriter docToTermOrd = new GrowableWriter(startTermsBPV, reader.maxDoc(), fasterButMoreRAM);
-
-    // 0 is reserved for "unset"
-    bytes.copyUsingLengthPrefix(new BytesRef());
-    int termOrd = 1;
-
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      DocsEnum docs = null;
-
-      while(true) {
-        final BytesRef term = termsEnum.next();
-        if (term == null) {
-          break;
-        }
-        if (termOrd >= termCountHardLimit) {
-          break;
-        }
-
-        if (termOrd == termOrdToBytesOffset.size()) {
-          // NOTE: this code only runs if the incoming
-          // reader impl doesn't implement
-          // getUniqueTermCount (which should be uncommon)
-          termOrdToBytesOffset = termOrdToBytesOffset.resize(ArrayUtil.oversize(1+termOrd, 1));
-        }
-        termOrdToBytesOffset.set(termOrd, bytes.copyUsingLengthPrefix(term));
-        docs = termsEnum.docs(null, docs);
-        while (true) {
-          final int docID = docs.nextDoc();
-          if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-            break;
-          }
-          docToTermOrd.set(docID, termOrd);
-        }
-        termOrd++;
-      }
-
-      if (termOrdToBytesOffset.size() > termOrd) {
-        termOrdToBytesOffset = termOrdToBytesOffset.resize(termOrd);
-      }
-    }
-
-    // maybe an int-only impl?
-    return new DocTermsIndexImpl(bytes.freeze(true), termOrdToBytesOffset.getMutable(), docToTermOrd.getMutable(), termOrd);
-  }
-
-  @Override
-  public DocTermsIndex validate(DocTermsIndex entry, IndexReader reader) throws IOException {
-    // TODO? nothing? perhaps subsequent call with FASTER_BUT_MORE_RAM?
-    return entry;
-  }
-
-  //-----------------------------------------------------------------------------
-  //-----------------------------------------------------------------------------
-
-  public static class DocTermsIndexImpl extends DocTermsIndex {
-    private final PagedBytes.Reader bytes;
-    private final PackedInts.Reader termOrdToBytesOffset;
-    private final PackedInts.Reader docToTermOrd;
-    private final int numOrd;
-
-    public DocTermsIndexImpl(PagedBytes.Reader bytes, PackedInts.Reader termOrdToBytesOffset, PackedInts.Reader docToTermOrd, int numOrd) {
-      this.bytes = bytes;
-      this.docToTermOrd = docToTermOrd;
-      this.termOrdToBytesOffset = termOrdToBytesOffset;
-      this.numOrd = numOrd;
-    }
-
-    @Override
-    public PackedInts.Reader getDocToOrd() {
-      return docToTermOrd;
-    }
-
-    @Override
-    public int numOrd() {
-      return numOrd;
-    }
-
-    @Override
-    public int getOrd(int docID) {
-      return (int) docToTermOrd.get(docID);
-    }
-
-    @Override
-    public int size() {
-      return docToTermOrd.size();
-    }
-
-    @Override
-    public BytesRef lookup(int ord, BytesRef ret) {
-      return bytes.fill(ret, termOrdToBytesOffset.get(ord));
-    }
-
-    @Override
-    public TermsEnum getTermsEnum() {
-      return this.new DocTermsIndexEnum();
-    }
-
-    class DocTermsIndexEnum extends TermsEnum {
-      int currentOrd;
-      int currentBlockNumber;
-      int end;  // end position in the current block
-      final byte[][] blocks;
-      final int[] blockEnds;
-
-      final BytesRef term = new BytesRef();
-
-      public DocTermsIndexEnum() {
-        currentOrd = 0;
-        currentBlockNumber = 0;
-        blocks = bytes.getBlocks();
-        blockEnds = bytes.getBlockEnds();
-        currentBlockNumber = bytes.fillAndGetIndex(term, termOrdToBytesOffset.get(0));
-        end = blockEnds[currentBlockNumber];
-      }
-
-      @Override
-      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;
-          seekExact(mid);
-          int cmp = term.compareTo(text);
-
-          if (cmp < 0)
-            low = mid + 1;
-          else if (cmp > 0)
-            high = mid - 1;
-          else
-            return SeekStatus.FOUND; // key found
-        }
-        
-        if (low == numOrd) {
-          return SeekStatus.END;
-        } else {
-          seekExact(low);
-          return SeekStatus.NOT_FOUND;
-        }
-      }
-
-      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;
-      }
-
-      @Override
-      public BytesRef next() throws IOException {
-        int start = term.offset + term.length;
-        if (start >= end) {
-          // switch byte blocks
-          if (currentBlockNumber +1 >= blocks.length) {
-            return null;
-          }
-          currentBlockNumber++;
-          term.bytes = blocks[currentBlockNumber];
-          end = blockEnds[currentBlockNumber];
-          start = 0;
-          if (end<=0) return null;  // special case of empty last array
-        }
-
-        currentOrd++;
-
-        byte[] block = term.bytes;
-        if ((block[start] & 128) == 0) {
-          term.length = block[start];
-          term.offset = start+1;
-        } else {
-          term.length = (((block[start] & 0x7f)) << 8) | (block[1+start] & 0xff);
-          term.offset = start+2;
-        }
-
-        return term;
-      }
-
-      @Override
-      public BytesRef term() throws IOException {
-        return term;
-      }
-
-      @Override
-      public long ord() throws IOException {
-        return currentOrd;
-      }
-
-      @Override
-      public int docFreq() {
-        throw new UnsupportedOperationException();
-      }
-
-      @Override
-      public long totalTermFreq() {
-        return -1;
-      }
-
-      @Override
-      public DocsEnum docs(Bits liveDocs, DocsEnum reuse) throws IOException {
-        throw new UnsupportedOperationException();
-      }
-
-      @Override
-      public DocsAndPositionsEnum docsAndPositions(Bits liveDocs, DocsAndPositionsEnum reuse) throws IOException {
-        throw new UnsupportedOperationException();
-      }
-
-      @Override
-      public Comparator<BytesRef> getComparator() throws IOException {
-        return BytesRef.getUTF8SortedAsUnicodeComparator();
-      }
-
-      @Override
-      public void seekExact(BytesRef term, TermState state) throws IOException {
-        assert state != null && state instanceof OrdTermState;
-        this.seekExact(((OrdTermState)state).ord);
-      }
-
-      @Override
-      public TermState termState() throws IOException {
-        OrdTermState state = new OrdTermState();
-        state.ord = currentOrd;
-        return state;
-      }
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/EntryCreatorWithOptions.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/EntryCreatorWithOptions.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/EntryCreatorWithOptions.java	(working copy)
@@ -1,45 +0,0 @@
-package org.apache.lucene.search.cache;
-
-
-/**
- * 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.
- */
-
-
-public abstract class EntryCreatorWithOptions<T> extends EntryCreator<T>
-{
-  public static final int OPTION_VALIDATE = 1;
-
-  private int flags;
-
-  public EntryCreatorWithOptions( int flag ) {
-    this.flags = flag;
-  }
-
-  @Override
-  public boolean shouldValidate() {
-    return hasOption( OPTION_VALIDATE );
-  }
-
-  public boolean hasOption( int key )
-  {
-    return (flags & key) == key;
-  }
-
-  public void setFlag(int flag) {
-    this.flags |= flag;
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/cache/IntValuesCreator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/cache/IntValuesCreator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/cache/IntValuesCreator.java	(working copy)
@@ -1,165 +0,0 @@
-package org.apache.lucene.search.cache;
-
-/**
- * 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.
- */
-
-import java.io.IOException;
-
-import org.apache.lucene.index.DocsEnum;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.MultiFields;
-import org.apache.lucene.index.Terms;
-import org.apache.lucene.index.TermsEnum;
-import org.apache.lucene.search.DocIdSetIterator;
-import org.apache.lucene.search.FieldCache;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.FieldCache.IntParser;
-import org.apache.lucene.search.FieldCache.Parser;
-import org.apache.lucene.search.cache.CachedArray.IntValues;
-import org.apache.lucene.util.Bits;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.FixedBitSet;
-
-public class IntValuesCreator extends CachedArrayCreator<IntValues>
-{
-  protected IntParser parser;
-
-  public IntValuesCreator( String field, IntParser parser, int options )
-  {
-    super( field, options );
-    this.parser = parser;
-  }
-
-  public IntValuesCreator( String field, IntParser parser )
-  {
-    super( field );
-    this.parser = parser;
-  }
-
-  @Override
-  public Class getArrayType() {
-    return Integer.class;
-  }
-
-  @Override
-  public Parser getParser() {
-    return parser;
-  }
-  
-  @Override
-  public SortField.Type getSortType() {
-    return SortField.Type.INT;
-  }
-
-
-  //--------------------------------------------------------------------------------
-  //--------------------------------------------------------------------------------
-
-  @Override
-  public IntValues create(IndexReader reader) throws IOException {
-    return validate( new IntValues(), reader );
-  }
-
-  @Override
-  public synchronized IntValues validate(IntValues entry, IndexReader reader) throws IOException {
-    boolean ok = false;
-    
-    if( hasOption(OPTION_CACHE_VALUES) ) {
-      ok = true;
-      if( entry.values == null ) {
-        fillIntValues(entry, reader, field);
-      }
-      else {
-        assertSameParser( entry, parser );
-      }
-    }
-    if( hasOption(OPTION_CACHE_BITS) ) {
-      ok = true;
-      if( entry.valid == null ) {
-        fillValidBits(entry, reader, field);
-      }
-    }
-    if( !ok ) {
-      throw new RuntimeException( "the config must cache values and/or bits" );
-    }
-    return entry;
-  }
-
-  protected void fillIntValues( IntValues vals, IndexReader reader, String field ) throws IOException
-  {
-    if( parser == null ) {
-      try {
-        parser = FieldCache.DEFAULT_INT_PARSER;
-        fillIntValues( vals, reader, field );
-        return;
-      }
-      catch (NumberFormatException ne) {
-        vals.parserHashCode = null;
-        parser = FieldCache.NUMERIC_UTILS_INT_PARSER;
-        fillIntValues( vals, reader, field );
-        return;
-      }
-    }
-    setParserAndResetCounts(vals, parser);
-    
-    Terms terms = MultiFields.getTerms(reader, field);
-    int maxDoc = reader.maxDoc();
-    vals.values = null;
-    if (terms != null) {
-      final TermsEnum termsEnum = terms.iterator();
-      FixedBitSet validBits = (hasOption(OPTION_CACHE_BITS)) ? new FixedBitSet( maxDoc ) : null;
-      DocsEnum docs = null;
-      try {
-        while(true) {
-          final BytesRef term = termsEnum.next();
-          if (term == null) {
-            break;
-          }
-          final int termval = parser.parseInt(term);
-          docs = termsEnum.docs(null, docs);
-          while (true) {
-            final int docID = docs.nextDoc();
-            if (docID == DocIdSetIterator.NO_MORE_DOCS) {
-              break;
-            }
-            if(vals.values == null) {
-              vals.values = new int[maxDoc];
-            }
-            vals.values[docID] = termval;
-            vals.numDocs++;
-            if( validBits != null ) {
-              validBits.set( docID );
-            }
-          }
-          vals.numTerms++;
-        }
-      } catch (FieldCache.StopFillCacheException stop) {}
-
-      if( vals.valid == null ) {
-        vals.valid = checkMatchAllBits( validBits, vals.numDocs, maxDoc );
-      }
-    }
-
-    if(vals.values == null) {
-      vals.values = new int[maxDoc];
-    }
-
-    if( vals.valid == null && vals.numDocs < 1 ) {
-      vals.valid = new Bits.MatchNoBits( maxDoc );
-    }
-  }
-}
Index: lucene/src/java/org/apache/lucene/search/FieldComparator.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/FieldComparator.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/FieldComparator.java	(working copy)
@@ -17,19 +17,23 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+
 import org.apache.lucene.index.IndexReader.AtomicReaderContext;
+import org.apache.lucene.index.values.IndexDocValues.Source;
 import org.apache.lucene.index.values.IndexDocValues;
-import org.apache.lucene.index.values.IndexDocValues.Source;
+import org.apache.lucene.search.FieldCache.ByteParser;
 import org.apache.lucene.search.FieldCache.DocTerms;
 import org.apache.lucene.search.FieldCache.DocTermsIndex;
-import org.apache.lucene.search.cache.*;
-import org.apache.lucene.search.cache.CachedArray.*;
+import org.apache.lucene.search.FieldCache.DoubleParser;
+import org.apache.lucene.search.FieldCache.FloatParser;
+import org.apache.lucene.search.FieldCache.IntParser;
+import org.apache.lucene.search.FieldCache.LongParser;
+import org.apache.lucene.search.FieldCache.ShortParser;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.packed.PackedInts;
 
-import java.io.IOException;
-
 /**
  * Expert: a FieldComparator compares hits so as to determine their
  * sort order when collecting the top results with {@link
@@ -185,38 +189,43 @@
     }
   }
 
-  public static abstract class NumericComparator<T extends CachedArray, U extends Number> extends FieldComparator<U> {
-    protected final CachedArrayCreator<T> creator;
-    protected T cached;
-    protected final boolean checkMissing;
-    protected Bits valid;
+  public static abstract class NumericComparator<T extends Number> extends FieldComparator<T> {
+    protected final T missingValue;
+    protected final String field;
+    protected Bits docsWithField;
     
-    public NumericComparator( CachedArrayCreator<T> c, boolean checkMissing ) {
-      this.creator = c;
-      this.checkMissing = checkMissing;
+    public NumericComparator(String field, T missingValue) {
+      this.field = field;
+      this.missingValue = missingValue;
     }
 
-    protected FieldComparator setup(T cached) {
-      this.cached = cached;
-      if (checkMissing)
-        valid = cached.valid;
+    @Override
+    public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
+      if (missingValue != null) {
+        docsWithField = FieldCache.DEFAULT.getDocsWithField(context.reader, field);
+        // optimization to remove unneeded checks on the bit interface:
+        if (docsWithField instanceof Bits.MatchAllBits) {
+          docsWithField = null;
+        }
+      } else {
+        docsWithField = null;
+      }
       return this;
     }
   }
 
   /** Parses field's values as byte (using {@link
    *  FieldCache#getBytes} and sorts by ascending value */
-  public static final class ByteComparator extends NumericComparator<ByteValues,Byte> {
-    private byte[] docValues;
+  public static final class ByteComparator extends NumericComparator<Byte> {
     private final byte[] values;
-    private final byte missingValue;
+    private final ByteParser parser;
+    private byte[] currentReaderValues;
     private byte bottom;
 
-    ByteComparator(int numHits, ByteValuesCreator creator, Byte missingValue ) {
-      super( creator, missingValue!=null );
+    ByteComparator(int numHits, String field, FieldCache.Parser parser, Byte missingValue) {
+      super(field, missingValue);
       values = new byte[numHits];
-      this.missingValue = checkMissing
-         ? missingValue.byteValue() : 0;
+      this.parser = (ByteParser) parser;
     }
 
     @Override
@@ -226,27 +235,29 @@
 
     @Override
     public int compareBottom(int doc) {
-      byte v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      byte v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0;
         v2 = missingValue;
+      }
 
       return bottom - v2;
     }
 
     @Override
     public void copy(int slot, int doc) {
-      byte v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      byte v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
-
+      }
       values[slot] = v2;
     }
 
     @Override
     public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
-      setup(FieldCache.DEFAULT.getBytes(context.reader, creator.field, creator));
-      docValues = cached.values;
-      return this;
+      currentReaderValues = FieldCache.DEFAULT.getBytes(context.reader, field, parser);
+      return super.setNextReader(context);
     }
     
     @Override
@@ -263,17 +274,16 @@
   
   /** Parses field's values as double (using {@link
    *  FieldCache#getDoubles} and sorts by ascending value */
-  public static final class DoubleComparator extends NumericComparator<DoubleValues,Double> {
-    private double[] docValues;
+  public static final class DoubleComparator extends NumericComparator<Double> {
     private final double[] values;
-    private final double missingValue;
+    private final DoubleParser parser;
+    private double[] currentReaderValues;
     private double bottom;
 
-    DoubleComparator(int numHits, DoubleValuesCreator creator, Double missingValue ) {
-      super( creator, missingValue != null );
+    DoubleComparator(int numHits, String field, FieldCache.Parser parser, Double missingValue) {
+      super(field, missingValue);
       values = new double[numHits];
-      this.missingValue = checkMissing
-        ? missingValue.doubleValue() : 0;
+      this.parser = (DoubleParser) parser;
     }
 
     @Override
@@ -291,9 +301,11 @@
 
     @Override
     public int compareBottom(int doc) {
-      double v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      double v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       if (bottom > v2) {
         return 1;
@@ -306,18 +318,19 @@
 
     @Override
     public void copy(int slot, int doc) {
-      double v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      double v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       values[slot] = v2;
     }
 
     @Override
     public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
-      setup(FieldCache.DEFAULT.getDoubles(context.reader, creator.field, creator));
-      docValues = cached.values;
-      return this;
+      currentReaderValues = FieldCache.DEFAULT.getDoubles(context.reader, field, parser);
+      return super.setNextReader(context);
     }
     
     @Override
@@ -334,8 +347,8 @@
   /** Uses float index values to sort by ascending value */
   public static final class FloatDocValuesComparator extends FieldComparator<Double> {
     private final double[] values;
+    private final String field;
     private Source currentReaderValues;
-    private final String field;
     private double bottom;
 
     FloatDocValuesComparator(int numHits, String field) {
@@ -395,17 +408,16 @@
 
   /** Parses field's values as float (using {@link
    *  FieldCache#getFloats} and sorts by ascending value */
-  public static final class FloatComparator extends NumericComparator<FloatValues,Float> {
-    private float[] docValues;
+  public static final class FloatComparator extends NumericComparator<Float> {
     private final float[] values;
-    private final float missingValue;
+    private final FloatParser parser;
+    private float[] currentReaderValues;
     private float bottom;
 
-    FloatComparator(int numHits, FloatValuesCreator creator, Float missingValue ) {
-      super( creator, missingValue != null );
+    FloatComparator(int numHits, String field, FieldCache.Parser parser, Float missingValue) {
+      super(field, missingValue);
       values = new float[numHits];
-      this.missingValue = checkMissing
-        ? missingValue.floatValue() : 0;
+      this.parser = (FloatParser) parser;
     }
     
     @Override
@@ -426,10 +438,11 @@
     @Override
     public int compareBottom(int doc) {
       // TODO: are there sneaky non-branch ways to compute sign of float?
-      float v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      float v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
-
+      }
       
       if (bottom > v2) {
         return 1;
@@ -442,18 +455,19 @@
 
     @Override
     public void copy(int slot, int doc) {
-      float v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      float v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       values[slot] = v2;
     }
 
     @Override
     public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
-      setup(FieldCache.DEFAULT.getFloats(context.reader, creator.field, creator));
-      docValues = cached.values;
-      return this;
+      currentReaderValues = FieldCache.DEFAULT.getFloats(context.reader, field, parser);
+      return super.setNextReader(context);
     }
     
     @Override
@@ -469,17 +483,16 @@
 
   /** Parses field's values as short (using {@link
    *  FieldCache#getShorts} and sorts by ascending value */
-  public static final class ShortComparator extends NumericComparator<ShortValues,Short> {
-    private short[] docValues;
+  public static final class ShortComparator extends NumericComparator<Short> {
     private final short[] values;
+    private final ShortParser parser;
+    private short[] currentReaderValues;
     private short bottom;
-    private final short missingValue;
 
-    ShortComparator(int numHits, ShortValuesCreator creator, Short missingValue ) {
-      super( creator, missingValue != null );
+    ShortComparator(int numHits, String field, FieldCache.Parser parser, Short missingValue) {
+      super(field, missingValue);
       values = new short[numHits];
-      this.missingValue = checkMissing
-        ? missingValue.shortValue() : 0;
+      this.parser = (ShortParser) parser;
     }
 
     @Override
@@ -489,27 +502,30 @@
 
     @Override
     public int compareBottom(int doc) {
-      short v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      short v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       return bottom - v2;
     }
 
     @Override
     public void copy(int slot, int doc) {
-      short v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      short v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       values[slot] = v2;
     }
 
     @Override
     public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
-      setup( FieldCache.DEFAULT.getShorts(context.reader, creator.field, creator));
-      docValues = cached.values;
-      return this;
+      currentReaderValues = FieldCache.DEFAULT.getShorts(context.reader, field, parser);
+      return super.setNextReader(context);
     }
 
     @Override
@@ -525,17 +541,16 @@
 
   /** Parses field's values as int (using {@link
    *  FieldCache#getInts} and sorts by ascending value */
-  public static final class IntComparator extends NumericComparator<IntValues,Integer> {
-    private int[] docValues;
+  public static final class IntComparator extends NumericComparator<Integer> {
     private final int[] values;
+    private final IntParser parser;
+    private int[] currentReaderValues;
     private int bottom;                           // Value of bottom of queue
-    final int missingValue;
-    
-    IntComparator(int numHits, IntValuesCreator creator, Integer missingValue ) {
-      super( creator, missingValue != null );
+
+    IntComparator(int numHits, String field, FieldCache.Parser parser, Integer missingValue) {
+      super(field, missingValue);
       values = new int[numHits];
-      this.missingValue = checkMissing
-        ? missingValue.intValue() : 0;
+      this.parser = (IntParser) parser;
     }
         
     @Override
@@ -561,9 +576,11 @@
       // -1/+1/0 sign
       // Cannot return bottom - values[slot2] because that
       // may overflow
-      int v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      int v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       if (bottom > v2) {
         return 1;
@@ -576,18 +593,19 @@
 
     @Override
     public void copy(int slot, int doc) {
-      int v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      int v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       values[slot] = v2;
     }
 
     @Override
     public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
-      setup(FieldCache.DEFAULT.getInts(context.reader, creator.field, creator));
-      docValues = cached.values;
-      return this;
+      currentReaderValues = FieldCache.DEFAULT.getInts(context.reader, field, parser);
+      return super.setNextReader(context);
     }
     
     @Override
@@ -669,19 +687,18 @@
 
   /** Parses field's values as long (using {@link
    *  FieldCache#getLongs} and sorts by ascending value */
-  public static final class LongComparator extends NumericComparator<LongValues,Long> {
-    private long[] docValues;
+  public static final class LongComparator extends NumericComparator<Long> {
     private final long[] values;
+    private final LongParser parser;
+    private long[] currentReaderValues;
     private long bottom;
-    private final long missingValue;
 
-    LongComparator(int numHits, LongValuesCreator creator, Long missingValue ) {
-      super( creator, missingValue != null );
+    LongComparator(int numHits, String field, FieldCache.Parser parser, Long missingValue) {
+      super(field, missingValue);
       values = new long[numHits];
-      this.missingValue = checkMissing
-        ? missingValue.longValue() : 0;
+      this.parser = (LongParser) parser;
     }
-    
+
     @Override
     public int compare(int slot1, int slot2) {
       // TODO: there are sneaky non-branch ways to compute
@@ -701,11 +718,12 @@
     public int compareBottom(int doc) {
       // TODO: there are sneaky non-branch ways to compute
       // -1/+1/0 sign
-      long v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      long v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
-      
       if (bottom > v2) {
         return 1;
       } else if (bottom < v2) {
@@ -717,18 +735,19 @@
 
     @Override
     public void copy(int slot, int doc) {
-      long v2 = docValues[doc];
-      if (valid != null && v2==0 && !valid.get(doc))
+      long v2 = currentReaderValues[doc];
+      if (docsWithField != null && !docsWithField.get(doc)) {
+        assert v2 == 0; 
         v2 = missingValue;
+      }
 
       values[slot] = v2;
     }
 
     @Override
     public FieldComparator setNextReader(AtomicReaderContext context) throws IOException {
-      setup(FieldCache.DEFAULT.getLongs(context.reader, creator.field, creator));
-      docValues = cached.values;
-      return this;
+      currentReaderValues = FieldCache.DEFAULT.getLongs(context.reader, field, parser);
+      return super.setNextReader(context);
     }
     
     @Override
Index: lucene/src/java/org/apache/lucene/search/SortField.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/SortField.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/SortField.java	(working copy)
@@ -20,7 +20,6 @@
 import java.io.IOException;
 import java.util.Comparator;
 
-import org.apache.lucene.search.cache.*;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.StringHelper;
 
@@ -104,12 +103,14 @@
   private String field;
   private Type type;  // defaults to determining type dynamically
   boolean reverse = false;  // defaults to natural order
-  private CachedArrayCreator<?> creator;
-  public Object missingValue = null; // used for 'sortMissingFirst/Last'
+  private FieldCache.Parser parser;
 
   // Used for CUSTOM sort
   private FieldComparatorSource comparatorSource;
 
+  // Used for 'sortMissingFirst/Last'
+  public Object missingValue = null;
+
   /** Creates a sort by terms in the given field with the type of term
    * values explicitly given.
    * @param field  Name of field to sort by.  Can be <code>null</code> if
@@ -141,10 +142,7 @@
    *  by testing which numeric parser the parser subclasses.
    * @throws IllegalArgumentException if the parser fails to
    *  subclass an existing numeric parser, or field is null
-   *  
-   *  @deprecated (4.0) use EntryCreator version
    */
-  @Deprecated
   public SortField(String field, FieldCache.Parser parser) {
     this(field, parser, false);
   }
@@ -159,65 +157,27 @@
    * @param reverse True if natural order should be reversed.
    * @throws IllegalArgumentException if the parser fails to
    *  subclass an existing numeric parser, or field is null
-   *  
-   *  @deprecated (4.0) use EntryCreator version
    */
-  @Deprecated
   public SortField(String field, FieldCache.Parser parser, boolean reverse) {
-    if (field == null) {
-      throw new IllegalArgumentException("field can only be null when type is SCORE or DOC");
-    } 
-    this.field = field;
-    this.reverse = reverse;
-    
-    if (parser instanceof FieldCache.IntParser) {
-      this.creator = new IntValuesCreator( field, (FieldCache.IntParser)parser );
-    }
-    else if (parser instanceof FieldCache.FloatParser) {
-      this.creator = new FloatValuesCreator( field, (FieldCache.FloatParser)parser );
-    }
-    else if (parser instanceof FieldCache.ShortParser) {
-      this.creator = new ShortValuesCreator( field, (FieldCache.ShortParser)parser );
-    }
-    else if (parser instanceof FieldCache.ByteParser) {
-      this.creator = new ByteValuesCreator( field, (FieldCache.ByteParser)parser );
-    }
-    else if (parser instanceof FieldCache.LongParser) {
-      this.creator = new LongValuesCreator( field, (FieldCache.LongParser)parser );
-    }
-    else if (parser instanceof FieldCache.DoubleParser) {
-      this.creator = new DoubleValuesCreator( field, (FieldCache.DoubleParser)parser );
-    }
-    else
+    if (parser instanceof FieldCache.IntParser) initFieldType(field, Type.INT);
+    else if (parser instanceof FieldCache.FloatParser) initFieldType(field, Type.FLOAT);
+    else if (parser instanceof FieldCache.ShortParser) initFieldType(field, Type.SHORT);
+    else if (parser instanceof FieldCache.ByteParser) initFieldType(field, Type.BYTE);
+    else if (parser instanceof FieldCache.LongParser) initFieldType(field, Type.LONG);
+    else if (parser instanceof FieldCache.DoubleParser) initFieldType(field, Type.DOUBLE);
+    else {
       throw new IllegalArgumentException("Parser instance does not subclass existing numeric parser from FieldCache (got " + parser + ")");
+    }
 
-    this.type = this.creator.getSortType();
-  }
-  
-  /**
-   * Sort by a cached entry value
-   * @param creator
-   * @param reverse
-   */
-  public SortField( CachedArrayCreator<?> creator, boolean reverse ) 
-  {
-    this.field = creator.field;
     this.reverse = reverse;
-    this.creator = creator;
-    this.type = creator.getSortType();
+    this.parser = parser;
   }
   
-  public SortField setMissingValue( Object v )
-  {
-    missingValue = v;
-    if( missingValue != null ) {
-      if( this.creator == null ) {
-        throw new IllegalArgumentException( "Missing value only works for sort fields with a CachedArray" );
-      }
-
-      // Set the flag to get bits 
-      creator.setFlag( CachedArrayCreator.OPTION_CACHE_BITS );
+  public SortField setMissingValue(Object missingValue) {
+    if (type != Type.BYTE && type != Type.SHORT && type != Type.INT && type != Type.FLOAT && type != Type.LONG && type != Type.DOUBLE) {
+      throw new IllegalArgumentException( "Missing value only works for numeric types" );
     }
+    this.missingValue = missingValue;
     return this;
   }
 
@@ -246,23 +206,12 @@
   private void initFieldType(String field, Type type) {
     this.type = type;
     if (field == null) {
-      if (type != Type.SCORE && type != Type.DOC)
+      if (type != Type.SCORE && type != Type.DOC) {
         throw new IllegalArgumentException("field can only be null when type is SCORE or DOC");
+      }
     } else {
       this.field = field;
     }
-    
-    if( creator != null ) {
-      throw new IllegalStateException( "creator already exists: "+creator );
-    }
-    switch( type ) {
-    case BYTE:   creator = new ByteValuesCreator( field, null ); break;
-    case SHORT:  creator = new ShortValuesCreator( field, null ); break;
-    case INT:    creator = new IntValuesCreator( field, null ); break;
-    case LONG:   creator = new LongValuesCreator( field, null ); break;
-    case FLOAT:  creator = new FloatValuesCreator( field, null ); break;
-    case DOUBLE: creator = new DoubleValuesCreator( field, null ); break;
-    }
   }
 
   /** Returns the name of the field.  Could return <code>null</code>
@@ -283,17 +232,11 @@
   /** Returns the instance of a {@link FieldCache} parser that fits to the given sort type.
    * May return <code>null</code> if no parser was specified. Sorting is using the default parser then.
    * @return An instance of a {@link FieldCache} parser, or <code>null</code>.
-   * @deprecated (4.0) use getEntryCreator()
    */
-  @Deprecated
   public FieldCache.Parser getParser() {
-    return (creator==null) ? null : creator.getParser();
+    return parser;
   }
 
-  public CachedArrayCreator<?> getEntryCreator() {
-    return creator;
-  }
-
   /** Returns whether the sort should be reversed.
    * @return  True if natural order should be reversed.
    */
@@ -365,7 +308,6 @@
         break;
     }
 
-    if (creator != null) buffer.append('(').append(creator).append(')');
     if (reverse) buffer.append('!');
 
     return buffer.toString();
@@ -385,7 +327,6 @@
       && other.type == this.type
       && other.reverse == this.reverse
       && (other.comparatorSource == null ? this.comparatorSource == null : other.comparatorSource.equals(this.comparatorSource))
-      && (other.creator == null ? this.creator == null : other.creator.equals(this.creator))
     );
   }
 
@@ -399,7 +340,6 @@
     int hash = type.hashCode() ^ 0x346565dd + Boolean.valueOf(reverse).hashCode() ^ 0xaf5998bb;
     if (field != null) hash += field.hashCode()^0xff5685dd;
     if (comparatorSource != null) hash += comparatorSource.hashCode();
-    if (creator != null) hash += creator.hashCode()^0x3aaf56ff;
     return hash;
   }
 
@@ -448,27 +388,27 @@
       if (useIndexValues) {
         return new FieldComparator.IntDocValuesComparator(numHits, field);
       } else {
-        return new FieldComparator.IntComparator(numHits, (IntValuesCreator)creator, (Integer) missingValue);
+        return new FieldComparator.IntComparator(numHits, field, parser, (Integer) missingValue);
       }
 
     case FLOAT:
       if (useIndexValues) {
         return new FieldComparator.FloatDocValuesComparator(numHits, field);
       } else {
-        return new FieldComparator.FloatComparator(numHits, (FloatValuesCreator) creator, (Float) missingValue);
+        return new FieldComparator.FloatComparator(numHits, field, parser, (Float) missingValue);
       }
 
     case LONG:
-      return new FieldComparator.LongComparator(numHits, (LongValuesCreator)creator, (Long)missingValue );
+      return new FieldComparator.LongComparator(numHits, field, parser, (Long) missingValue);
 
     case DOUBLE:
-      return new FieldComparator.DoubleComparator(numHits, (DoubleValuesCreator)creator, (Double)missingValue );
+      return new FieldComparator.DoubleComparator(numHits, field, parser, (Double) missingValue);
 
     case BYTE:
-      return new FieldComparator.ByteComparator(numHits, (ByteValuesCreator)creator, (Byte)missingValue );
+      return new FieldComparator.ByteComparator(numHits, field, parser, (Byte) missingValue);
 
     case SHORT:
-      return new FieldComparator.ShortComparator(numHits, (ShortValuesCreator)creator, (Short)missingValue );
+      return new FieldComparator.ShortComparator(numHits, field, parser, (Short) missingValue);
 
     case CUSTOM:
       assert comparatorSource != null;
Index: lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java
===================================================================
--- lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/search/FieldCacheImpl.java	(working copy)
@@ -17,28 +17,42 @@
  * limitations under the License.
  */
 
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+
 import org.apache.lucene.index.DocTermOrds;
+import org.apache.lucene.index.DocsAndPositionsEnum;
+import org.apache.lucene.index.DocsEnum;
 import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.search.cache.*;
-import org.apache.lucene.search.cache.CachedArray.*;
+import org.apache.lucene.index.MultiFields;
+import org.apache.lucene.index.OrdTermState;
+import org.apache.lucene.index.TermState;
+import org.apache.lucene.index.Terms;
+import org.apache.lucene.index.TermsEnum;
+import org.apache.lucene.util.ArrayUtil;
+import org.apache.lucene.util.Bits;
+import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.FieldCacheSanityChecker;
+import org.apache.lucene.util.FixedBitSet;
+import org.apache.lucene.util.PagedBytes;
+import org.apache.lucene.util.packed.GrowableWriter;
+import org.apache.lucene.util.packed.PackedInts;
 
-import java.io.IOException;
-import java.io.PrintStream;
-import java.util.*;
-
 /**
  * Expert: The default cache implementation, storing all values in memory.
  * A WeakHashMap is used for storage.
  *
  * <p>Created: May 19, 2004 4:40:36 PM
- * 
- * @lucene.internal -- this is now public so that the tests can use reflection
- * to call methods.  It will likely be removed without (much) notice.
- * 
+ *
  * @since   lucene 1.4
  */
-public class FieldCacheImpl implements FieldCache {  // Made Public so that 
+class FieldCacheImpl implements FieldCache {
 	
   private Map<Class<?>,Cache> caches;
   FieldCacheImpl() {
@@ -46,17 +60,18 @@
   }
   private synchronized void init() {
     caches = new HashMap<Class<?>,Cache>(9);
-    caches.put(Byte.TYPE, new Cache<ByteValues>(this));
-    caches.put(Short.TYPE, new Cache<ShortValues>(this));
-    caches.put(Integer.TYPE, new Cache<IntValues>(this));
-    caches.put(Float.TYPE, new Cache<FloatValues>(this));
-    caches.put(Long.TYPE, new Cache<LongValues>(this));
-    caches.put(Double.TYPE, new Cache<DoubleValues>(this));
-    caches.put(DocTermsIndex.class, new Cache<DocTermsIndex>(this));
-    caches.put(DocTerms.class, new Cache<DocTerms>(this));
-    caches.put(DocTermOrds.class, new Cache<DocTermOrds>(this));
+    caches.put(Byte.TYPE, new ByteCache(this));
+    caches.put(Short.TYPE, new ShortCache(this));
+    caches.put(Integer.TYPE, new IntCache(this));
+    caches.put(Float.TYPE, new FloatCache(this));
+    caches.put(Long.TYPE, new LongCache(this));
+    caches.put(Double.TYPE, new DoubleCache(this));
+    caches.put(DocTerms.class, new DocTermsCache(this));
+    caches.put(DocTermsIndex.class, new DocTermsIndexCache(this));
+    caches.put(DocTermOrds.class, new DocTermOrdsCache(this));
+    caches.put(DocsWithFieldCache.class, new DocsWithFieldCache(this));
   }
-  
+
   public synchronized void purgeAllCaches() {
     init();
   }
@@ -70,15 +85,17 @@
   public synchronized CacheEntry[] getCacheEntries() {
     List<CacheEntry> result = new ArrayList<CacheEntry>(17);
     for(final Map.Entry<Class<?>,Cache> cacheEntry: caches.entrySet()) {
-      final Cache<?> cache = cacheEntry.getValue();
+      final Cache cache = cacheEntry.getValue();
       final Class<?> cacheType = cacheEntry.getKey();
       synchronized(cache.readerCache) {
-        for( Object readerKey : cache.readerCache.keySet() ) {
-          Map<?, Object> innerCache = cache.readerCache.get(readerKey);
-          for (final Map.Entry<?, Object> mapEntry : innerCache.entrySet()) {
-            Entry entry = (Entry)mapEntry.getKey();
+        for (final Map.Entry<Object,Map<Entry, Object>> readerCacheEntry : cache.readerCache.entrySet()) {
+          final Object readerKey = readerCacheEntry.getKey();
+          if (readerKey == null) continue;
+          final Map<Entry, Object> innerCache = readerCacheEntry.getValue();
+          for (final Map.Entry<Entry, Object> mapEntry : innerCache.entrySet()) {
+            Entry entry = mapEntry.getKey();
             result.add(new CacheEntryImpl(readerKey, entry.field,
-                                          cacheType, entry.creator,
+                                          cacheType, entry.custom,
                                           mapEntry.getValue()));
           }
         }
@@ -91,11 +108,11 @@
     private final Object readerKey;
     private final String fieldName;
     private final Class<?> cacheType;
-    private final EntryCreator custom;
+    private final Object custom;
     private final Object value;
     CacheEntryImpl(Object readerKey, String fieldName,
                    Class<?> cacheType,
-                   EntryCreator custom,
+                   Object custom,
                    Object value) {
         this.readerKey = readerKey;
         this.fieldName = fieldName;
@@ -121,15 +138,23 @@
     public Object getValue() { return value; }
   }
 
+  /**
+   * Hack: When thrown from a Parser (NUMERIC_UTILS_* ones), this stops
+   * processing terms and returns the current FieldCache
+   * array.
+   */
+  static final class StopFillCacheException extends RuntimeException {
+  }
+
   final static IndexReader.ReaderFinishedListener purgeReader = new IndexReader.ReaderFinishedListener() {
-    @Override
+    // @Override -- not until Java 1.6
     public void finished(IndexReader reader) {
       FieldCache.DEFAULT.purge(reader);
     }
   };
 
   /** Expert: Internal cache. */
-  final static class Cache<T> {
+  abstract static class Cache {
     Cache() {
       this.wrapper = null;
     }
@@ -140,12 +165,11 @@
 
     final FieldCache wrapper;
 
-    final Map<Object,Map<Entry<T>,Object>> readerCache = new WeakHashMap<Object,Map<Entry<T>,Object>>();
+    final Map<Object,Map<Entry,Object>> readerCache = new WeakHashMap<Object,Map<Entry,Object>>();
+    
+    protected abstract Object createValue(IndexReader reader, Entry key)
+        throws IOException;
 
-    protected Object createValue(IndexReader reader, Entry entryKey) throws IOException {
-      return entryKey.creator.create( reader );
-    }
-
     /** Remove this reader from the cache, if present. */
     public void purge(IndexReader r) {
       Object readerKey = r.getCoreCacheKey();
@@ -154,16 +178,15 @@
       }
     }
 
-    @SuppressWarnings("unchecked")
-    public Object get(IndexReader reader, Entry<T> key) throws IOException {
-      Map<Entry<T>,Object> innerCache;
+    public Object get(IndexReader reader, Entry key) throws IOException {
+      Map<Entry,Object> innerCache;
       Object value;
       final Object readerKey = reader.getCoreCacheKey();
       synchronized (readerCache) {
         innerCache = readerCache.get(readerKey);
         if (innerCache == null) {
           // First time this reader is using FieldCache
-          innerCache = new HashMap<Entry<T>,Object>();
+          innerCache = new HashMap<Entry,Object>();
           readerCache.put(readerKey, innerCache);
           reader.addReaderFinishedListener(purgeReader);
           value = null;
@@ -187,7 +210,7 @@
             // Only check if key.custom (the parser) is
             // non-null; else, we check twice for a single
             // call to FieldCache.getXXX
-            if (key.creator != null && wrapper != null) {
+            if (key.custom != null && wrapper != null) {
               final PrintStream infoStream = wrapper.getInfoStream();
               if (infoStream != null) {
                 printNewInsanity(infoStream, progress.value);
@@ -197,11 +220,6 @@
           return progress.value;
         }
       }
-      
-      // Validate new entries
-      if( key.creator.shouldValidate() ) {
-        key.creator.validate( (T)value, reader);
-      }
       return value;
     }
 
@@ -224,14 +242,14 @@
   }
 
   /** Expert: Every composite-key in the internal cache is of this type. */
-  static class Entry<T> {
+  static class Entry {
     final String field;        // which Fieldable
-    final EntryCreator<T> creator;       // which custom comparator or parser
+    final Object custom;       // which custom comparator or parser
 
     /** Creates one of these objects for a custom comparator/parser. */
-    Entry (String field, EntryCreator<T> custom) {
+    Entry (String field, Object custom) {
       this.field = field;
-      this.creator = custom;
+      this.custom = custom;
     }
 
     /** Two of these are equal iff they reference the same field and type. */
@@ -240,9 +258,9 @@
       if (o instanceof Entry) {
         Entry other = (Entry) o;
         if (other.field.equals(field)) {
-          if (other.creator == null) {
-            if (creator == null) return true;
-          } else if (other.creator.equals (creator)) {
+          if (other.custom == null) {
+            if (custom == null) return true;
+          } else if (other.custom.equals (custom)) {
             return true;
           }
         }
@@ -253,136 +271,871 @@
     /** Composes a hashcode based on the field and type. */
     @Override
     public int hashCode() {
-      return field.hashCode() ^ (creator==null ? 0 : creator.hashCode());
+      return field.hashCode() ^ (custom==null ? 0 : custom.hashCode());
     }
   }
 
   // inherit javadocs
   public byte[] getBytes (IndexReader reader, String field) throws IOException {
-    return getBytes(reader, field, new ByteValuesCreator(field, null)).values;
+    return getBytes(reader, field, null);
   }
 
   // inherit javadocs
-  public byte[] getBytes(IndexReader reader, String field, ByteParser parser) throws IOException {
-    return getBytes(reader, field, new ByteValuesCreator(field, parser)).values;
+  public byte[] getBytes(IndexReader reader, String field, ByteParser parser)
+      throws IOException {
+    return (byte[]) caches.get(Byte.TYPE).get(reader, new Entry(field, parser));
   }
 
-  @SuppressWarnings("unchecked")
-  public ByteValues getBytes(IndexReader reader, String field, EntryCreator<ByteValues> creator ) throws IOException 
-  {
-    return (ByteValues)caches.get(Byte.TYPE).get(reader, new Entry(field, creator));
+  static final class ByteCache extends Cache {
+    ByteCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+      Entry entry = entryKey;
+      String field = entry.field;
+      ByteParser parser = (ByteParser) entry.custom;
+      if (parser == null) {
+        return wrapper.getBytes(reader, field, FieldCache.DEFAULT_BYTE_PARSER);
+      }
+      final byte[] retArray = new byte[reader.maxDoc()];
+
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        try {
+          while(true) {
+            final BytesRef term = termsEnum.next();
+            if (term == null) {
+              break;
+            }
+            final byte termval = parser.parseByte(term);
+            docs = termsEnum.docs(null, docs);
+            while (true) {
+              final int docID = docs.nextDoc();
+              if (docID == DocsEnum.NO_MORE_DOCS) {
+                break;
+              }
+              retArray[docID] = termval;
+            }
+          }
+        } catch (StopFillCacheException stop) {
+        }
+      }
+      return retArray;
+    }
   }
   
   // inherit javadocs
   public short[] getShorts (IndexReader reader, String field) throws IOException {
-    return getShorts(reader, field, new ShortValuesCreator(field,null)).values;
+    return getShorts(reader, field, null);
   }
 
   // inherit javadocs
-  public short[] getShorts(IndexReader reader, String field, ShortParser parser) throws IOException {
-    return getShorts(reader, field, new ShortValuesCreator(field,parser)).values;
+  public short[] getShorts(IndexReader reader, String field, ShortParser parser)
+      throws IOException {
+    return (short[]) caches.get(Short.TYPE).get(reader, new Entry(field, parser));
   }
 
-  @SuppressWarnings("unchecked")
-  public ShortValues getShorts(IndexReader reader, String field, EntryCreator<ShortValues> creator ) throws IOException 
-  {
-    return (ShortValues)caches.get(Short.TYPE).get(reader, new Entry(field, creator));
+  static final class ShortCache extends Cache {
+    ShortCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+      Entry entry =  entryKey;
+      String field = entry.field;
+      ShortParser parser = (ShortParser) entry.custom;
+      if (parser == null) {
+        return wrapper.getShorts(reader, field, FieldCache.DEFAULT_SHORT_PARSER);
+      }
+      final short[] retArray = new short[reader.maxDoc()];
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        try {
+          while(true) {
+            final BytesRef term = termsEnum.next();
+            if (term == null) {
+              break;
+            }
+            final short termval = parser.parseShort(term);
+            docs = termsEnum.docs(null, docs);
+            while (true) {
+              final int docID = docs.nextDoc();
+              if (docID == DocsEnum.NO_MORE_DOCS) {
+                break;
+              }
+              retArray[docID] = termval;
+            }
+          }
+        } catch (StopFillCacheException stop) {
+        }
+      }
+      return retArray;
+    }
   }
   
   // inherit javadocs
   public int[] getInts (IndexReader reader, String field) throws IOException {
-    return getInts(reader, field, new IntValuesCreator( field, null )).values;
+    return getInts(reader, field, null);
   }
 
   // inherit javadocs
-  public int[] getInts(IndexReader reader, String field, IntParser parser) throws IOException {
-    return getInts(reader, field, new IntValuesCreator( field, parser )).values;
+  public int[] getInts(IndexReader reader, String field, IntParser parser)
+      throws IOException {
+    return (int[]) caches.get(Integer.TYPE).get(reader, new Entry(field, parser));
   }
 
-  @SuppressWarnings("unchecked")
-  public IntValues getInts(IndexReader reader, String field, EntryCreator<IntValues> creator ) throws IOException {
-    return (IntValues)caches.get(Integer.TYPE).get(reader, new Entry(field, creator));
+  static final class IntCache extends Cache {
+    IntCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+      Entry entry = entryKey;
+      String field = entry.field;
+      IntParser parser = (IntParser) entry.custom;
+      if (parser == null) {
+        try {
+          return wrapper.getInts(reader, field, DEFAULT_INT_PARSER);
+        } catch (NumberFormatException ne) {
+          return wrapper.getInts(reader, field, NUMERIC_UTILS_INT_PARSER);      
+        }
+      }
+      int[] retArray = null;
+
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        try {
+          while(true) {
+            final BytesRef term = termsEnum.next();
+            if (term == null) {
+              break;
+            }
+            final int termval = parser.parseInt(term);
+            if (retArray == null) {
+              // late init so numeric fields don't double allocate
+              retArray = new int[reader.maxDoc()];
+            }
+
+            docs = termsEnum.docs(null, docs);
+            while (true) {
+              final int docID = docs.nextDoc();
+              if (docID == DocsEnum.NO_MORE_DOCS) {
+                break;
+              }
+              retArray[docID] = termval;
+            }
+          }
+        } catch (StopFillCacheException stop) {
+        }
+      }
+
+      if (retArray == null) {
+        // no values
+        retArray = new int[reader.maxDoc()];
+      }
+      return retArray;
+    }
   }
   
+  public Bits getDocsWithField(IndexReader reader, String field)
+      throws IOException {
+    return (Bits) caches.get(DocsWithFieldCache.class).get(reader, new Entry(field, null));
+  }
+
+  static final class DocsWithFieldCache extends Cache {
+    DocsWithFieldCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+    
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+    throws IOException {
+      final Entry entry = entryKey;
+      final String field = entry.field;      
+      FixedBitSet res = null;
+      final int maxDoc = reader.maxDoc();
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        // if the field is fully populated, don't bother enumerating
+        if (terms.getDocCount() == maxDoc) {
+          return new Bits.MatchAllBits(maxDoc);
+        }
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        while(true) {
+          final BytesRef term = termsEnum.next();
+          if (term == null) {
+            break;
+          }
+          if (res == null) {
+            // lazy init
+            res = new FixedBitSet(reader.maxDoc());
+          }
+
+          docs = termsEnum.docs(null, docs);
+          // TODO: use bulk API
+          while (true) {
+            final int docID = docs.nextDoc();
+            if (docID == DocsEnum.NO_MORE_DOCS) {
+              break;
+            }
+            res.set(docID);
+          }
+        }
+      }
+      if (res == null) {
+        return new Bits.MatchNoBits(maxDoc);
+      }
+      final int numSet = res.cardinality();
+      if (numSet >= maxDoc) {
+        // The cardinality of the BitSet is maxDoc if all documents have a value.
+        assert numSet == maxDoc;
+        return new Bits.MatchAllBits(maxDoc);
+      }
+      return res;
+    }
+  }
+
   // inherit javadocs
-  public float[] getFloats (IndexReader reader, String field) throws IOException {
-    return getFloats(reader, field, new FloatValuesCreator( field, null ) ).values;
+  public float[] getFloats (IndexReader reader, String field)
+    throws IOException {
+    return getFloats(reader, field, null);
   }
 
   // inherit javadocs
-  public float[] getFloats(IndexReader reader, String field, FloatParser parser) throws IOException {
-    return getFloats(reader, field, new FloatValuesCreator( field, parser ) ).values;
+  public float[] getFloats(IndexReader reader, String field, FloatParser parser)
+    throws IOException {
+
+    return (float[]) caches.get(Float.TYPE).get(reader, new Entry(field, parser));
   }
 
-  @SuppressWarnings("unchecked")
-  public FloatValues getFloats(IndexReader reader, String field, EntryCreator<FloatValues> creator ) throws IOException {
-    return (FloatValues)caches.get(Float.TYPE).get(reader, new Entry(field, creator));
+  static final class FloatCache extends Cache {
+    FloatCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+      Entry entry = entryKey;
+      String field = entry.field;
+      FloatParser parser = (FloatParser) entry.custom;
+      if (parser == null) {
+        try {
+          return wrapper.getFloats(reader, field, DEFAULT_FLOAT_PARSER);
+        } catch (NumberFormatException ne) {
+          return wrapper.getFloats(reader, field, NUMERIC_UTILS_FLOAT_PARSER);      
+        }
+      }
+      float[] retArray = null;
+
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        try {
+          while(true) {
+            final BytesRef term = termsEnum.next();
+            if (term == null) {
+              break;
+            }
+            final float termval = parser.parseFloat(term);
+            if (retArray == null) {
+              // late init so numeric fields don't double allocate
+              retArray = new float[reader.maxDoc()];
+            }
+            
+            docs = termsEnum.docs(null, docs);
+            while (true) {
+              final int docID = docs.nextDoc();
+              if (docID == DocsEnum.NO_MORE_DOCS) {
+                break;
+              }
+              retArray[docID] = termval;
+            }
+          }
+        } catch (StopFillCacheException stop) {
+        }
+      }
+
+      if (retArray == null) {
+        // no values
+        retArray = new float[reader.maxDoc()];
+      }
+      return retArray;
+    }
   }
 
+
   public long[] getLongs(IndexReader reader, String field) throws IOException {
-    return getLongs(reader, field, new LongValuesCreator( field, null ) ).values;
+    return getLongs(reader, field, null);
   }
-
+  
   // inherit javadocs
-  public long[] getLongs(IndexReader reader, String field, FieldCache.LongParser parser) throws IOException {
-    return getLongs(reader, field, new LongValuesCreator( field, parser ) ).values;
+  public long[] getLongs(IndexReader reader, String field, FieldCache.LongParser parser)
+      throws IOException {
+    return (long[]) caches.get(Long.TYPE).get(reader, new Entry(field, parser));
   }
 
-  @SuppressWarnings("unchecked")
-  public LongValues getLongs(IndexReader reader, String field, EntryCreator<LongValues> creator ) throws IOException {
-    return (LongValues)caches.get(Long.TYPE).get(reader, new Entry(field, creator));
+  static final class LongCache extends Cache {
+    LongCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entry)
+        throws IOException {
+      String field = entry.field;
+      FieldCache.LongParser parser = (FieldCache.LongParser) entry.custom;
+      if (parser == null) {
+        try {
+          return wrapper.getLongs(reader, field, DEFAULT_LONG_PARSER);
+        } catch (NumberFormatException ne) {
+          return wrapper.getLongs(reader, field, NUMERIC_UTILS_LONG_PARSER);      
+        }
+      }
+      long[] retArray = null;
+
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        try {
+          while(true) {
+            final BytesRef term = termsEnum.next();
+            if (term == null) {
+              break;
+            }
+            final long termval = parser.parseLong(term);
+            if (retArray == null) {
+              // late init so numeric fields don't double allocate
+              retArray = new long[reader.maxDoc()];
+            }
+
+            docs = termsEnum.docs(null, docs);
+            while (true) {
+              final int docID = docs.nextDoc();
+              if (docID == DocsEnum.NO_MORE_DOCS) {
+                break;
+              }
+              retArray[docID] = termval;
+            }
+          }
+        } catch (StopFillCacheException stop) {
+        }
+      }
+
+      if (retArray == null) {
+        // no values
+        retArray = new long[reader.maxDoc()];
+      }
+      return retArray;
+    }
   }
-  
+
   // inherit javadocs
-  public double[] getDoubles(IndexReader reader, String field) throws IOException {
-    return getDoubles(reader, field, new DoubleValuesCreator( field, null ) ).values;
+  public double[] getDoubles(IndexReader reader, String field)
+    throws IOException {
+    return getDoubles(reader, field, null);
   }
 
   // inherit javadocs
-  public double[] getDoubles(IndexReader reader, String field, FieldCache.DoubleParser parser) throws IOException {
-    return getDoubles(reader, field, new DoubleValuesCreator( field, parser ) ).values;
+  public double[] getDoubles(IndexReader reader, String field, FieldCache.DoubleParser parser)
+      throws IOException {
+    return (double[]) caches.get(Double.TYPE).get(reader, new Entry(field, parser));
   }
 
-  @SuppressWarnings("unchecked")
-  public DoubleValues getDoubles(IndexReader reader, String field, EntryCreator<DoubleValues> creator ) throws IOException {
-    return (DoubleValues)caches.get(Double.TYPE).get(reader, new Entry(field, creator));
+  static final class DoubleCache extends Cache {
+    DoubleCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+      Entry entry = entryKey;
+      String field = entry.field;
+      FieldCache.DoubleParser parser = (FieldCache.DoubleParser) entry.custom;
+      if (parser == null) {
+        try {
+          return wrapper.getDoubles(reader, field, DEFAULT_DOUBLE_PARSER);
+        } catch (NumberFormatException ne) {
+          return wrapper.getDoubles(reader, field, NUMERIC_UTILS_DOUBLE_PARSER);      
+        }
+      }
+      double[] retArray = null;
+
+      Terms terms = MultiFields.getTerms(reader, field);
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        try {
+          while(true) {
+            final BytesRef term = termsEnum.next();
+            if (term == null) {
+              break;
+            }
+            final double termval = parser.parseDouble(term);
+            if (retArray == null) {
+              // late init so numeric fields don't double allocate
+              retArray = new double[reader.maxDoc()];
+            }
+
+            docs = termsEnum.docs(null, docs);
+            while (true) {
+              final int docID = docs.nextDoc();
+              if (docID == DocsEnum.NO_MORE_DOCS) {
+                break;
+              }
+              retArray[docID] = termval;
+            }
+          }
+        } catch (StopFillCacheException stop) {
+        }
+      }
+      if (retArray == null) // no values
+        retArray = new double[reader.maxDoc()];
+      return retArray;
+    }
   }
 
-  public DocTermsIndex getTermsIndex(IndexReader reader, String field) throws IOException {    
-    return getTermsIndex(reader, field, new DocTermsIndexCreator(field));
+  public static class DocTermsIndexImpl extends DocTermsIndex {
+    private final PagedBytes.Reader bytes;
+    private final PackedInts.Reader termOrdToBytesOffset;
+    private final PackedInts.Reader docToTermOrd;
+    private final int numOrd;
+
+    public DocTermsIndexImpl(PagedBytes.Reader bytes, PackedInts.Reader termOrdToBytesOffset, PackedInts.Reader docToTermOrd, int numOrd) {
+      this.bytes = bytes;
+      this.docToTermOrd = docToTermOrd;
+      this.termOrdToBytesOffset = termOrdToBytesOffset;
+      this.numOrd = numOrd;
+    }
+
+    @Override
+    public PackedInts.Reader getDocToOrd() {
+      return docToTermOrd;
+    }
+
+    @Override
+    public int numOrd() {
+      return numOrd;
+    }
+
+    @Override
+    public int getOrd(int docID) {
+      return (int) docToTermOrd.get(docID);
+    }
+
+    @Override
+    public int size() {
+      return docToTermOrd.size();
+    }
+
+    @Override
+    public BytesRef lookup(int ord, BytesRef ret) {
+      return bytes.fill(ret, termOrdToBytesOffset.get(ord));
+    }
+
+    @Override
+    public TermsEnum getTermsEnum() {
+      return this.new DocTermsIndexEnum();
+    }
+
+    class DocTermsIndexEnum extends TermsEnum {
+      int currentOrd;
+      int currentBlockNumber;
+      int end;  // end position in the current block
+      final byte[][] blocks;
+      final int[] blockEnds;
+
+      final BytesRef term = new BytesRef();
+
+      public DocTermsIndexEnum() {
+        currentOrd = 0;
+        currentBlockNumber = 0;
+        blocks = bytes.getBlocks();
+        blockEnds = bytes.getBlockEnds();
+        currentBlockNumber = bytes.fillAndGetIndex(term, termOrdToBytesOffset.get(0));
+        end = blockEnds[currentBlockNumber];
+      }
+
+      @Override
+      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;
+          seekExact(mid);
+          int cmp = term.compareTo(text);
+
+          if (cmp < 0)
+            low = mid + 1;
+          else if (cmp > 0)
+            high = mid - 1;
+          else
+            return SeekStatus.FOUND; // key found
+        }
+        
+        if (low == numOrd) {
+          return SeekStatus.END;
+        } else {
+          seekExact(low);
+          return SeekStatus.NOT_FOUND;
+        }
+      }
+
+      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;
+      }
+
+      @Override
+      public BytesRef next() throws IOException {
+        int start = term.offset + term.length;
+        if (start >= end) {
+          // switch byte blocks
+          if (currentBlockNumber +1 >= blocks.length) {
+            return null;
+          }
+          currentBlockNumber++;
+          term.bytes = blocks[currentBlockNumber];
+          end = blockEnds[currentBlockNumber];
+          start = 0;
+          if (end<=0) return null;  // special case of empty last array
+        }
+
+        currentOrd++;
+
+        byte[] block = term.bytes;
+        if ((block[start] & 128) == 0) {
+          term.length = block[start];
+          term.offset = start+1;
+        } else {
+          term.length = (((block[start] & 0x7f)) << 8) | (block[1+start] & 0xff);
+          term.offset = start+2;
+        }
+
+        return term;
+      }
+
+      @Override
+      public BytesRef term() throws IOException {
+        return term;
+      }
+
+      @Override
+      public long ord() throws IOException {
+        return currentOrd;
+      }
+
+      @Override
+      public int docFreq() {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public long totalTermFreq() {
+        return -1;
+      }
+
+      @Override
+      public DocsEnum docs(Bits liveDocs, DocsEnum reuse) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public DocsAndPositionsEnum docsAndPositions(Bits liveDocs, DocsAndPositionsEnum reuse) throws IOException {
+        throw new UnsupportedOperationException();
+      }
+
+      @Override
+      public Comparator<BytesRef> getComparator() throws IOException {
+        return BytesRef.getUTF8SortedAsUnicodeComparator();
+      }
+
+      @Override
+      public void seekExact(BytesRef term, TermState state) throws IOException {
+        assert state != null && state instanceof OrdTermState;
+        this.seekExact(((OrdTermState)state).ord);
+      }
+
+      @Override
+      public TermState termState() throws IOException {
+        OrdTermState state = new OrdTermState();
+        state.ord = currentOrd;
+        return state;
+      }
+    }
   }
 
-  public DocTermsIndex getTermsIndex(IndexReader reader, String field, boolean fasterButMoreRAM) throws IOException {    
-    return getTermsIndex(reader, field, new DocTermsIndexCreator(field, 
-        fasterButMoreRAM ? DocTermsIndexCreator.FASTER_BUT_MORE_RAM : 0));
+  private static boolean DEFAULT_FASTER_BUT_MORE_RAM = true;
+
+  public DocTermsIndex getTermsIndex(IndexReader reader, String field) throws IOException {
+    return getTermsIndex(reader, field, DEFAULT_FASTER_BUT_MORE_RAM);
   }
 
-  @SuppressWarnings("unchecked")
-  public DocTermsIndex getTermsIndex(IndexReader reader, String field, EntryCreator<DocTermsIndex> creator) throws IOException {
-    return (DocTermsIndex)caches.get(DocTermsIndex.class).get(reader, new Entry(field, creator));
+  public DocTermsIndex getTermsIndex(IndexReader reader, String field, boolean fasterButMoreRAM) throws IOException {
+    return (DocTermsIndex) caches.get(DocTermsIndex.class).get(reader, new Entry(field, Boolean.valueOf(fasterButMoreRAM)));
   }
 
+  static class DocTermsIndexCache extends Cache {
+    DocTermsIndexCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+
+      Terms terms = MultiFields.getTerms(reader, entryKey.field);
+
+      final boolean fasterButMoreRAM = ((Boolean) entryKey.custom).booleanValue();
+
+      final PagedBytes bytes = new PagedBytes(15);
+
+      int startBytesBPV;
+      int startTermsBPV;
+      int startNumUniqueTerms;
+
+      int maxDoc = reader.maxDoc();
+      final int termCountHardLimit;
+      if (maxDoc == Integer.MAX_VALUE) {
+        termCountHardLimit = Integer.MAX_VALUE;
+      } else {
+        termCountHardLimit = maxDoc+1;
+      }
+
+      if (terms != null) {
+        // Try for coarse estimate for number of bits; this
+        // should be an underestimate most of the time, which
+        // is fine -- GrowableWriter will reallocate as needed
+        long numUniqueTerms = 0;
+        try {
+          numUniqueTerms = terms.getUniqueTermCount();
+        } catch (UnsupportedOperationException uoe) {
+          numUniqueTerms = -1;
+        }
+        if (numUniqueTerms != -1) {
+
+          if (numUniqueTerms > termCountHardLimit) {
+            // app is misusing the API (there is more than
+            // one term per doc); in this case we make best
+            // effort to load what we can (see LUCENE-2142)
+            numUniqueTerms = termCountHardLimit;
+          }
+
+          startBytesBPV = PackedInts.bitsRequired(numUniqueTerms*4);
+          startTermsBPV = PackedInts.bitsRequired(numUniqueTerms);
+
+          startNumUniqueTerms = (int) numUniqueTerms;
+        } else {
+          startBytesBPV = 1;
+          startTermsBPV = 1;
+          startNumUniqueTerms = 1;
+        }
+      } else {
+        startBytesBPV = 1;
+        startTermsBPV = 1;
+        startNumUniqueTerms = 1;
+      }
+
+      GrowableWriter termOrdToBytesOffset = new GrowableWriter(startBytesBPV, 1+startNumUniqueTerms, fasterButMoreRAM);
+      final GrowableWriter docToTermOrd = new GrowableWriter(startTermsBPV, reader.maxDoc(), fasterButMoreRAM);
+
+      // 0 is reserved for "unset"
+      bytes.copyUsingLengthPrefix(new BytesRef());
+      int termOrd = 1;
+
+      if (terms != null) {
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+
+        while(true) {
+          final BytesRef term = termsEnum.next();
+          if (term == null) {
+            break;
+          }
+          if (termOrd >= termCountHardLimit) {
+            break;
+          }
+
+          if (termOrd == termOrdToBytesOffset.size()) {
+            // NOTE: this code only runs if the incoming
+            // reader impl doesn't implement
+            // getUniqueTermCount (which should be uncommon)
+            termOrdToBytesOffset = termOrdToBytesOffset.resize(ArrayUtil.oversize(1+termOrd, 1));
+          }
+          termOrdToBytesOffset.set(termOrd, bytes.copyUsingLengthPrefix(term));
+          docs = termsEnum.docs(null, docs);
+          while (true) {
+            final int docID = docs.nextDoc();
+            if (docID == DocsEnum.NO_MORE_DOCS) {
+              break;
+            }
+            docToTermOrd.set(docID, termOrd);
+          }
+          termOrd++;
+        }
+
+        if (termOrdToBytesOffset.size() > termOrd) {
+          termOrdToBytesOffset = termOrdToBytesOffset.resize(termOrd);
+        }
+      }
+
+      // maybe an int-only impl?
+      return new DocTermsIndexImpl(bytes.freeze(true), termOrdToBytesOffset.getMutable(), docToTermOrd.getMutable(), termOrd);
+    }
+  }
+
+  private static class DocTermsImpl extends DocTerms {
+    private final PagedBytes.Reader bytes;
+    private final PackedInts.Reader docToOffset;
+
+    public DocTermsImpl(PagedBytes.Reader bytes, PackedInts.Reader docToOffset) {
+      this.bytes = bytes;
+      this.docToOffset = docToOffset;
+    }
+
+    @Override
+    public int size() {
+      return docToOffset.size();
+    }
+
+    @Override
+    public boolean exists(int docID) {
+      return docToOffset.get(docID) == 0;
+    }
+
+    @Override
+    public BytesRef getTerm(int docID, BytesRef ret) {
+      final int pointer = (int) docToOffset.get(docID);
+      return bytes.fill(ret, pointer);
+    }      
+  }
+
   // TODO: this if DocTermsIndex was already created, we
   // should share it...
   public DocTerms getTerms(IndexReader reader, String field) throws IOException {
-    return getTerms(reader, field, new DocTermsCreator(field));
+    return getTerms(reader, field, DEFAULT_FASTER_BUT_MORE_RAM);
   }
 
   public DocTerms getTerms(IndexReader reader, String field, boolean fasterButMoreRAM) throws IOException {
-    return getTerms(reader, field, new DocTermsCreator(field,
-        fasterButMoreRAM ? DocTermsCreator.FASTER_BUT_MORE_RAM : 0));
+    return (DocTerms) caches.get(DocTerms.class).get(reader, new Entry(field, Boolean.valueOf(fasterButMoreRAM)));
   }
 
-  @SuppressWarnings("unchecked")
-  public DocTerms getTerms(IndexReader reader, String field, EntryCreator<DocTerms> creator) throws IOException {
-    return (DocTerms)caches.get(DocTerms.class).get(reader, new Entry(field, creator));
+  static final class DocTermsCache extends Cache {
+    DocTermsCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+
+      Terms terms = MultiFields.getTerms(reader, entryKey.field);
+
+      final boolean fasterButMoreRAM = ((Boolean) entryKey.custom).booleanValue();
+
+      final int termCountHardLimit = reader.maxDoc();
+
+      // Holds the actual term data, expanded.
+      final PagedBytes bytes = new PagedBytes(15);
+
+      int startBPV;
+
+      if (terms != null) {
+        // Try for coarse estimate for number of bits; this
+        // should be an underestimate most of the time, which
+        // is fine -- GrowableWriter will reallocate as needed
+        long numUniqueTerms = 0;
+        try {
+          numUniqueTerms = terms.getUniqueTermCount();
+        } catch (UnsupportedOperationException uoe) {
+          numUniqueTerms = -1;
+        }
+        if (numUniqueTerms != -1) {
+          if (numUniqueTerms > termCountHardLimit) {
+            numUniqueTerms = termCountHardLimit;
+          }
+          startBPV = PackedInts.bitsRequired(numUniqueTerms*4);
+        } else {
+          startBPV = 1;
+        }
+      } else {
+        startBPV = 1;
+      }
+
+      final GrowableWriter docToOffset = new GrowableWriter(startBPV, reader.maxDoc(), fasterButMoreRAM);
+      
+      // pointer==0 means not set
+      bytes.copyUsingLengthPrefix(new BytesRef());
+
+      if (terms != null) {
+        int termCount = 0;
+        final TermsEnum termsEnum = terms.iterator();
+        DocsEnum docs = null;
+        while(true) {
+          if (termCount++ == termCountHardLimit) {
+            // app is misusing the API (there is more than
+            // one term per doc); in this case we make best
+            // effort to load what we can (see LUCENE-2142)
+            break;
+          }
+
+          final BytesRef term = termsEnum.next();
+          if (term == null) {
+            break;
+          }
+          final long pointer = bytes.copyUsingLengthPrefix(term);
+          docs = termsEnum.docs(null, docs);
+          while (true) {
+            final int docID = docs.nextDoc();
+            if (docID == DocsEnum.NO_MORE_DOCS) {
+              break;
+            }
+            docToOffset.set(docID, pointer);
+          }
+        }
+      }
+
+      // maybe an int-only impl?
+      return new DocTermsImpl(bytes.freeze(true), docToOffset.getMutable());
+    }
   }
 
-  @SuppressWarnings("unchecked")
   public DocTermOrds getDocTermOrds(IndexReader reader, String field) throws IOException {
-    return (DocTermOrds) caches.get(DocTermOrds.class).get(reader, new Entry(field, new DocTermOrdsCreator(field, 0)));
+    return (DocTermOrds) caches.get(DocTermOrds.class).get(reader, new Entry(field, null));
   }
 
+  static final class DocTermOrdsCache extends Cache {
+    DocTermOrdsCache(FieldCache wrapper) {
+      super(wrapper);
+    }
+
+    @Override
+    protected Object createValue(IndexReader reader, Entry entryKey)
+        throws IOException {
+      return new DocTermOrds(reader, entryKey.field);
+    }
+  }
+
   private volatile PrintStream infoStream;
 
   public void setInfoStream(PrintStream stream) {
Index: lucene/src/java/org/apache/lucene/util/FieldCacheSanityChecker.java
===================================================================
--- lucene/src/java/org/apache/lucene/util/FieldCacheSanityChecker.java	(revision 1199574)
+++ lucene/src/java/org/apache/lucene/util/FieldCacheSanityChecker.java	(working copy)
@@ -119,6 +119,13 @@
       final CacheEntry item = cacheEntries[i];
       final Object val = item.getValue();
 
+      // It's OK to have dup entries, where one is eg
+      // float[] and the other is the Bits (from
+      // getDocWithField())
+      if (val instanceof Bits) {
+        continue;
+      }
+
       if (val instanceof FieldCache.CreationPlaceholder)
         continue;
 
@@ -208,7 +215,7 @@
       
       if (seen.contains(rf)) continue;
 
-      List<Object> kids = getAllDescendentReaderKeys(rf.readerKey);
+      List<Object> kids = getAllDescendantReaderKeys(rf.readerKey);
       for (Object kidKey : kids) {
         ReaderField kid = new ReaderField(kidKey, rf.fieldName);
         
@@ -266,7 +273,7 @@
    * the hierarchy of subReaders building up a list of the objects 
    * returned by obj.getFieldCacheKey()
    */
-  private List<Object> getAllDescendentReaderKeys(Object seed) {
+  private List<Object> getAllDescendantReaderKeys(Object seed) {
     List<Object> all = new ArrayList<Object>(17); // will grow as we iter
     all.add(seed);
     for (int i = 0; i < all.size(); i++) {
