Merge branch 'rs/sha1-file-close-mapped-file-on-error'
authorJunio C Hamano <gitster@pobox.com>
Fri, 18 Jan 2019 21:49:56 +0000 (13:49 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 18 Jan 2019 21:49:56 +0000 (13:49 -0800)
Code clean-up.

* rs/sha1-file-close-mapped-file-on-error:
sha1-file: close fd of empty file in map_sha1_file_1()

1  2 
sha1-file.c
diff --combined sha1-file.c
index efcb2cbe747683297d2551da85e95b864120f692,fb098c7a17a5b020a9f9b6220e8226a0537c28bc..386b96e1d76622e4650c1bbab90092fef7dd7303
@@@ -346,21 -346,25 +346,21 @@@ static void fill_sha1_path(struct strbu
        }
  }
  
 -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)
 +const char *loose_object_path(struct repository *r, struct strbuf *buf,
 +                            const unsigned char *sha1)
  {
 -      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)
 -{
 -      struct strbuf *buf = alt_scratch_buf(alt);
 -      fill_sha1_path(buf, sha1);
 -      return buf->buf;
 +      return odb_loose_path(r->objects->odb, buf, sha1);
  }
  
  /*
@@@ -370,7 -374,7 +370,7 @@@ static int alt_odb_usable(struct raw_ob
                          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)) {
         * 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))
   * 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
@@@ -415,7 -419,7 +415,7 @@@ static void read_info_alternates(struc
  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) {
                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 */
@@@ -502,7 -505,7 +502,7 @@@ static void link_alt_odb_entries(struc
                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);
@@@ -537,6 -540,18 +537,6 @@@ static void read_info_alternates(struc
        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;
                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);
        }
@@@ -669,11 -684,11 +669,11 @@@ out
  
  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;
  
  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. */
@@@ -716,27 -731,23 +716,27 @@@ int check_and_freshen_file(const char *
        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;
@@@ -877,17 -888,25 +877,17 @@@ int git_open_cloexec(const char *name, 
   *
   * 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;
        }
@@@ -903,17 -922,25 +903,17 @@@ static int open_sha1_file(struct reposi
                          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;
        }
        return -1;
  }
  
 +static int quick_has_loose(struct repository *r,
 +                         const unsigned char *sha1)
 +{
 +      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) {
 +              if (oid_array_lookup(odb_loose_cache(odb, &oid), &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".
@@@ -960,6 -971,7 +960,7 @@@ static void *map_sha1_file_1(struct rep
                        if (!*size) {
                                /* mmap() is forbidden on empty files */
                                error(_("object file %s is empty"), path);
+                               close(fd);
                                return NULL;
                        }
                        map = xmmap(NULL, *size, PROT_READ, MAP_PRIVATE, fd, 0);
@@@ -1187,8 -1199,6 +1188,8 @@@ static int sha1_loose_object_info(struc
        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)
@@@ -1617,7 -1627,8 +1618,7 @@@ static int write_loose_object(const str
        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) {
@@@ -2124,63 -2135,43 +2125,63 @@@ int for_each_loose_file_in_objdir(cons
        return r;
  }
  
 -struct loose_alt_odb_data {
 -      each_loose_object_fn *cb;
 -      void *data;
 -};
 +int for_each_loose_object(each_loose_object_fn cb, void *data,
 +                        enum for_each_object_flags flags)
 +{
 +      struct object_directory *odb;
 +
 +      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;
 +}
  
 -static int loose_from_alt_odb(struct alternate_object_database *alt,
 -                            void *vdata)
 +static int append_loose_object(const struct object_id *oid, const char *path,
 +                             void *data)
  {
 -      struct loose_alt_odb_data *data = vdata;
 +      oid_array_append(data, oid);
 +      return 0;
 +}
 +
 +struct oid_array *odb_loose_cache(struct object_directory *odb,
 +                                const struct object_id *oid)
 +{
 +      int subdir_nr = oid->hash[0];
        struct strbuf buf = STRBUF_INIT;
 -      int r;
  
 -      strbuf_addstr(&buf, alt->path);
 -      r = for_each_loose_file_in_objdir_buf(&buf,
 -                                            data->cb, NULL, NULL,
 -                                            data->data);
 +      if (subdir_nr < 0 ||
 +          subdir_nr >= ARRAY_SIZE(odb->loose_objects_subdir_seen))
 +              BUG("subdir_nr out of range");
 +
 +      if (odb->loose_objects_subdir_seen[subdir_nr])
 +              return &odb->loose_objects_cache[subdir_nr];
 +
 +      strbuf_addstr(&buf, odb->path);
 +      for_each_file_in_obj_subdir(subdir_nr, &buf,
 +                                  append_loose_object,
 +                                  NULL, NULL,
 +                                  &odb->loose_objects_cache[subdir_nr]);
 +      odb->loose_objects_subdir_seen[subdir_nr] = 1;
        strbuf_release(&buf);
 -      return r;
 +      return &odb->loose_objects_cache[subdir_nr];
  }
  
 -int for_each_loose_object(each_loose_object_fn cb, void *data,
 -                        enum for_each_object_flags flags)
 +void odb_clear_loose_cache(struct object_directory *odb)
  {
 -      struct loose_alt_odb_data alt;
 -      int r;
 -
 -      r = for_each_loose_file_in_objdir(get_object_directory(),
 -                                        cb, NULL, NULL, data);
 -      if (r)
 -              return r;
 -
 -      if (flags & FOR_EACH_OBJECT_LOCAL_ONLY)
 -              return 0;
 +      int i;
  
 -      alt.cb = cb;
 -      alt.data = data;
 -      return foreach_alt_odb(loose_from_alt_odb, &alt);
 +      for (i = 0; i < ARRAY_SIZE(odb->loose_objects_cache); i++)
 +              oid_array_clear(&odb->loose_objects_cache[i]);
 +      memset(&odb->loose_objects_subdir_seen, 0,
 +             sizeof(odb->loose_objects_subdir_seen));
  }
  
  static int check_stream_sha1(git_zstream *stream,