pack-objects: allocate memory more efficiently

The packbuilder code allocates memory in chunks. When it needs to
allocate, it tries to add 1024 to the number of objects and multiply by
3/2. However, it actually multiplies by 1 instead, since it performs an
integral division in the expression "3 / 2" and only then multiplies by
the increased number of objects.

The current behavior causes the code to waste massive amounts of time
copying memory when it reallocates, causing inserting all non-blob
objects in the Linux repository into a new pack to take some
indeterminate time greater than 5 minutes instead of 52 seconds.

Correct this error by first dividing by two, and only then multiplying
by 3. We still check for overflow for the multiplication, which is the
only part that can overflow. This appears to be the only place in the
code base which has this problem.
parent f92d495d
...@@ -223,7 +223,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, ...@@ -223,7 +223,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
if (pb->nr_objects >= pb->nr_alloc) { if (pb->nr_objects >= pb->nr_alloc) {
GIT_ERROR_CHECK_ALLOC_ADD(&newsize, pb->nr_alloc, 1024); GIT_ERROR_CHECK_ALLOC_ADD(&newsize, pb->nr_alloc, 1024);
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&newsize, newsize, 3 / 2); GIT_ERROR_CHECK_ALLOC_MULTIPLY(&newsize, newsize / 2, 3);
if (!git__is_uint32(newsize)) { if (!git__is_uint32(newsize)) {
git_error_set(GIT_ERROR_NOMEMORY, "packfile too large to fit in memory."); git_error_set(GIT_ERROR_NOMEMORY, "packfile too large to fit in memory.");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment