You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2014/06/05 21:34:23 UTC

svn commit: r1600741 [1/3] - in /lucene/dev/branches/branch_4x: ./ lucene/ lucene/codecs/ lucene/codecs/src/java/org/apache/lucene/codecs/memory/ lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/ lucene/core/ lucene/core/src/java/org/apache/l...

Author: rmuir
Date: Thu Jun  5 19:34:21 2014
New Revision: 1600741

URL: http://svn.apache.org/r1600741
Log:
LUCENE-5703: BinaryDocValues producers don't allocate or copy bytes on each access anymore

Modified:
    lucene/dev/branches/branch_4x/   (props changed)
    lucene/dev/branches/branch_4x/lucene/   (props changed)
    lucene/dev/branches/branch_4x/lucene/CHANGES.txt   (contents, props changed)
    lucene/dev/branches/branch_4x/lucene/codecs/   (props changed)
    lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/DirectDocValuesProducer.java
    lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesProducer.java
    lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextDocValuesReader.java
    lucene/dev/branches/branch_4x/lucene/core/   (props changed)
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/DocValuesConsumer.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40DocValuesReader.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesProducer.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesProducer.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene49/Lucene49DocValuesProducer.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/BinaryDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocTermOrds.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/MultiDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/ReadersAndUpdates.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SingletonSortedSetDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SlowCompositeReaderWrapper.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedSetDocValuesTermsEnum.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/search/FieldCacheImpl.java
    lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/search/FieldComparator.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/codecs/perfield/TestPerFieldDocValuesFormat.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/Test2BBinaryDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/Test2BSortedDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestBackwardsCompatibility.java   (contents, props changed)
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestBackwardsCompatibility3x.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestBinaryDocValuesUpdates.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestDocValuesIndexing.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestDocValuesWithThreads.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestIndexWriter.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestMixedDocValuesUpdates.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestMultiDocValues.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/index/TestNumericDocValuesUpdates.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/search/TestElevationComparator.java
    lucene/dev/branches/branch_4x/lucene/core/src/test/org/apache/lucene/search/TestFieldCache.java
    lucene/dev/branches/branch_4x/lucene/facet/   (props changed)
    lucene/dev/branches/branch_4x/lucene/facet/src/java/org/apache/lucene/facet/sortedset/DefaultSortedSetDocValuesReaderState.java
    lucene/dev/branches/branch_4x/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesFacetCounts.java
    lucene/dev/branches/branch_4x/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/DocValuesOrdinalsReader.java
    lucene/dev/branches/branch_4x/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/FastTaxonomyFacetCounts.java
    lucene/dev/branches/branch_4x/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetSumFloatAssociations.java
    lucene/dev/branches/branch_4x/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetSumIntAssociations.java
    lucene/dev/branches/branch_4x/lucene/grouping/   (props changed)
    lucene/dev/branches/branch_4x/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermAllGroupHeadsCollector.java
    lucene/dev/branches/branch_4x/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermAllGroupsCollector.java
    lucene/dev/branches/branch_4x/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermDistinctValuesCollector.java
    lucene/dev/branches/branch_4x/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermFirstPassGroupingCollector.java
    lucene/dev/branches/branch_4x/lucene/grouping/src/java/org/apache/lucene/search/grouping/term/TermGroupFacetCollector.java
    lucene/dev/branches/branch_4x/lucene/join/   (props changed)
    lucene/dev/branches/branch_4x/lucene/join/src/java/org/apache/lucene/search/join/TermsCollector.java
    lucene/dev/branches/branch_4x/lucene/join/src/java/org/apache/lucene/search/join/TermsWithScoreCollector.java
    lucene/dev/branches/branch_4x/lucene/join/src/test/org/apache/lucene/search/join/TestJoinUtil.java
    lucene/dev/branches/branch_4x/lucene/misc/   (props changed)
    lucene/dev/branches/branch_4x/lucene/misc/src/java/org/apache/lucene/index/sorter/SortingAtomicReader.java
    lucene/dev/branches/branch_4x/lucene/misc/src/test/org/apache/lucene/index/sorter/SorterTestBase.java
    lucene/dev/branches/branch_4x/lucene/queries/   (props changed)
    lucene/dev/branches/branch_4x/lucene/queries/src/java/org/apache/lucene/queries/function/docvalues/DocTermsIndexDocValues.java
    lucene/dev/branches/branch_4x/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/BytesRefFieldSource.java
    lucene/dev/branches/branch_4x/lucene/queries/src/java/org/apache/lucene/queries/function/valuesource/JoinDocFreqValueSource.java
    lucene/dev/branches/branch_4x/lucene/sandbox/   (props changed)
    lucene/dev/branches/branch_4x/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/SlowCollatedStringComparator.java
    lucene/dev/branches/branch_4x/lucene/sandbox/src/java/org/apache/lucene/sandbox/queries/SortedSetSortField.java
    lucene/dev/branches/branch_4x/lucene/spatial/   (props changed)
    lucene/dev/branches/branch_4x/lucene/spatial/src/java/org/apache/lucene/spatial/serialized/SerializedDVStrategy.java
    lucene/dev/branches/branch_4x/lucene/suggest/   (props changed)
    lucene/dev/branches/branch_4x/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingInfixSuggester.java
    lucene/dev/branches/branch_4x/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/BlendedInfixSuggester.java
    lucene/dev/branches/branch_4x/lucene/test-framework/   (props changed)
    lucene/dev/branches/branch_4x/lucene/test-framework/src/java/org/apache/lucene/index/AssertingAtomicReader.java
    lucene/dev/branches/branch_4x/lucene/test-framework/src/java/org/apache/lucene/index/BaseDocValuesFormatTestCase.java
    lucene/dev/branches/branch_4x/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java
    lucene/dev/branches/branch_4x/solr/   (props changed)
    lucene/dev/branches/branch_4x/solr/core/   (props changed)
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/handler/component/FieldFacetStats.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/request/DocValuesFacets.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/request/SimpleFacets.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/BoolField.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/DateField.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/SortableDoubleField.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/SortableFloatField.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/SortableIntField.java
    lucene/dev/branches/branch_4x/solr/core/src/java/org/apache/solr/schema/SortableLongField.java

Modified: lucene/dev/branches/branch_4x/lucene/CHANGES.txt
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/CHANGES.txt?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/CHANGES.txt (original)
+++ lucene/dev/branches/branch_4x/lucene/CHANGES.txt Thu Jun  5 19:34:21 2014
@@ -114,6 +114,10 @@ API Changes
   removed, because buffering and checksumming is provided by FilterOutputStreams,
   provided by the JDK.  (Uwe Schindler, Mike McCandless)
 
+* LUCENE-5703: BinaryDocValues API changed to work like TermsEnum and not allocate/
+  copy bytes on each access, you are responsible for cloning if you want to keep
+  data around. (Adrien Grand)
+
 Optimizations
 
 * LUCENE-5603: hunspell stemmer more efficiently strips prefixes
@@ -156,6 +160,9 @@ Optimizations
 * LUCENE-5730: FSDirectory.open returns MMapDirectory for 64-bit operating
   systems, not just Linux and Windows. (Robert Muir)
 
+* LUCENE-5703: BinaryDocValues producers don't allocate or copy bytes on 
+  each access anymore.  (Adrien Grand)
+
 Bug fixes
 
 * LUCENE-5673: MMapDirectory: Work around a "bug" in the JDK that throws

Modified: lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/DirectDocValuesProducer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/DirectDocValuesProducer.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/DirectDocValuesProducer.java (original)
+++ lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/DirectDocValuesProducer.java Thu Jun  5 19:34:21 2014
@@ -57,9 +57,9 @@ class DirectDocValuesProducer extends Do
   // ram instances we have already loaded
   private final Map<Integer,NumericDocValues> numericInstances = 
       new HashMap<>();
-  private final Map<Integer,BinaryDocValues> binaryInstances =
+  private final Map<Integer,BinaryRawValues> binaryInstances =
       new HashMap<>();
-  private final Map<Integer,SortedDocValues> sortedInstances =
+  private final Map<Integer,SortedRawValues> sortedInstances =
       new HashMap<>();
   private final Map<Integer,SortedSetRawValues> sortedSetInstances =
       new HashMap<>();
@@ -178,9 +178,13 @@ class DirectDocValuesProducer extends Do
       } else if (fieldType == BYTES) {
         binaries.put(fieldNumber, readBinaryEntry(meta));
       } else if (fieldType == SORTED) {
-        sorteds.put(fieldNumber, readSortedEntry(meta));
+        SortedEntry entry = readSortedEntry(meta);
+        sorteds.put(fieldNumber, entry);
+        binaries.put(fieldNumber, entry.values);
       } else if (fieldType == SORTED_SET) {
-        sortedSets.put(fieldNumber, readSortedSetEntry(meta));
+        SortedSetEntry entry = readSortedSetEntry(meta);
+        sortedSets.put(fieldNumber, entry);
+        binaries.put(fieldNumber, entry.values);
       } else {
         throw new CorruptIndexException("invalid entry type: " + fieldType + ", input=" + meta);
       }
