private void expandAndRehashImpl(long capacity) {
    long expandTime = System.currentTimeMillis();
    final long[] oldRefs = refs;
    validateCapacity(capacity);
    long[] newRefs = new long[(int)capacity];

    // We store some hash bits in ref; for every expansion, we need to add one bit to hash.
    // If we have enough bits, we'll do that; if we don't, we'll rehash.
    // LOG.info("Expanding the hashtable to " + capacity + " capacity");
    int newHashBitCount = hashBitCount + 1;

    // Relocate all assigned slots from the old hash table.
    int maxSteps = 0;
    for (int oldSlot = 0; oldSlot < oldRefs.length; ++oldSlot) {
      long oldRef = oldRefs[oldSlot];
      if (oldRef == 0) {
        continue;
      }
      // TODO: we could actually store a bit flag in ref indicating whether this is a hash
      //       match or a probe, and in the former case use hash bits (for a first few resizes).
      // int hashCodeOrPart = oldSlot | Ref.getNthHashBit(oldRef, startingHashBitCount, newHashBitCount);
      writeBuffers.setUnsafeReadPoint(getFirstRecordLengthsOffset(oldRef, null));
      // Read the value and key length for the first record.
      int hashCode = (int)writeBuffers.unsafeReadNByteLong(Ref.getOffset(oldRef)
          - writeBuffers.unsafeReadVLong() - writeBuffers.unsafeReadVLong() - 4, 4);
      int probeSteps = relocateKeyRef(newRefs, oldRef, hashCode);
      maxSteps = Math.max(probeSteps, maxSteps);
    }
    this.refs = newRefs;
    this.largestNumberOfSteps = maxSteps;
    this.hashBitCount = newHashBitCount;
    this.resizeThreshold = (int)(capacity * loadFactor);
    metricExpandsMs += (System.currentTimeMillis() - expandTime);
    ++metricExpands;
  }
@param ref Reference.
@return The offset to value and key length vlongs of the first record referenced by ref.
ql/src/java/org/apache/hadoop/hive/ql/exec/persistence/BytesBytesMultiHashMap.java