odb/source: generalize `reprepare()` callback

The `reprepare()` callback function can be used to flush caches of a
given object source and then prepare it anew. This is for example used
when a concurrent process may have written new objects. Ultimately, this
can be seen as doing two separate steps:

  1. We drop any caches.

  2. We prepare the source.

We have one callsite in git-grep(1) though that really only want to do
(2). This is done by reaching into the "files" backend directly and then
calling `odb_source_packed_prepare()`, which of course may not work with
alternate backends.

We could in theory just call `reprepare()` here, and that would likely
not have any significant downside. But this would certainly feel like a
code smell.

Instead, generalize the `reprepare()` callback to `prepare()` with a
flag that optionally instructs the backend to also flush the caches,
which allows us to drop the external `odb_source_packed_prepare()`
declaration.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
main
Patrick Steinhardt 2026-06-22 10:47:54 +02:00 committed by Junio C Hamano
parent 1bba44eee3
commit 27bba4258b
11 changed files with 56 additions and 56 deletions

View File

@ -25,12 +25,11 @@
#include "setup.h"
#include "submodule.h"
#include "submodule-config.h"
#include "object-file.h"
#include "object-name.h"
#include "odb.h"
#include "odb/source.h"
#include "oid-array.h"
#include "oidset.h"
#include "packfile.h"
#include "pager.h"
#include "path.h"
#include "promisor-remote.h"
@ -1361,10 +1360,8 @@ int cmd_grep(int argc,
struct odb_source *source;

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);
odb_source_packed_prepare(files->packed);
}
for (source = the_repository->objects->sources; source; source = source->next)
odb_source_prepare(source, 0);
}

start_threads(&opt);

2
midx.c
View File

@ -101,7 +101,7 @@ static int midx_read_object_offsets(const unsigned char *chunk_start,

struct multi_pack_index *get_multi_pack_index(struct odb_source_packed *source)
{
odb_source_packed_prepare(source);
odb_source_prepare(&source->base, 0);
return source->midx;
}


2
odb.c
View File

@ -1086,7 +1086,7 @@ void odb_reprepare(struct object_database *o)
odb_prepare_alternates(o);

for (source = o->sources; source; source = source->next)
odb_source_reprepare(source);
odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);

o->object_count_valid = 0;


8
odb.h
View File

@ -124,6 +124,14 @@ void odb_free(struct object_database *o);
*/
void odb_close(struct object_database *o);

enum odb_prepare_flags {
/*
* Flush caches, reload alternates and then re-prepare each object
* source so that new objects may become accessible.
*/
ODB_PREPARE_FLUSH_CACHES = (1 << 0),
};

/*
* Clear caches, reload alternates and then reload object sources so that new
* objects may become accessible.

View File

@ -41,11 +41,12 @@ static void odb_source_files_close(struct odb_source *source)
odb_source_close(&files->packed->base);
}

static void odb_source_files_reprepare(struct odb_source *source)
static void odb_source_files_prepare(struct odb_source *source,
enum odb_prepare_flags flags)
{
struct odb_source_files *files = odb_source_files_downcast(source);
odb_source_reprepare(&files->loose->base);
odb_source_reprepare(&files->packed->base);
odb_source_prepare(&files->loose->base, flags);
odb_source_prepare(&files->packed->base, flags);
}

static int odb_source_files_read_object_info(struct odb_source *source,
@ -273,7 +274,7 @@ struct odb_source_files *odb_source_files_new(struct object_database *odb,

files->base.free = odb_source_files_free;
files->base.close = odb_source_files_close;
files->base.reprepare = odb_source_files_reprepare;
files->base.prepare = odb_source_files_prepare;
files->base.read_object_info = odb_source_files_read_object_info;
files->base.read_object_stream = odb_source_files_read_object_stream;
files->base.for_each_object = odb_source_files_for_each_object;

View File

@ -325,7 +325,8 @@ static void odb_source_inmemory_close(struct odb_source *source UNUSED)
{
}

static void odb_source_inmemory_reprepare(struct odb_source *source UNUSED)
static void odb_source_inmemory_prepare(struct odb_source *source UNUSED,
enum odb_prepare_flags flags UNUSED)
{
}

@ -365,7 +366,7 @@ struct odb_source_inmemory *odb_source_inmemory_new(struct object_database *odb)

source->base.free = odb_source_inmemory_free;
source->base.close = odb_source_inmemory_close;
source->base.reprepare = odb_source_inmemory_reprepare;
source->base.prepare = odb_source_inmemory_prepare;
source->base.read_object_info = odb_source_inmemory_read_object_info;
source->base.read_object_stream = odb_source_inmemory_read_object_stream;
source->base.for_each_object = odb_source_inmemory_for_each_object;

View File

@ -672,10 +672,12 @@ static void odb_source_loose_clear_cache(struct odb_source_loose *loose)
sizeof(loose->subdir_seen));
}

static void odb_source_loose_reprepare(struct odb_source *source)
static void odb_source_loose_prepare(struct odb_source *source,
enum odb_prepare_flags flags)
{
struct odb_source_loose *loose = odb_source_loose_downcast(source);
odb_source_loose_clear_cache(loose);
if (flags & ODB_PREPARE_FLUSH_CACHES)
odb_source_loose_clear_cache(loose);
}

static void odb_source_loose_close(struct odb_source *source UNUSED)
@ -716,7 +718,7 @@ struct odb_source_loose *odb_source_loose_new(struct object_database *odb,

loose->base.free = odb_source_loose_free;
loose->base.close = odb_source_loose_close;
loose->base.reprepare = odb_source_loose_reprepare;
loose->base.prepare = odb_source_loose_prepare;
loose->base.read_object_info = odb_source_loose_read_object_info;
loose->base.read_object_stream = odb_source_loose_read_object_stream;
loose->base.for_each_object = odb_source_loose_for_each_object;

View File

@ -15,7 +15,7 @@ static int find_pack_entry(struct odb_source_packed *store,
{
struct packfile_list_entry *l;

odb_source_packed_prepare(store);
odb_source_prepare(&store->base, 0);
if (store->midx && fill_midx_entry(store->midx, oid, e))
return 1;

@ -47,7 +47,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
* been added since the last time we have prepared the packfile store.
*/
if (flags & OBJECT_INFO_SECOND_READ)
odb_source_reprepare(source);
odb_source_prepare(source, ODB_PREPARE_FLUSH_CACHES);

