odb: introduce "in-memory" source

Next to our typical object database sources, each object database also has an implicit source of "cached" objects. These cached objects only exist in memory and some use cases: - They contain evergreen objects that we expect to always exist, like for example the empty tree. - They can be used to store temporary objects that we don't want to persist to disk, which is used by git-blame(1) to create a fake worktree commit. Overall, their use is somewhat restricted though. For example, we don't provide the ability to use it as a temporary object database source that allows the user to write objects, but discard them after Git exists. So while these cached objects behave almost like a source, they aren't used as one. This is about to change over the following commits, where we will turn cached objects into a new "in-memory" source. This will allow us to use it exactly the same as any other source by providing the same common interface as the "files" source. For now, the in-memory source only hosts the cached objects and doesn't provide any logic yet. This will change with subsequent commits, where we move respective functionality into the source. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Apr 10, 2026 at 14:12 UTC 822d403651aa6baff064095f98d8d8349d876eb8
7 files changed +67 -10
Makefile
+1
@@ -1218,6 +1218,7 @@ LIB_OBJS += object.o
1218 LIB_OBJS += odb.o
1219 LIB_OBJS += odb/source.o
1220 LIB_OBJS += odb/source-files.o
1221 +LIB_OBJS += odb/source-inmemory.o
1222 LIB_OBJS += odb/streaming.o
1223 LIB_OBJS += odb/transaction.o
1224 LIB_OBJS += oid-array.o
meson.build
+1
@@ -404,6 +404,7 @@ libgit_sources = [
404 'odb.c',
405 'odb/source.c',
406 'odb/source-files.c',
407 + 'odb/source-inmemory.c',
408 'odb/streaming.c',
409 'odb/transaction.c',
410 'oid-array.c',
odb.c
+13 -8
@@ -14,6 +14,7 @@
14 #include "object-file.h"
15 #include "object-name.h"
16 #include "odb.h"
17 +#include "odb/source-inmemory.h"
18 #include "packfile.h"
19 #include "path.h"
20 #include "promisor-remote.h"
@@ -53,9 +54,9 @@ static const struct cached_object *find_cached_object(struct object_database *ob
54 .type = OBJ_TREE,
55 .buf = "",
56 };
56 - const struct cached_object_entry *co = object_store->cached_objects;
57 + const struct cached_object_entry *co = object_store->inmemory_objects->objects;
58
58 - for (size_t i = 0; i < object_store->cached_object_nr; i++, co++)
59 + for (size_t i = 0; i < object_store->inmemory_objects->objects_nr; i++, co++)
60 if (oideq(&co->oid, oid))
61 return &co->value;
62
@@ -792,9 +793,10 @@ int odb_pretend_object(struct object_database *odb,
793 find_cached_object(odb, oid))
794 return 0;
795
795 - ALLOC_GROW(odb->cached_objects,
796 - odb->cached_object_nr + 1, odb->cached_object_alloc);
797 - co = &odb->cached_objects[odb->cached_object_nr++];
796 + ALLOC_GROW(odb->inmemory_objects->objects,
797 + odb->inmemory_objects->objects_nr + 1,
798 + odb->inmemory_objects->objects_alloc);
799 + co = &odb->inmemory_objects->objects[odb->inmemory_objects->objects_nr++];
800 co->value.size = len;
801 co->value.type = type;
802 co_buf = xmalloc(len);
@@ -1083,6 +1085,7 @@ struct object_database *odb_new(struct repository *repo,
1085 o->sources = odb_source_new(o, primary_source, true);
1086 o->sources_tail = &o->sources->next;
1087 o->alternate_db = xstrdup_or_null(secondary_sources);
1088 + o->inmemory_objects = odb_source_inmemory_new(o);
1089
1090 free(to_free);
1091
@@ -1123,9 +1126,11 @@ void odb_free(struct object_database *o)
1126 odb_close(o);
1127 odb_free_sources(o);
1128
1126 - for (size_t i = 0; i < o->cached_object_nr; i++)
1127 - free((char *) o->cached_objects[i].value.buf);
1128 - free(o->cached_objects);
1129 + for (size_t i = 0; i < o->inmemory_objects->objects_nr; i++)
1130 + free((char *) o->inmemory_objects->objects[i].value.buf);
1131 + free(o->inmemory_objects->objects);
1132 + free(o->inmemory_objects->base.path);
1133 + free(o->inmemory_objects);
1134
1135 string_list_clear(&o->submodule_source_paths, 0);
1136
odb.h
+2 -2
@@ -8,6 +8,7 @@
8 #include "thread-utils.h"
9
10 struct cached_object_entry;
11 +struct odb_source_inmemory;
12 struct packed_git;
13 struct repository;
14 struct strbuf;
@@ -80,8 +81,7 @@ struct object_database {
81 * to write them into the object store (e.g. a browse-only
82 * application).
83 */
83 - struct cached_object_entry *cached_objects;
84 - size_t cached_object_nr, cached_object_alloc;
84 + struct odb_source_inmemory *inmemory_objects;
85
86 /*
87 * A fast, rough count of the number of objects in the repository.
odb/source-inmemory.c new
+12
@@ -0,0 +1,12 @@
1 +#include "git-compat-util.h"
2 +#include "odb/source-inmemory.h"
3 +
4 +struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)
5 +{
6 + struct odb_source_inmemory *source;
7 +
8 + CALLOC_ARRAY(source, 1);
9 + odb_source_init(&source->base, odb, ODB_SOURCE_INMEMORY, "source", false);
10 +
11 + return source;
12 +}
odb/source-inmemory.h new
+35
@@ -0,0 +1,35 @@
1 +#ifndef ODB_SOURCE_INMEMORY_H
2 +#define ODB_SOURCE_INMEMORY_H
3 +
4 +#include "odb/source.h"
5 +
6 +struct cached_object_entry;
7 +
8 +/*
9 + * An in-memory source that you can write objects to that shall be made
10 + * available for reading, but that shouldn't ever be persisted to disk. Note
11 + * that any objects written to this source will be stored in memory, so the
12 + * number of objects you can store is limited by available system memory.
13 + */
14 +struct odb_source_inmemory {
15 + struct odb_source base;
16 +
17 + struct cached_object_entry *objects;
18 + size_t objects_nr, objects_alloc;
19 +};
20 +
21 +/* Create a new in-memory object database source. */
22 +struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb);
23 +
24 +/*
25 + * Cast the given object database source to the in-memory backend. This will
26 + * cause a BUG in case the source doesn't use this backend.
27 + */
28 +static inline struct odb_source_inmemory *odb_source_inmemory_downcast(struct odb_source *source)
29 +{
30 + if (source->type != ODB_SOURCE_INMEMORY)
31 + BUG("trying to downcast source of type '%d' to in-memory", source->type);
32 + return container_of(source, struct odb_source_inmemory, base);
33 +}
34 +
35 +#endif
odb/source.h
+3
@@ -13,6 +13,9 @@ enum odb_source_type {
13
14 /* The "files" backend that uses loose objects and packfiles. */
15 ODB_SOURCE_FILES,
16 +
17 + /* The "in-memory" backend that stores objects in memory. */
18 + ODB_SOURCE_INMEMORY,
19 };
20
21 struct object_id;