hollow/src/main/java/com/netflix/hollow/core/memory/ByteArrayOrdinalMap.java
public void compact(ThreadSafeBitSet usedOrdinals) {
        long[] populatedReverseKeys = new long[size];

        int counter = 0;
        AtomicLongArray pao = pointersAndOrdinals;

        for (int i = 0; i < pao.length(); i++) {
            long key = pao.get(i);
            if (key != EMPTY_BUCKET_VALUE) {
                populatedReverseKeys[counter++] = key << BITS_PER_ORDINAL | key >>> BITS_PER_POINTER;
            }
        }

        Arrays.sort(populatedReverseKeys);

        SegmentedByteArray arr = byteData.getUnderlyingArray();
        long currentCopyPointer = 0;

        for (int i = 0; i < populatedReverseKeys.length; i++) {
            int ordinal = (int) (populatedReverseKeys[i] & ORDINAL_MASK);

            if (usedOrdinals.get(ordinal)) {
                long pointer = populatedReverseKeys[i] >>> BITS_PER_ORDINAL;
                int length = VarInt.readVInt(arr, pointer);
                length += VarInt.sizeOfVInt(length);

                if (currentCopyPointer != pointer) {
                    arr.copy(arr, pointer, currentCopyPointer, length);
                }

                populatedReverseKeys[i] = populatedReverseKeys[i] << BITS_PER_POINTER | currentCopyPointer;

                currentCopyPointer += length;
            } else {
                freeOrdinalTracker.returnOrdinalToPool(ordinal);
                populatedReverseKeys[i] = EMPTY_BUCKET_VALUE;
            }
        }

        byteData.setPosition(currentCopyPointer);
        freeOrdinalTracker.sort();

        // Reset the array then fill with compacted values
        // Volatile store not required, could use plain store
        // See VarHandles for JDK >= 9
        for (int i = 0; i < pao.length(); i++) {
            pao.lazySet(i, EMPTY_BUCKET_VALUE);
        }
        populateNewHashArray(pao, populatedReverseKeys);
        size = usedOrdinals.cardinality();

        pointersByOrdinal = null;
        unusedPreviousOrdinals = null;
    }
public void compact(ThreadSafeBitSet usedOrdinals) {
        long[] populatedReverseKeys = new long[size];

        int counter = 0;
        AtomicLongArray pao = pointersAndOrdinals;

        for (int i = 0; i < pao.length(); i++) {
            long key = pao.get(i);
            if (key != EMPTY_BUCKET_VALUE) {
                populatedReverseKeys[counter++] = key << BITS_PER_ORDINAL | key >>> BITS_PER_POINTER;
            }
        }

        Arrays.sort(populatedReverseKeys);

        SegmentedByteArray arr = byteData.getUnderlyingArray();
        long currentCopyPointer = 0;

        for (int i = 0; i < populatedReverseKeys.length; i++) {
            int ordinal = (int) (populatedReverseKeys[i] & ORDINAL_MASK);

            if (usedOrdinals.get(ordinal)) {
                long pointer = populatedReverseKeys[i] >>> BITS_PER_ORDINAL;
                int length = VarInt.readVInt(arr, pointer);
                length += VarInt.sizeOfVInt(length);

                if (currentCopyPointer != pointer) {
                    arr.copy(arr, pointer, currentCopyPointer, length);
                }

                populatedReverseKeys[i] = populatedReverseKeys[i] << BITS_PER_POINTER | currentCopyPointer;

                currentCopyPointer += length;
            } else {
                freeOrdinalTracker.returnOrdinalToPool(ordinal);
                populatedReverseKeys[i] = EMPTY_BUCKET_VALUE;
            }
        }

        byteData.setPosition(currentCopyPointer);
        freeOrdinalTracker.sort();

        // Reset the array then fill with compacted values
        // Volatile store not required, could use plain store
        // See VarHandles for JDK >= 9
        for (int i = 0; i < pao.length(); i++) {
            pao.lazySet(i, EMPTY_BUCKET_VALUE);
        }
        populateNewHashArray(pao, populatedReverseKeys);
        size = usedOrdinals.cardinality();

        pointersByOrdinal = null;
        unusedPreviousOrdinals = null;
    }
Reclaim space in the byte array used in the previous cycle, but not referenced in this cycle.<p>
<p>
This is achieved by shifting all used byte sequences down in the byte array, then updating
the key array to reflect the new pointers and exclude the removed entries.  This is also where ordinals
which are unused are returned to the pool.<p>

@param usedOrdinals a bit set representing the ordinals which are currently referenced by any image.