public SortedDocValuesWriter(FieldInfo fieldInfo, Counter iwBytesUsed) {
   this.fieldInfo = fieldInfo;
   this.iwBytesUsed = iwBytesUsed;
   hash =
       new BytesRefHash(
           new ByteBlockPool(new ByteBlockPool.DirectTrackingAllocator(iwBytesUsed)),
           BytesRefHash.DEFAULT_CAPACITY,
           new DirectBytesStartArray(BytesRefHash.DEFAULT_CAPACITY, iwBytesUsed));
   pending = PackedLongValues.deltaPackedBuilder(PackedInts.COMPACT);
   docsWithField = new DocsWithFieldSet();
   bytesUsed = pending.ramBytesUsed() + docsWithField.ramBytesUsed();
   iwBytesUsed.addAndGet(bytesUsed);
 }
  @Override
  public void flush(SegmentWriteState state, Sorter.DocMap sortMap, DocValuesConsumer dvConsumer)
      throws IOException {
    final int valueCount = hash.size();
    final PackedLongValues ords;
    final int[] sortedValues;
    final int[] ordMap;
    if (finalOrds == null) {
      sortedValues = hash.sort();
      ords = pending.build();
      ordMap = new int[valueCount];
      for (int ord = 0; ord < valueCount; ord++) {
        ordMap[sortedValues[ord]] = ord;
      }
    } else {
      sortedValues = finalSortedValues;
      ords = finalOrds;
      ordMap = finalOrdMap;
    }

    final int[] sorted;
    if (sortMap != null) {
      sorted =
          sortDocValues(
              state.segmentInfo.maxDoc(),
              sortMap,
              new BufferedSortedDocValues(
                  hash, valueCount, ords, sortedValues, ordMap, docsWithField.iterator()));
    } else {
      sorted = null;
    }
    dvConsumer.addSortedField(
        fieldInfo,
        new EmptyDocValuesProducer() {
          @Override
          public SortedDocValues getSorted(FieldInfo fieldInfoIn) {
            if (fieldInfoIn != fieldInfo) {
              throw new IllegalArgumentException("wrong fieldInfo");
            }
            final SortedDocValues buf =
                new BufferedSortedDocValues(
                    hash, valueCount, ords, sortedValues, ordMap, docsWithField.iterator());
            if (sorted == null) {
              return buf;
            }
            return new SortingLeafReader.SortingSortedDocValues(buf, sorted);
          }
        });
  }
 @Override
 Sorter.DocComparator getDocComparator(int maxDoc, SortField sortField) throws IOException {
   assert sortField.getType().equals(SortField.Type.STRING);
   assert finalSortedValues == null && finalOrdMap == null && finalOrds == null;
   int valueCount = hash.size();
   finalSortedValues = hash.sort();
   finalOrds = pending.build();
   finalOrdMap = new int[valueCount];
   for (int ord = 0; ord < valueCount; ord++) {
     finalOrdMap[finalSortedValues[ord]] = ord;
   }
   final SortedDocValues docValues =
       new BufferedSortedDocValues(
           hash, valueCount, finalOrds, finalSortedValues, finalOrdMap, docsWithField.iterator());
   return Sorter.getDocComparator(maxDoc, sortField, () -> docValues, () -> null);
 }
  public void addValue(int docID, BytesRef value) {
    if (docID <= lastDocID) {
      throw new IllegalArgumentException(
          "DocValuesField \""
              + fieldInfo.name
              + "\" appears more than once in this document (only one value is allowed per field)");
    }
    if (value == null) {
      throw new IllegalArgumentException(
          "field \"" + fieldInfo.name + "\": null value not allowed");
    }
    if (value.length > (BYTE_BLOCK_SIZE - 2)) {
      throw new IllegalArgumentException(
          "DocValuesField \""
              + fieldInfo.name
              + "\" is too large, must be <= "
              + (BYTE_BLOCK_SIZE - 2));
    }

    addOneValue(value);
    docsWithField.add(docID);

    lastDocID = docID;
  }
 private void updateBytesUsed() {
   final long newBytesUsed = pending.ramBytesUsed() + docsWithField.ramBytesUsed();
   iwBytesUsed.addAndGet(newBytesUsed - bytesUsed);
   bytesUsed = newBytesUsed;
 }