[pacman-dev] [PATCH 2/2] Overhaul archive fgets function

Xavier Chantry chantry.xavier at gmail.com
Sun Dec 19 12:32:07 EST 2010

On Wed, Dec 15, 2010 at 7:48 AM, Dan McGee <dan at archlinux.org> wrote:
> The old function was written in a time before we relied on it for nearly
> every operation. Since then, we have switched to the archive backend and now
> fast parsing is a big deal.
> The former function made a per-character call to the libarchive
> archive_read_data() function, which resulted in some 21 million calls in a
> typical "load all sync dbs" operation. If we instead do some buffering of
> our own and read the blocks directly, and then find our newlines from there,
> we can cut out the multiple layers of overhead and go from archive to parsed
> data much quicker.
> Both users of the former function are switched over to the new signature,
> made easier by the macros now in place in the sync backend parsing code.
> Performance: for a `pacman -Su` (no upgrades available),
> _alpm_archive_fgets() goes from being 29% of the total time to 12% The time
> spent on the libarchive function being called dropped from 24% to 6%.
> This pushes _alpm_pkg_find back to the title of slowest low-level function.
> Signed-off-by: Dan McGee <dan at archlinux.org>
> ---
> I wish this one was a bit easier to comprehend and grok, but the cost of
> performance here is a bit more complicated fgets function than the very
> simplistic one we had before.
> The new function revolves around the zero-copy, retrieve an entire block
> functinoality of libarchive. We create a structure to keep all the bookkeeping
> info we need around, including a buffer of our own where each line ends up and
> auto-resizes itself as we poll through an archive file entry, and also cleans
> itself up when the file is EOF. This means malloc/free is not necessary by the
> caller, which keeps most concerns in the fgets function.
> Please let me know if it is unclear how the new function works, so more
> comments can be put in there.

Since we have just one line, I would not have bothered trying to alloc
exactly what we need. I would just have used a static or dynamic buf
of max line size, and be done with it.
But anyway you already implemented the more complex way and I don't
see a problem with that as long as its tested (especially the re-alloc
part) :)
I could not spot a problem by simply reading the code.

Another minor observation : in the !done case, the alloc block does a
strict allocation and thus does not take into account that we will
very likely have to extend it on the next iteration (if we did not
reach the last archive block).

Finally can it actually happen with our sync archives which only has
very small files that a line is split across two blocks ?

In any cases, this is another very welcome improvement.

More information about the pacman-dev mailing list