]> git.ipfire.org Git - thirdparty/git.git/commitdiff
object-file: generalize counting objects
authorPatrick Steinhardt <ps@pks.im>
Thu, 12 Mar 2026 08:42:59 +0000 (09:42 +0100)
committerJunio C Hamano <gitster@pobox.com>
Thu, 12 Mar 2026 15:38:42 +0000 (08:38 -0700)
Generalize the function introduced in the preceding commit to not only
be able to approximate the number of loose objects, but to also provide
an accurate count. The behaviour can be toggled via a new flag.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/gc.c
object-file.c
object-file.h
odb.h

index a08c7554cb1374385681c4140b8cf9e5331c4e8d..3a64d28da81b611eb28b7b6030b6566fa6208732 100644 (file)
@@ -474,8 +474,9 @@ static int too_many_loose_objects(int limit)
        int auto_threshold = DIV_ROUND_UP(limit, 256) * 256;
        unsigned long loose_count;
 
-       if (odb_source_loose_approximate_object_count(the_repository->objects->sources,
-                                                     &loose_count) < 0)
+       if (odb_source_loose_count_objects(the_repository->objects->sources,
+                                          ODB_COUNT_OBJECTS_APPROXIMATE,
+                                          &loose_count) < 0)
                return 0;
 
        return loose_count > auto_threshold;
index da67e3c9ff576fa363cfd9537c8f94531fb6eaa2..569ce6eaed95d4940974a3c24e1bb0bd50dc574f 100644 (file)
@@ -1868,40 +1868,57 @@ int odb_source_loose_for_each_object(struct odb_source *source,
                                             NULL, NULL, &data);
 }
 
-int odb_source_loose_approximate_object_count(struct odb_source *source,
-                                             unsigned long *out)
+static int count_loose_object(const struct object_id *oid UNUSED,
+                             struct object_info *oi UNUSED,
+                             void *payload)
+{
+       unsigned long *count = payload;
+       (*count)++;
+       return 0;
+}
+
+int odb_source_loose_count_objects(struct odb_source *source,
+                                  enum odb_count_objects_flags flags,
+                                  unsigned long *out)
 {
        const unsigned hexsz = source->odb->repo->hash_algo->hexsz - 2;
-       unsigned long count = 0;
-       struct dirent *ent;
        char *path = NULL;
        DIR *dir = NULL;
        int ret;
 
-       path = xstrfmt("%s/17", source->path);
+       if (flags & ODB_COUNT_OBJECTS_APPROXIMATE) {
+               unsigned long count = 0;
+               struct dirent *ent;
 
-       dir = opendir(path);
-       if (!dir) {
-               if (errno == ENOENT) {
-                       *out = 0;
-                       ret = 0;
+               path = xstrfmt("%s/17", source->path);
+
+               dir = opendir(path);
+               if (!dir) {
+                       if (errno == ENOENT) {
+                               *out = 0;
+                               ret = 0;
+                               goto out;
+                       }
+
+                       ret = error_errno("cannot open object shard '%s'", path);
                        goto out;
                }
 
-               ret = error_errno("cannot open object shard '%s'", path);
-               goto out;
-       }
+               while ((ent = readdir(dir)) != NULL) {
+                       if (strspn(ent->d_name, "0123456789abcdef") != hexsz ||
+                           ent->d_name[hexsz] != '\0')
+                               continue;
+                       count++;
+               }
 
-       while ((ent = readdir(dir)) != NULL) {
-               if (strspn(ent->d_name, "0123456789abcdef") != hexsz ||
-                   ent->d_name[hexsz] != '\0')
-                       continue;
-               count++;
+               *out = count * 256;
+               ret = 0;
+       } else {
+               *out = 0;
+               ret = odb_source_loose_for_each_object(source, NULL, count_loose_object,
+                                                      out, 0);
        }
 
-       *out = count * 256;
-       ret = 0;
-
 out:
        if (dir)
                closedir(dir);
index b870ea9fa8deb2bb44cde7a0df89a3a1ed5f6f89..f8d8805a18cc8cb940347c7190448e38bd7d8158 100644 (file)
@@ -149,8 +149,9 @@ int odb_source_loose_for_each_object(struct odb_source *source,
  *
  * Returns 0 on success, a negative error code otherwise.
  */
-int odb_source_loose_approximate_object_count(struct odb_source *source,
-                                             unsigned long *out);
+int odb_source_loose_count_objects(struct odb_source *source,
+                                  enum odb_count_objects_flags flags,
+                                  unsigned long *out);
 
 /**
  * format_object_header() is a thin wrapper around s xsnprintf() that
diff --git a/odb.h b/odb.h
index 7a583e38732b7d50a0b98024b5419116eab7909b..e6057477f624cd1559ffcd8f25ac5e43dbab8d76 100644 (file)
--- a/odb.h
+++ b/odb.h
@@ -500,6 +500,15 @@ int odb_for_each_object(struct object_database *odb,
                        void *cb_data,
                        unsigned flags);
 
+enum odb_count_objects_flags {
+       /*
+        * Instead of providing an accurate count, allow the number of objects
+        * to be approximated. Details of how this approximation works are
+        * subject to the specific source's implementation.
+        */
+       ODB_COUNT_OBJECTS_APPROXIMATE = (1 << 0),
+};
+
 enum {
        /*
         * By default, `odb_write_object()` does not actually write anything