]> git.ipfire.org Git - thirdparty/git.git/commitdiff
repack: remove pack_geometry API from the builtin
authorTaylor Blau <me@ttaylorr.com>
Wed, 15 Oct 2025 22:28:47 +0000 (18:28 -0400)
committerJunio C Hamano <gitster@pobox.com>
Thu, 16 Oct 2025 17:08:55 +0000 (10:08 -0700)
Now that the pack_geometry API is fully factored and isolated from the
rest of the builtin, declare it within repack.h and move its
implementation to "repack-geometry.c" as a separate component.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Makefile
builtin/repack.c
meson.build
repack-geometry.c [new file with mode: 0644]
repack.h

index 2a01bd92dc740c61d306b83176ffd9d95be47db8..3ee8d27dba24b8c46edbe71d4e5a6a7dc5ac6dc2 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1137,6 +1137,7 @@ LIB_OBJS += refs/ref-cache.o
 LIB_OBJS += refspec.o
 LIB_OBJS += remote.o
 LIB_OBJS += repack.o
+LIB_OBJS += repack-geometry.o
 LIB_OBJS += repack-promisor.o
 LIB_OBJS += replace-object.o
 LIB_OBJS += repo-settings.o
index f6d04b33a79c6c6e65547fe30d4cd1b7bde27711..e2313c80c3901894798ad761d62d3208325f40ec 100644 (file)
@@ -107,241 +107,6 @@ static int repack_config(const char *var, const char *value,
        return git_default_config(var, value, ctx, cb);
 }
 
