Merge branch 'jk/loose-object-cache'
authorJunio C Hamano <gitster@pobox.com>
Fri, 4 Jan 2019 21:33:32 +0000 (13:33 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 4 Jan 2019 21:33:32 +0000 (13:33 -0800)
Code clean-up with optimization for the codepath that checks
(non-)existence of loose objects.

* jk/loose-object-cache:
odb_load_loose_cache: fix strbuf leak
fetch-pack: drop custom loose object cache
sha1-file: use loose object cache for quick existence check
object-store: provide helpers for loose_objects_cache
sha1-file: use an object_directory for the main object dir
handle alternates paths the same as the main object dir
sha1_file_name(): overwrite buffer instead of appending
rename "alternate_object_database" to "object_directory"
submodule--helper: prefer strip_suffix() to ends_with()
fsck: do not reuse child_process structs

18 files changed:
builtin/count-objects.c
builtin/fsck.c
builtin/grep.c
builtin/submodule--helper.c
commit-graph.c
environment.c
fetch-pack.c
http-walker.c
http.c
midx.c
object-store.h
object.c
packfile.c
path.c
repository.c
sha1-file.c
sha1-name.c
transport.c
index a7cad052c615807b819f32c999c161f0f905c1bc..3fae474f6f1f4fb78911ab4a26a160f04527d292 100644 (file)
@@ -78,10 +78,10 @@ static int count_cruft(const char *basename, const char *path, void *data)
        return 0;
 }
 
-static int print_alternate(struct alternate_object_database *alt, void *data)
+static int print_alternate(struct object_directory *odb, void *data)
 {
        printf("alternate: ");
-       quote_c_style(alt->path, NULL, stdout, 0);
+       quote_c_style(odb->path, NULL, stdout, 0);
        putchar('\n');
        return 0;
 }
