odb/source-loose: start converting to a proper `struct odb_source`

Start converting `struct odb_source_loose` into a proper pluggable `struct odb_source` by embedding the base struct and assigning it the new `ODB_SOURCE_LOOSE` type. Furthermore, wire up lifecycle management of this source by implementing the `free` callback and taking ownership of the chdir notifications. Note that the loose source is not yet functional as a standalone `struct odb_source`, as it's missing all of the callback implementations. These will be wired up in subsequent commits. 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 ead691927b05dbbd2655db9a7183d5fcb935bf3b
6 files changed +63 -20
object-file.c
-17
@@ -2041,14 +2041,6 @@ static struct oidtree *odb_source_loose_cache(struct odb_source *source,
2041 return files->loose->cache;
2042 }
2043
2044 -static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
2045 -{
2046 - oidtree_clear(loose->cache);
2047 - FREE_AND_NULL(loose->cache);
2048 - memset(&loose->subdir_seen, 0,
2049 - sizeof(loose->subdir_seen));
2050 -}
2051 -
2044 void odb_source_loose_reprepare(struct odb_source *source)
2045 {
2046 struct odb_source_files *files = odb_source_files_downcast(source);
@@ -2205,15 +2197,6 @@ struct odb_transaction *odb_transaction_files_begin(struct odb_source *source)
2197 return &transaction->base;
2198 }
2199
2208 -void odb_source_loose_free(struct odb_source_loose *loose)
2209 -{
2210 - if (!loose)
2211 - return;
2212 - odb_source_loose_clear_cache(loose);
2213 - loose_object_map_clear(&loose->map);
2214 - free(loose);
2215 -}
2216 -
2200 struct odb_loose_read_stream {
2201 struct odb_read_stream base;
2202 git_zstream z;
object-file.h
-2
@@ -21,8 +21,6 @@ struct object_info;
21 struct odb_read_stream;
22 struct odb_source;
23
24 -void odb_source_loose_free(struct odb_source_loose *loose);
25 -
24 /* Reprepare the loose source by emptying the loose object cache. */
25 void odb_source_loose_reprepare(struct odb_source *source);
26
odb/source-files.c
+1 -1
@@ -27,7 +27,7 @@ static void odb_source_files_free(struct odb_source *source)
27 {
28 struct odb_source_files *files = odb_source_files_downcast(source);
29 chdir_notify_unregister(NULL, odb_source_files_reparent, files);
30 - odb_source_loose_free(files->loose);
30 + odb_source_free(&files->loose->base);
31 packfile_store_free(files->packed);
32 odb_source_release(&files->base);
33 free(files);
odb/source-loose.c
+45
@@ -1,10 +1,55 @@
1 #include "git-compat-util.h"
2 +#include "abspath.h"
3 +#include "chdir-notify.h"
4 +#include "loose.h"
5 +#include "odb.h"
6 +#include "odb/source-files.h"
7 #include "odb/source-loose.h"
8 +#include "oidtree.h"
9 +
10 +void odb_source_loose_clear_cache(struct odb_source_loose *loose)
11 +{
12 + oidtree_clear(loose->cache);
13 + FREE_AND_NULL(loose->cache);
14 + memset(&loose->subdir_seen, 0,
15 + sizeof(loose->subdir_seen));
16 +}
17 +
18 +static void odb_source_loose_reparent(const char *name UNUSED,
19 + const char *old_cwd,
20 + const char *new_cwd,
21 + void *cb_data)
22 +{
23 + struct odb_source_loose *loose = cb_data;
24 + char *path = reparent_relative_path(old_cwd, new_cwd,
25 + loose->base.path);
26 + free(loose->base.path);
27 + loose->base.path = path;
28 +}
29 +
30 +static void odb_source_loose_free(struct odb_source *source)
31 +{
32 + struct odb_source_loose *loose = odb_source_loose_downcast(source);
33 + odb_source_loose_clear_cache(loose);
34 + loose_object_map_clear(&loose->map);
35 + chdir_notify_unregister(NULL, odb_source_loose_reparent, loose);
36 + odb_source_release(&loose->base);
37 + free(loose);
38 +}
39
40 struct odb_source_loose *odb_source_loose_new(struct odb_source_files *files)
41 {
42 struct odb_source_loose *loose;
43 +
44 CALLOC_ARRAY(loose, 1);
45 + odb_source_init(&loose->base, files->base.odb, ODB_SOURCE_LOOSE,
46 + files->base.path, files->base.local);
47 loose->files = files;
48 +
49 + loose->base.free = odb_source_loose_free;
50 +
51 + if (!is_absolute_path(loose->base.path))
52 + chdir_notify_register(NULL, odb_source_loose_reparent, loose);
53 +
54 return loose;
55 }
odb/source-loose.h
+14
@@ -12,6 +12,7 @@ struct oidtree;
12 * file per object. This source is part of the files source.
13 */
14 struct odb_source_loose {
15 + struct odb_source base;
16 struct odb_source_files *files;
17
18 /*
@@ -32,4 +33,17 @@ struct odb_source_loose {
33
34 struct odb_source_loose *odb_source_loose_new(struct odb_source_files *files);
35
36 +/*
37 + * Cast the given object database source to the loose backend. This will cause
38 + * a BUG in case the source doesn't use this backend.
39 + */
40 +static inline struct odb_source_loose *odb_source_loose_downcast(struct odb_source *source)
41 +{
42 + if (source->type != ODB_SOURCE_LOOSE)
43 + BUG("trying to downcast source of type '%d' to loose", source->type);
44 + return container_of(source, struct odb_source_loose, base);
45 +}
46 +
47 +void odb_source_loose_clear_cache(struct odb_source_loose *loose);
48 +
49 #endif
odb/source.h
+3
@@ -14,6 +14,9 @@ enum odb_source_type {
14 /* The "files" backend that uses loose objects and packfiles. */
15 ODB_SOURCE_FILES,
16
17 + /* The "loose" backend that uses loose objects, only. */
18 + ODB_SOURCE_LOOSE,
19 +
20 /* The "in-memory" backend that stores objects in memory. */
21 ODB_SOURCE_INMEMORY,
22 };