Am 12.11.2018 um 15:54 schrieb Jeff King:
> diff --git a/sha1-file.c b/sha1-file.c
> index 4aae716a37..e53da0b701 100644
> --- a/sha1-file.c
> +++ b/sha1-file.c
> @@ -921,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);

Is this thread-safe?  What happens if e.g. one index-pack thread resizes
the array while another one sorts it?

Loading the cache explicitly up-front would avoid that, and improves
performance a bit in my (very limited) tests on an SSD.  Demo patch for
next at the bottom.  How does it do against your test cases?

> +             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".
> @@ -1171,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)
> 

 builtin/fetch.c      |  2 ++
 builtin/index-pack.c |  2 ++
 fetch-pack.c         |  2 ++
 object-store.h       |  1 +
 sha1-file.c          | 30 +++++++++++++++++++++++++++---
 5 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index e0140327aa..4b031f5da5 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -301,6 +301,8 @@ static void find_non_local_tags(const struct ref *refs,
        refname_hash_init(&existing_refs);
        refname_hash_init(&remote_refs);
 
+       repo_load_loose_cache(the_repository);
+
        for_each_ref(add_one_refname, &existing_refs);
        for (ref = refs; ref; ref = ref->next) {
                if (!starts_with(ref->name, "refs/tags/"))
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index ac1f4ea9a7..7fc6321c77 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1772,6 +1772,8 @@ int cmd_index_pack(int argc, const char **argv, const 
char *prefix)
        if (show_stat)
                obj_stat = xcalloc(st_add(nr_objects, 1), sizeof(struct 
object_stat));
        ofs_deltas = xcalloc(nr_objects, sizeof(struct ofs_delta_entry));
+       if (startup_info->have_repository)
+               repo_load_loose_cache(the_repository);
        parse_pack_objects(pack_hash);
        if (report_end_of_input)
                write_in_full(2, "\0", 1);
diff --git a/fetch-pack.c b/fetch-pack.c
index dd6700bda9..96c4624d9e 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -656,6 +656,8 @@ static void mark_complete_and_common_ref(struct 
fetch_negotiator *negotiator,
 
        save_commit_buffer = 0;
 
+       repo_load_loose_cache(the_repository);
+
        for (ref = *refs; ref; ref = ref->next) {
                struct object *o;
 
diff --git a/object-store.h b/object-store.h
index 8dceed0f31..f98dd3c857 100644
--- a/object-store.h
+++ b/object-store.h
@@ -53,6 +53,7 @@ void add_to_alternates_memory(const char *dir);
  * from 0 to 255 inclusive).
  */
 void odb_load_loose_cache(struct object_directory *odb, int subdir_nr);
+void repo_load_loose_cache(struct repository *r);
 
 struct packed_git {
        struct packed_git *next;
diff --git a/sha1-file.c b/sha1-file.c
index 05f63dfd4e..ae12f0a198 100644
--- a/sha1-file.c
+++ b/sha1-file.c
@@ -921,10 +921,19 @@ static int open_sha1_file(struct repository *r,
        return -1;
 }
 
+static int quick_has_loose_odb(struct object_directory *odb,
+                              const struct object_id *oid)
+{
+       int subdir_nr = oid->hash[0];
+
+       if (odb->loose_objects_subdir_seen[subdir_nr])
+               return oid_array_lookup(&odb->loose_objects_cache, oid) >= 0;
+       return check_and_freshen_odb(odb, oid, 0);
+}
+
 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;
 
@@ -932,8 +941,7 @@ static int quick_has_loose(struct repository *r,
 
        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)
+               if (quick_has_loose_odb(odb, &oid))
                        return 1;
        }
        return 0;
@@ -2178,6 +2186,22 @@ void odb_load_loose_cache(struct object_directory *odb, 
int subdir_nr)
        strbuf_release(&buf);
 }
 
+void repo_load_loose_cache(struct repository *r)
+{
+       struct object_directory *odb;
+
+       prepare_alt_odb(r);
+       for (odb = r->objects->odb; odb; odb = odb->next) {
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(odb->loose_objects_subdir_seen); i++)
+                       odb_load_loose_cache(odb, i);
+
+               /* Sort as a side-effect, only read the cache from here on. */
+               oid_array_lookup(&odb->loose_objects_cache, &null_oid);
+       }
+}
+
 static int check_stream_sha1(git_zstream *stream,
                             const char *hdr,
                             unsigned long size,

Reply via email to