if (!find_pack_entry(packed, oid, &e))
return 1;
@ -668,27 +668,25 @@ static int sort_pack(const struct packfile_list_entry *a,
return -1;
}

void odb_source_packed_prepare(struct odb_source_packed *source)
{
if (source->initialized)
return;

prepare_multi_pack_index_one(source);
prepare_packed_git_one(source);

sort_packs(&source->packs.head, sort_pack);
for (struct packfile_list_entry *e = source->packs.head; e; e = e->next)
if (!e->next)
source->packs.tail = e;

source->initialized = true;
}

static void odb_source_packed_reprepare(struct odb_source *source)
static void odb_source_packed_prepare(struct odb_source *source,
enum odb_prepare_flags flags)
{
struct odb_source_packed *packed = odb_source_packed_downcast(source);
packed->initialized = false;
odb_source_packed_prepare(packed);

if (flags & ODB_PREPARE_FLUSH_CACHES)
packed->initialized = false;
if (packed->initialized)
return;

prepare_multi_pack_index_one(packed);
prepare_packed_git_one(packed);

sort_packs(&packed->packs.head, sort_pack);
for (struct packfile_list_entry *e = packed->packs.head; e; e = e->next)
if (!e->next)
packed->packs.tail = e;

packed->initialized = true;
}

static void odb_source_packed_reparent(const char *name UNUSED,
@ -744,7 +742,7 @@ struct odb_source_packed *odb_source_packed_new(struct object_database *odb,

packed->base.free = odb_source_packed_free;
packed->base.close = odb_source_packed_close;
packed->base.reprepare = odb_source_packed_reprepare;
packed->base.prepare = odb_source_packed_prepare;
packed->base.read_object_info = odb_source_packed_read_object_info;
packed->base.read_object_stream = odb_source_packed_read_object_stream;
packed->base.for_each_object = odb_source_packed_for_each_object;

View File

@ -82,13 +82,4 @@ static inline struct odb_source_packed *odb_source_packed_downcast(struct odb_so
return container_of(source, struct odb_source_packed, base);
}

/*
* Prepare the source by loading packfiles and multi-pack indices for
* all alternates. This becomes a no-op if the source is already prepared.
*
* It shouldn't typically be necessary to call this function directly, as
* functions that access the source know to prepare it.
*/
void odb_source_packed_prepare(struct odb_source_packed *source);

#endif

View File

@ -83,11 +83,12 @@ struct odb_source {
void (*close)(struct odb_source *source);

/*
* This callback is expected to clear underlying caches of the object
* database source. The function is called when the repository has for
* example just been repacked so that new objects will become visible.
* This callback is expected to prepare the source so that it becomes
* ready for use. It optionally clears underlying caches of the object
* database source.
*/
void (*reprepare)(struct odb_source *source);
void (*prepare)(struct odb_source *source,
enum odb_prepare_flags flags);

/*
* This callback is expected to read object information from the object
@ -308,13 +309,14 @@ static inline void odb_source_close(struct odb_source *source)
}

/*
* Reprepare the object database source and clear any caches. Depending on the
* Prepare the object database source and clear any caches. Depending on the
* backend used this may have the effect that concurrently-written objects
* become visible.
*/
static inline void odb_source_reprepare(struct odb_source *source)
static inline void odb_source_prepare(struct odb_source *source,
enum odb_prepare_flags flags)
{
source->reprepare(source);
source->prepare(source, flags);
}

/*

View File

@ -855,7 +855,7 @@ void for_each_file_in_pack_dir(const char *objdir,

struct packfile_list_entry *packfile_store_get_packs(struct odb_source_packed *store)
{
odb_source_packed_prepare(store);
odb_source_prepare(&store->base, 0);

if (store->midx) {
struct multi_pack_index *m = store->midx;