-struct pack_geometry {
-       struct packed_git **pack;
-       uint32_t pack_nr, pack_alloc;
-       uint32_t split;
-
-       int split_factor;
-};
-
-static uint32_t pack_geometry_weight(struct packed_git *p)
-{
-       if (open_pack_index(p))
-               die(_("cannot open index for %s"), p->pack_name);
-       return p->num_objects;
-}
-
-static int pack_geometry_cmp(const void *va, const void *vb)
-{
-       uint32_t aw = pack_geometry_weight(*(struct packed_git **)va),
-                bw = pack_geometry_weight(*(struct packed_git **)vb);
-
-       if (aw < bw)
-               return -1;
-       if (aw > bw)
-               return 1;
-       return 0;
-}
-
-static void pack_geometry_init(struct pack_geometry *geometry,
-                              struct existing_packs *existing,
-                              const struct pack_objects_args *args,
-                              int pack_kept_objects)
-{
-       struct packfile_store *packs = existing->repo->objects->packfiles;
-       struct packed_git *p;
-       struct strbuf buf = STRBUF_INIT;
-
-       for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
-               if (args->local && !p->pack_local)
-                       /*
-                        * When asked to only repack local packfiles we skip
-                        * over any packfiles that are borrowed from alternate
-                        * object directories.
-                        */
-                       continue;
-
-               if (!pack_kept_objects) {
-                       /*
-                        * Any pack that has its pack_keep bit set will
-                        * appear in existing->kept_packs below, but
-                        * this saves us from doing a more expensive
-                        * check.
-                        */
-                       if (p->pack_keep)
-                               continue;
-
-                       /*
-                        * The pack may be kept via the --keep-pack
-                        * option; check 'existing->kept_packs' to
-                        * determine whether to ignore it.
-                        */
-                       strbuf_reset(&buf);
-                       strbuf_addstr(&buf, pack_basename(p));
-                       strbuf_strip_suffix(&buf, ".pack");
-
-                       if (string_list_has_string(&existing->kept_packs, buf.buf))
-                               continue;
-               }
-               if (p->is_cruft)
-                       continue;
-
-               ALLOC_GROW(geometry->pack,
-                          geometry->pack_nr + 1,
-                          geometry->pack_alloc);
-
-               geometry->pack[geometry->pack_nr] = p;
-               geometry->pack_nr++;
-       }
-
-       QSORT(geometry->pack, geometry->pack_nr, pack_geometry_cmp);
-       strbuf_release(&buf);
-}
-
-static void pack_geometry_split(struct pack_geometry *geometry)
-{
-       uint32_t i;
-       uint32_t split;
-       off_t total_size = 0;
-
-       if (!geometry->pack_nr) {
-               geometry->split = geometry->pack_nr;
-               return;
-       }
-
-       /*
-        * First, count the number of packs (in descending order of size) which
-        * already form a geometric progression.
-        */
-       for (i = geometry->pack_nr - 1; i > 0; i--) {
-               struct packed_git *ours = geometry->pack[i];
-               struct packed_git *prev = geometry->pack[i - 1];
-
-               if (unsigned_mult_overflows(geometry->split_factor,
-                                           pack_geometry_weight(prev)))
-                       die(_("pack %s too large to consider in geometric "
-                             "progression"),
-                           prev->pack_name);
-
-               if (pack_geometry_weight(ours) <
-                   geometry->split_factor * pack_geometry_weight(prev))
-                       break;
-       }
-
-       split = i;
-
-       if (split) {
-               /*
-                * Move the split one to the right, since the top element in the
-                * last-compared pair can't be in the progression. Only do this
-                * when we split in the middle of the array (otherwise if we got
-                * to the end, then the split is in the right place).
-                */
-               split++;
-       }
-
-       /*
-        * Then, anything to the left of 'split' must be in a new pack. But,
-        * creating that new pack may cause packs in the heavy half to no longer
-        * form a geometric progression.
-        *
-        * Compute an expected size of the new pack, and then determine how many
-        * packs in the heavy half need to be joined into it (if any) to restore
-        * the geometric progression.
-        */
-       for (i = 0; i < split; i++) {
-               struct packed_git *p = geometry->pack[i];
-
-               if (unsigned_add_overflows(total_size, pack_geometry_weight(p)))
-                       die(_("pack %s too large to roll up"), p->pack_name);
-               total_size += pack_geometry_weight(p);
-       }
-       for (i = split; i < geometry->pack_nr; i++) {
-               struct packed_git *ours = geometry->pack[i];
-
-               if (unsigned_mult_overflows(geometry->split_factor,
-                                           total_size))
-                       die(_("pack %s too large to roll up"), ours->pack_name);
-
-               if (pack_geometry_weight(ours) <
-                   geometry->split_factor * total_size) {
-                       if (unsigned_add_overflows(total_size,
-                                                  pack_geometry_weight(ours)))
-                               die(_("pack %s too large to roll up"),
-                                   ours->pack_name);
-
-                       split++;
-                       total_size += pack_geometry_weight(ours);
-               } else
-                       break;
-       }
-
-       geometry->split = split;
-}
-
-static struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry)
-{
-       uint32_t i;
-
-       if (!geometry) {
-               /*
-                * No geometry means either an all-into-one repack (in which
-                * case there is only one pack left and it is the largest) or an
-                * incremental one.
-                *
-                * If repacking incrementally, then we could check the size of
-                * all packs to determine which should be preferred, but leave
-                * this for later.
-                */
-               return NULL;
-       }
-       if (geometry->split == geometry->pack_nr)
-               return NULL;
-
-       /*
-        * The preferred pack is the largest pack above the split line. In
-        * other words, it is the largest pack that does not get rolled up in
-        * the geometric repack.
-        */
-       for (i = geometry->pack_nr; i > geometry->split; i--)
-               /*
-                * A pack that is not local would never be included in a
-                * multi-pack index. We thus skip over any non-local packs.
-                */
-               if (geometry->pack[i - 1]->pack_local)
-                       return geometry->pack[i - 1];
-
-       return NULL;
-}
-
-static void pack_geometry_remove_redundant(struct pack_geometry *geometry,
-                                          struct string_list *names,
-                                          struct existing_packs *existing,
-                                          const char *packdir)
-{
-       const struct git_hash_algo *algop = existing->repo->hash_algo;
-       struct strbuf buf = STRBUF_INIT;
-       uint32_t i;
-
-       for (i = 0; i < geometry->split; i++) {
-               struct packed_git *p = geometry->pack[i];
-               if (string_list_has_string(names, hash_to_hex_algop(p->hash,
-                                                                   algop)))
-                       continue;
-
-               strbuf_reset(&buf);
-               strbuf_addstr(&buf, pack_basename(p));
-               strbuf_strip_suffix(&buf, ".pack");
-
-               if ((p->pack_keep) ||
-                   (string_list_has_string(&existing->kept_packs, buf.buf)))
-                       continue;
-
-               repack_remove_redundant_pack(existing->repo, packdir, buf.buf);
-       }
-
-       strbuf_release(&buf);
-}
-
-static void pack_geometry_release(struct pack_geometry *geometry)
-{
-       if (!geometry)
-               return;
-
-       free(geometry->pack);
-}
-
 static int midx_has_unknown_packs(char **midx_pack_names,
                                  size_t midx_pack_names_nr,
                                  struct string_list *include,
index 1fbb8c52a645b4932f06e850d928d366a27db34e..47b05089eeceeeeb4002734c9f11528988b498bd 100644 (file)
@@ -463,6 +463,7 @@ libgit_sources = [
   'reftable/writer.c',
   'remote.c',
   'repack.c',
+  'repack-geometry.c',
   'repack-promisor.c',
   'replace-object.c',
   'repo-settings.c',
diff --git a/repack-geometry.c b/repack-geometry.c
new file mode 100644 (file)
index 0000000..f58f1fc
--- /dev/null
@@ -0,0 +1,234 @@
+#define DISABLE_SIGN_COMPARE_WARNINGS
+
+#include "git-compat-util.h"
+#include "repack.h"
+#include "repository.h"
+#include "hex.h"
+#include "packfile.h"
+
+static uint32_t pack_geometry_weight(struct packed_git *p)
+{
+       if (open_pack_index(p))
+               die(_("cannot open index for %s"), p->pack_name);
+       return p->num_objects;
+}
+
+static int pack_geometry_cmp(const void *va, const void *vb)
+{
+       uint32_t aw = pack_geometry_weight(*(struct packed_git **)va),
+                bw = pack_geometry_weight(*(struct packed_git **)vb);
+
+       if (aw < bw)
+               return -1;
+       if (aw > bw)
+               return 1;
+       return 0;
+}
+
+void pack_geometry_init(struct pack_geometry *geometry,
+                       struct existing_packs *existing,
+                       const struct pack_objects_args *args,
+                       int pack_kept_objects)
+{
+       struct packfile_store *packs = existing->repo->objects->packfiles;
+       struct packed_git *p;
+       struct strbuf buf = STRBUF_INIT;
+
+       for (p = packfile_store_get_all_packs(packs); p; p = p->next) {
+               if (args->local && !p->pack_local)
+                       /*
+                        * When asked to only repack local packfiles we skip
+                        * over any packfiles that are borrowed from alternate
+                        * object directories.
+                        */
+                       continue;
+
+               if (!pack_kept_objects) {
+                       /*
+                        * Any pack that has its pack_keep bit set will
+                        * appear in existing->kept_packs below, but
+                        * this saves us from doing a more expensive
+                        * check.
+                        */
+                       if (p->pack_keep)
+                               continue;
+
+                       /*
+                        * The pack may be kept via the --keep-pack
+                        * option; check 'existing->kept_packs' to
+                        * determine whether to ignore it.
+                        */
+                       strbuf_reset(&buf);
+                       strbuf_addstr(&buf, pack_basename(p));
+                       strbuf_strip_suffix(&buf, ".pack");
+
+                       if (string_list_has_string(&existing->kept_packs, buf.buf))
+                               continue;
+               }
+               if (p->is_cruft)
+                       continue;
+
+               ALLOC_GROW(geometry->pack,
+                          geometry->pack_nr + 1,
+                          geometry->pack_alloc);
+
+               geometry->pack[geometry->pack_nr] = p;
+               geometry->pack_nr++;
+       }
+
+       QSORT(geometry->pack, geometry->pack_nr, pack_geometry_cmp);
+       strbuf_release(&buf);
+}
+
+void pack_geometry_split(struct pack_geometry *geometry)
+{
+       uint32_t i;
+       uint32_t split;
+       off_t total_size = 0;
+
+       if (!geometry->pack_nr) {
+               geometry->split = geometry->pack_nr;
+               return;
+       }
+
+       /*
+        * First, count the number of packs (in descending order of size) which
+        * already form a geometric progression.
+        */
+       for (i = geometry->pack_nr - 1; i > 0; i--) {
+               struct packed_git *ours = geometry->pack[i];
+               struct packed_git *prev = geometry->pack[i - 1];
+
+               if (unsigned_mult_overflows(geometry->split_factor,
+                                           pack_geometry_weight(prev)))
+                       die(_("pack %s too large to consider in geometric "
+                             "progression"),
+                           prev->pack_name);
+
+               if (pack_geometry_weight(ours) <
+                   geometry->split_factor * pack_geometry_weight(prev))
+                       break;
+       }
+
+       split = i;
+
+       if (split) {
+               /*
+                * Move the split one to the right, since the top element in the
+                * last-compared pair can't be in the progression. Only do this
+                * when we split in the middle of the array (otherwise if we got
+                * to the end, then the split is in the right place).
+                */
+               split++;
+       }
+
+       /*
+        * Then, anything to the left of 'split' must be in a new pack. But,
+        * creating that new pack may cause packs in the heavy half to no longer
+        * form a geometric progression.
+        *
+        * Compute an expected size of the new pack, and then determine how many
+        * packs in the heavy half need to be joined into it (if any) to restore
+        * the geometric progression.
+        */
+       for (i = 0; i < split; i++) {
+               struct packed_git *p = geometry->pack[i];
+
+               if (unsigned_add_overflows(total_size, pack_geometry_weight(p)))
+                       die(_("pack %s too large to roll up"), p->pack_name);
+               total_size += pack_geometry_weight(p);
+       }
+       for (i = split; i < geometry->pack_nr; i++) {
+               struct packed_git *ours = geometry->pack[i];
+
+               if (unsigned_mult_overflows(geometry->split_factor,
+                                           total_size))
+                       die(_("pack %s too large to roll up"), ours->pack_name);
+
+               if (pack_geometry_weight(ours) <
+                   geometry->split_factor * total_size) {
+                       if (unsigned_add_overflows(total_size,
+                                                  pack_geometry_weight(ours)))
+                               die(_("pack %s too large to roll up"),
+                                   ours->pack_name);
+
+                       split++;
+                       total_size += pack_geometry_weight(ours);
+               } else
+                       break;
+       }
+
+       geometry->split = split;
+}
+
+struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry)
+{
+       uint32_t i;
+
+       if (!geometry) {
+               /*
+                * No geometry means either an all-into-one repack (in which
+                * case there is only one pack left and it is the largest) or an
+                * incremental one.
+                *
+                * If repacking incrementally, then we could check the size of
+                * all packs to determine which should be preferred, but leave
+                * this for later.
+                */
+               return NULL;
+       }
+       if (geometry->split == geometry->pack_nr)
+               return NULL;
+
+       /*
+        * The preferred pack is the largest pack above the split line. In
+        * other words, it is the largest pack that does not get rolled up in
+        * the geometric repack.
+        */
+       for (i = geometry->pack_nr; i > geometry->split; i--)
+               /*
+                * A pack that is not local would never be included in a
+                * multi-pack index. We thus skip over any non-local packs.
+                */
+               if (geometry->pack[i - 1]->pack_local)
+                       return geometry->pack[i - 1];
+
+       return NULL;
+}
+
+void pack_geometry_remove_redundant(struct pack_geometry *geometry,
+                                   struct string_list *names,
+                                   struct existing_packs *existing,
+                                   const char *packdir)
+{
+       const struct git_hash_algo *algop = existing->repo->hash_algo;
+       struct strbuf buf = STRBUF_INIT;
+       uint32_t i;
+
+       for (i = 0; i < geometry->split; i++) {
+               struct packed_git *p = geometry->pack[i];
+               if (string_list_has_string(names, hash_to_hex_algop(p->hash,
+                                                                   algop)))
+                       continue;
+
+               strbuf_reset(&buf);
+               strbuf_addstr(&buf, pack_basename(p));
+               strbuf_strip_suffix(&buf, ".pack");
+
+               if ((p->pack_keep) ||
+                   (string_list_has_string(&existing->kept_packs, buf.buf)))
+                       continue;
+
+               repack_remove_redundant_pack(existing->repo, packdir, buf.buf);
+       }
+
+       strbuf_release(&buf);
+}
+
+void pack_geometry_release(struct pack_geometry *geometry)
+{
+       if (!geometry)
+               return;
+
+       free(geometry->pack);
+}
index 19dc4fd738dcc16a356e2632a22d3d3cac968cd5..cea7969ae47b19c71bd8fd0bcafb27281b54cca6 100644 (file)
--- a/repack.h
+++ b/repack.h
@@ -78,4 +78,24 @@ void repack_promisor_objects(struct repository *repo,
                             const struct pack_objects_args *args,
                             struct string_list *names, const char *packtmp);
 
+struct pack_geometry {
+       struct packed_git **pack;
+       uint32_t pack_nr, pack_alloc;
+       uint32_t split;
+
+       int split_factor;
+};
+
+void pack_geometry_init(struct pack_geometry *geometry,
+                       struct existing_packs *existing,
+                       const struct pack_objects_args *args,
+                       int pack_kept_objects);
+void pack_geometry_split(struct pack_geometry *geometry);
+struct packed_git *pack_geometry_preferred_pack(struct pack_geometry *geometry);
+void pack_geometry_remove_redundant(struct pack_geometry *geometry,
+                                   struct string_list *names,
+                                   struct existing_packs *existing,
+                                   const char *packdir);
+void pack_geometry_release(struct pack_geometry *geometry);
+
 #endif /* REPACK_H */