odb: introduce "files" source

Introduce a new "files" object database source. This source encapsulates access to both loose object files and the packfile store, similar to how the "files" backend for refs encapsulates access to loose refs and the packed-refs file. Note that for now the "files" source is still a direct member of a `struct odb_source`. This architecture will be reversed in the next commit so that the files source contains a `struct odb_source`. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Mar 5, 2026 at 15:19 UTC cb506a8a69c953f7b87bb3ae099e0bed8218d3ab
20 files changed +114 -68
Makefile
+1
@@ -1215,6 +1215,7 @@ LIB_OBJS += object-name.o
1215 LIB_OBJS += object.o
1216 LIB_OBJS += odb.o
1217 LIB_OBJS += odb/source.o
1218 +LIB_OBJS += odb/source-files.o
1219 LIB_OBJS += odb/streaming.o
1220 LIB_OBJS += oid-array.o
1221 LIB_OBJS += oidmap.o
builtin/cat-file.c
+1 -1
@@ -882,7 +882,7 @@ static void batch_each_object(struct batch_options *opt,
882 struct object_info oi = { 0 };
883
884 for (source = the_repository->objects->sources; source; source = source->next) {
885 - int ret = packfile_store_for_each_object(source->packfiles, &oi,
885 + int ret = packfile_store_for_each_object(source->files->packed, &oi,
886 batch_one_object_oi, &payload, flags);
887 if (ret)
888 break;
builtin/fast-import.c
+3 -3
@@ -900,7 +900,7 @@ static void end_packfile(void)
900 idx_name = keep_pack(create_index());
901
902 /* Register the packfile with core git's machinery. */
903 - new_p = packfile_store_load_pack(pack_data->repo->objects->sources->packfiles,
903 + new_p = packfile_store_load_pack(pack_data->repo->objects->sources->files->packed,
904 idx_name, 1);
905 if (!new_p)
906 die(_("core Git rejected index %s"), idx_name);
@@ -982,7 +982,7 @@ static int store_object(
982 }
983
984 for (source = the_repository->objects->sources; source; source = source->next) {
985 - if (!packfile_list_find_oid(packfile_store_get_packs(source->packfiles), &oid))
985 + if (!packfile_list_find_oid(packfile_store_get_packs(source->files->packed), &oid))
986 continue;
987 e->type = type;
988 e->pack_id = MAX_PACK_ID;
@@ -1187,7 +1187,7 @@ static void stream_blob(uintmax_t len, struct object_id *oidout, uintmax_t mark)
1187 }
1188
1189 for (source = the_repository->objects->sources; source; source = source->next) {
1190 - if (!packfile_list_find_oid(packfile_store_get_packs(source->packfiles), &oid))
1190 + if (!packfile_list_find_oid(packfile_store_get_packs(source->files->packed), &oid))
1191 continue;
1192 e->type = OBJ_BLOB;
1193 e->pack_id = MAX_PACK_ID;
builtin/grep.c
+1 -1
@@ -1219,7 +1219,7 @@ int cmd_grep(int argc,
1219
1220 odb_prepare_alternates(the_repository->objects);
1221 for (source = the_repository->objects->sources; source; source = source->next)
1222 - packfile_store_prepare(source->packfiles);
1222 + packfile_store_prepare(source->files->packed);
1223 }
1224
1225 start_threads(&opt);
builtin/index-pack.c
+1 -1
@@ -1638,7 +1638,7 @@ static void final(const char *final_pack_name, const char *curr_pack_name,
1638 hash, "idx", 1);
1639
1640 if (do_fsck_object && startup_info->have_repository)
1641 - packfile_store_load_pack(the_repository->objects->sources->packfiles,
1641 + packfile_store_load_pack(the_repository->objects->sources->files->packed,
1642 final_index_name, 0);
1643
1644 if (!from_stdin) {
builtin/pack-objects.c
+4 -4
@@ -1531,7 +1531,7 @@ static int want_cruft_object_mtime(struct repository *r,
1531 struct odb_source *source;
1532
1533 for (source = r->objects->sources; source; source = source->next) {
1534 - struct packed_git **cache = packfile_store_get_kept_pack_cache(source->packfiles, flags);
1534 + struct packed_git **cache = packfile_store_get_kept_pack_cache(source->files->packed, flags);
1535
1536 for (; *cache; cache++) {
1537 struct packed_git *p = *cache;
@@ -1753,11 +1753,11 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
1753 }
1754
1755 for (source = the_repository->objects->sources; source; source = source->next) {
1756 - for (e = source->packfiles->packs.head; e; e = e->next) {
1756 + for (e = source->files->packed->packs.head; e; e = e->next) {
1757 struct packed_git *p = e->pack;
1758 want = want_object_in_pack_one(p, oid, exclude, found_pack, found_offset, found_mtime);
1759 if (!exclude && want > 0)
1760 - packfile_list_prepend(&source->packfiles->packs, p);
1760 + packfile_list_prepend(&source->files->packed->packs, p);
1761 if (want != -1)
1762 return want;
1763 }
@@ -4340,7 +4340,7 @@ static void add_objects_in_unpacked_packs(void)
4340 if (!source->local)
4341 continue;
4342
4343 - if (packfile_store_for_each_object(source->packfiles, &oi,
4343 + if (packfile_store_for_each_object(source->files->packed, &oi,
4344 add_object_in_unpacked_pack, NULL,
4345 ODB_FOR_EACH_OBJECT_PACK_ORDER |
4346 ODB_FOR_EACH_OBJECT_LOCAL_ONLY |
commit-graph.c
+1 -1
@@ -1981,7 +1981,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
1981
1982 odb_prepare_alternates(ctx->r->objects);
1983 for (source = ctx->r->objects->sources; source; source = source->next)
1984 - packfile_store_for_each_object(source->packfiles, &oi, add_packed_commits_oi,
1984 + packfile_store_for_each_object(source->files->packed, &oi, add_packed_commits_oi,
1985 ctx, ODB_FOR_EACH_OBJECT_PACK_ORDER);
1986
1987 if (ctx->progress_done < ctx->approx_nr_objects)
http.c
+1 -1
@@ -2544,7 +2544,7 @@ void http_install_packfile(struct packed_git *p,
2544 struct packfile_list *list_to_remove_from)
2545 {
2546 packfile_list_remove(list_to_remove_from, p);
2547 - packfile_store_add_pack(the_repository->objects->sources->packfiles, p);
2547 + packfile_store_add_pack(the_repository->objects->sources->files->packed, p);
2548 }
2549
2550 struct http_pack_request *new_http_pack_request(
loose.c
+9 -9
@@ -49,13 +49,13 @@ static int insert_loose_map(struct odb_source *source,
49 const struct object_id *oid,
50 const struct object_id *compat_oid)
51 {
52 - struct loose_object_map *map = source->loose->map;
52 + struct loose_object_map *map = source->files->loose->map;
53 int inserted = 0;
54
55 inserted |= insert_oid_pair(map->to_compat, oid, compat_oid);
56 inserted |= insert_oid_pair(map->to_storage, compat_oid, oid);
57 if (inserted)
58 - oidtree_insert(source->loose->cache, compat_oid);
58 + oidtree_insert(source->files->loose->cache, compat_oid);
59
60 return inserted;
61 }
@@ -65,11 +65,11 @@ static int load_one_loose_object_map(struct repository *repo, struct odb_source
65 struct strbuf buf = STRBUF_INIT, path = STRBUF_INIT;
66 FILE *fp;
67
68 - if (!source->loose->map)
69 - loose_object_map_init(&source->loose->map);
70 - if (!source->loose->cache) {
71 - ALLOC_ARRAY(source->loose->cache, 1);
72 - oidtree_init(source->loose->cache);
68 + if (!source->files->loose->map)
69 + loose_object_map_init(&source->files->loose->map);
70 + if (!source->files->loose->cache) {
71 + ALLOC_ARRAY(source->files->loose->cache, 1);
72 + oidtree_init(source->files->loose->cache);
73 }
74
75 insert_loose_map(source, repo->hash_algo->empty_tree, repo->compat_hash_algo->empty_tree);
@@ -125,7 +125,7 @@ int repo_read_loose_object_map(struct repository *repo)
125
126 int repo_write_loose_object_map(struct repository *repo)
127 {
128 - kh_oid_map_t *map = repo->objects->sources->loose->map->to_compat;
128 + kh_oid_map_t *map = repo->objects->sources->files->loose->map->to_compat;
129 struct lock_file lock;
130 int fd;
131 khiter_t iter;
@@ -231,7 +231,7 @@ int repo_loose_object_map_oid(struct repository *repo,
231 khiter_t pos;
232
233 for (source = repo->objects->sources; source; source = source->next) {
234 - struct loose_object_map *loose_map = source->loose->map;
234 + struct loose_object_map *loose_map = source->files->loose->map;
235 if (!loose_map)
236 continue;
237 map = (to == repo->compat_hash_algo) ?
meson.build
+1
@@ -398,6 +398,7 @@ libgit_sources = [
398 'object.c',
399 'odb.c',
400 'odb/source.c',
401 + 'odb/source-files.c',
402 'odb/streaming.c',
403 'oid-array.c',
404 'oidmap.c',
midx.c
+9 -9
@@ -95,8 +95,8 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,
95
96 struct multi_pack_index *get_multi_pack_index(struct odb_source *source)
97 {
98 - packfile_store_prepare(source->packfiles);
99 - return source->packfiles->midx;
98 + packfile_store_prepare(source->files->packed);
99 + return source->files->packed->midx;
100 }
101
102 static struct multi_pack_index *load_multi_pack_index_one(struct odb_source *source,
@@ -459,7 +459,7 @@ int prepare_midx_pack(struct multi_pack_index *m,
459
460 strbuf_addf(&pack_name, "%s/pack/%s", m->source->path,
461 m->pack_names[pack_int_id]);
462 - p = packfile_store_load_pack(m->source->packfiles,
462 + p = packfile_store_load_pack(m->source->files->packed,
463 pack_name.buf, m->source->local);
464 strbuf_release(&pack_name);
465
@@ -709,12 +709,12 @@ int prepare_multi_pack_index_one(struct odb_source *source)
709 if (!r->settings.core_multi_pack_index)
710 return 0;
711
712 - if (source->packfiles->midx)
712 + if (source->files->packed->midx)
713 return 1;
714
715 - source->packfiles->midx = load_multi_pack_index(source);
715 + source->files->packed->midx = load_multi_pack_index(source);
716
717 - return !!source->packfiles->midx;
717 + return !!source->files->packed->midx;
718 }
719
720 int midx_checksum_valid(struct multi_pack_index *m)
@@ -803,9 +803,9 @@ void clear_midx_file(struct repository *r)
803 struct odb_source *source;
804
805 for (source = r->objects->sources; source; source = source->next) {
806 - if (source->packfiles->midx)
807 - close_midx(source->packfiles->midx);
808 - source->packfiles->midx = NULL;
806 + if (source->files->packed->midx)
807 + close_midx(source->files->packed->midx);
808 + source->files->packed->midx = NULL;
809 }
810 }
811
object-file.c
+12 -12
@@ -220,7 +220,7 @@ static void *odb_source_loose_map_object(struct odb_source *source,
220 unsigned long *size)
221 {
222 const char *p;
223 - int fd = open_loose_object(source->loose, oid, &p);
223 + int fd = open_loose_object(source->files->loose, oid, &p);
224
225 if (fd < 0)
226 return NULL;
@@ -423,7 +423,7 @@ static int read_object_info_from_path(struct odb_source *source,
423 struct stat st;
424
425 if ((!oi || (!oi->disk_sizep && !oi->mtimep)) && (flags & OBJECT_INFO_QUICK)) {
426 - ret = quick_has_loose(source->loose, oid) ? 0 : -1;
426 + ret = quick_has_loose(source->files->loose, oid) ? 0 : -1;
427 goto out;
428 }
429
@@ -1868,31 +1868,31 @@ struct oidtree *odb_source_loose_cache(struct odb_source *source,
1868 {
1869 int subdir_nr = oid->hash[0];
1870 struct strbuf buf = STRBUF_INIT;
1871 - size_t word_bits = bitsizeof(source->loose->subdir_seen[0]);
1871 + size_t word_bits = bitsizeof(source->files->loose->subdir_seen[0]);
1872 size_t word_index = subdir_nr / word_bits;
1873 size_t mask = (size_t)1u << (subdir_nr % word_bits);
1874 uint32_t *bitmap;
1875
1876 if (subdir_nr < 0 ||
1877 - (size_t) subdir_nr >= bitsizeof(source->loose->subdir_seen))
1877 + (size_t) subdir_nr >= bitsizeof(source->files->loose->subdir_seen))
1878 BUG("subdir_nr out of range");
1879
1880 - bitmap = &source->loose->subdir_seen[word_index];
1880 + bitmap = &source->files->loose->subdir_seen[word_index];
1881 if (*bitmap & mask)
1882 - return source->loose->cache;
1883 - if (!source->loose->cache) {
1884 - ALLOC_ARRAY(source->loose->cache, 1);
1885 - oidtree_init(source->loose->cache);
1882 + return source->files->loose->cache;
1883 + if (!source->files->loose->cache) {
1884 + ALLOC_ARRAY(source->files->loose->cache, 1);
1885 + oidtree_init(source->files->loose->cache);
1886 }
1887 strbuf_addstr(&buf, source->path);
1888 for_each_file_in_obj_subdir(subdir_nr, &buf,
1889 source->odb->repo->hash_algo,
1890 append_loose_object,
1891 NULL, NULL,
1892 - source->loose->cache);
1892 + source->files->loose->cache);
1893 *bitmap |= mask;
1894 strbuf_release(&buf);
1895 - return source->loose->cache;
1895 + return source->files->loose->cache;
1896 }
1897
1898 static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
@@ -1905,7 +1905,7 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
1905
1906 void odb_source_loose_reprepare(struct odb_source *source)
1907 {
1908 - odb_source_loose_clear_cache(source->loose);
1908 + odb_source_loose_clear_cache(source->files->loose);
1909 }
1910
1911 static int check_stream_oid(git_zstream *stream,
odb.c
+6 -6
@@ -691,7 +691,7 @@ static int do_oid_object_info_extended(struct object_database *odb,
691
692 /* Most likely it's a loose object. */
693 for (source = odb->sources; source; source = source->next) {
694 - if (!packfile_store_read_object_info(source->packfiles, real, oi, flags) ||
694 + if (!packfile_store_read_object_info(source->files->packed, real, oi, flags) ||
695 !odb_source_loose_read_object_info(source, real, oi, flags))
696 return 0;
697 }
@@ -700,7 +700,7 @@ static int do_oid_object_info_extended(struct object_database *odb,
700 if (!(flags & OBJECT_INFO_QUICK)) {
701 odb_reprepare(odb->repo->objects);
702 for (source = odb->sources; source; source = source->next)
703 - if (!packfile_store_read_object_info(source->packfiles, real, oi, flags))
703 + if (!packfile_store_read_object_info(source->files->packed, real, oi, flags))
704 return 0;
705 }
706
@@ -962,7 +962,7 @@ int odb_freshen_object(struct object_database *odb,
962
963 odb_prepare_alternates(odb);
964 for (source = odb->sources; source; source = source->next) {
965 - if (packfile_store_freshen_object(source->packfiles, oid))
965 + if (packfile_store_freshen_object(source->files->packed, oid))
966 return 1;
967
968 if (odb_source_loose_freshen_object(source, oid))
@@ -992,7 +992,7 @@ int odb_for_each_object(struct object_database *odb,
992 return ret;
993 }
994
995 - ret = packfile_store_for_each_object(source->packfiles, request,
995 + ret = packfile_store_for_each_object(source->files->packed, request,
996 cb, cb_data, flags);
997 if (ret)
998 return ret;
@@ -1091,7 +1091,7 @@ void odb_close(struct object_database *o)
1091 {
1092 struct odb_source *source;
1093 for (source = o->sources; source; source = source->next)
1094 - packfile_store_close(source->packfiles);
1094 + packfile_store_close(source->files->packed);
1095 close_commit_graph(o);
1096 }
1097
@@ -1149,7 +1149,7 @@ void odb_reprepare(struct object_database *o)
1149
1150 for (source = o->sources; source; source = source->next) {
1151 odb_source_loose_reprepare(source);
1152 - packfile_store_reprepare(source->packfiles);
1152 + packfile_store_reprepare(source->files->packed);
1153 }
1154
1155 o->approximate_object_count_valid = 0;
odb/source-files.c new
+23
@@ -0,0 +1,23 @@
1 +#include "git-compat-util.h"
2 +#include "object-file.h"
3 +#include "odb/source-files.h"
4 +#include "packfile.h"
5 +
6 +void odb_source_files_free(struct odb_source_files *files)
7 +{
8 + if (!files)
9 + return;
10 + odb_source_loose_free(files->loose);
11 + packfile_store_free(files->packed);
12 + free(files);
13 +}
14 +
15 +struct odb_source_files *odb_source_files_new(struct odb_source *source)
16 +{
17 + struct odb_source_files *files;
18 + CALLOC_ARRAY(files, 1);
19 + files->source = source;
20 + files->loose = odb_source_loose_new(source);
21 + files->packed = packfile_store_new(source);
22 + return files;
23 +}
odb/source-files.h new
+24
@@ -0,0 +1,24 @@
1 +#ifndef ODB_SOURCE_FILES_H
2 +#define ODB_SOURCE_FILES_H
3 +
4 +struct odb_source_loose;
5 +struct odb_source;
6 +struct packfile_store;
7 +
8 +/*
9 + * The files object database source uses a combination of loose objects and
10 + * packfiles. It is the default backend used by Git to store objects.
11 + */
12 +struct odb_source_files {
13 + struct odb_source *source;
14 + struct odb_source_loose *loose;
15 + struct packfile_store *packed;
16 +};
17 +
18 +/* Allocate and initialize a new object source. */
19 +struct odb_source_files *odb_source_files_new(struct odb_source *source);
20 +
21 +/* Free the object source and release all associated resources. */
22 +void odb_source_files_free(struct odb_source_files *files);
23 +
24 +#endif
odb/source.c
+2 -4
@@ -13,8 +13,7 @@ struct odb_source *odb_source_new(struct object_database *odb,
13 source->odb = odb;
14 source->local = local;
15 source->path = xstrdup(path);
16 - source->loose = odb_source_loose_new(source);
17 - source->packfiles = packfile_store_new(source);
16 + source->files = odb_source_files_new(source);
17
18 return source;
19 }
@@ -22,7 +21,6 @@ struct odb_source *odb_source_new(struct object_database *odb,
21 void odb_source_free(struct odb_source *source)
22 {
23 free(source->path);
25 - odb_source_loose_free(source->loose);
26 - packfile_store_free(source->packfiles);
24 + odb_source_files_free(source->files);
25 free(source);
26 }
odb/source.h
+4 -5
@@ -1,6 +1,8 @@
1 #ifndef ODB_SOURCE_H
2 #define ODB_SOURCE_H
3
4 +#include "odb/source-files.h"
5 +
6 /*
7 * The source is the part of the object database that stores the actual
8 * objects. It thus encapsulates the logic to read and write the specific
@@ -19,11 +21,8 @@ struct odb_source {
21 /* Object database that owns this object source. */
22 struct object_database *odb;
23
22 - /* Private state for loose objects. */
23 - struct odb_source_loose *loose;
24 -
25 - /* Should only be accessed directly by packfile.c and midx.c. */
26 - struct packfile_store *packfiles;
24 + /* The backend used to store objects. */
25 + struct odb_source_files *files;
26
27 /*
28 * Figure out whether this is the local source of the owning
odb/streaming.c
+1 -1
@@ -187,7 +187,7 @@ static int istream_source(struct odb_read_stream **out,
187
188 odb_prepare_alternates(odb);
189 for (source = odb->sources; source; source = source->next) {
190 - if (!packfile_store_read_object_stream(out, source->packfiles, oid) ||
190 + if (!packfile_store_read_object_stream(out, source->files->packed, oid) ||
191 !odb_source_loose_read_object_stream(out, source, oid))
192 return 0;
193 }
packfile.c
+8 -8
@@ -363,7 +363,7 @@ static int unuse_one_window(struct object_database *odb)
363 struct pack_window *lru_w = NULL, *lru_l = NULL;
364
365 for (source = odb->sources; source; source = source->next)
366 - for (e = source->packfiles->packs.head; e; e = e->next)
366 + for (e = source->files->packed->packs.head; e; e = e->next)
367 scan_windows(e->pack, &lru_p, &lru_w, &lru_l);
368
369 if (lru_p) {
@@ -537,7 +537,7 @@ static int close_one_pack(struct repository *r)
537 int accept_windows_inuse = 1;
538
539 for (source = r->objects->sources; source; source = source->next) {
540 - for (e = source->packfiles->packs.head; e; e = e->next) {
540 + for (e = source->files->packed->packs.head; e; e = e->next) {
541 if (e->pack->pack_fd == -1)
542 continue;
543 find_lru_pack(e->pack, &lru_p, &mru_w, &accept_windows_inuse);
@@ -990,10 +990,10 @@ static void prepare_pack(const char *full_name, size_t full_name_len,
990 size_t base_len = full_name_len;
991
992 if (strip_suffix_mem(full_name, &base_len, ".idx") &&
993 - !(data->source->packfiles->midx &&
994 - midx_contains_pack(data->source->packfiles->midx, file_name))) {
993 + !(data->source->files->packed->midx &&
994 + midx_contains_pack(data->source->files->packed->midx, file_name))) {
995 char *trimmed_path = xstrndup(full_name, full_name_len);
996 - packfile_store_load_pack(data->source->packfiles,
996 + packfile_store_load_pack(data->source->files->packed,
997 trimmed_path, data->source->local);
998 free(trimmed_path);
999 }
@@ -1248,7 +1248,7 @@ const struct packed_git *has_packed_and_bad(struct repository *r,
1248
1249 for (source = r->objects->sources; source; source = source->next) {
1250 struct packfile_list_entry *e;
1251 - for (e = source->packfiles->packs.head; e; e = e->next)
1251 + for (e = source->files->packed->packs.head; e; e = e->next)
1252 if (oidset_contains(&e->pack->bad_objects, oid))
1253 return e->pack;
1254 }
@@ -2254,7 +2254,7 @@ int has_object_pack(struct repository *r, const struct object_id *oid)
2254
2255 odb_prepare_alternates(r->objects);
2256 for (source = r->objects->sources; source; source = source->next) {
2257 - int ret = find_pack_entry(source->packfiles, oid, &e);
2257 + int ret = find_pack_entry(source->files->packed, oid, &e);
2258 if (ret)
2259 return ret;
2260 }
@@ -2271,7 +2271,7 @@ int has_object_kept_pack(struct repository *r, const struct object_id *oid,
2271 for (source = r->objects->sources; source; source = source->next) {
2272 struct packed_git **cache;
2273
2274 - cache = packfile_store_get_kept_pack_cache(source->packfiles, flags);
2274 + cache = packfile_store_get_kept_pack_cache(source->files->packed, flags);
2275
2276 for (; *cache; cache++) {
2277 struct packed_git *p = *cache;
packfile.h
+2 -2
@@ -192,7 +192,7 @@ static inline struct repo_for_each_pack_data repo_for_eack_pack_data_init(struct
192 odb_prepare_alternates(repo->objects);
193
194 for (struct odb_source *source = repo->objects->sources; source; source = source->next) {
195 - struct packfile_list_entry *entry = packfile_store_get_packs(source->packfiles);
195 + struct packfile_list_entry *entry = packfile_store_get_packs(source->files->packed);
196 if (!entry)
197 continue;
198 data.source = source;
@@ -212,7 +212,7 @@ static inline void repo_for_each_pack_data_next(struct repo_for_each_pack_data *
212 return;
213
214 for (source = data->source->next; source; source = source->next) {
215 - struct packfile_list_entry *entry = packfile_store_get_packs(source->packfiles);
215 + struct packfile_list_entry *entry = packfile_store_get_packs(source->files->packed);
216 if (!entry)
217 continue;
218 data->source = source;