odb/source-loose: wire up `count_objects()` callback
Move `odb_source_loose_count_objects()` and its associated helpers from "object-file.c" into "odb/source-loose.c" and wire it up as the `count_objects()` callback of the loose source. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jun 1, 2026 at 10:20 UTC
2ade08ac2978dc1c908602c2a4d653836ecb5acb
5 files changed
+65
-78
builtin/gc.c
+3
-3
@@ -466,6 +466,7 @@ out:
466
467
static int too_many_loose_objects(int limit)
468
{
469
+ struct odb_source_files *files = odb_source_files_downcast(the_repository->objects->sources);
470
/*
471
* This is weird, but stems from legacy behaviour: the GC auto
472
* threshold was always essentially interpreted as if it was rounded up
@@ -474,9 +475,8 @@ static int too_many_loose_objects(int limit)
475
int auto_threshold = DIV_ROUND_UP(limit, 256) * 256;
476
unsigned long loose_count;
477
477
- if (odb_source_loose_count_objects(the_repository->objects->sources,
478
- ODB_COUNT_OBJECTS_APPROXIMATE,
479
- &loose_count) < 0)
478
+ if (odb_source_count_objects(&files->loose->base, ODB_COUNT_OBJECTS_APPROXIMATE,
479
+ &loose_count) < 0)
480
return 0;
481
482
return loose_count > auto_threshold;
object-file.c
-60
@@ -1602,66 +1602,6 @@ int for_each_loose_file_in_source(struct odb_source *source,
1602
return r;
1603
}
1604
1605
-static int count_loose_object(const struct object_id *oid UNUSED,
1606
- struct object_info *oi UNUSED,
1607
- void *payload)
1608
-{
1609
- unsigned long *count = payload;
1610
- (*count)++;
1611
- return 0;
1612
-}
1613
-
1614
-int odb_source_loose_count_objects(struct odb_source *source,
1615
- enum odb_count_objects_flags flags,
1616
- unsigned long *out)
1617
-{
1618
- struct odb_source_files *files = odb_source_files_downcast(source);
1619
- const unsigned hexsz = source->odb->repo->hash_algo->hexsz - 2;
1620
- char *path = NULL;
1621
- DIR *dir = NULL;
1622
- int ret;
1623
-
1624
- if (flags & ODB_COUNT_OBJECTS_APPROXIMATE) {
1625
- unsigned long count = 0;
1626
- struct dirent *ent;
1627
-
1628
- path = xstrfmt("%s/17", source->path);
1629
-
1630
- dir = opendir(path);
1631
- if (!dir) {
1632
- if (errno == ENOENT) {
1633
- *out = 0;
1634
- ret = 0;
1635
- goto out;
1636
- }
1637
-
1638
- ret = error_errno("cannot open object shard '%s'", path);
1639
- goto out;
1640
- }
1641
-
1642
- while ((ent = readdir(dir)) != NULL) {
1643
- if (strspn(ent->d_name, "0123456789abcdef") != hexsz ||
1644
- ent->d_name[hexsz] != '\0')
1645
- continue;
1646
- count++;
1647
- }
1648
-
1649
- *out = count * 256;
1650
- ret = 0;
1651
- } else {
1652
- struct odb_for_each_object_options opts = { 0 };
1653
- *out = 0;
1654
- ret = odb_source_for_each_object(&files->loose->base, NULL, count_loose_object,
1655
- out, &opts);
1656
- }
1657
-
1658
-out:
1659
- if (dir)
1660
- closedir(dir);
1661
- free(path);
1662
- return ret;
1663
-}
1664
-
1605
static int check_stream_oid(git_zstream *stream,
1606
const char *hdr,
1607
unsigned long size,
object-file.h
-14
@@ -96,20 +96,6 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr,
96
each_loose_subdir_fn subdir_cb,
97
void *data);
98
99
-/*
100
- * Count the number of loose objects in this source.
101
- *
102
- * The object count is approximated by opening a single sharding directory for
103
- * loose objects and scanning its contents. The result is then extrapolated by
104
- * 256. This should generally work as a reasonable estimate given that the
105
- * object hash is supposed to be indistinguishable from random.
106
- *
107
- * Returns 0 on success, a negative error code otherwise.
108
- */
109
-int odb_source_loose_count_objects(struct odb_source *source,
110
- enum odb_count_objects_flags flags,
111
- unsigned long *out);
112
-
99
/**
100
* format_object_header() is a thin wrapper around s xsnprintf() that
101
* writes the initial "<type> <obj-len>" part of the loose object
odb/source-files.c
+1
-1
@@ -109,7 +109,7 @@ static int odb_source_files_count_objects(struct odb_source *source,
109
if (!(flags & ODB_COUNT_OBJECTS_APPROXIMATE)) {
110
unsigned long loose_count;
111
112
- ret = odb_source_loose_count_objects(source, flags, &loose_count);
112
+ ret = odb_source_count_objects(&files->loose->base, flags, &loose_count);
113
if (ret < 0)
114
goto out;
115
odb/source-loose.c
+61
@@ -520,6 +520,66 @@ static int odb_source_loose_find_abbrev_len(struct odb_source *source,
520
return ret;
521
}
522
523
+static int count_loose_object(const struct object_id *oid UNUSED,
524
+ struct object_info *oi UNUSED,
525
+ void *payload)
526
+{
527
+ unsigned long *count = payload;
528
+ (*count)++;
529
+ return 0;
530
+}
531
+
532
+static int odb_source_loose_count_objects(struct odb_source *source,
533
+ enum odb_count_objects_flags flags,
534
+ unsigned long *out)
535
+{
536
+ struct odb_source_loose *loose = odb_source_loose_downcast(source);
537
+ const unsigned hexsz = source->odb->repo->hash_algo->hexsz - 2;
538
+ char *path = NULL;
539
+ DIR *dir = NULL;
540
+ int ret;
541
+
542
+ if (flags & ODB_COUNT_OBJECTS_APPROXIMATE) {
543
+ unsigned long count = 0;
544
+ struct dirent *ent;
545
+
546
+ path = xstrfmt("%s/17", source->path);
547
+
548
+ dir = opendir(path);
549
+ if (!dir) {
550
+ if (errno == ENOENT) {
551
+ *out = 0;
552
+ ret = 0;
553
+ goto out;
554
+ }
555
+
556
+ ret = error_errno("cannot open object shard '%s'", path);
557
+ goto out;
558
+ }
559
+
560
+ while ((ent = readdir(dir)) != NULL) {
561
+ if (strspn(ent->d_name, "0123456789abcdef") != hexsz ||
562
+ ent->d_name[hexsz] != '\0')
563
+ continue;
564
+ count++;
565
+ }
566
+
567
+ *out = count * 256;
568
+ ret = 0;
569
+ } else {
570
+ struct odb_for_each_object_options opts = { 0 };
571
+ *out = 0;
572
+ ret = odb_source_for_each_object(&loose->base, NULL, count_loose_object,
573
+ out, &opts);
574
+ }
575
+
576
+out:
577
+ if (dir)
578
+ closedir(dir);
579
+ free(path);
580
+ return ret;
581
+}
582
+
583
static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
584
{
585
oidtree_clear(loose->cache);
@@ -577,6 +637,7 @@ struct odb_source_loose *odb_source_loose_new(struct odb_source_files *files)
637
loose->base.read_object_stream = odb_source_loose_read_object_stream;
638
loose->base.for_each_object = odb_source_loose_for_each_object;
639
loose->base.find_abbrev_len = odb_source_loose_find_abbrev_len;
640
+ loose->base.count_objects = odb_source_loose_count_objects;
641
642
if (!is_absolute_path(loose->base.path))
643
chdir_notify_register(NULL, odb_source_loose_reparent, loose);