odb/source-packed: wire up `reprepare()` callback
Move the logic to prepare and reprepare the "packed" source into "odb/source-packed.c" and wire it up as the `reprepare()` callback. Note that "preparing" a source is not yet generic. Eventually, it would probably make sense to turn the existing `reprepare()` callback into a `prepare()` callback with an optional flag to force re-preparing. But this step will be handled in a separate patch series. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jun 17, 2026 at 08:39 UTC
9ea4ef8586d8fa74bf45c1dd8da2256099abebbd
7 files changed
+172
-177
builtin/grep.c
+1
-1
@@ -1363,7 +1363,7 @@ int cmd_grep(int argc,
1363
odb_prepare_alternates(the_repository->objects);
1364
for (source = the_repository->objects->sources; source; source = source->next) {
1365
struct odb_source_files *files = odb_source_files_downcast(source);
1366
- packfile_store_prepare(files->packed);
1366
+ odb_source_packed_prepare(files->packed);
1367
}
1368
}
1369
midx.c
+1
-1
@@ -102,7 +102,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
102
struct multi_pack_index *get_multi_pack_index(struct odb_source *source)
103
{
104
struct odb_source_files *files = odb_source_files_downcast(source);
105
- packfile_store_prepare(files->packed);
105
+ odb_source_packed_prepare(files->packed);
106
return files->packed->midx;
107
}
108
odb/source-files.c
+1
-1
@@ -45,7 +45,7 @@ static void odb_source_files_reprepare(struct odb_source *source)
45
{
46
struct odb_source_files *files = odb_source_files_downcast(source);
47
odb_source_reprepare(&files->loose->base);
48
- packfile_store_reprepare(files->packed);
48
+ odb_source_reprepare(&files->packed->base);
49
}
50
51
static int odb_source_files_read_object_info(struct odb_source *source,
odb/source-packed.c
+157
@@ -1,10 +1,166 @@
1
#include "git-compat-util.h"
2
#include "abspath.h"
3
#include "chdir-notify.h"
4
+#include "dir.h"
5
+#include "mergesort.h"
6
#include "midx.h"
7
#include "odb/source-packed.h"
8
#include "packfile.h"
9
10
+void (*report_garbage)(unsigned seen_bits, const char *path);
11
+
12
+static void report_helper(const struct string_list *list,
13
+ int seen_bits, int first, int last)
14
+{
15
+ if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX))
16
+ return;
17
+
18
+ for (; first < last; first++)
19
+ report_garbage(seen_bits, list->items[first].string);
20
+}
21
+
22
+static void report_pack_garbage(struct string_list *list)
23
+{
24
+ int baselen = -1, first = 0, seen_bits = 0;
25
+
26
+ if (!report_garbage)
27
+ return;
28
+
29
+ string_list_sort(list);
30
+
31
+ for (size_t i = 0; i < list->nr; i++) {
32
+ const char *path = list->items[i].string;
33
+ if (baselen != -1 &&
34
+ strncmp(path, list->items[first].string, baselen)) {
35
+ report_helper(list, seen_bits, first, i);
36
+ baselen = -1;
37
+ seen_bits = 0;
38
+ }
39
+ if (baselen == -1) {
40
+ const char *dot = strrchr(path, '.');
41
+ if (!dot) {
42
+ report_garbage(PACKDIR_FILE_GARBAGE, path);
43
+ continue;
44
+ }
45
+ baselen = dot - path + 1;
46
+ first = i;
47
+ }
48
+ if (!strcmp(path + baselen, "pack"))
49
+ seen_bits |= 1;
50
+ else if (!strcmp(path + baselen, "idx"))
51
+ seen_bits |= 2;
52
+ }
53
+ report_helper(list, seen_bits, first, list->nr);
54
+}
55
+
56
+struct prepare_pack_data {
57
+ struct odb_source *source;
58
+ struct string_list *garbage;
59
+};
60
+
61
+static void prepare_pack(const char *full_name, size_t full_name_len,
62
+ const char *file_name, void *_data)
63
+{
64
+ struct prepare_pack_data *data = (struct prepare_pack_data *)_data;
65
+ struct odb_source_files *files = odb_source_files_downcast(data->source);
66
+ size_t base_len = full_name_len;
67
+
68
+ if (strip_suffix_mem(full_name, &base_len, ".idx") &&
69
+ !(files->packed->midx &&
70
+ midx_contains_pack(files->packed->midx, file_name))) {
71
+ char *trimmed_path = xstrndup(full_name, full_name_len);
72
+ packfile_store_load_pack(files->packed,
73
+ trimmed_path, data->source->local);
74
+ free(trimmed_path);
75
+ }
76
+
77
+ if (!report_garbage)
78
+ return;
79
+
80
+ if (!strcmp(file_name, "multi-pack-index") ||
81
+ !strcmp(file_name, "multi-pack-index.d"))
82
+ return;
83
+ if (starts_with(file_name, "multi-pack-index") &&
84
+ (ends_with(file_name, ".bitmap") || ends_with(file_name, ".rev")))
85
+ return;
86
+ if (ends_with(file_name, ".idx") ||
87
+ ends_with(file_name, ".rev") ||
88
+ ends_with(file_name, ".pack") ||
89
+ ends_with(file_name, ".bitmap") ||
90
+ ends_with(file_name, ".keep") ||
91
+ ends_with(file_name, ".promisor") ||
92
+ ends_with(file_name, ".mtimes"))
93
+ string_list_append(data->garbage, full_name);
94
+ else
95
+ report_garbage(PACKDIR_FILE_GARBAGE, full_name);
96
+}
97
+
98
+static void prepare_packed_git_one(struct odb_source *source)
99
+{
100
+ struct string_list garbage = STRING_LIST_INIT_DUP;
101
+ struct prepare_pack_data data = {
102
+ .source = source,
103
+ .garbage = &garbage,
104
+ };
105
+
106
+ for_each_file_in_pack_dir(source->path, prepare_pack, &data);
107
+
108
+ report_pack_garbage(data.garbage);
109
+ string_list_clear(data.garbage, 0);
110
+}
111
+
112
+DEFINE_LIST_SORT(static, sort_packs, struct packfile_list_entry, next);
113
+
114
+static int sort_pack(const struct packfile_list_entry *a,
115
+ const struct packfile_list_entry *b)
116
+{
117
+ int st;
118
+
119
+ /*
120
+ * Local packs tend to contain objects specific to our
121
+ * variant of the project than remote ones. In addition,
122
+ * remote ones could be on a network mounted filesystem.
123
+ * Favor local ones for these reasons.
124
+ */
125
+ st = a->pack->pack_local - b->pack->pack_local;
126
+ if (st)
127
+ return -st;
128
+
129
+ /*
130
+ * Younger packs tend to contain more recent objects,
131
+ * and more recent objects tend to get accessed more
132
+ * often.
133
+ */
134
+ if (a->pack->mtime < b->pack->mtime)
135
+ return 1;
136
+ else if (a->pack->mtime == b->pack->mtime)
137
+ return 0;
138
+ return -1;
139
+}
140
+
141
+void odb_source_packed_prepare(struct odb_source_packed *source)
142
+{
143
+ if (source->initialized)
144
+ return;
145
+
146
+ prepare_multi_pack_index_one(&source->files->base);
147
+ prepare_packed_git_one(&source->files->base);
148
+
149
+ sort_packs(&source->packs.head, sort_pack);
150
+ for (struct packfile_list_entry *e = source->packs.head; e; e = e->next)
151
+ if (!e->next)
152
+ source->packs.tail = e;
153
+
154
+ source->initialized = true;
155
+}
156
+
157
+static void odb_source_packed_reprepare(struct odb_source *source)
158
+{
159
+ struct odb_source_packed *packed = odb_source_packed_downcast(source);
160
+ packed->initialized = false;
161
+ odb_source_packed_prepare(packed);
162
+}
163
+
164
static void odb_source_packed_reparent(const char *name UNUSED,
165
const char *old_cwd,
166
const char *new_cwd,
@@ -58,6 +214,7 @@ struct odb_source_packed *odb_source_packed_new(struct odb_source_files *parent)
214
215
packed->base.free = odb_source_packed_free;
216
packed->base.close = odb_source_packed_close;
217
+ packed->base.reprepare = odb_source_packed_reprepare;
218
219
if (!is_absolute_path(parent->base.path))
220
chdir_notify_register(NULL, odb_source_packed_reparent, packed);
odb/source-packed.h
+9
@@ -81,4 +81,13 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so
81
return container_of(source, struct odb_source_packed, base);
82
}
83
84
+/*
85
+ * Prepare the source by loading packfiles and multi-pack indices for
86
+ * all alternates. This becomes a no-op if the source is already prepared.
87
+ *
88
+ * It shouldn't typically be necessary to call this function directly, as
89
+ * functions that access the source know to prepare it.
90
+ */
91
+void odb_source_packed_prepare(struct odb_source_packed *source);
92
+
93
#endif
packfile.c
+3
-157
@@ -8,7 +8,6 @@
8
#include "pack.h"
9
#include "repository.h"
10
#include "dir.h"
11
-#include "mergesort.h"
11
#include "packfile.h"
12
#include "delta.h"
13
#include "hash-lookup.h"
@@ -812,52 +811,6 @@ struct packed_git *packfile_store_load_pack(struct odb_source_packed *store,
811
return p;
812
}
813
815
-void (*report_garbage)(unsigned seen_bits, const char *path);
816
-
817
-static void report_helper(const struct string_list *list,
818
- int seen_bits, int first, int last)
819
-{
820
- if (seen_bits == (PACKDIR_FILE_PACK|PACKDIR_FILE_IDX))
821
- return;
822
-
823
- for (; first < last; first++)
824
- report_garbage(seen_bits, list->items[first].string);
825
-}
826
-
827
-static void report_pack_garbage(struct string_list *list)
828
-{
829
- int i, baselen = -1, first = 0, seen_bits = 0;
830
-
831
- if (!report_garbage)
832
- return;
833
-
834
- string_list_sort(list);
835
-
836
- for (i = 0; i < list->nr; i++) {
837
- const char *path = list->items[i].string;
838
- if (baselen != -1 &&
839
- strncmp(path, list->items[first].string, baselen)) {
840
- report_helper(list, seen_bits, first, i);
841
- baselen = -1;
842
- seen_bits = 0;
843
- }
844
- if (baselen == -1) {
845
- const char *dot = strrchr(path, '.');
846
- if (!dot) {
847
- report_garbage(PACKDIR_FILE_GARBAGE, path);
848
- continue;
849
- }
850
- baselen = dot - path + 1;
851
- first = i;
852
- }
853
- if (!strcmp(path + baselen, "pack"))
854
- seen_bits |= 1;
855
- else if (!strcmp(path + baselen, "idx"))
856
- seen_bits |= 2;
857
- }
858
- report_helper(list, seen_bits, first, list->nr);
859
-}
860
-
814
void for_each_file_in_pack_subdir(const char *objdir,
815
const char *subdir,
816
each_file_in_pack_dir_fn fn,
@@ -900,116 +853,9 @@ void for_each_file_in_pack_dir(const char *objdir,
853
for_each_file_in_pack_subdir(objdir, NULL, fn, data);
854
}
855
903
-struct prepare_pack_data {
904
- struct odb_source *source;
905
- struct string_list *garbage;
906
-};
907
-
908
-static void prepare_pack(const char *full_name, size_t full_name_len,
909
- const char *file_name, void *_data)
910
-{
911
- struct prepare_pack_data *data = (struct prepare_pack_data *)_data;
912
- struct odb_source_files *files = odb_source_files_downcast(data->source);
913
- size_t base_len = full_name_len;
914
-
915
- if (strip_suffix_mem(full_name, &base_len, ".idx") &&
916
- !(files->packed->midx &&
917
- midx_contains_pack(files->packed->midx, file_name))) {
918
- char *trimmed_path = xstrndup(full_name, full_name_len);
919
- packfile_store_load_pack(files->packed,
920
- trimmed_path, data->source->local);
921
- free(trimmed_path);
922
- }
923
-
924
- if (!report_garbage)
925
- return;
926
-
927
- if (!strcmp(file_name, "multi-pack-index") ||
928
- !strcmp(file_name, "multi-pack-index.d"))
929
- return;
930
- if (starts_with(file_name, "multi-pack-index") &&
931
- (ends_with(file_name, ".bitmap") || ends_with(file_name, ".rev")))
932
- return;
933
- if (ends_with(file_name, ".idx") ||
934
- ends_with(file_name, ".rev") ||
935
- ends_with(file_name, ".pack") ||
936
- ends_with(file_name, ".bitmap") ||
937
- ends_with(file_name, ".keep") ||
938
- ends_with(file_name, ".promisor") ||
939
- ends_with(file_name, ".mtimes"))
940
- string_list_append(data->garbage, full_name);
941
- else
942
- report_garbage(PACKDIR_FILE_GARBAGE, full_name);
943
-}
944
-
945
-static void prepare_packed_git_one(struct odb_source *source)
946
-{
947
- struct string_list garbage = STRING_LIST_INIT_DUP;
948
- struct prepare_pack_data data = {
949
- .source = source,
950
- .garbage = &garbage,
951
- };
952
-
953
- for_each_file_in_pack_dir(source->path, prepare_pack, &data);
954
-
955
- report_pack_garbage(data.garbage);
956
- string_list_clear(data.garbage, 0);
957
-}
958
-
959
-DEFINE_LIST_SORT(static, sort_packs, struct packfile_list_entry, next);
960
-
961
-static int sort_pack(const struct packfile_list_entry *a,
962
- const struct packfile_list_entry *b)
963
-{
964
- int st;
965
-
966
- /*
967
- * Local packs tend to contain objects specific to our
968
- * variant of the project than remote ones. In addition,
969
- * remote ones could be on a network mounted filesystem.
970
- * Favor local ones for these reasons.
971
- */
972
- st = a->pack->pack_local - b->pack->pack_local;
973
- if (st)
974
- return -st;
975
-
976
- /*
977
- * Younger packs tend to contain more recent objects,
978
- * and more recent objects tend to get accessed more
979
- * often.
980
- */
981
- if (a->pack->mtime < b->pack->mtime)
982
- return 1;
983
- else if (a->pack->mtime == b->pack->mtime)
984
- return 0;
985
- return -1;
986
-}
987
-
988
-void packfile_store_prepare(struct odb_source_packed *store)
989
-{
990
- if (store->initialized)
991
- return;
992
-
993
- prepare_multi_pack_index_one(&store->files->base);
994
- prepare_packed_git_one(&store->files->base);
995
-
996
- sort_packs(&store->packs.head, sort_pack);
997
- for (struct packfile_list_entry *e = store->packs.head; e; e = e->next)
998
- if (!e->next)
999
- store->packs.tail = e;
1000
-
1001
- store->initialized = true;
1002
-}
1003
-
1004
-void packfile_store_reprepare(struct odb_source_packed *store)
1005
-{
1006
- store->initialized = false;
1007
- packfile_store_prepare(store);
1008
-}
1009
-
856
struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)
857
{
1012
- packfile_store_prepare(store);
858
+ odb_source_packed_prepare(store);
859
860
if (store->midx) {
861
struct multi_pack_index *m = store->midx;
@@ -2083,7 +1929,7 @@ static int find_pack_entry(struct odb_source_packed *store,
1929
{
1930
struct packfile_list_entry *l;
1931
2086
- packfile_store_prepare(store);
1932
+ odb_source_packed_prepare(store);
1933
if (store->midx && fill_midx_entry(store->midx, oid, e))
1934
return 1;
1935
@@ -2130,7 +1976,7 @@ int packfile_store_read_object_info(struct odb_source_packed *store,
1976
* been added since the last time we have prepared the packfile store.
1977
*/
1978
if (flags & OBJECT_INFO_SECOND_READ)
2133
- packfile_store_reprepare(store);
1979
+ odb_source_reprepare(&store->base);
1980
1981
if (!find_pack_entry(store, oid, &e))
1982
return 1;
packfile.h
-17
@@ -55,23 +55,6 @@ struct packed_git {
55
char pack_name[FLEX_ARRAY]; /* more */
56
};
57
58
-/*
59
- * Prepare the packfile store by loading packfiles and multi-pack indices for
60
- * all alternates. This becomes a no-op if the store is already prepared.
61
- *
62
- * It shouldn't typically be necessary to call this function directly, as
63
- * functions that access the store know to prepare it.
64
- */
65
-void packfile_store_prepare(struct odb_source_packed *store);
66
-
67
-/*
68
- * Clear the packfile caches and try to look up any new packfiles that have
69
- * appeared since last preparing the packfiles store.
70
- *
71
- * This function must be called under the `odb_read_lock()`.
72
- */
73
-void packfile_store_reprepare(struct odb_source_packed *store);
74
-
58
/*
59
* Add the pack to the store so that contained objects become accessible via
60
* the store. This moves ownership into the store.