reftable/merged: transfer ownership of records when iterating
commit19b9496c1f0630a4ba252abcdfd313bf9c46347a
authorPatrick Steinhardt <ps@pks.im>
Wed, 3 Jan 2024 06:22:43 +0000 (3 07:22 +0100)
committerJunio C Hamano <gitster@pobox.com>
Wed, 3 Jan 2024 17:54:21 +0000 (3 09:54 -0800)
tree9a99dd2ac181b4a483241d5632abadce09c613a9
parent5473aca3767b00eab502b34a37b595de099980ae
reftable/merged: transfer ownership of records when iterating

When iterating over records with the merged iterator we put the records
into a priority queue before yielding them to the caller. This means
that we need to allocate the contents of these records before we can
pass them over to the caller.

The handover to the caller is quite inefficient though because we first
deallocate the record passed in by the caller and then copy over the new
record, which requires us to reallocate memory.

Refactor the code to instead transfer ownership of the new record to the
caller. So instead of reallocating all contents, we now release the old
record and then copy contents of the new record into place.

The following benchmark of `git show-ref --quiet` in a repository with
around 350k refs shows a clear improvement. Before:

    HEAP SUMMARY:
        in use at exit: 21,163 bytes in 193 blocks
      total heap usage: 708,058 allocs, 707,865 frees, 36,783,255 bytes allocated

After:

    HEAP SUMMARY:
        in use at exit: 21,163 bytes in 193 blocks
      total heap usage: 357,007 allocs, 356,814 frees, 24,193,602 bytes allocated

This shows that we now have roundabout a single allocation per record
that we're yielding from the iterator. Ideally, we'd also get rid of
this allocation so that the number of allocations doesn't scale with the
number of refs anymore. This would require some larger surgery though
because the memory is owned by the priority queue before transferring it
over to the caller.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
reftable/merged.c