@@ -279,16 +283,29 @@ class DirectDocValuesProducer extends Do
 
   @Override
   public synchronized BinaryDocValues getBinary(FieldInfo field) throws IOException {
-    BinaryDocValues instance = binaryInstances.get(field.number);
+    BinaryRawValues instance = binaryInstances.get(field.number);
     if (instance == null) {
       // Lazy load
       instance = loadBinary(binaries.get(field.number));
       binaryInstances.put(field.number, instance);
     }
-    return instance;
+    final byte[] bytes = instance.bytes;
+    final int[] address = instance.address;
+
+    return new BinaryDocValues() {
+      final BytesRef term = new BytesRef();
+
+      @Override
+      public BytesRef get(int docID) {
+        term.bytes = bytes;
+        term.offset = address[docID];
+        term.length = address[docID+1] - term.offset;
+        return term;
+      }
+    };
   }
   
-  private BinaryDocValues loadBinary(BinaryEntry entry) throws IOException {
+  private BinaryRawValues loadBinary(BinaryEntry entry) throws IOException {
     data.seek(entry.offset);
     final byte[] bytes = new byte[entry.numBytes];
     data.readBytes(bytes, 0, entry.numBytes);
@@ -302,31 +319,26 @@ class DirectDocValuesProducer extends Do
 
     ramBytesUsed.addAndGet(RamUsageEstimator.sizeOf(bytes) + RamUsageEstimator.sizeOf(address));
 
-    return new BinaryDocValues() {
-      @Override
-      public void get(int docID, BytesRef result) {
-        result.bytes = bytes;
-        result.offset = address[docID];
-        result.length = address[docID+1] - result.offset;
-      };
-    };
+    BinaryRawValues values = new BinaryRawValues();
+    values.bytes = bytes;
+    values.address = address;
+    return values;
   }
   
   @Override
-  public synchronized SortedDocValues getSorted(FieldInfo field) throws IOException {
-    SortedDocValues instance = sortedInstances.get(field.number);
-    if (instance == null) {
-      // Lazy load
-      instance = loadSorted(field);
-      sortedInstances.put(field.number, instance);
-    }
-    return instance;
-  }
-
-  private SortedDocValues loadSorted(FieldInfo field) throws IOException {
+  public SortedDocValues getSorted(FieldInfo field) throws IOException {
     final SortedEntry entry = sorteds.get(field.number);
-    final NumericDocValues docToOrd = loadNumeric(entry.docToOrd);
-    final BinaryDocValues values = loadBinary(entry.values);
+    SortedRawValues instance;
+    synchronized (this) {
+      instance = sortedInstances.get(field.number);
+      if (instance == null) {
+        // Lazy load
+        instance = loadSorted(field);
+        sortedInstances.put(field.number, instance);
+      }
+    }
+    final NumericDocValues docToOrd = instance.docToOrd;
+    final BinaryDocValues values = getBinary(field);
 
     return new SortedDocValues() {
 
@@ -336,8 +348,8 @@ class DirectDocValuesProducer extends Do
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
-        values.get(ord, result);
+      public BytesRef lookupOrd(int ord) {
+        return values.get(ord);
       }
 
       @Override
@@ -351,6 +363,14 @@ class DirectDocValuesProducer extends Do
     };
   }
 
+  private SortedRawValues loadSorted(FieldInfo field) throws IOException {
+    final SortedEntry entry = sorteds.get(field.number);
+    final NumericDocValues docToOrd = loadNumeric(entry.docToOrd);
+    final SortedRawValues values = new SortedRawValues();
+    values.docToOrd = docToOrd;
+    return values;
+  }
+
   @Override
   public synchronized SortedSetDocValues getSortedSet(FieldInfo field) throws IOException {
     SortedSetRawValues instance = sortedSetInstances.get(field.number);
@@ -363,7 +383,7 @@ class DirectDocValuesProducer extends Do
 
     final NumericDocValues docToOrdAddress = instance.docToOrdAddress;
     final NumericDocValues ords = instance.ords;
-    final BinaryDocValues values = instance.values;
+    final BinaryDocValues values = getBinary(field);
 
     // Must make a new instance since the iterator has state:
     return new RandomAccessOrds() {
@@ -387,8 +407,8 @@ class DirectDocValuesProducer extends Do
       }
 
       @Override
-      public void lookupOrd(long ord, BytesRef result) {
-        values.get((int) ord, result);
+      public BytesRef lookupOrd(long ord) {
+        return values.get((int) ord);
       }
 
       @Override
@@ -416,7 +436,6 @@ class DirectDocValuesProducer extends Do
     SortedSetRawValues instance = new SortedSetRawValues();
     instance.docToOrdAddress = loadNumeric(entry.docToOrdAddress);
     instance.ords = loadNumeric(entry.ords);
-    instance.values = loadBinary(entry.values);
     return instance;
   }
 
@@ -465,11 +484,19 @@ class DirectDocValuesProducer extends Do
   public void close() throws IOException {
     data.close();
   }
-  
+
+  static class BinaryRawValues {
+    byte[] bytes;
+    int[] address;
+  }
+
+  static class SortedRawValues {
+    NumericDocValues docToOrd;
+  }
+
   static class SortedSetRawValues {
     NumericDocValues docToOrdAddress;
     NumericDocValues ords;
-    BinaryDocValues values;
   }
 
   static class NumericEntry {

Modified: lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesProducer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesProducer.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesProducer.java (original)
+++ lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/memory/MemoryDocValuesProducer.java Thu Jun  5 19:34:21 2014
@@ -72,7 +72,7 @@ class MemoryDocValuesProducer extends Do
   // ram instances we have already loaded
   private final Map<Integer,NumericDocValues> numericInstances = 
       new HashMap<>();
-  private final Map<Integer,BinaryDocValues> binaryInstances =
+  private final Map<Integer,BytesAndAddresses> pagedBytesInstances =
       new HashMap<>();
   private final Map<Integer,FST<Long>> fstInstances =
       new HashMap<>();
@@ -280,50 +280,68 @@ class MemoryDocValuesProducer extends Do
   }
 
   @Override
-  public synchronized BinaryDocValues getBinary(FieldInfo field) throws IOException {
-    BinaryDocValues instance = binaryInstances.get(field.number);
-    if (instance == null) {
-      instance = loadBinary(field);
-      binaryInstances.put(field.number, instance);
-    }
-    return instance;
-  }
-  
-  private BinaryDocValues loadBinary(FieldInfo field) throws IOException {
+  public BinaryDocValues getBinary(FieldInfo field) throws IOException {
     BinaryEntry entry = binaries.get(field.number);
-    data.seek(entry.offset);
-    PagedBytes bytes = new PagedBytes(16);
-    bytes.copy(data, entry.numBytes);
-    final PagedBytes.Reader bytesReader = bytes.freeze(true);
-    if (entry.minLength == entry.maxLength) {
+
+    BytesAndAddresses instance;
+    synchronized (this) {
+      instance = pagedBytesInstances.get(field.number);
+      if (instance == null) {
+        instance = loadBinary(field);
+        pagedBytesInstances.put(field.number, instance);
+      }
+    }
+    final PagedBytes.Reader bytesReader = instance.reader;
+    final MonotonicBlockPackedReader addresses = instance.addresses;
+
+    if (addresses == null) {
+      assert entry.minLength == entry.maxLength;
       final int fixedLength = entry.minLength;
-      ramBytesUsed.addAndGet(bytes.ramBytesUsed());
       return new BinaryDocValues() {
+        final BytesRef term = new BytesRef();
+
         @Override
-        public void get(int docID, BytesRef result) {
-          bytesReader.fillSlice(result, fixedLength * (long)docID, fixedLength);
+        public BytesRef get(int docID) {
+          bytesReader.fillSlice(term, fixedLength * (long)docID, fixedLength);
+          return term;
         }
       };
     } else {
-      data.seek(data.getFilePointer() + entry.missingBytes);
-      final MonotonicBlockPackedReader addresses = new MonotonicBlockPackedReader(data, entry.packedIntsVersion, entry.blockSize, maxDoc, false);
-      ramBytesUsed.addAndGet(bytes.ramBytesUsed() + addresses.ramBytesUsed());
       return new BinaryDocValues() {
+        final BytesRef term = new BytesRef();
+
         @Override
-        public void get(int docID, BytesRef result) {
+        public BytesRef get(int docID) {
           long startAddress = docID == 0 ? 0 : addresses.get(docID-1);
-          long endAddress = addresses.get(docID); 
-          bytesReader.fillSlice(result, startAddress, (int) (endAddress - startAddress));
+          long endAddress = addresses.get(docID);
+          bytesReader.fillSlice(term, startAddress, (int) (endAddress - startAddress));
+          return term;
         }
       };
     }
   }
   
+  private BytesAndAddresses loadBinary(FieldInfo field) throws IOException {
+    BytesAndAddresses bytesAndAddresses = new BytesAndAddresses();
+    BinaryEntry entry = binaries.get(field.number);
+    data.seek(entry.offset);
+    PagedBytes bytes = new PagedBytes(16);
+    bytes.copy(data, entry.numBytes);
+    bytesAndAddresses.reader = bytes.freeze(true);
+    ramBytesUsed.addAndGet(bytesAndAddresses.reader.ramBytesUsed());
+    if (entry.minLength != entry.maxLength) {
+      data.seek(data.getFilePointer() + entry.missingBytes);
+      bytesAndAddresses.addresses = new MonotonicBlockPackedReader(data, entry.packedIntsVersion, entry.blockSize, maxDoc, false);
+      ramBytesUsed.addAndGet(bytesAndAddresses.addresses.ramBytesUsed());
+    }
+    return bytesAndAddresses;
+  }
+  
   @Override
   public SortedDocValues getSorted(FieldInfo field) throws IOException {
     final FSTEntry entry = fsts.get(field.number);
     if (entry.numOrds == 0) {
-      return DocValues.EMPTY_SORTED;
+      return DocValues.emptySorted();
     }
     FST<Long> instance;
     synchronized(this) {
@@ -346,21 +364,21 @@ class MemoryDocValuesProducer extends Do
     final BytesRefFSTEnum<Long> fstEnum = new BytesRefFSTEnum<>(fst);
     
     return new SortedDocValues() {
+      final BytesRef term = new BytesRef();
+
       @Override
       public int getOrd(int docID) {
         return (int) docToOrd.get(docID);
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
+      public BytesRef lookupOrd(int ord) {
         try {
           in.setPosition(0);
           fst.getFirstArc(firstArc);
           IntsRef output = Util.getByOutput(fst, ord, in, firstArc, scratchArc, scratchInts);
-          result.bytes = new byte[output.length];
-          result.offset = 0;
-          result.length = 0;
-          Util.toBytesRef(output, result);
+          Util.toBytesRef(output, term);
+          return term;
         } catch (IOException bogus) {
           throw new RuntimeException(bogus);
         }
@@ -398,7 +416,7 @@ class MemoryDocValuesProducer extends Do
   public SortedSetDocValues getSortedSet(FieldInfo field) throws IOException {
     final FSTEntry entry = fsts.get(field.number);
     if (entry.numOrds == 0) {
-      return DocValues.EMPTY_SORTED_SET; // empty FST!
+      return DocValues.emptySortedSet(); // empty FST!
     }
     FST<Long> instance;
     synchronized(this) {
@@ -419,9 +437,10 @@ class MemoryDocValuesProducer extends Do
     final Arc<Long> scratchArc = new Arc<>();
     final IntsRef scratchInts = new IntsRef();
     final BytesRefFSTEnum<Long> fstEnum = new BytesRefFSTEnum<>(fst);
-    final BytesRef ref = new BytesRef();
     final ByteArrayDataInput input = new ByteArrayDataInput();
     return new SortedSetDocValues() {
+      final BytesRef term = new BytesRef();
+      BytesRef ref;
       long currentOrd;
 
       @Override
@@ -436,21 +455,19 @@ class MemoryDocValuesProducer extends Do
       
       @Override
       public void setDocument(int docID) {
-        docToOrds.get(docID, ref);
+        ref = docToOrds.get(docID);
         input.reset(ref.bytes, ref.offset, ref.length);
         currentOrd = 0;
       }
 
       @Override
-      public void lookupOrd(long ord, BytesRef result) {
+      public BytesRef lookupOrd(long ord) {
         try {
           in.setPosition(0);
           fst.getFirstArc(firstArc);
           IntsRef output = Util.getByOutput(fst, ord, in, firstArc, scratchArc, scratchInts);
-          result.bytes = new byte[output.length];
-          result.offset = 0;
-          result.length = 0;
-          Util.toBytesRef(output, result);
+          Util.toBytesRef(output, term);
+          return term;
         } catch (IOException bogus) {
           throw new RuntimeException(bogus);
         }
@@ -553,7 +570,12 @@ class MemoryDocValuesProducer extends Do
     long offset;
     long numOrds;
   }
-  
+
+  static class BytesAndAddresses {
+    PagedBytes.Reader reader;
+    MonotonicBlockPackedReader addresses;
+  }
+
   // exposes FSTEnum directly as a TermsEnum: avoids binary-search next()
   static class FSTTermsEnum extends TermsEnum {
     final BytesRefFSTEnum<Long> in;

Modified: lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextDocValuesReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextDocValuesReader.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextDocValuesReader.java (original)
+++ lucene/dev/branches/branch_4x/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextDocValuesReader.java Thu Jun  5 19:34:21 2014
@@ -216,8 +216,10 @@ class SimpleTextDocValuesReader extends 
     final DecimalFormat decoder = new DecimalFormat(field.pattern, new DecimalFormatSymbols(Locale.ROOT));
 
     return new BinaryDocValues() {
+      final BytesRef term = new BytesRef();
+
       @Override
-      public void get(int docID, BytesRef result) {
+      public BytesRef get(int docID) {
         try {
           if (docID < 0 || docID >= maxDoc) {
             throw new IndexOutOfBoundsException("docID must be 0 .. " + (maxDoc-1) + "; got " + docID);
@@ -231,10 +233,11 @@ class SimpleTextDocValuesReader extends 
           } catch (ParseException pe) {
             throw new CorruptIndexException("failed to parse int length (resource=" + in + ")", pe);
           }
-          result.bytes = new byte[len];
-          result.offset = 0;
-          result.length = len;
-          in.readBytes(result.bytes, 0, len);
+          term.grow(len);
+          term.offset = 0;
+          term.length = len;
+          in.readBytes(term.bytes, 0, len);
+          return term;
         } catch (IOException ioe) {
           throw new RuntimeException(ioe);
         }
@@ -293,6 +296,8 @@ class SimpleTextDocValuesReader extends 
     final DecimalFormat ordDecoder = new DecimalFormat(field.ordPattern, new DecimalFormatSymbols(Locale.ROOT));
 
     return new SortedDocValues() {
+      final BytesRef term = new BytesRef();
+
       @Override
       public int getOrd(int docID) {
         if (docID < 0 || docID >= maxDoc) {
@@ -312,7 +317,7 @@ class SimpleTextDocValuesReader extends 
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
+      public BytesRef lookupOrd(int ord) {
         try {
           if (ord < 0 || ord >= field.numValues) {
             throw new IndexOutOfBoundsException("ord must be 0 .. " + (field.numValues-1) + "; got " + ord);
@@ -326,10 +331,11 @@ class SimpleTextDocValuesReader extends 
           } catch (ParseException pe) {
             throw new CorruptIndexException("failed to parse int length (resource=" + in + ")", pe);
           }
-          result.bytes = new byte[len];
-          result.offset = 0;
-          result.length = len;
-          in.readBytes(result.bytes, 0, len);
+          term.grow(len);
+          term.offset = 0;
+          term.length = len;
+          in.readBytes(term.bytes, 0, len);
+          return term;
         } catch (IOException ioe) {
           throw new RuntimeException(ioe);
         }
@@ -357,6 +363,7 @@ class SimpleTextDocValuesReader extends 
     return new SortedSetDocValues() {
       String[] currentOrds = new String[0];
       int currentIndex = 0;
+      final BytesRef term = new BytesRef();
       
       @Override
       public long nextOrd() {
@@ -388,7 +395,7 @@ class SimpleTextDocValuesReader extends 
       }
 
       @Override
-      public void lookupOrd(long ord, BytesRef result) {
+      public BytesRef lookupOrd(long ord) {
         try {
           if (ord < 0 || ord >= field.numValues) {
             throw new IndexOutOfBoundsException("ord must be 0 .. " + (field.numValues-1) + "; got " + ord);
@@ -402,10 +409,11 @@ class SimpleTextDocValuesReader extends 
           } catch (ParseException pe) {
             throw new CorruptIndexException("failed to parse int length (resource=" + in + ")", pe);
           }
-          result.bytes = new byte[len];
-          result.offset = 0;
-          result.length = len;
-          in.readBytes(result.bytes, 0, len);
+          term.grow(len);
+          term.offset = 0;
+          term.length = len;
+          in.readBytes(term.bytes, 0, len);
+          return term;
         } catch (IOException ioe) {
           throw new RuntimeException(ioe);
         }

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/DocValuesConsumer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/DocValuesConsumer.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/DocValuesConsumer.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/DocValuesConsumer.java Thu Jun  5 19:34:21 2014
@@ -199,7 +199,7 @@ public abstract class DocValuesConsumer 
                        return new Iterator<BytesRef>() {
                          int readerUpto = -1;
                          int docIDUpto;
-                         BytesRef nextValue = new BytesRef();
+                         BytesRef nextValue;
                          BytesRef nextPointer; // points to null if missing, or nextValue
                          AtomicReader currentReader;
                          BinaryDocValues currentValues;
@@ -248,7 +248,7 @@ public abstract class DocValuesConsumer 
                              if (currentLiveDocs == null || currentLiveDocs.get(docIDUpto)) {
                                nextIsSet = true;
                                if (currentDocsWithField.get(docIDUpto)) {
-                                 currentValues.get(docIDUpto, nextValue);
+                                 nextValue = currentValues.get(docIDUpto);
                                  nextPointer = nextValue;
                                } else {
                                  nextPointer = null;
@@ -308,7 +308,6 @@ public abstract class DocValuesConsumer 
           @Override
           public Iterator<BytesRef> iterator() {
             return new Iterator<BytesRef>() {
-              final BytesRef scratch = new BytesRef();
               int currentOrd;
 
               @Override
@@ -323,9 +322,9 @@ public abstract class DocValuesConsumer 
                 }
                 int segmentNumber = map.getFirstSegmentNumber(currentOrd);
                 int segmentOrd = (int)map.getFirstSegmentOrd(currentOrd);
-                dvs[segmentNumber].lookupOrd(segmentOrd, scratch);
+                final BytesRef term = dvs[segmentNumber].lookupOrd(segmentOrd);
                 currentOrd++;
-                return scratch;
+                return term;
               }
 
               @Override
@@ -444,7 +443,6 @@ public abstract class DocValuesConsumer 
           @Override
           public Iterator<BytesRef> iterator() {
             return new Iterator<BytesRef>() {
-              final BytesRef scratch = new BytesRef();
               long currentOrd;
 
               @Override
@@ -459,9 +457,9 @@ public abstract class DocValuesConsumer 
                 }
                 int segmentNumber = map.getFirstSegmentNumber(currentOrd);
                 long segmentOrd = map.getFirstSegmentOrd(currentOrd);
-                dvs[segmentNumber].lookupOrd(segmentOrd, scratch);
+                final BytesRef term = dvs[segmentNumber].lookupOrd(segmentOrd);
                 currentOrd++;
-                return scratch;
+                return term;
               }
 
               @Override

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40DocValuesReader.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40DocValuesReader.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40DocValuesReader.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene40/Lucene40DocValuesReader.java Thu Jun  5 19:34:21 2014
@@ -329,9 +329,12 @@ final class Lucene40DocValuesReader exte
       success = true;
       ramBytesUsed.addAndGet(bytes.ramBytesUsed());
       return new BinaryDocValues() {
+
         @Override
-        public void get(int docID, BytesRef result) {
-          bytesReader.fillSlice(result, fixedLength * (long)docID, fixedLength);
+        public BytesRef get(int docID) {
+          final BytesRef term = new BytesRef();
+          bytesReader.fillSlice(term, fixedLength * (long)docID, fixedLength);
+          return term;
         }
       };
     } finally {
@@ -369,10 +372,12 @@ final class Lucene40DocValuesReader exte
       ramBytesUsed.addAndGet(bytes.ramBytesUsed() + reader.ramBytesUsed());
       return new BinaryDocValues() {
         @Override
-        public void get(int docID, BytesRef result) {
+        public BytesRef get(int docID) {
+          final BytesRef term = new BytesRef();
           long startAddress = reader.get(docID);
           long endAddress = reader.get(docID+1);
-          bytesReader.fillSlice(result, startAddress, (int)(endAddress - startAddress));
+          bytesReader.fillSlice(term, startAddress, (int)(endAddress - startAddress));
+          return term;
         }
       };
     } finally {
@@ -412,9 +417,11 @@ final class Lucene40DocValuesReader exte
       success = true;
       return new BinaryDocValues() {
         @Override
-        public void get(int docID, BytesRef result) {
+        public BytesRef get(int docID) {
+          final BytesRef term = new BytesRef();
           final long offset = fixedLength * reader.get(docID);
-          bytesReader.fillSlice(result, offset, fixedLength);
+          bytesReader.fillSlice(term, offset, fixedLength);
+          return term;
         }
       };
     } finally {
@@ -452,20 +459,23 @@ final class Lucene40DocValuesReader exte
       ramBytesUsed.addAndGet(bytes.ramBytesUsed() + reader.ramBytesUsed());
       success = true;
       return new BinaryDocValues() {
+        
         @Override
-        public void get(int docID, BytesRef result) {
+        public BytesRef get(int docID) {
+          final BytesRef term = new BytesRef();
           long startAddress = reader.get(docID);
           BytesRef lengthBytes = new BytesRef();
           bytesReader.fillSlice(lengthBytes, startAddress, 1);
           byte code = lengthBytes.bytes[lengthBytes.offset];
           if ((code & 128) == 0) {
             // length is 1 byte
-            bytesReader.fillSlice(result, startAddress + 1, (int) code);
+            bytesReader.fillSlice(term, startAddress + 1, (int) code);
           } else {
             bytesReader.fillSlice(lengthBytes, startAddress + 1, 1);
             int length = ((code & 0x7f) << 8) | (lengthBytes.bytes[lengthBytes.offset] & 0xff);
-            bytesReader.fillSlice(result, startAddress + 2, length);
+            bytesReader.fillSlice(term, startAddress + 2, length);
           }
+          return term;
         }
       };
     } finally {
@@ -538,8 +548,10 @@ final class Lucene40DocValuesReader exte
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
-        bytesReader.fillSlice(result, fixedLength * (long) ord, fixedLength);
+      public BytesRef lookupOrd(int ord) {
+        final BytesRef term = new BytesRef();
+        bytesReader.fillSlice(term, fixedLength * (long) ord, fixedLength);
+        return term;
       }
 
       @Override
@@ -574,10 +586,12 @@ final class Lucene40DocValuesReader exte
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
+      public BytesRef lookupOrd(int ord) {
+        final BytesRef term = new BytesRef();
         long startAddress = addressReader.get(ord);
         long endAddress = addressReader.get(ord+1);
-        bytesReader.fillSlice(result, startAddress, (int)(endAddress - startAddress));
+        bytesReader.fillSlice(term, startAddress, (int)(endAddress - startAddress));
+        return term;
       }
 
       @Override
@@ -604,8 +618,8 @@ final class Lucene40DocValuesReader exte
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
-        in.lookupOrd(ord+1, result);
+      public BytesRef lookupOrd(int ord) {
+        return in.lookupOrd(ord+1);
       }
 
       @Override

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesProducer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesProducer.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesProducer.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene42/Lucene42DocValuesProducer.java Thu Jun  5 19:34:21 2014
@@ -41,6 +41,7 @@ import org.apache.lucene.index.TermsEnum
 import org.apache.lucene.store.ByteArrayDataInput;
 import org.apache.lucene.store.ChecksumIndexInput;
 import org.apache.lucene.store.IndexInput;
+import org.apache.lucene.util.ArrayUtil;
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 import org.apache.lucene.util.IOUtils;
@@ -293,19 +294,24 @@ class Lucene42DocValuesProducer extends 
       ramBytesUsed.addAndGet(bytes.ramBytesUsed());
       return new BinaryDocValues() {
         @Override
-        public void get(int docID, BytesRef result) {
-          bytesReader.fillSlice(result, fixedLength * (long)docID, fixedLength);
+        public BytesRef get(int docID) {
+          final BytesRef term = new BytesRef();
+          bytesReader.fillSlice(term, fixedLength * (long)docID, fixedLength);
+          return term;
         }
       };
     } else {
       final MonotonicBlockPackedReader addresses = new MonotonicBlockPackedReader(data, entry.packedIntsVersion, entry.blockSize, maxDoc, false);
       ramBytesUsed.addAndGet(bytes.ramBytesUsed() + addresses.ramBytesUsed());
       return new BinaryDocValues() {
+
         @Override
-        public void get(int docID, BytesRef result) {
+        public BytesRef get(int docID) {
           long startAddress = docID == 0 ? 0 : addresses.get(docID-1);
           long endAddress = addresses.get(docID); 
-          bytesReader.fillSlice(result, startAddress, (int) (endAddress - startAddress));
+          final BytesRef term = new BytesRef();
+          bytesReader.fillSlice(term, startAddress, (int) (endAddress - startAddress));
+          return term;
         }
       };
     }
@@ -335,21 +341,24 @@ class Lucene42DocValuesProducer extends 
     final BytesRefFSTEnum<Long> fstEnum = new BytesRefFSTEnum<>(fst);
     
     return new SortedDocValues() {
+
+      final BytesRef term = new BytesRef();
+
       @Override
       public int getOrd(int docID) {
         return (int) docToOrd.get(docID);
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
+      public BytesRef lookupOrd(int ord) {
         try {
           in.setPosition(0);
           fst.getFirstArc(firstArc);
           IntsRef output = Util.getByOutput(fst, ord, in, firstArc, scratchArc, scratchInts);
-          result.bytes = new byte[output.length];
-          result.offset = 0;
-          result.length = 0;
-          Util.toBytesRef(output, result);
+          term.bytes = ArrayUtil.grow(term.bytes, output.length);
+          term.offset = 0;
+          term.length = 0;
+          return Util.toBytesRef(output, term);
         } catch (IOException bogus) {
           throw new RuntimeException(bogus);
         }
@@ -387,7 +396,7 @@ class Lucene42DocValuesProducer extends 
   public SortedSetDocValues getSortedSet(FieldInfo field) throws IOException {
     final FSTEntry entry = fsts.get(field.number);
     if (entry.numOrds == 0) {
-      return DocValues.EMPTY_SORTED_SET; // empty FST!
+      return DocValues.emptySortedSet(); // empty FST!
     }
     FST<Long> instance;
     synchronized(this) {
@@ -408,9 +417,10 @@ class Lucene42DocValuesProducer extends 
     final Arc<Long> scratchArc = new Arc<>();
     final IntsRef scratchInts = new IntsRef();
     final BytesRefFSTEnum<Long> fstEnum = new BytesRefFSTEnum<>(fst);
-    final BytesRef ref = new BytesRef();
     final ByteArrayDataInput input = new ByteArrayDataInput();
     return new SortedSetDocValues() {
+      final BytesRef term = new BytesRef();
+      BytesRef ordsRef;
       long currentOrd;
 
       @Override
@@ -425,21 +435,21 @@ class Lucene42DocValuesProducer extends 
       
       @Override
       public void setDocument(int docID) {
-        docToOrds.get(docID, ref);
-        input.reset(ref.bytes, ref.offset, ref.length);
+        ordsRef = docToOrds.get(docID);
+        input.reset(ordsRef.bytes, ordsRef.offset, ordsRef.length);
         currentOrd = 0;
       }
 
       @Override
-      public void lookupOrd(long ord, BytesRef result) {
+      public BytesRef lookupOrd(long ord) {
         try {
           in.setPosition(0);
           fst.getFirstArc(firstArc);
           IntsRef output = Util.getByOutput(fst, ord, in, firstArc, scratchArc, scratchInts);
-          result.bytes = new byte[output.length];
-          result.offset = 0;
-          result.length = 0;
-          Util.toBytesRef(output, result);
+          term.bytes = ArrayUtil.grow(term.bytes, output.length);
+          term.offset = 0;
+          term.length = 0;
+          return Util.toBytesRef(output, term);
         } catch (IOException bogus) {
           throw new RuntimeException(bogus);
         }

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesProducer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesProducer.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesProducer.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene45/Lucene45DocValuesProducer.java Thu Jun  5 19:34:21 2014
@@ -384,18 +384,20 @@ public class Lucene45DocValuesProducer e
     final IndexInput data = this.data.clone();
 
     return new LongBinaryDocValues() {
+      final BytesRef term;
+      {
+        term = new BytesRef(bytes.maxLength);
+        term.offset = 0;
+        term.length = bytes.maxLength;
+      }
+
       @Override
-      public void get(long id, BytesRef result) {
+      public BytesRef get(long id) {
         long address = bytes.offset + id * bytes.maxLength;
         try {
           data.seek(address);
-          // NOTE: we could have one buffer, but various consumers (e.g. FieldComparatorSource) 
-          // assume "they" own the bytes after calling this!
-          final byte[] buffer = new byte[bytes.maxLength];
-          data.readBytes(buffer, 0, buffer.length);
-          result.bytes = buffer;
-          result.offset = 0;
-          result.length = buffer.length;
+          data.readBytes(term.bytes, 0, term.length);
+          return term;
         } catch (IOException e) {
           throw new RuntimeException(e);
         }
@@ -426,20 +428,18 @@ public class Lucene45DocValuesProducer e
     final MonotonicBlockPackedReader addresses = getAddressInstance(data, field, bytes);
 
     return new LongBinaryDocValues() {
+      final BytesRef term = new BytesRef(Math.max(0, bytes.maxLength));
+
       @Override
-      public void get(long id, BytesRef result) {
+      public BytesRef get(long id) {
         long startAddress = bytes.offset + (id == 0 ? 0 : addresses.get(id-1));
         long endAddress = bytes.offset + addresses.get(id);
         int length = (int) (endAddress - startAddress);
         try {
           data.seek(startAddress);
-          // NOTE: we could have one buffer, but various consumers (e.g. FieldComparatorSource) 
-          // assume "they" own the bytes after calling this!
-          final byte[] buffer = new byte[length];
-          data.readBytes(buffer, 0, buffer.length);
-          result.bytes = buffer;
-          result.offset = 0;
-          result.length = length;
+          data.readBytes(term.bytes, 0, length);
+          term.length = length;
+          return term;
         } catch (IOException e) {
           throw new RuntimeException(e);
         }
@@ -497,8 +497,8 @@ public class Lucene45DocValuesProducer e
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
-        binary.get(ord, result);
+      public BytesRef lookupOrd(int ord) {
+        return binary.get(ord);
       }
 
       @Override
@@ -584,8 +584,8 @@ public class Lucene45DocValuesProducer e
       }
 
       @Override
-      public void lookupOrd(long ord, BytesRef result) {
-        binary.get(ord, result);
+      public BytesRef lookupOrd(long ord) {
+        return binary.get(ord);
       }
 
       @Override
@@ -724,11 +724,11 @@ public class Lucene45DocValuesProducer e
   // internally we compose complex dv (sorted/sortedset) from other ones
   static abstract class LongBinaryDocValues extends BinaryDocValues {
     @Override
-    public final void get(int docID, BytesRef result) {
-      get((long)docID, result);
+    public final BytesRef get(int docID) {
+      return get((long) docID);
     }
     
-    abstract void get(long id, BytesRef Result);
+    abstract BytesRef get(long id);
   }
   
   // in the compressed case, we add a few additional operations for
@@ -753,13 +753,10 @@ public class Lucene45DocValuesProducer e
     }
     
     @Override
-    public void get(long id, BytesRef result) {
+    public BytesRef get(long id) {
       try {
         termsEnum.seekExact(id);
-        BytesRef term = termsEnum.term();
-        result.bytes = term.bytes;
-        result.offset = term.offset;
-        result.length = term.length;
+        return termsEnum.term();
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
@@ -794,28 +791,18 @@ public class Lucene45DocValuesProducer e
       return new TermsEnum() {
         private long currentOrd = -1;
         // TODO: maxLength is negative when all terms are merged away...
-        private final BytesRef termBuffer = new BytesRef(bytes.maxLength < 0 ? 0 : bytes.maxLength);
-        private final BytesRef term = new BytesRef(); // TODO: paranoia?
+        private final BytesRef term = new BytesRef(bytes.maxLength < 0 ? 0 : bytes.maxLength);
 
         @Override
         public BytesRef next() throws IOException {
-          if (doNext() == null) {
-            return null;
-          } else {
-            setTerm();
-            return term;
-          }
-        }
-        
-        private BytesRef doNext() throws IOException {
           if (++currentOrd >= numValues) {
             return null;
           } else {
             int start = input.readVInt();
             int suffix = input.readVInt();
-            input.readBytes(termBuffer.bytes, start, suffix);
-            termBuffer.length = start + suffix;
-            return termBuffer;
+            input.readBytes(term.bytes, start, suffix);
+            term.length = start + suffix;
+            return term;
           }
         }
 
@@ -828,8 +815,8 @@ public class Lucene45DocValuesProducer e
 
           while (low <= high) {
             long mid = (low + high) >>> 1;
-            doSeek(mid * interval);
-            int cmp = termBuffer.compareTo(text);
+            seekExact(mid * interval);
+            int cmp = term.compareTo(text);
 
             if (cmp < 0) {
               low = mid + 1;
@@ -837,7 +824,6 @@ public class Lucene45DocValuesProducer e
               high = mid - 1;
             } else {
               // we got lucky, found an indexed term
-              setTerm();
               return SeekStatus.FOUND;
             }
           }
@@ -848,15 +834,13 @@ public class Lucene45DocValuesProducer e
           
           // block before insertion point
           long block = low-1;
-          doSeek(block < 0 ? -1 : block * interval);
+          seekExact(block < 0 ? -1 : block * interval);
           
-          while (doNext() != null) {
-            int cmp = termBuffer.compareTo(text);
+          while (next() != null) {
+            int cmp = term.compareTo(text);
             if (cmp == 0) {
-              setTerm();
               return SeekStatus.FOUND;
             } else if (cmp > 0) {
-              setTerm();
               return SeekStatus.NOT_FOUND;
             }
           }
@@ -866,11 +850,6 @@ public class Lucene45DocValuesProducer e
 
         @Override
         public void seekExact(long ord) throws IOException {
-          doSeek(ord);
-          setTerm();
-        }
-        
-        private void doSeek(long ord) throws IOException {
           long block = ord / interval;
 
           if (ord >= currentOrd && block == currentOrd / interval) {
@@ -882,16 +861,9 @@ public class Lucene45DocValuesProducer e
           }
           
           while (currentOrd < ord) {
-            doNext();
+            next();
           }
         }
-        
-        private void setTerm() {
-          // TODO: is there a cleaner way
-          term.bytes = new byte[termBuffer.length];
-          term.offset = 0;
-          term.copyBytes(termBuffer);
-        }
 
         @Override
         public BytesRef term() throws IOException {

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene49/Lucene49DocValuesProducer.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene49/Lucene49DocValuesProducer.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene49/Lucene49DocValuesProducer.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/codecs/lucene49/Lucene49DocValuesProducer.java Thu Jun  5 19:34:21 2014
@@ -364,18 +364,20 @@ public class Lucene49DocValuesProducer e
     final IndexInput data = this.data.clone();
 
     return new LongBinaryDocValues() {
+      final BytesRef term;
+      {
+        term = new BytesRef(bytes.maxLength);
+        term.offset = 0;
+        term.length = bytes.maxLength;
+      }
+      
       @Override
-      public void get(long id, BytesRef result) {
+      public BytesRef get(long id) {
         long address = bytes.offset + id * bytes.maxLength;
         try {
           data.seek(address);
-          // NOTE: we could have one buffer, but various consumers (e.g. FieldComparatorSource) 
-          // assume "they" own the bytes after calling this!
-          final byte[] buffer = new byte[bytes.maxLength];
-          data.readBytes(buffer, 0, buffer.length);
-          result.bytes = buffer;
-          result.offset = 0;
-          result.length = buffer.length;
+          data.readBytes(term.bytes, 0, term.length);
+          return term;
         } catch (IOException e) {
           throw new RuntimeException(e);
         }
@@ -406,20 +408,18 @@ public class Lucene49DocValuesProducer e
     final MonotonicBlockPackedReader addresses = getAddressInstance(data, field, bytes);
 
     return new LongBinaryDocValues() {
+      final BytesRef term = new BytesRef(Math.max(0, bytes.maxLength));
+      
       @Override
-      public void get(long id, BytesRef result) {
+      public BytesRef get(long id) {
         long startAddress = bytes.offset + (id == 0 ? 0 : addresses.get(id-1));
         long endAddress = bytes.offset + addresses.get(id);
         int length = (int) (endAddress - startAddress);
         try {
           data.seek(startAddress);
-          // NOTE: we could have one buffer, but various consumers (e.g. FieldComparatorSource) 
-          // assume "they" own the bytes after calling this!
-          final byte[] buffer = new byte[length];
-          data.readBytes(buffer, 0, buffer.length);
-          result.bytes = buffer;
-          result.offset = 0;
-          result.length = length;
+          data.readBytes(term.bytes, 0, length);
+          term.length = length;
+          return term;
         } catch (IOException e) {
           throw new RuntimeException(e);
         }
@@ -475,8 +475,8 @@ public class Lucene49DocValuesProducer e
       }
 
       @Override
-      public void lookupOrd(int ord, BytesRef result) {
-        binary.get(ord, result);
+      public BytesRef lookupOrd(int ord) {
+        return binary.get(ord);
       }
 
       @Override
@@ -562,8 +562,8 @@ public class Lucene49DocValuesProducer e
       }
 
       @Override
-      public void lookupOrd(long ord, BytesRef result) {
-        binary.get(ord, result);
+      public BytesRef lookupOrd(long ord) {
+        return binary.get(ord);
       }
 
       @Override
@@ -705,11 +705,11 @@ public class Lucene49DocValuesProducer e
   // internally we compose complex dv (sorted/sortedset) from other ones
   static abstract class LongBinaryDocValues extends BinaryDocValues {
     @Override
-    public final void get(int docID, BytesRef result) {
-      get((long)docID, result);
+    public final BytesRef get(int docID) {
+      return get((long)docID);
     }
     
-    abstract void get(long id, BytesRef Result);
+    abstract BytesRef get(long id);
   }
   
   // in the compressed case, we add a few additional operations for
@@ -734,13 +734,10 @@ public class Lucene49DocValuesProducer e
     }
     
     @Override
-    public void get(long id, BytesRef result) {
+    public BytesRef get(long id) {
       try {
         termsEnum.seekExact(id);
-        BytesRef term = termsEnum.term();
-        result.bytes = term.bytes;
-        result.offset = term.offset;
-        result.length = term.length;
+        return termsEnum.term();
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
@@ -775,28 +772,18 @@ public class Lucene49DocValuesProducer e
       return new TermsEnum() {
         private long currentOrd = -1;
         // TODO: maxLength is negative when all terms are merged away...
-        private final BytesRef termBuffer = new BytesRef(bytes.maxLength < 0 ? 0 : bytes.maxLength);
-        private final BytesRef term = new BytesRef(); // TODO: paranoia?
+        private final BytesRef term = new BytesRef(bytes.maxLength < 0 ? 0 : bytes.maxLength);
 
         @Override
         public BytesRef next() throws IOException {
-          if (doNext() == null) {
-            return null;
-          } else {
-            setTerm();
-            return term;
-          }
-        }
-        
-        private BytesRef doNext() throws IOException {
           if (++currentOrd >= numValues) {
             return null;
           } else {
             int start = input.readVInt();
             int suffix = input.readVInt();
-            input.readBytes(termBuffer.bytes, start, suffix);
-            termBuffer.length = start + suffix;
-            return termBuffer;
+            input.readBytes(term.bytes, start, suffix);
+            term.length = start + suffix;
+            return term;
           }
         }
 
@@ -809,8 +796,8 @@ public class Lucene49DocValuesProducer e
 
           while (low <= high) {
             long mid = (low + high) >>> 1;
-            doSeek(mid * interval);
-            int cmp = termBuffer.compareTo(text);
+            seekExact(mid * interval);
+            int cmp = term.compareTo(text);
 
             if (cmp < 0) {
               low = mid + 1;
@@ -818,7 +805,6 @@ public class Lucene49DocValuesProducer e
               high = mid - 1;
             } else {
               // we got lucky, found an indexed term
-              setTerm();
               return SeekStatus.FOUND;
             }
           }
@@ -829,15 +815,13 @@ public class Lucene49DocValuesProducer e
           
           // block before insertion point
           long block = low-1;
-          doSeek(block < 0 ? -1 : block * interval);
+          seekExact(block < 0 ? -1 : block * interval);
           
-          while (doNext() != null) {
-            int cmp = termBuffer.compareTo(text);
+          while (next() != null) {
+            int cmp = term.compareTo(text);
             if (cmp == 0) {
-              setTerm();
               return SeekStatus.FOUND;
             } else if (cmp > 0) {
-              setTerm();
               return SeekStatus.NOT_FOUND;
             }
           }
@@ -847,11 +831,6 @@ public class Lucene49DocValuesProducer e
 
         @Override
         public void seekExact(long ord) throws IOException {
-          doSeek(ord);
-          setTerm();
-        }
-        
-        private void doSeek(long ord) throws IOException {
           long block = ord / interval;
 
           if (ord >= currentOrd && block == currentOrd / interval) {
@@ -863,16 +842,9 @@ public class Lucene49DocValuesProducer e
           }
           
           while (currentOrd < ord) {
-            doNext();
+            next();
           }
         }
-        
-        private void setTerm() {
-          // TODO: is there a cleaner way
-          term.bytes = new byte[termBuffer.length];
-          term.offset = 0;
-          term.copyBytes(termBuffer);
-        }
 
         @Override
         public BytesRef term() throws IOException {

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/BinaryDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/BinaryDocValues.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/BinaryDocValues.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/BinaryDocValues.java Thu Jun  5 19:34:21 2014
@@ -28,6 +28,9 @@ public abstract class BinaryDocValues {
    * constructors, typically implicit.) */
   protected BinaryDocValues() {}
 
-  /** Lookup the value for document. */
-  public abstract void get(int docID, BytesRef result);
+  /** Lookup the value for document.  The returned {@link BytesRef} may be
+   * re-used across calls to {@link #get(int)} so make sure to
+   * {@link BytesRef#deepCopyOf(BytesRef) copy it} if you want to keep it
+   * around. */
+  public abstract BytesRef get(int docID);
 }

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java Thu Jun  5 19:34:21 2014
@@ -1422,12 +1422,11 @@ public class CheckIndex {
   }
   
   private static void checkBinaryDocValues(String fieldName, AtomicReader reader, BinaryDocValues dv, Bits docsWithField) {
-    BytesRef scratch = new BytesRef();
     for (int i = 0; i < reader.maxDoc(); i++) {
-      dv.get(i, scratch);
-      assert scratch.isValid();
-      if (docsWithField.get(i) == false && scratch.length > 0) {
-        throw new RuntimeException("dv for field: " + fieldName + " is missing but has value=" + scratch + " for doc: " + i);
+      final BytesRef term = dv.get(i);
+      assert term.isValid();
+      if (docsWithField.get(i) == false && term.length > 0) {
+        throw new RuntimeException("dv for field: " + fieldName + " is missing but has value=" + term + " for doc: " + i);
       }
     }
   }
@@ -1460,16 +1459,15 @@ public class CheckIndex {
       throw new RuntimeException("dv for field: " + fieldName + " has holes in its ords, valueCount=" + dv.getValueCount() + " but only used: " + seenOrds.cardinality());
     }
     BytesRef lastValue = null;
-    BytesRef scratch = new BytesRef();
     for (int i = 0; i <= maxOrd; i++) {
-      dv.lookupOrd(i, scratch);
-      assert scratch.isValid();
+      final BytesRef term = dv.lookupOrd(i);
+      assert term.isValid();
       if (lastValue != null) {
-        if (scratch.compareTo(lastValue) <= 0) {
-          throw new RuntimeException("dv for field: " + fieldName + " has ords out of order: " + lastValue + " >=" + scratch);
+        if (term.compareTo(lastValue) <= 0) {
+          throw new RuntimeException("dv for field: " + fieldName + " has ords out of order: " + lastValue + " >=" + term);
         }
       }
-      lastValue = BytesRef.deepCopyOf(scratch);
+      lastValue = BytesRef.deepCopyOf(term);
     }
   }
   
@@ -1531,16 +1529,15 @@ public class CheckIndex {
     }
     
     BytesRef lastValue = null;
-    BytesRef scratch = new BytesRef();
     for (long i = 0; i <= maxOrd; i++) {
-      dv.lookupOrd(i, scratch);
-      assert scratch.isValid();
+      final BytesRef term = dv.lookupOrd(i);
+      assert term.isValid();
       if (lastValue != null) {
-        if (scratch.compareTo(lastValue) <= 0) {
-          throw new RuntimeException("dv for field: " + fieldName + " has ords out of order: " + lastValue + " >=" + scratch);
+        if (term.compareTo(lastValue) <= 0) {
+          throw new RuntimeException("dv for field: " + fieldName + " has ords out of order: " + lastValue + " >=" + term);
         }
       }
-      lastValue = BytesRef.deepCopyOf(scratch);
+      lastValue = BytesRef.deepCopyOf(term);
     }
   }
 

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocTermOrds.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocTermOrds.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocTermOrds.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocTermOrds.java Thu Jun  5 19:34:21 2014
@@ -768,7 +768,7 @@ public class DocTermOrds {
   /** Returns a SortedSetDocValues view of this instance */
   public SortedSetDocValues iterator(AtomicReader reader) throws IOException {
     if (isEmpty()) {
-      return DocValues.EMPTY_SORTED_SET;
+      return DocValues.emptySortedSet();
     } else {
       return new Iterator(reader);
     }
@@ -869,16 +869,12 @@ public class DocTermOrds {
     }
 
     @Override
-    public void lookupOrd(long ord, BytesRef result) {
-      BytesRef ref = null;
+    public BytesRef lookupOrd(long ord) {
       try {
-        ref = DocTermOrds.this.lookupTerm(te, (int) ord);
+        return DocTermOrds.this.lookupTerm(te, (int) ord);
       } catch (IOException e) {
         throw new RuntimeException(e);
       }
-      result.bytes = ref.bytes;
-      result.offset = ref.offset;
-      result.length = ref.length;
     }
 
     @Override

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocValues.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocValues.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/DocValues.java Thu Jun  5 19:34:21 2014
@@ -17,6 +17,8 @@ package org.apache.lucene.index;
  * limitations under the License.
  */
 
+import java.io.IOException;
+
 import org.apache.lucene.util.Bits;
 import org.apache.lucene.util.BytesRef;
 
@@ -24,87 +26,92 @@ import org.apache.lucene.util.BytesRef;
  * This class contains utility methods and constants for DocValues
  */
 public final class DocValues {
-  
+
   /* no instantiation */
   private DocValues() {}
-  
+
   /** 
    * An empty BinaryDocValues which returns {@link BytesRef#EMPTY_BYTES} for every document 
    */
-  public static final BinaryDocValues EMPTY_BINARY = new BinaryDocValues() {
-    @Override
-    public void get(int docID, BytesRef result) {
-      result.bytes = BytesRef.EMPTY_BYTES;
-      result.offset = 0;
-      result.length = 0;
-    }
-  };
+  public static final BinaryDocValues emptyBinary() {
+    final BytesRef empty = new BytesRef();
+    return new BinaryDocValues() {
+      @Override
+      public BytesRef get(int docID) {
+        return empty;
+      }
+    };
+  }
 
   /** 
    * An empty NumericDocValues which returns zero for every document 
    */
-  public static final NumericDocValues EMPTY_NUMERIC = new NumericDocValues() {
-    @Override
-    public long get(int docID) {
-      return 0;
-    }
-  };
+  public static final NumericDocValues emptyNumeric() {
+    return new NumericDocValues() {
+      @Override
+      public long get(int docID) {
+        return 0;
+      }
+    };
+  }
 
   /** 
    * An empty SortedDocValues which returns {@link BytesRef#EMPTY_BYTES} for every document 
    */
-  public static final SortedDocValues EMPTY_SORTED = new SortedDocValues() {
-    @Override
-    public int getOrd(int docID) {
-      return -1;
-    }
+  public static final SortedDocValues emptySorted() {
+    final BytesRef empty = new BytesRef();
+    return new SortedDocValues() {
+      @Override
+      public int getOrd(int docID) {
+        return -1;
+      }
 
-    @Override
-    public void lookupOrd(int ord, BytesRef result) {
-      result.bytes = BytesRef.EMPTY_BYTES;
-      result.offset = 0;
-      result.length = 0;
-    }
+      @Override
+      public BytesRef lookupOrd(int ord) {
+        return empty;
+      }
 
-    @Override
-    public int getValueCount() {
-      return 0;
-    }
-  };
+      @Override
+      public int getValueCount() {
+        return 0;
+      }
+    };
+  }
 
   /** 
    * An empty SortedDocValues which returns {@link SortedSetDocValues#NO_MORE_ORDS} for every document 
    */
-  public static final SortedSetDocValues EMPTY_SORTED_SET = new RandomAccessOrds() {
-
-    @Override
-    public long nextOrd() {
-      return NO_MORE_ORDS;
-    }
-
-    @Override
-    public void setDocument(int docID) {}
-
-    @Override
-    public void lookupOrd(long ord, BytesRef result) {
-      throw new IndexOutOfBoundsException();
-    }
-
-    @Override
-    public long getValueCount() {
-      return 0;
-    }
-
-    @Override
-    public long ordAt(int index) {
-      throw new IndexOutOfBoundsException();
-    }
-
-    @Override
-    public int cardinality() {
-      return 0;
-    }
-  };
+  public static final SortedSetDocValues emptySortedSet() {
+    return new RandomAccessOrds() {
+      @Override
+      public long nextOrd() {
+        return NO_MORE_ORDS;
+      }
+      
+      @Override
+      public void setDocument(int docID) {}
+      
+      @Override
+      public BytesRef lookupOrd(long ord) {
+        throw new IndexOutOfBoundsException();
+      }
+      
+      @Override
+      public long getValueCount() {
+        return 0;
+      }
+      
+      @Override
+      public long ordAt(int index) {
+        throw new IndexOutOfBoundsException();
+      }
+      
+      @Override
+      public int cardinality() {
+        return 0;
+      }
+    };
+  }
   
   /** 
    * Returns a multi-valued view over the provided SortedDocValues 
@@ -159,4 +166,72 @@ public final class DocValues {
       }
     };
   }
+  
+  // some helpers, for transition from fieldcache apis.
+  // as opposed to the AtomicReader apis (which must be strict for consistency), these are lenient
+  
+  /**
+   * Returns NumericDocValues for the reader, or {@link #emptyNumeric()} if it has none. 
+   */
+  public static NumericDocValues getNumeric(AtomicReader in, String field) throws IOException {
+    NumericDocValues dv = in.getNumericDocValues(field);
+    if (dv == null) {
+      return emptyNumeric();
+    } else {
+      return dv;
+    }
+  }
+  
+  /**
+   * Returns BinaryDocValues for the reader, or {@link #emptyBinary} if it has none. 
+   */
+  public static BinaryDocValues getBinary(AtomicReader in, String field) throws IOException {
+    BinaryDocValues dv = in.getBinaryDocValues(field);
+    if (dv == null) {
+      dv = in.getSortedDocValues(field);
+      if (dv == null) {
+        return emptyBinary();
+      }
+    }
+    return dv;
+  }
+  
+  /**
+   * Returns SortedDocValues for the reader, or {@link #emptySorted} if it has none. 
+   */
+  public static SortedDocValues getSorted(AtomicReader in, String field) throws IOException {
+    SortedDocValues dv = in.getSortedDocValues(field);
+    if (dv == null) {
+      return emptySorted();
+    } else {
+      return dv;
+    }
+  }
+  
+  /**
+   * Returns SortedSetDocValues for the reader, or {@link #emptySortedSet} if it has none. 
+   */
+  public static SortedSetDocValues getSortedSet(AtomicReader in, String field) throws IOException {
+    SortedSetDocValues dv = in.getSortedSetDocValues(field);
+    if (dv == null) {
+      SortedDocValues sorted = in.getSortedDocValues(field);
+      if (sorted == null) {
+        return emptySortedSet();
+      }
+      return singleton(sorted);
+    }
+    return dv;
+  }
+  
+  /**
+   * Returns Bits for the reader, or {@link Bits} matching nothing if it has none. 
+   */
+  public static Bits getDocsWithField(AtomicReader in, String field) throws IOException {
+    Bits dv = in.getDocsWithField(field);
+    if (dv == null) {
+      return new Bits.MatchNoBits(in.maxDoc());
+    } else {
+      return dv;
+    }
+  }
 }

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/MultiDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/MultiDocValues.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/MultiDocValues.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/MultiDocValues.java Thu Jun  5 19:34:21 2014
@@ -74,7 +74,7 @@ public class MultiDocValues {
       AtomicReaderContext context = leaves.get(i);
       NumericDocValues v = context.reader().getNormValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_NUMERIC;
+        v = DocValues.emptyNumeric();
       } else {
         anyReal = true;
       }
@@ -116,7 +116,7 @@ public class MultiDocValues {
       AtomicReaderContext context = leaves.get(i);
       NumericDocValues v = context.reader().getNumericDocValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_NUMERIC;
+        v = DocValues.emptyNumeric();
       } else {
         anyReal = true;
       }
@@ -206,7 +206,7 @@ public class MultiDocValues {
       AtomicReaderContext context = leaves.get(i);
       BinaryDocValues v = context.reader().getBinaryDocValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_BINARY;
+        v = DocValues.emptyBinary();
       } else {
         anyReal = true;
       }
@@ -220,9 +220,9 @@ public class MultiDocValues {
     } else {
       return new BinaryDocValues() {
         @Override
-        public void get(int docID, BytesRef result) {
+        public BytesRef get(int docID) {
           int subIndex = ReaderUtil.subIndex(docID, starts);
-          values[subIndex].get(docID - starts[subIndex], result);
+          return values[subIndex].get(docID - starts[subIndex]);
         }
       };
     }
@@ -251,7 +251,7 @@ public class MultiDocValues {
       AtomicReaderContext context = leaves.get(i);
       SortedDocValues v = context.reader().getSortedDocValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_SORTED;
+        v = DocValues.emptySorted();
       } else {
         anyReal = true;
       }
@@ -295,7 +295,7 @@ public class MultiDocValues {
       AtomicReaderContext context = leaves.get(i);
       SortedSetDocValues v = context.reader().getSortedSetDocValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_SORTED_SET;
+        v = DocValues.emptySortedSet();
       } else {
         anyReal = true;
       }
@@ -453,10 +453,10 @@ public class MultiDocValues {
     }
  
     @Override
-    public void lookupOrd(int ord, BytesRef result) {
+    public BytesRef lookupOrd(int ord) {
       int subIndex = mapping.getFirstSegmentNumber(ord);
       int segmentOrd = (int) mapping.getFirstSegmentOrd(ord);
-      values[subIndex].lookupOrd(segmentOrd, result);
+      return values[subIndex].lookupOrd(segmentOrd);
     }
  
     @Override
@@ -504,10 +504,10 @@ public class MultiDocValues {
     }
  
     @Override
-    public void lookupOrd(long ord, BytesRef result) {
+    public BytesRef lookupOrd(long ord) {
       int subIndex = mapping.getFirstSegmentNumber(ord);
       long segmentOrd = mapping.getFirstSegmentOrd(ord);
-      values[subIndex].lookupOrd(segmentOrd, result);
+      return values[subIndex].lookupOrd(segmentOrd);
     }
  
     @Override

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/ReadersAndUpdates.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/ReadersAndUpdates.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/ReadersAndUpdates.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/ReadersAndUpdates.java Thu Jun  5 19:34:21 2014
@@ -455,7 +455,6 @@ class ReadersAndUpdates {
               
               int curDoc = -1;
               int updateDoc = updatesIter.nextDoc();
-              BytesRef scratch = new BytesRef();
               
               @Override
               public boolean hasNext() {
@@ -476,8 +475,7 @@ class ReadersAndUpdates {
                   assert curDoc < updateDoc;
                   if (currentValues != null && docsWithField.get(curDoc)) {
                     // only read the current value if the document had a value before
-                    currentValues.get(curDoc, scratch);
-                    return scratch;
+                    return currentValues.get(curDoc);
                   } else {
                     return null;
                   }

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java Thu Jun  5 19:34:21 2014
@@ -170,7 +170,7 @@ final class SegmentMerger {
               NumericDocValues values = reader.getNumericDocValues(field.name);
               Bits bits = reader.getDocsWithField(field.name);
               if (values == null) {
-                values = DocValues.EMPTY_NUMERIC;
+                values = DocValues.emptyNumeric();
                 bits = new Bits.MatchNoBits(reader.maxDoc());
               }
               toMerge.add(values);
@@ -184,7 +184,7 @@ final class SegmentMerger {
               BinaryDocValues values = reader.getBinaryDocValues(field.name);
               Bits bits = reader.getDocsWithField(field.name);
               if (values == null) {
-                values = DocValues.EMPTY_BINARY;
+                values = DocValues.emptyBinary();
                 bits = new Bits.MatchNoBits(reader.maxDoc());
               }
               toMerge.add(values);
@@ -196,7 +196,7 @@ final class SegmentMerger {
             for (AtomicReader reader : mergeState.readers) {
               SortedDocValues values = reader.getSortedDocValues(field.name);
               if (values == null) {
-                values = DocValues.EMPTY_SORTED;
+                values = DocValues.emptySorted();
               }
               toMerge.add(values);
             }
@@ -206,7 +206,7 @@ final class SegmentMerger {
             for (AtomicReader reader : mergeState.readers) {
               SortedSetDocValues values = reader.getSortedSetDocValues(field.name);
               if (values == null) {
-                values = DocValues.EMPTY_SORTED_SET;
+                values = DocValues.emptySortedSet();
               }
               toMerge.add(values);
             }
@@ -237,7 +237,7 @@ final class SegmentMerger {
           for (AtomicReader reader : mergeState.readers) {
             NumericDocValues norms = reader.getNormValues(field.name);
             if (norms == null) {
-              norms = DocValues.EMPTY_NUMERIC;
+              norms = DocValues.emptyNumeric();
             }
             toMerge.add(norms);
             docsWithField.add(new Bits.MatchAllBits(reader.maxDoc()));

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SingletonSortedSetDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SingletonSortedSetDocValues.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SingletonSortedSetDocValues.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SingletonSortedSetDocValues.java Thu Jun  5 19:34:21 2014
@@ -59,9 +59,9 @@ final class SingletonSortedSetDocValues 
   }
 
   @Override
-  public void lookupOrd(long ord, BytesRef result) {
+  public BytesRef lookupOrd(long ord) {
     // cast is ok: single-valued cannot exceed Integer.MAX_VALUE
-    in.lookupOrd((int)ord, result);
+    return in.lookupOrd((int) ord);
   }
 
   @Override

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SlowCompositeReaderWrapper.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SlowCompositeReaderWrapper.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SlowCompositeReaderWrapper.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SlowCompositeReaderWrapper.java Thu Jun  5 19:34:21 2014
@@ -140,7 +140,7 @@ public final class SlowCompositeReaderWr
       AtomicReaderContext context = in.leaves().get(i);
       SortedDocValues v = context.reader().getSortedDocValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_SORTED;
+        v = DocValues.emptySorted();
       }
       values[i] = v;
       starts[i] = context.docBase;
@@ -179,7 +179,7 @@ public final class SlowCompositeReaderWr
       AtomicReaderContext context = in.leaves().get(i);
       SortedSetDocValues v = context.reader().getSortedSetDocValues(field);
       if (v == null) {
-        v = DocValues.EMPTY_SORTED_SET;
+        v = DocValues.emptySortedSet();
       }
       values[i] = v;
       starts[i] = context.docBase;

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValues.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValues.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValues.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValues.java Thu Jun  5 19:34:21 2014
@@ -28,7 +28,7 @@ import org.apache.lucene.util.BytesRef;
  * are dense and in increasing sorted order.
  */
 public abstract class SortedDocValues extends BinaryDocValues {
-  
+
   /** Sole constructor. (For invocation by subclass 
    * constructors, typically implicit.) */
   protected SortedDocValues() {}
@@ -42,12 +42,14 @@ public abstract class SortedDocValues ex
    */
   public abstract int getOrd(int docID);
 
-  /** Retrieves the value for the specified ordinal.
+  /** Retrieves the value for the specified ordinal. The returned
+   * {@link BytesRef} may be re-used across calls to {@link #lookupOrd(int)}
+   * so make sure to {@link BytesRef#deepCopyOf(BytesRef) copy it} if you want
+   * to keep it around.
    * @param ord ordinal to lookup (must be &gt;= 0 and &lt {@link #getValueCount()})
-   * @param result will be populated with the ordinal's value
    * @see #getOrd(int) 
    */
-  public abstract void lookupOrd(int ord, BytesRef result);
+  public abstract BytesRef lookupOrd(int ord);
 
   /**
    * Returns the number of unique values.
@@ -56,15 +58,15 @@ public abstract class SortedDocValues ex
    */
   public abstract int getValueCount();
 
+  private final BytesRef empty = new BytesRef();
+
   @Override
-  public void get(int docID, BytesRef result) {
+  public BytesRef get(int docID) {
     int ord = getOrd(docID);
     if (ord == -1) {
-      result.bytes = BytesRef.EMPTY_BYTES;
-      result.length = 0;
-      result.offset = 0;
+      return empty;
     } else {
-      lookupOrd(ord, result);
+      return lookupOrd(ord);
     }
   }
 
@@ -75,14 +77,13 @@ public abstract class SortedDocValues ex
    *  @param key Key to look up
    **/
   public int lookupTerm(BytesRef key) {
-    BytesRef spare = new BytesRef();
     int low = 0;
     int high = getValueCount()-1;
 
     while (low <= high) {
       int mid = (low + high) >>> 1;
-      lookupOrd(mid, spare);
-      int cmp = spare.compareTo(key);
+      final BytesRef term = lookupOrd(mid);
+      int cmp = term.compareTo(key);
 
       if (cmp < 0) {
         low = mid + 1;

Modified: lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java
URL: http://svn.apache.org/viewvc/lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java?rev=1600741&r1=1600740&r2=1600741&view=diff
==============================================================================
--- lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java (original)
+++ lucene/dev/branches/branch_4x/lucene/core/src/java/org/apache/lucene/index/SortedDocValuesTermsEnum.java Thu Jun  5 19:34:21 2014
@@ -29,11 +29,13 @@ import org.apache.lucene.util.BytesRef;
 class SortedDocValuesTermsEnum extends TermsEnum {
   private final SortedDocValues values;
   private int currentOrd = -1;
-  private final BytesRef term = new BytesRef();
+  private BytesRef term;
+  private final BytesRef scratch;
 
   /** Creates a new TermsEnum over the provided values */
   public SortedDocValuesTermsEnum(SortedDocValues values) {
     this.values = values;
+    scratch = new BytesRef();
   }
 
   @Override
@@ -41,12 +43,8 @@ class SortedDocValuesTermsEnum extends T
     int ord = values.lookupTerm(text);
     if (ord >= 0) {
       currentOrd = ord;
-      term.offset = 0;
-      // TODO: is there a cleaner way?
-      // term.bytes may be pointing to codec-private byte[]
-      // storage, so we must force new byte[] allocation:
-      term.bytes = new byte[text.length];
-      term.copyBytes(text);
+      scratch.copyBytes(text);
+      term = scratch;
       return SeekStatus.FOUND;
     } else {
       currentOrd = -ord-1;
@@ -54,7 +52,7 @@ class SortedDocValuesTermsEnum extends T
         return SeekStatus.END;
       } else {
         // TODO: hmm can we avoid this "extra" lookup?:
-        values.lookupOrd(currentOrd, term);
+        term = values.lookupOrd(currentOrd);
         return SeekStatus.NOT_FOUND;
       }
     }
@@ -64,13 +62,9 @@ class SortedDocValuesTermsEnum extends T
   public boolean seekExact(BytesRef text) throws IOException {
     int ord = values.lookupTerm(text);
     if (ord >= 0) {
-      term.offset = 0;
-      // TODO: is there a cleaner way?
-      // term.bytes may be pointing to codec-private byte[]
-      // storage, so we must force new byte[] allocation:
-      term.bytes = new byte[text.length];
-      term.copyBytes(text);
       currentOrd = ord;
+      scratch.copyBytes(text);
+      term = scratch;
       return true;
     } else {
       return false;
@@ -81,7 +75,7 @@ class SortedDocValuesTermsEnum extends T
   public void seekExact(long ord) throws IOException {
     assert ord >= 0 && ord < values.getValueCount();
     currentOrd = (int) ord;
-    values.lookupOrd(currentOrd, term);
+    term = values.lookupOrd(currentOrd);
   }
 
   @Override
@@ -90,7 +84,7 @@ class SortedDocValuesTermsEnum extends T
     if (currentOrd >= values.getValueCount()) {
       return null;
     }
-    values.lookupOrd(currentOrd, term);
+    term = values.lookupOrd(currentOrd);
     return term;
   }