Merge branch 'ps/odb-eagerly-load-alternates' into ps/odb-alternates-at-creation

* ps/odb-eagerly-load-alternates:
  odb: drop `alternates_db` field
  odb: drop `loaded_alternates` field
  odb: eagerly initialize alternates
  odb: decouple source path comparisons from `the_repository`
  setup: create ref and object databases after config is written
This commit is contained in:
Junio C Hamano committed 2026-08-25 10:27:03 -07:00
commit 02e44450dd
13 files changed
+92 -93

No files matched your search

-3
View File
@@ -1069,7 +1069,6 @@ int cmd_fsck(int argc,
odb_for_each_object(repo->objects, NULL,
mark_object_for_connectivity, repo, 0);
} else {
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next)
fsck_source(repo, source);
@@ -1155,7 +1154,6 @@ int cmd_fsck(int argc,
if (repo->settings.core_commit_graph) {
struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
child_process_init(&commit_graph_verify);
commit_graph_verify.git_cmd = 1;
@@ -1173,7 +1171,6 @@ int cmd_fsck(int argc,
if (repo->settings.core_multi_pack_index) {
struct child_process midx_verify = CHILD_PROCESS_INIT;
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
child_process_init(&midx_verify);
midx_verify.git_cmd = 1;
-3
View File
@@ -1780,8 +1780,6 @@ static int want_object_in_pack_mtime(const struct object_id *oid,
*found_offset = 0;
}
odb_prepare_alternates(the_repository->objects);
for (source = the_repository->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
struct multi_pack_index *m = get_multi_pack_index(files->packed);
@@ -4520,7 +4518,6 @@ static void add_objects_in_unpacked_packs(void)
.source_infop = &source_info,
};
odb_prepare_alternates(to_pack.repo->objects);
for (source = to_pack.repo->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
-4
View File
@@ -651,8 +651,6 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,
count = st->st_size / (odb->repo->hash_algo->hexsz + 1);
CALLOC_ARRAY(oids, count);
odb_prepare_alternates(odb);
for (i = 0; i < count; i++) {
struct odb_source *source;
@@ -768,7 +766,6 @@ static struct commit_graph *prepare_commit_graph(struct repository *r)
if (!commit_graph_compatible(r))
return NULL;
odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
r->objects->commit_graph = read_commit_graph_one(source);
if (r->objects->commit_graph)
@@ -2018,7 +2015,6 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)
_("Finding commits for commit graph among packed objects"),
ctx->approx_nr_objects);
odb_prepare_alternates(ctx->r->objects);
for (source = ctx->r->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
odb_source_for_each_object(&files->packed->base, &oi, add_packed_commits_oi,
-1
View File
@@ -115,7 +115,6 @@ int repo_read_loose_object_map(struct repository *repo)
{
struct odb_source *source;
odb_prepare_alternates(repo->objects);
for (source = repo->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
if (loose_object_map_load(files->loose) < 0)
-1
View File
@@ -280,7 +280,6 @@ static int init_object_disambiguation(struct repository *r,
ds->len = len;
ds->repo = r;
odb_prepare_alternates(r->objects);
return 0;
}
+68 -56
View File
@@ -2,11 +2,10 @@
#include "abspath.h"
#include "commit-graph.h"
#include "config.h"
#include "dir.h"
#include "environment.h"
#include "gettext.h"
#include "hashmap.h"
#include "hex.h"
#include "khash.h"
#include "lockfile.h"
#include "loose.h"
#include "midx.h"
@@ -29,8 +28,47 @@
#include "trace2.h"
#include "write-or-die.h"
KHASH_INIT(odb_path_map, const char * /* key: odb_path */,
struct odb_source *, 1, fspathhash, fspatheq)
/*
* NEEDSWORK: we're using "core.ignoreCase" to deduplicate alternates that
* _may_ be the same. This requires quite a bit of boilerplate for dubious
* benefit:
*
* - Duplicating alternates should really only lead to regressed performance.
*
* - We don't properly resolve symlinks or mointpoints, so we may still end
* up duplicating alternates.
*
* - The value may be lying, in which case we might deduplicate alternates
* that are in fact not mapping to the same directory.
*
* We should investigate whether we can remove this whole mechanism outright.
*/
static int odb_source_paths_cmp(struct object_database *o,
const char *a, const char *b)
{
if (o->source_paths_icase < 0) {
int icase = 0;
repo_config_get_bool(o->repo, "core.ignorecase", &icase);
o->source_paths_icase = icase;
}
return o->source_paths_icase ? strcasecmp(a, b) : strcmp(a, b);
}
static int odb_source_by_path_cmp(const void *cb_data,
const struct hashmap_entry *entry,
const struct hashmap_entry *entry_or_key,
const void *keydata)
{
struct object_database *o = (struct object_database *)cb_data;
const struct odb_source *source = container_of(entry, const struct odb_source, by_path_entry);
const char *path = keydata;
if (!path)
path = container_of(entry_or_key, const struct odb_source, by_path_entry)->path;
return odb_source_paths_cmp(o, source->path, path);
}
int odb_mkstemp(struct object_database *odb,
struct strbuf *temp_filename, const char *pattern)
@@ -58,8 +96,8 @@ int odb_mkstemp(struct object_database *odb,
*/
static bool odb_is_source_usable(struct object_database *o, const char *path)
{
int r;
struct strbuf normalized_objdir = STRBUF_INIT;
struct hashmap_entry key;
bool usable = false;
strbuf_realpath(&normalized_objdir, o->sources->path, 1);
@@ -76,20 +114,18 @@ static bool odb_is_source_usable(struct object_database *o, const char *path)
* Prevent the common mistake of listing the same
* thing twice, or object directory itself.
*/
if (!o->source_by_path) {
khiter_t p;
o->source_by_path = kh_init_odb_path_map();
if (!hashmap_get_size(&o->source_by_path)) {
assert(!o->sources->next);
p = kh_put_odb_path_map(o->source_by_path, o->sources->path, &r);
assert(r == 1); /* never used */
kh_value(o->source_by_path, p) = o->sources;
hashmap_entry_init(&o->sources->by_path_entry,
strihash(o->sources->path));
hashmap_add(&o->source_by_path, &o->sources->by_path_entry);
}
if (fspatheq(path, normalized_objdir.buf))
if (!odb_source_paths_cmp(o, path, normalized_objdir.buf))
goto out;
if (kh_get_odb_path_map(o->source_by_path, path) < kh_end(o->source_by_path))
hashmap_entry_init(&key, strihash(path));
if (hashmap_get(&o->source_by_path, &key, path))
goto out;
usable = true;
@@ -172,8 +208,6 @@ static struct odb_source *odb_add_alternate_recursively(struct object_database *
{
struct odb_source *alternate = NULL;
struct strvec sources = STRVEC_INIT;
khiter_t pos;
int ret;
if (!odb_is_source_usable(odb, source))
goto error;
@@ -184,10 +218,11 @@ static struct odb_source *odb_add_alternate_recursively(struct object_database *
*odb->sources_tail = alternate;
odb->sources_tail = &(alternate->next);
pos = kh_put_odb_path_map(odb->source_by_path, alternate->path, &ret);
if (!ret)
hashmap_entry_init(&alternate->by_path_entry, strihash(alternate->path));
if (hashmap_get(&odb->source_by_path, &alternate->by_path_entry,
alternate->path))
BUG("source must not yet exist");
kh_value(odb->source_by_path, pos) = alternate;
hashmap_add(&odb->source_by_path, &alternate->by_path_entry);
/* recursively add alternates */
odb_source_read_alternates(alternate, &sources);
@@ -210,18 +245,12 @@ void odb_add_to_alternates_file(struct object_database *odb,
int ret = odb_source_write_alternate(odb->sources, dir);
if (ret < 0)
die(NULL);
if (odb->loaded_alternates)
odb_add_alternate_recursively(odb, dir, 0);
odb_add_alternate_recursively(odb, dir, 0);
}
struct odb_source *odb_add_to_alternates_memory(struct object_database *odb,
const char *dir)
{
/*
* Make sure alternates are initialized, or else our entry may be
* overwritten when they are.
*/
odb_prepare_alternates(odb);
return odb_add_alternate_recursively(odb, dir, 0);
}
@@ -230,12 +259,6 @@ struct odb_source *odb_set_temporary_primary_source(struct object_database *odb,
{
struct odb_source *source;
/*
* Make sure alternates are initialized, or else our entry may be
* overwritten when they are.
*/
odb_prepare_alternates(odb);
/*
* Make a new primary odb and link the old primary ODB in as an
* alternate
@@ -341,7 +364,6 @@ struct odb_source *odb_find_source(struct object_database *odb, const char *obj_
char *obj_dir_real = real_pathdup(obj_dir, 1);
struct strbuf odb_path_real = STRBUF_INIT;
odb_prepare_alternates(odb);
for (source = odb->sources; source; source = source->next) {
strbuf_realpath(&odb_path_real, source->path, 1);
if (!strcmp(obj_dir_real, odb_path_real.buf))
@@ -475,7 +497,6 @@ int odb_for_each_alternate(struct object_database *odb,
struct odb_source *alternate;
int r = 0;
odb_prepare_alternates(odb);
for (alternate = odb->sources->next; alternate; alternate = alternate->next) {
r = cb(alternate, payload);
if (r)
@@ -484,26 +505,22 @@ int odb_for_each_alternate(struct object_database *odb,
return r;
}
void odb_prepare_alternates(struct object_database *odb)
static void odb_prepare_alternates(struct object_database *odb,
const char *alternate_db)
{
struct strvec sources = STRVEC_INIT;
if (odb->loaded_alternates)
return;
parse_alternates(odb->alternate_db, PATH_SEP, NULL, &sources);
parse_alternates(alternate_db, PATH_SEP, NULL, &sources);
odb_source_read_alternates(odb->sources, &sources);
for (size_t i = 0; i < sources.nr; i++)
odb_add_alternate_recursively(odb, sources.v[i], 0);
odb->loaded_alternates = 1;
strvec_clear(&sources);
}
int odb_has_alternates(struct object_database *odb)
{
odb_prepare_alternates(odb);
return !!odb->sources->next;
}
@@ -563,8 +580,6 @@ static int do_oid_object_info_extended(struct object_database *odb,
if (!odb_source_read_object_info(odb->inmemory_objects, oid, oi, flags))
return 0;
odb_prepare_alternates(odb);
while (1) {
struct odb_source *source;
@@ -827,7 +842,6 @@ int odb_freshen_object(struct object_database *odb,
const struct object_id *oid)
{
struct odb_source *source;
odb_prepare_alternates(odb);
for (source = odb->sources; source; source = source->next)
if (odb_source_freshen_object(source, oid, NULL))
return 1;
@@ -842,7 +856,6 @@ int odb_for_each_object_ext(struct object_database *odb,
{
int ret;
odb_prepare_alternates(odb);
for (struct odb_source *source = odb->sources; source; source = source->next) {
if (opts->flags & ODB_FOR_EACH_OBJECT_LOCAL_ONLY && !source->local)
continue;
@@ -880,7 +893,6 @@ int odb_count_objects(struct object_database *odb,
return 0;
}
odb_prepare_alternates(odb);
for (source = odb->sources; source; source = source->next) {
unsigned long c;
@@ -960,7 +972,6 @@ int odb_find_abbrev_len(struct object_database *odb,
goto out;
}
odb_prepare_alternates(odb);
for (struct odb_source *source = odb->sources; source; source = source->next) {
ret = odb_source_find_abbrev_len(source, oid, len, &len);
if (ret)
@@ -1056,6 +1067,8 @@ struct object_database *odb_new(struct repository *repo,
o->repo = repo;
pthread_mutex_init(&o->replace_mutex, NULL);
string_list_init_dup(&o->submodule_source_paths);
hashmap_init(&o->source_by_path, odb_source_by_path_cmp, o, 0);
o->source_paths_icase = -1;
if (flags & ODB_NEW_HONOR_ENV) {
primary_source = xstrdup_or_null(getenv(DB_ENVIRONMENT));
@@ -1066,9 +1079,11 @@ struct object_database *odb_new(struct repository *repo,
o->sources = odb_source_new(o, primary_source, true);
o->sources_tail = &o->sources->next;
o->alternate_db = secondary_sources;
o->inmemory_objects = &odb_source_inmemory_new(o)->base;
odb_prepare_alternates(o, secondary_sources);
free(secondary_sources);
free(primary_source);
return o;
}
@@ -1094,8 +1109,7 @@ static void odb_free_sources(struct object_database *o)
odb_source_free(o->inmemory_objects);
o->inmemory_objects = NULL;
kh_destroy_odb_path_map(o->source_by_path);
o->source_by_path = NULL;
hashmap_clear(&o->source_by_path);
}
void odb_free(struct object_database *o)
@@ -1103,8 +1117,6 @@ void odb_free(struct object_database *o)
if (!o)
return;
free(o->alternate_db);
oidmap_clear(&o->replace_map, 1);
pthread_mutex_destroy(&o->replace_mutex);
@@ -1126,14 +1138,14 @@ void odb_prepare(struct object_database *o, enum odb_prepare_flags flags)
* Reprepare alt odbs, in case the alternates file was modified
* during the course of this process. This only _adds_ odbs to
* the linked list, so existing odbs will continue to exist for
* the lifetime of the process.
* the lifetime of the process. Consequently, we don't have to
* reprocess GIT_ALTERNATE_OBJECT_DIRECTORIES here.
*/
if (flags & ODB_PREPARE_FLUSH_CACHES) {
o->loaded_alternates = 0;
odb_prepare_alternates(o, NULL);
o->object_count_valid = 0;
}
odb_prepare_alternates(o);
for (source = o->sources; source; source = source->next)
odb_source_prepare(source, flags);
+11 -13
View File
@@ -1,6 +1,7 @@
#ifndef ODB_H
#define ODB_H
#include "hashmap.h"
#include "object.h"
#include "oidset.h"
#include "oidmap.h"
@@ -54,16 +55,19 @@ struct object_database {
*/
struct odb_source *sources;
struct odb_source **sources_tail;
struct kh_odb_path_map *source_by_path;
int loaded_alternates;
/*
* A list of alternate object directories loaded from the environment;
* this should not generally need to be accessed directly, but will
* populate the "sources" list when odb_prepare_alternates() is run.
* Map of object database sources, keyed by their respective paths.
* This map is used to detect the case where the same source is
* registered multiple times.
*/
char *alternate_db;
struct hashmap source_by_path;
/*
* Whether source paths shall be compared case-insensitively, as
* determined by "core.ignoreCase".
*/
int source_paths_icase;
/*
* Objects that should be substituted by other objects
@@ -260,12 +264,6 @@ void odb_for_each_alternate_ref(struct object_database *odb,
int odb_mkstemp(struct object_database *odb,
struct strbuf *temp_filename, const char *pattern);
/*
* Prepare alternate object sources for the given database by reading
* "objects/info/alternates" and opening the respective sources.
*/
void odb_prepare_alternates(struct object_database *odb);
/*
* Check whether the object database has any alternates. The primary object
* source does not count as alternate.
+7
View File
@@ -1,6 +1,7 @@
#ifndef ODB_SOURCE_H
#define ODB_SOURCE_H
#include "hashmap.h"
#include "object.h"
#include "odb.h"
#include "odb/transaction.h"
@@ -50,6 +51,12 @@ struct strvec;
struct odb_source {
struct odb_source *next;
/*
* Entry in the object database's map of sources, keyed by this
* source's path.
*/
struct hashmap_entry by_path_entry;
/* Object database that owns this object source. */
struct object_database *odb;
-1
View File
@@ -184,7 +184,6 @@ static int istream_source(struct odb_stream **out,
{
struct odb_source *source;
odb_prepare_alternates(odb);
for (source = odb->sources; source; source = source->next)
if (!odb_source_read_object_stream(out, source, oid))
return 0;
-2
View File
@@ -717,7 +717,6 @@ static int open_bitmap(struct repository *r,
assert(!bitmap_git->map);
odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
@@ -3417,7 +3416,6 @@ int verify_bitmap_files(struct repository *r)
struct packed_git *p;
int res = 0;
odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
struct multi_pack_index *m = get_multi_pack_index(files->packed);
-1
View File
@@ -1936,7 +1936,6 @@ int has_object_pack(struct repository *r, const struct object_id *oid)
{
struct odb_source *source;
odb_prepare_alternates(r->objects);
for (source = r->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
if (!odb_source_read_object_info(&files->packed->base, oid, NULL, 0))
-2
View File
@@ -77,8 +77,6 @@ static inline struct repo_for_each_pack_data repo_for_eack_pack_data_init(struct
{
struct repo_for_each_pack_data data = { 0 };
odb_prepare_alternates(repo->objects);
for (struct odb_source *source = repo->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
struct packfile_list_entry *entry = packfile_store_get_packs(files->packed);
+6 -6
View File
@@ -2880,12 +2880,6 @@ int init_db(struct repository *repo,
reinit = create_default_files(repo, template_dir, original_git_dir,
&repo_fmt, init_shared_repository);
if (!(flags & INIT_DB_SKIP_REFDB))
create_reference_database(repo, initial_branch, flags & INIT_DB_QUIET);
create_object_database(repo);
startup_info->have_repository = 1;
if (repo_settings_get_shared_repository(repo)) {
char buf[10];
/* We do not spell "group" and such, so that
@@ -2907,6 +2901,12 @@ int init_db(struct repository *repo,
repo_config_set(repo, "receive.denyNonFastforwards", "true");
}
if (!(flags & INIT_DB_SKIP_REFDB))
create_reference_database(repo, initial_branch, flags & INIT_DB_QUIET);
create_object_database(repo);
startup_info->have_repository = 1;
if (!(flags & INIT_DB_QUIET)) {
int len = strlen(git_dir);