From: Derrick Stolee <derrickstolee@xxxxxxxxxx> When an object is not found in a repository's object store, we sometimes call reprepare_packed_git() to see if the object was temporarily moved into a new pack-file (and its old pack-file or loose object was deleted). This process does a scan of each pack directory within each odb, but does not reevaluate if the odb list needs updating. Create a new reprepare_alt_odb() method that is a similar wrapper around prepare_alt_odb(). Call it from reprepare_packed_git() under the object read lock to avoid readers from interacting with a potentially incomplete odb being added to the odb list. prepare_alt_odb() already avoids adding duplicate odbs to the list during its progress, so it is safe to call it again from reprepare_alt_odb() without worrying about duplicate odbs. This change is specifically for concurrent changes to the repository, so it is difficult to create a test that guarantees this behavior is correct. I manually verified by introducing a reprepare_packed_git() call into get_revision() and stepped into that call in a debugger with a parent 'git log' process. Multiple runs of reprepare_alt_odb() kept the_repository->objects->odb as a single-item chain until I added a .git/objects/info/alternates file in a different process. The next run added the new odb to the chain and subsequent runs did not add to the chain. Signed-off-by: Derrick Stolee <derrickstolee@xxxxxxxxxx> --- object-file: reprepare alternates when necessary This subtlety was notice by Michael Haggerty due to how alternates are used server-side at $DAYJOB. Moving pack-files from a repository to the alternate occasionally causes failures because processes that start before the alternate exists don't know how to find that alternate at run-time. Thanks, * Stolee Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-1490%2Fderrickstolee%2Fstolee%2Freprepare-alternates-v1 Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1490/derrickstolee/stolee/reprepare-alternates-v1 Pull-Request: https://github.com/gitgitgadget/git/pull/1490 object-file.c | 6 ++++++ object-store.h | 1 + packfile.c | 1 + 3 files changed, 8 insertions(+) diff --git a/object-file.c b/object-file.c index 939865c1ae0..22acc7fd8e9 100644 --- a/object-file.c +++ b/object-file.c @@ -944,6 +944,12 @@ void prepare_alt_odb(struct repository *r) r->objects->loaded_alternates = 1; } +void reprepare_alt_odb(struct repository *r) +{ + r->objects->loaded_alternates = 0; + prepare_alt_odb(r); +} + /* Returns 1 if we have successfully freshened the file, 0 otherwise. */ static int freshen_file(const char *fn) { diff --git a/object-store.h b/object-store.h index 1a713d89d7c..750c29daa54 100644 --- a/object-store.h +++ b/object-store.h @@ -56,6 +56,7 @@ KHASH_INIT(odb_path_map, const char * /* key: odb_path */, struct object_directory *, 1, fspathhash, fspatheq) void prepare_alt_odb(struct repository *r); +void reprepare_alt_odb(struct repository *r); char *compute_alternate_path(const char *path, struct strbuf *err); struct object_directory *find_odb(struct repository *r, const char *obj_dir); typedef int alt_odb_fn(struct object_directory *, void *); diff --git a/packfile.c b/packfile.c index 79e21ab18e7..2b28918a05e 100644 --- a/packfile.c +++ b/packfile.c @@ -1008,6 +1008,7 @@ void reprepare_packed_git(struct repository *r) struct object_directory *odb; obj_read_lock(); + reprepare_alt_odb(r); for (odb = r->objects->odb; odb; odb = odb->next) odb_clear_loose_cache(odb); base-commit: d15644fe0226af7ffc874572d968598564a230dd -- gitgitgadget