index a281d7cd123b830bf89c2e21ccbcb10f55f40ab9..c03a9c42db90a5e85b21bec13247fb813b1a900d 100644 (file)
@@ -739,7 +739,7 @@ static struct option fsck_opts[] = {
 int cmd_fsck(int argc, const char **argv, const char *prefix)
 {
        int i;
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
 
        /* fsck knows how to handle missing promisor objects */
        fetch_if_missing = 0;
@@ -775,14 +775,9 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                for_each_loose_object(mark_loose_for_connectivity, NULL, 0);
                for_each_packed_object(mark_packed_for_connectivity, NULL, 0);
        } else {
-               struct alternate_object_database *alt_odb_list;
-
-               fsck_object_dir(get_object_directory());
-
                prepare_alt_odb(the_repository);
-               alt_odb_list = the_repository->objects->alt_odb_list;
-               for (alt = alt_odb_list; alt; alt = alt->next)
-                       fsck_object_dir(alt->path);
+               for (odb = the_repository->objects->odb; odb; odb = odb->next)
+                       fsck_object_dir(odb->path);
 
                if (check_full) {
                        struct packed_git *p;
@@ -884,15 +879,13 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                struct child_process commit_graph_verify = CHILD_PROCESS_INIT;
                const char *verify_argv[] = { "commit-graph", "verify", NULL, NULL, NULL };
 
-               commit_graph_verify.argv = verify_argv;
-               commit_graph_verify.git_cmd = 1;
-               if (run_command(&commit_graph_verify))
-                       errors_found |= ERROR_COMMIT_GRAPH;
-
                prepare_alt_odb(the_repository);
-               for (alt =  the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+               for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+                       child_process_init(&commit_graph_verify);
+                       commit_graph_verify.argv = verify_argv;
+                       commit_graph_verify.git_cmd = 1;
                        verify_argv[2] = "--object-dir";
-                       verify_argv[3] = alt->path;
+                       verify_argv[3] = odb->path;
                        if (run_command(&commit_graph_verify))
                                errors_found |= ERROR_COMMIT_GRAPH;
                }
@@ -902,15 +895,13 @@ int cmd_fsck(int argc, const char **argv, const char *prefix)
                struct child_process midx_verify = CHILD_PROCESS_INIT;
                const char *midx_argv[] = { "multi-pack-index", "verify", NULL, NULL, NULL };
 
-               midx_verify.argv = midx_argv;
-               midx_verify.git_cmd = 1;
-               if (run_command(&midx_verify))
-                       errors_found |= ERROR_COMMIT_GRAPH;
-
                prepare_alt_odb(the_repository);
-               for (alt =  the_repository->objects->alt_odb_list; alt; alt = alt->next) {
+               for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+                       child_process_init(&midx_verify);
+                       midx_verify.argv = midx_argv;
+                       midx_verify.git_cmd = 1;
                        midx_argv[2] = "--object-dir";
-                       midx_argv[3] = alt->path;
+                       midx_argv[3] = odb->path;
                        if (run_command(&midx_verify))
                                errors_found |= ERROR_COMMIT_GRAPH;
                }
index 71df52a333cbc756b057e93bf3d2affca8157860..bad9c0a3d5134a69d9388e169793b03c9952d9bf 100644 (file)
@@ -437,7 +437,7 @@ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
         * store is no longer global and instead is a member of the repository
         * object.
         */
-       add_to_alternates_memory(submodule.objects->objectdir);
+       add_to_alternates_memory(submodule.objects->odb->path);
        grep_read_unlock();
 
        if (oid) {
index d38113a31aeb3838190b7339475c7454e45f3a89..b45514be317eafb765a8943241b5d880f65e3117 100644 (file)
@@ -1265,19 +1265,20 @@ struct submodule_alternate_setup {
        SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL }
 
 static int add_possible_reference_from_superproject(
-               struct alternate_object_database *alt, void *sas_cb)
+               struct object_directory *odb, void *sas_cb)
 {
        struct submodule_alternate_setup *sas = sas_cb;
+       size_t len;
 
        /*
         * If the alternate object store is another repository, try the
         * standard layout with .git/(modules/<name>)+/objects
         */
-       if (ends_with(alt->path, "/objects")) {
+       if (strip_suffix(odb->path, "/objects", &len)) {
                char *sm_alternate;
                struct strbuf sb = STRBUF_INIT;
                struct strbuf err = STRBUF_INIT;
-               strbuf_add(&sb, alt->path, strlen(alt->path) - strlen("objects"));
+               strbuf_add(&sb, odb->path, len);
 
                /*
                 * We need to end the new path with '/' to mark it as a dir,
@@ -1285,7 +1286,7 @@ static int add_possible_reference_from_superproject(
                 * as the last part of a missing submodule reference would
                 * be taken as a file name.
                 */
-               strbuf_addf(&sb, "modules/%s/", sas->submodule_name);
+               strbuf_addf(&sb, "/modules/%s/", sas->submodule_name);
 
                sm_alternate = compute_alternate_path(sb.buf, &err);
                if (sm_alternate) {
index 40c855f1855595fbf5b285008d3c829e6a2f41eb..99163c244bdca8cf2eb0ec4452cd4d9de835ae25 100644 (file)
@@ -230,8 +230,7 @@ static void prepare_commit_graph_one(struct repository *r, const char *obj_dir)
  */
 static int prepare_commit_graph(struct repository *r)
 {
-       struct alternate_object_database *alt;
-       char *obj_dir;
+       struct object_directory *odb;
        int config_value;
 
        if (r->objects->commit_graph_attempted)
@@ -252,13 +251,11 @@ static int prepare_commit_graph(struct repository *r)
        if (!commit_graph_compatible(r))
                return 0;
 
-       obj_dir = r->objects->objectdir;
-       prepare_commit_graph_one(r, obj_dir);
        prepare_alt_odb(r);
-       for (alt = r->objects->alt_odb_list;
-            !r->objects->commit_graph && alt;
-            alt = alt->next)
-               prepare_commit_graph_one(r, alt->path);
+       for (odb = r->objects->odb;
+            !r->objects->commit_graph && odb;
+            odb = odb->next)
+               prepare_commit_graph_one(r, odb->path);
        return !!r->objects->commit_graph;
 }
 
index 346559770773e923766c06593ada84c72815061f..0e37741d838256d196b2ec9f3ca4e54395c66d31 100644 (file)
@@ -274,9 +274,9 @@ const char *get_git_work_tree(void)
 
 char *get_object_directory(void)
 {
-       if (!the_repository->objects->objectdir)
+       if (!the_repository->objects->odb)
                BUG("git environment hasn't been setup");
-       return the_repository->objects->objectdir;
+       return the_repository->objects->odb->path;
 }
 
 int odb_mkstemp(struct strbuf *temp_filename, const char *pattern)
index 9691046e6445837beefde3d8ae5e842063842575..dd6700bda9240f2278e663f9147df1c0808d2efc 100644 (file)
@@ -636,23 +636,6 @@ struct loose_object_iter {
        struct ref *refs;
 };
 
-/*
- *  If the number of refs is not larger than the number of loose objects,
- *  this function stops inserting.
- */
-static int add_loose_objects_to_set(const struct object_id *oid,
-                                   const char *path,
-                                   void *data)
-{
-       struct loose_object_iter *iter = data;
-       oidset_insert(iter->loose_object_set, oid);
-       if (iter->refs == NULL)
-               return 1;
-
-       iter->refs = iter->refs->next;
-       return 0;
-}
-
 /*
  * Mark recent commits available locally and reachable from a local ref as
  * COMPLETE. If args->no_dependents is false, also mark COMPLETE remote refs as
@@ -670,30 +653,14 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
        struct ref *ref;
        int old_save_commit_buffer = save_commit_buffer;
        timestamp_t cutoff = 0;
-       struct oidset loose_oid_set = OIDSET_INIT;
-       int use_oidset = 0;
-       struct loose_object_iter iter = {&loose_oid_set, *refs};
-
-       /* Enumerate all loose objects or know refs are not so many. */
-       use_oidset = !for_each_loose_object(add_loose_objects_to_set,
-                                           &iter, 0);
 
        save_commit_buffer = 0;
 
        for (ref = *refs; ref; ref = ref->next) {
                struct object *o;
-               unsigned int flags = OBJECT_INFO_QUICK;
 
-               if (use_oidset &&
-                   !oidset_contains(&loose_oid_set, &ref->old_oid)) {
-                       /*
-                        * I know this does not exist in the loose form,
-                        * so check if it exists in a non-loose form.
-                        */
-                       flags |= OBJECT_INFO_IGNORE_LOOSE;
-               }
-
-               if (!has_object_file_with_flags(&ref->old_oid, flags))
+               if (!has_object_file_with_flags(&ref->old_oid,
+                                               OBJECT_INFO_QUICK))
                        continue;
                o = parse_object(the_repository, &ref->old_oid);
                if (!o)
@@ -710,8 +677,6 @@ static void mark_complete_and_common_ref(struct fetch_negotiator *negotiator,
                }
        }
 
-       oidset_clear(&loose_oid_set);
-
        if (!args->deepen) {
                for_each_ref(mark_complete_oid, NULL);
                for_each_cached_alternate(NULL, mark_alternate_complete);
index b3334bf657b5ea64e779eb470525eb0b7337baa9..0a392c85b67af254ddeca382faa79458c4ec3ca8 100644 (file)
@@ -547,7 +547,7 @@ static int fetch_object(struct walker *walker, unsigned char *sha1)
                ret = error("File %s has bad hash", hex);
        } else if (req->rename < 0) {
                struct strbuf buf = STRBUF_INIT;
-               sha1_file_name(the_repository, &buf, req->sha1);
+               loose_object_path(the_repository, &buf, req->sha1);
                ret = error("unable to write sha1 filename %s", buf.buf);
                strbuf_release(&buf);
        }
diff --git a/http.c b/http.c
index b8258fc78fddbb05192f3f4cfed3eac1cd406834..0b6807cef9aa0994be486581ecf18f7829ee4e19 100644 (file)
--- a/http.c
+++ b/http.c
@@ -2353,7 +2353,7 @@ struct http_object_request *new_http_object_request(const char *base_url,
        hashcpy(freq->sha1, sha1);
        freq->localfile = -1;
 
-       sha1_file_name(the_repository, &filename, sha1);
+       loose_object_path(the_repository, &filename, sha1);
        strbuf_addf(&freq->tmpfile, "%s.temp", filename.buf);
 
        strbuf_addf(&prevfile, "%s.prev", filename.buf);
@@ -2504,7 +2504,7 @@ int finish_http_object_request(struct http_object_request *freq)
                unlink_or_warn(freq->tmpfile.buf);
                return -1;
        }
-       sha1_file_name(the_repository, &filename, freq->sha1);
+       loose_object_path(the_repository, &filename, freq->sha1);
        freq->rename = finalize_object_file(freq->tmpfile.buf, filename.buf);
        strbuf_release(&filename);
 
diff --git a/midx.c b/midx.c
index 2a6a24fcd7eff1a074c37e6c556f2143ef134c19..8a505fd423efccf9986079542b47967cc93df7dc 100644 (file)
--- a/midx.c
+++ b/midx.c
@@ -931,7 +931,7 @@ int write_midx_file(const char *object_dir)
 
 void clear_midx_file(struct repository *r)
 {
-       char *midx = get_midx_filename(r->objects->objectdir);
+       char *midx = get_midx_filename(r->objects->odb->path);
 
        if (r->objects && r->objects->multi_pack_index) {
                close_midx(r->objects->multi_pack_index);
index 63b7605a3e0b3000641d8f39f22e1d5c8139f19b..60758efad89d1a09959ba9850cb3c7445861aabe 100644 (file)
@@ -7,19 +7,17 @@
 #include "sha1-array.h"
 #include "strbuf.h"
 
-struct alternate_object_database {
-       struct alternate_object_database *next;
-
-       /* see alt_scratch_buf() */
-       struct strbuf scratch;
-       size_t base_len;
+struct object_directory {
+       struct object_directory *next;
 
        /*
-        * Used to store the results of readdir(3) calls when searching
-        * for unique abbreviated hashes.  This cache is never
-        * invalidated, thus it's racy and not necessarily accurate.
-        * That's fine for its purpose; don't use it for tasks requiring
-        * greater accuracy!
+        * Used to store the results of readdir(3) calls when we are OK
+        * sacrificing accuracy due to races for speed. That includes
+        * object existence with OBJECT_INFO_QUICK, as well as
+        * our search for unique abbreviated hashes. Don't use it for tasks
+        * requiring greater accuracy!
+        *
+        * Be sure to call odb_load_loose_cache() before using.
         */
        char loose_objects_subdir_seen[256];
        struct oid_array loose_objects_cache;
@@ -28,19 +26,14 @@ struct alternate_object_database {
         * Path to the alternative object store. If this is a relative path,
         * it is relative to the current working directory.
         */
-       char path[FLEX_ARRAY];
+       char *path;
 };
+
 void prepare_alt_odb(struct repository *r);
 char *compute_alternate_path(const char *path, struct strbuf *err);
-typedef int alt_odb_fn(struct alternate_object_database *, void *);
+typedef int alt_odb_fn(struct object_directory *, void *);
 int foreach_alt_odb(alt_odb_fn, void*);
 
-/*
- * Allocate a "struct alternate_object_database" but do _not_ actually
- * add it to the list of alternates.
- */
-struct alternate_object_database *alloc_alt_odb(const char *dir);
-
 /*
  * Add the directory to the on-disk alternates file; the new entry will also
  * take effect in the current process.
@@ -55,12 +48,11 @@ void add_to_alternates_file(const char *dir);
 void add_to_alternates_memory(const char *dir);
 
 /*
- * Returns a scratch strbuf pre-filled with the alternate object directory,
- * including a trailing slash, which can be used to access paths in the
- * alternate. Always use this over direct access to alt->scratch, as it
- * cleans up any previous use of the scratch buffer.
+ * Populate an odb's loose object cache for one particular subdirectory (i.e.,
+ * the one that corresponds to the first byte of objects you're interested in,
+ * from 0 to 255 inclusive).
  */
-struct strbuf *alt_scratch_buf(struct alternate_object_database *alt);
+void odb_load_loose_cache(struct object_directory *odb, int subdir_nr);
 
 struct packed_git {
        struct packed_git *next;
@@ -92,17 +84,21 @@ struct multi_pack_index;
 
 struct raw_object_store {
        /*
-        * Path to the repository's object store.
-        * Cannot be NULL after initialization.
+        * Set of all object directories; the main directory is first (and
+        * cannot be NULL after initialization). Subsequent directories are
+        * alternates.
         */
-       char *objectdir;
+       struct object_directory *odb;
+       struct object_directory **odb_tail;
+       int loaded_alternates;
 
-       /* Path to extra alternate object database if not NULL */
+       /*
+        * A list of alternate object directories loaded from the environment;
+        * this should not generally need to be accessed directly, but will
+        * populate the "odb" list when prepare_alt_odb() is run.
+        */
        char *alternate_db;
 
-       struct alternate_object_database *alt_odb_list;
-       struct alternate_object_database **alt_odb_tail;
-
        /*
         * Objects that should be substituted by other objects
         * (see git-replace(1)).
@@ -157,7 +153,7 @@ void raw_object_store_clear(struct raw_object_store *o);
  * Put in `buf` the name of the file in the local object database that
  * would be used to store a loose object with the specified sha1.
  */
-void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1);
+const char *loose_object_path(struct repository *r, struct strbuf *buf, const unsigned char *sha1);
 
 void *map_sha1_file(struct repository *r, const unsigned char *sha1, unsigned long *size);
 
index e54160550c5a8e864f2e2bbcc58a29ff73045f8f..79d636091ca1a334a71d516326f14887ea91b946 100644 (file)
--- a/object.c
+++ b/object.c
@@ -482,27 +482,26 @@ struct raw_object_store *raw_object_store_new(void)
        return o;
 }
 
-static void free_alt_odb(struct alternate_object_database *alt)
+static void free_object_directory(struct object_directory *odb)
 {
-       strbuf_release(&alt->scratch);
-       oid_array_clear(&alt->loose_objects_cache);
-       free(alt);
+       free(odb->path);
+       oid_array_clear(&odb->loose_objects_cache);
+       free(odb);
 }
 
-static void free_alt_odbs(struct raw_object_store *o)
+static void free_object_directories(struct raw_object_store *o)
 {
-       while (o->alt_odb_list) {
-               struct alternate_object_database *next;
+       while (o->odb) {
+               struct object_directory *next;
 
-               next = o->alt_odb_list->next;
-               free_alt_odb(o->alt_odb_list);
-               o->alt_odb_list = next;
+               next = o->odb->next;
+               free_object_directory(o->odb);
+               o->odb = next;
        }
 }
 
 void raw_object_store_clear(struct raw_object_store *o)
 {
-       FREE_AND_NULL(o->objectdir);
        FREE_AND_NULL(o->alternate_db);
 
        oidmap_free(o->replace_map, 1);
@@ -512,8 +511,9 @@ void raw_object_store_clear(struct raw_object_store *o)
        o->commit_graph = NULL;
        o->commit_graph_attempted = 0;
 
-       free_alt_odbs(o);
-       o->alt_odb_tail = NULL;
+       free_object_directories(o);
+       o->odb_tail = NULL;
+       o->loaded_alternates = 0;
 
        INIT_LIST_HEAD(&o->packed_git_mru);
        close_all_packs(o);
index d1e6683ffe877d9bf1b0996f25f0720fdffe983a..8c6b47cc777708d4f8e450337f2b9d205f43591b 100644 (file)
@@ -971,16 +971,16 @@ static void prepare_packed_git_mru(struct repository *r)
 
 static void prepare_packed_git(struct repository *r)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
 
        if (r->objects->packed_git_initialized)
                return;
-       prepare_multi_pack_index_one(r, r->objects->objectdir, 1);
-       prepare_packed_git_one(r, r->objects->objectdir, 1);
+
        prepare_alt_odb(r);
-       for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
-               prepare_multi_pack_index_one(r, alt->path, 0);
-               prepare_packed_git_one(r, alt->path, 0);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               int local = (odb == r->objects->odb);
+               prepare_multi_pack_index_one(r, odb->path, local);
+               prepare_packed_git_one(r, odb->path, local);
        }
        rearrange_packed_git(r);
 
@@ -992,6 +992,14 @@ static void prepare_packed_git(struct repository *r)
 
 void reprepare_packed_git(struct repository *r)
 {
+       struct object_directory *odb;
+
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               oid_array_clear(&odb->loose_objects_cache);
+               memset(&odb->loose_objects_subdir_seen, 0,
+                      sizeof(odb->loose_objects_subdir_seen));
+       }
+
        r->objects->approximate_object_count_valid = 0;
        r->objects->packed_git_initialized = 0;
        prepare_packed_git(r);
diff --git a/path.c b/path.c
index dc3294c71e1e72ae2aae9164c790e27d1237e956..03ab712839a7878e3d3b5d79c698f4e2bb29c8b1 100644 (file)
--- a/path.c
+++ b/path.c
@@ -385,7 +385,7 @@ static void adjust_git_path(const struct repository *repo,
                strbuf_splice(buf, 0, buf->len,
                              repo->index_file, strlen(repo->index_file));
        else if (dir_prefix(base, "objects"))
-               replace_dir(buf, git_dir_len + 7, repo->objects->objectdir);
+               replace_dir(buf, git_dir_len + 7, repo->objects->odb->path);
        else if (git_hooks_path && dir_prefix(base, "hooks"))
                replace_dir(buf, git_dir_len + 5, git_hooks_path);
        else if (repo->different_commondir)
index 5dd148671811b383a64b8f3adab87804cea9db08..7b02e1dffac077d0c21ecaef915f4ea33abc57bc 100644 (file)
@@ -63,8 +63,14 @@ void repo_set_gitdir(struct repository *repo,
        free(old_gitdir);
 
        repo_set_commondir(repo, o->commondir);
-       expand_base_dir(&repo->objects->objectdir, o->object_dir,
+
+       if (!repo->objects->odb) {
+               repo->objects->odb = xcalloc(1, sizeof(*repo->objects->odb));
+               repo->objects->odb_tail = &repo->objects->odb->next;
+       }
+       expand_base_dir(&repo->objects->odb->path, o->object_dir,
                        repo->commondir, "objects");
+
        free(repo->objects->alternate_db);
        repo->objects->alternate_db = xstrdup_or_null(o->alternate_db);
        expand_base_dir(&repo->graft_file, o->graft_file,
index 5bd11c85bc563618b59dad3ff06e5ae5296c892b..5a272f70de149a2102a1db8f1b3165f3f20da935 100644 (file)
@@ -346,25 +346,21 @@ static void fill_sha1_path(struct strbuf *buf, const unsigned char *sha1)
        }
 }
 
-void sha1_file_name(struct repository *r, struct strbuf *buf, const unsigned char *sha1)
+static const char *odb_loose_path(struct object_directory *odb,
+                                 struct strbuf *buf,
+                                 const unsigned char *sha1)
 {
-       strbuf_addstr(buf, r->objects->objectdir);
+       strbuf_reset(buf);
+       strbuf_addstr(buf, odb->path);
        strbuf_addch(buf, '/');
        fill_sha1_path(buf, sha1);
+       return buf->buf;
 }
 
-struct strbuf *alt_scratch_buf(struct alternate_object_database *alt)
-{
-       strbuf_setlen(&alt->scratch, alt->base_len);
-       return &alt->scratch;
-}
-
-static const char *alt_sha1_path(struct alternate_object_database *alt,
-                                const unsigned char *sha1)
+const char *loose_object_path(struct repository *r, struct strbuf *buf,
+                             const unsigned char *sha1)
 {
-       struct strbuf *buf = alt_scratch_buf(alt);
-       fill_sha1_path(buf, sha1);
-       return buf->buf;
+       return odb_loose_path(r->objects->odb, buf, sha1);
 }
 
 /*
@@ -374,7 +370,7 @@ static int alt_odb_usable(struct raw_object_store *o,
                          struct strbuf *path,
                          const char *normalized_objdir)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
 
        /* Detect cases where alternate disappeared */
        if (!is_directory(path->buf)) {
@@ -388,8 +384,8 @@ static int alt_odb_usable(struct raw_object_store *o,
         * Prevent the common mistake of listing the same
         * thing twice, or object directory itself.
         */
-       for (alt = o->alt_odb_list; alt; alt = alt->next) {
-               if (!fspathcmp(path->buf, alt->path))
+       for (odb = o->odb; odb; odb = odb->next) {
+               if (!fspathcmp(path->buf, odb->path))
                        return 0;
        }
        if (!fspathcmp(path->buf, normalized_objdir))
@@ -402,7 +398,7 @@ static int alt_odb_usable(struct raw_object_store *o,
  * Prepare alternate object database registry.
  *
  * The variable alt_odb_list points at the list of struct
- * alternate_object_database.  The elements on this list come from
+ * object_directory.  The elements on this list come from
  * non-empty elements from colon separated ALTERNATE_DB_ENVIRONMENT
  * environment variable, and $GIT_OBJECT_DIRECTORY/info/alternates,
  * whose contents is similar to that environment variable but can be
@@ -419,7 +415,7 @@ static void read_info_alternates(struct repository *r,
 static int link_alt_odb_entry(struct repository *r, const char *entry,
        const char *relative_base, int depth, const char *normalized_objdir)
 {
-       struct alternate_object_database *ent;
+       struct object_directory *ent;
        struct strbuf pathbuf = STRBUF_INIT;
 
        if (!is_absolute_path(entry) && relative_base) {
@@ -447,11 +443,12 @@ static int link_alt_odb_entry(struct repository *r, const char *entry,
                return -1;
        }
 
-       ent = alloc_alt_odb(pathbuf.buf);
+       ent = xcalloc(1, sizeof(*ent));
+       ent->path = xstrdup(pathbuf.buf);
 
        /* add the alternate entry */
-       *r->objects->alt_odb_tail = ent;
-       r->objects->alt_odb_tail = &(ent->next);
+       *r->objects->odb_tail = ent;
+       r->objects->odb_tail = &(ent->next);
        ent->next = NULL;
 
        /* recursively add alternates */
@@ -505,7 +502,7 @@ static void link_alt_odb_entries(struct repository *r, const char *alt,
                return;
        }
 
-       strbuf_add_absolute_path(&objdirbuf, r->objects->objectdir);
+       strbuf_add_absolute_path(&objdirbuf, r->objects->odb->path);
        if (strbuf_normalize_path(&objdirbuf) < 0)
                die(_("unable to normalize object directory: %s"),
                    objdirbuf.buf);
@@ -540,18 +537,6 @@ static void read_info_alternates(struct repository *r,
        free(path);
 }
 
-struct alternate_object_database *alloc_alt_odb(const char *dir)
-{
-       struct alternate_object_database *ent;
-
-       FLEX_ALLOC_STR(ent, path, dir);
-       strbuf_init(&ent->scratch, 0);
-       strbuf_addf(&ent->scratch, "%s/", dir);
-       ent->base_len = ent->scratch.len;
-
-       return ent;
-}
-
 void add_to_alternates_file(const char *reference)
 {
        struct lock_file lock = LOCK_INIT;
@@ -588,7 +573,7 @@ void add_to_alternates_file(const char *reference)
                fprintf_or_die(out, "%s\n", reference);
                if (commit_lock_file(&lock))
                        die_errno(_("unable to move new alternates file into place"));
-               if (the_repository->objects->alt_odb_tail)
+               if (the_repository->objects->loaded_alternates)
                        link_alt_odb_entries(the_repository, reference,
                                             '\n', NULL, 0);
        }
@@ -684,11 +669,11 @@ char *compute_alternate_path(const char *path, struct strbuf *err)
 
 int foreach_alt_odb(alt_odb_fn fn, void *cb)
 {
-       struct alternate_object_database *ent;
+       struct object_directory *ent;
        int r = 0;
 
        prepare_alt_odb(the_repository);
-       for (ent = the_repository->objects->alt_odb_list; ent; ent = ent->next) {
+       for (ent = the_repository->objects->odb->next; ent; ent = ent->next) {
                r = fn(ent, cb);
                if (r)
                        break;
@@ -698,13 +683,13 @@ int foreach_alt_odb(alt_odb_fn fn, void *cb)
 
 void prepare_alt_odb(struct repository *r)
 {
-       if (r->objects->alt_odb_tail)
+       if (r->objects->loaded_alternates)
                return;
 
-       r->objects->alt_odb_tail = &r->objects->alt_odb_list;
        link_alt_odb_entries(r, r->objects->alternate_db, PATH_SEP, NULL, 0);
 
-       read_info_alternates(r, r->objects->objectdir, 0);
+       read_info_alternates(r, r->objects->odb->path, 0);
+       r->objects->loaded_alternates = 1;
 }
 
 /* Returns 1 if we have successfully freshened the file, 0 otherwise. */
@@ -731,23 +716,27 @@ int check_and_freshen_file(const char *fn, int freshen)
        return 1;
 }
 
-static int check_and_freshen_local(const struct object_id *oid, int freshen)
+static int check_and_freshen_odb(struct object_directory *odb,
+                                const struct object_id *oid,
+                                int freshen)
 {
-       static struct strbuf buf = STRBUF_INIT;
-
-       strbuf_reset(&buf);
-       sha1_file_name(the_repository, &buf, oid->hash);
+       static struct strbuf path = STRBUF_INIT;
+       odb_loose_path(odb, &path, oid->hash);
+       return check_and_freshen_file(path.buf, freshen);
+}
 
-       return check_and_freshen_file(buf.buf, freshen);
+static int check_and_freshen_local(const struct object_id *oid, int freshen)
+{
+       return check_and_freshen_odb(the_repository->objects->odb, oid, freshen);
 }
 
 static int check_and_freshen_nonlocal(const struct object_id *oid, int freshen)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
+
        prepare_alt_odb(the_repository);
-       for (alt = the_repository->objects->alt_odb_list; alt; alt = alt->next) {
-               const char *path = alt_sha1_path(alt, oid->hash);
-               if (check_and_freshen_file(path, freshen))
+       for (odb = the_repository->objects->odb->next; odb; odb = odb->next) {
+               if (check_and_freshen_odb(odb, oid, freshen))
                        return 1;
        }
        return 0;
@@ -888,25 +877,17 @@ int git_open_cloexec(const char *name, int flags)
  *
  * The "path" out-parameter will give the path of the object we found (if any).
  * Note that it may point to static storage and is only valid until another
- * call to sha1_file_name(), etc.
+ * call to stat_sha1_file().
  */
 static int stat_sha1_file(struct repository *r, const unsigned char *sha1,
                          struct stat *st, const char **path)
 {
-       struct alternate_object_database *alt;
+       struct object_directory *odb;
        static struct strbuf buf = STRBUF_INIT;
 
-       strbuf_reset(&buf);
-       sha1_file_name(r, &buf, sha1);
-       *path = buf.buf;
-
-       if (!lstat(*path, st))
-               return 0;
-
        prepare_alt_odb(r);
-       errno = ENOENT;
-       for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
-               *path = alt_sha1_path(alt, sha1);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               *path = odb_loose_path(odb, &buf, sha1);
                if (!lstat(*path, st))
                        return 0;
        }
@@ -922,25 +903,17 @@ static int open_sha1_file(struct repository *r,
                          const unsigned char *sha1, const char **path)
 {
        int fd;
-       struct alternate_object_database *alt;
-       int most_interesting_errno;
+       struct object_directory *odb;
+       int most_interesting_errno = ENOENT;
        static struct strbuf buf = STRBUF_INIT;
 
-       strbuf_reset(&buf);
-       sha1_file_name(r, &buf, sha1);
-       *path = buf.buf;
-
-       fd = git_open(*path);
-       if (fd >= 0)
-               return fd;
-       most_interesting_errno = errno;
-
        prepare_alt_odb(r);
-       for (alt = r->objects->alt_odb_list; alt; alt = alt->next) {
-               *path = alt_sha1_path(alt, sha1);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               *path = odb_loose_path(odb, &buf, sha1);
                fd = git_open(*path);
                if (fd >= 0)
                        return fd;
+
                if (most_interesting_errno == ENOENT)
                        most_interesting_errno = errno;
        }
@@ -948,6 +921,24 @@ static int open_sha1_file(struct repository *r,
        return -1;
 }
 
+static int quick_has_loose(struct repository *r,
+                          const unsigned char *sha1)
+{
+       int subdir_nr = sha1[0];
+       struct object_id oid;
+       struct object_directory *odb;
+
+       hashcpy(oid.hash, sha1);
+
+       prepare_alt_odb(r);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               odb_load_loose_cache(odb, subdir_nr);
+               if (oid_array_lookup(&odb->loose_objects_cache, &oid) >= 0)
+                       return 1;
+       }
+       return 0;
+}
+
 /*
  * Map the loose object at "path" if it is not NULL, or the path found by
  * searching for a loose object named "sha1".
@@ -1198,6 +1189,8 @@ static int sha1_loose_object_info(struct repository *r,
        if (!oi->typep && !oi->type_name && !oi->sizep && !oi->contentp) {
                const char *path;
                struct stat st;
+               if (!oi->disk_sizep && (flags & OBJECT_INFO_QUICK))
+                       return quick_has_loose(r, sha1) ? 0 : -1;
                if (stat_sha1_file(r, sha1, &st, &path) < 0)
                        return -1;
                if (oi->disk_sizep)
@@ -1626,8 +1619,7 @@ static int write_loose_object(const struct object_id *oid, char *hdr,
        static struct strbuf tmp_file = STRBUF_INIT;
        static struct strbuf filename = STRBUF_INIT;
 
-       strbuf_reset(&filename);
-       sha1_file_name(the_repository, &filename, oid->hash);
+       loose_object_path(the_repository, &filename, oid->hash);
 
        fd = create_tmpfile(&tmp_file, filename.buf);
        if (fd < 0) {
@@ -2134,43 +2126,50 @@ int for_each_loose_file_in_objdir(const char *path,
        return r;
 }
 
-struct loose_alt_odb_data {
-       each_loose_object_fn *cb;
-       void *data;
-};
-
-static int loose_from_alt_odb(struct alternate_object_database *alt,
-                             void *vdata)
+int for_each_loose_object(each_loose_object_fn cb, void *data,
+                         enum for_each_object_flags flags)
 {
-       struct loose_alt_odb_data *data = vdata;
-       struct strbuf buf = STRBUF_INIT;
-       int r;
+       struct object_directory *odb;
 
-       strbuf_addstr(&buf, alt->path);
-       r = for_each_loose_file_in_objdir_buf(&buf,
-                                             data->cb, NULL, NULL,
-                                             data->data);
-       strbuf_release(&buf);
-       return r;
+       prepare_alt_odb(the_repository);
+       for (odb = the_repository->objects->odb; odb; odb = odb->next) {
+               int r = for_each_loose_file_in_objdir(odb->path, cb, NULL,
+                                                     NULL, data);
+               if (r)
+                       return r;
+
+               if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
+                       break;
+       }
+
+       return 0;
 }
 
-int for_each_loose_object(each_loose_object_fn cb, void *data,
-                         enum for_each_object_flags flags)
+static int append_loose_object(const struct object_id *oid, const char *path,
+                              void *data)
 {
-       struct loose_alt_odb_data alt;
-       int r;
+       oid_array_append(data, oid);
+       return 0;
+}
 
-       r = for_each_loose_file_in_objdir(get_object_directory(),
-                                         cb, NULL, NULL, data);
-       if (r)
-               return r;
+void odb_load_loose_cache(struct object_directory *odb, int subdir_nr)
+{
+       struct strbuf buf = STRBUF_INIT;
 
-       if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
-               return 0;
+       if (subdir_nr < 0 ||
+           subdir_nr >= ARRAY_SIZE(odb->loose_objects_subdir_seen))
+               BUG("subdir_nr out of range");
 
-       alt.cb = cb;
-       alt.data = data;
-       return foreach_alt_odb(loose_from_alt_odb, &alt);
+       if (odb->loose_objects_subdir_seen[subdir_nr])
+               return;
+
+       strbuf_addstr(&buf, odb->path);
+       for_each_file_in_obj_subdir(subdir_nr, &buf,
+                                   append_loose_object,
+                                   NULL, NULL,
+                                   &odb->loose_objects_cache);
+       odb->loose_objects_subdir_seen[subdir_nr] = 1;
+       strbuf_release(&buf);
 }
 
 static int check_stream_sha1(git_zstream *stream,
index faa60f69e311f5f09cd5b91a8fbbaf3e3e744ab0..b24502811bbad1bb89908f0914366e4f1cb9178b 100644 (file)
@@ -83,51 +83,25 @@ static void update_candidates(struct disambiguate_state *ds, const struct object
        /* otherwise, current can be discarded and candidate is still good */
 }
 
-static int append_loose_object(const struct object_id *oid, const char *path,
-                              void *data)
-{
-       oid_array_append(data, oid);
-       return 0;
-}
-
 static int match_sha(unsigned, const unsigned char *, const unsigned char *);
 
 static void find_short_object_filename(struct disambiguate_state *ds)
 {
        int subdir_nr = ds->bin_pfx.hash[0];
-       struct alternate_object_database *alt;
-       static struct alternate_object_database *fakeent;
+       struct object_directory *odb;
 
-       if (!fakeent) {
-               /*
-                * Create a "fake" alternate object database that
-                * points to our own object database, to make it
-                * easier to get a temporary working space in
-                * alt->name/alt->base while iterating over the
-                * object databases including our own.
-                */
-               fakeent = alloc_alt_odb(get_object_directory());
-       }
-       fakeent->next = the_repository->objects->alt_odb_list;
-
-       for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
+       for (odb = the_repository->objects->odb;
+            odb && !ds->ambiguous;
+            odb = odb->next) {
                int pos;
 
-               if (!alt->loose_objects_subdir_seen[subdir_nr]) {
-                       struct strbuf *buf = alt_scratch_buf(alt);
-                       for_each_file_in_obj_subdir(subdir_nr, buf,
-                                                   append_loose_object,
-                                                   NULL, NULL,
-                                                   &alt->loose_objects_cache);
-                       alt->loose_objects_subdir_seen[subdir_nr] = 1;
-               }
-
-               pos = oid_array_lookup(&alt->loose_objects_cache, &ds->bin_pfx);
+               odb_load_loose_cache(odb, subdir_nr);
+               pos = oid_array_lookup(&odb->loose_objects_cache, &ds->bin_pfx);
                if (pos < 0)
                        pos = -1 - pos;
-               while (!ds->ambiguous && pos < alt->loose_objects_cache.nr) {
+               while (!ds->ambiguous && pos < odb->loose_objects_cache.nr) {
                        const struct object_id *oid;
-                       oid = alt->loose_objects_cache.oid + pos;
+                       oid = odb->loose_objects_cache.oid + pos;
                        if (!match_sha(ds->len, ds->bin_pfx.hash, oid->hash))
                                break;
                        update_candidates(ds, oid);
index 5a74b609ffad51752ec91cc93c602f00292288d1..040e92c1344ef96cc7a6f13fcda9734ad7c4edb5 100644 (file)
@@ -1433,7 +1433,7 @@ struct alternate_refs_data {
        void *data;
 };
 
-static int refs_from_alternate_cb(struct alternate_object_database *e,
+static int refs_from_alternate_cb(struct object_directory *e,
                                  void *data)
 {
        struct strbuf path = STRBUF_INIT;