]> git.ipfire.org Git - thirdparty/git.git/commitdiff
block alloc: add lifecycle APIs for cache_entry structs
authorJameson Miller <jamill@microsoft.com>
Mon, 2 Jul 2018 19:49:31 +0000 (19:49 +0000)
committerJunio C Hamano <gitster@pobox.com>
Tue, 3 Jul 2018 17:58:27 +0000 (10:58 -0700)
It has been observed that the time spent loading an index with a large
number of entries is partly dominated by malloc() calls. This change
is in preparation for using memory pools to reduce the number of
malloc() calls made to allocate cahce entries when loading an index.

Add an API to allocate and discard cache entries, abstracting the
details of managing the memory backing the cache entries. This commit
does actually change how memory is managed - this will be done in a
later commit in the series.

This change makes the distinction between cache entries that are
associated with an index and cache entries that are not associated with
an index. A main use of cache entries is with an index, and we can
optimize the memory management around this. We still have other cases
where a cache entry is not persisted with an index, and so we need to
handle the "transient" use case as well.

To keep the congnitive overhead of managing the cache entries, there
will only be a single discard function. This means there must be enough
information kept with the cache entry so that we know how to discard
them.

A summary of the main functions in the API is:

make_cache_entry: create cache entry for use in an index. Uses specified
                  parameters to populate cache_entry fields.

make_empty_cache_entry: Create an empty cache entry for use in an index.
                        Returns cache entry with empty fields.

make_transient_cache_entry: create cache entry that is not used in an
                            index. Uses specified parameters to populate
                            cache_entry fields.

make_empty_transient_cache_entry: create cache entry that is not used in
                                  an index. Returns cache entry with
                                  empty fields.

discard_cache_entry: A single function that knows how to discard a cache
                     entry regardless of how it was allocated.

Signed-off-by: Jameson Miller <jamill@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
13 files changed:
apply.c
blame.c
builtin/checkout.c
builtin/difftool.c
builtin/reset.c
builtin/update-index.c
cache.h
merge-recursive.c
read-cache.c
resolve-undo.c
split-index.c
tree.c
unpack-trees.c

diff --git a/apply.c b/apply.c
index 5dd634ceaf49fdbc042a09e04d47013c56c3f814..ee6c406c7a9fc5c402736bd504879f35ec1925dc 100644 (file)
--- a/apply.c
+++ b/apply.c
@@ -4090,12 +4090,12 @@ static int build_fake_ancestor(struct apply_state *state, struct patch *list)
                        return error(_("sha1 information is lacking or useless "
                                       "(%s)."), name);
 
-               ce = make_cache_entry(patch->old_mode, &oid, name, 0, 0);
+               ce = make_cache_entry(&result, patch->old_mode, &oid, name, 0, 0);
                if (!ce)
                        return error(_("make_cache_entry failed for path '%s'"),
                                     name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("could not add %s to temporary index"),
                                     name);
                }
@@ -4263,12 +4263,11 @@ static int add_index_file(struct apply_state *state,
        struct stat st;
        struct cache_entry *ce;
        int namelen = strlen(path);
-       unsigned ce_size = cache_entry_size(namelen);
 
        if (!state->update_index)
                return 0;
 
-       ce = xcalloc(1, ce_size);
+       ce = make_empty_cache_entry(&the_index, namelen);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = create_ce_flags(0);
@@ -4278,13 +4277,13 @@ static int add_index_file(struct apply_state *state,
 
                if (!skip_prefix(buf, "Subproject commit ", &s) ||
                    get_oid_hex(s, &ce->oid)) {
-                       free(ce);
-                      return error(_("corrupt patch for submodule %s"), path);
+                       discard_cache_entry(ce);
+                       return error(_("corrupt patch for submodule %s"), path);
                }
        } else {
                if (!state->cached) {
                        if (lstat(path, &st) < 0) {
-                               free(ce);
+                               discard_cache_entry(ce);
                                return error_errno(_("unable to stat newly "
                                                     "created file '%s'"),
                                                   path);
@@ -4292,13 +4291,13 @@ static int add_index_file(struct apply_state *state,
                        fill_stat_cache_info(ce, &st);
                }
                if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
                }
        }
        if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
-               free(ce);
+               discard_cache_entry(ce);
                return error(_("unable to add cache entry for %s"), path);
        }
 
@@ -4422,27 +4421,26 @@ static int add_conflicted_stages_file(struct apply_state *state,
                                       struct patch *patch)
 {
        int stage, namelen;
-       unsigned ce_size, mode;
+       unsigned mode;
        struct cache_entry *ce;
 
        if (!state->update_index)
                return 0;
        namelen = strlen(patch->new_name);
-       ce_size = cache_entry_size(namelen);
        mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
 
        remove_file_from_cache(patch->new_name);
        for (stage = 1; stage < 4; stage++) {
                if (is_null_oid(&patch->threeway_stage[stage - 1]))
                        continue;
-               ce = xcalloc(1, ce_size);
+               ce = make_empty_cache_entry(&the_index, namelen);
                memcpy(ce->name, patch->new_name, namelen);
                ce->ce_mode = create_ce_mode(mode);
                ce->ce_flags = create_ce_flags(stage);
                ce->ce_namelen = namelen;
                oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
                if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("unable to add cache entry for %s"),
                                     patch->new_name);
                }
diff --git a/blame.c b/blame.c
index 14d0e0b5751c2abaad16dac81a71436ca29ddde4..4c6668d0e16ad8f52df763f5e5f2fd849deb5b2c 100644 (file)
--- a/blame.c
+++ b/blame.c
@@ -154,7 +154,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
        struct strbuf buf = STRBUF_INIT;
        const char *ident;
        time_t now;
-       int size, len;
+       int len;
        struct cache_entry *ce;
        unsigned mode;
        struct strbuf msg = STRBUF_INIT;
@@ -252,8 +252,7 @@ static struct commit *fake_working_tree_commit(struct diff_options *opt,
                        /* Let's not bother reading from HEAD tree */
                        mode = S_IFREG | 0644;
        }
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, len);
        oidcpy(&ce->oid, &origin->blob_oid);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
index 548bf40f2549a85afc8bd0bfa55a8286017b5802..56d1e1a28d6ab1f8495e1b9c1898aecb027be332 100644 (file)
@@ -77,7 +77,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
                return READ_TREE_RECURSIVE;
 
        len = base->len + strlen(pathname);
-       ce = xcalloc(1, cache_entry_size(len));
+       ce = make_empty_cache_entry(&the_index, len);
        oidcpy(&ce->oid, oid);
        memcpy(ce->name, base->buf, base->len);
        memcpy(ce->name + base->len, pathname, len - base->len);
@@ -96,7 +96,7 @@ static int update_some(const struct object_id *oid, struct strbuf *base,
                if (ce->ce_mode == old->ce_mode &&
                    !oidcmp(&ce->oid, &old->oid)) {
                        old->ce_flags |= CE_UPDATE;
-                       free(ce);
+                       discard_cache_entry(ce);
                        return 0;
                }
        }
@@ -230,11 +230,11 @@ static int checkout_merged(int pos, const struct checkout *state)
        if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
                die(_("Unable to add merge result for '%s'"), path);
        free(result_buf.ptr);
-       ce = make_cache_entry(mode, &oid, path, 2, 0);
+       ce = make_transient_cache_entry(mode, &oid, path, 2);
        if (!ce)
                die(_("make_cache_entry failed for path '%s'"), path);
        status = checkout_entry(ce, state, NULL);
-       free(ce);
+       discard_cache_entry(ce);
        return status;
 }
 
index 873a06f0d90f35456d31a28f68ab10c71354e5c9..4593f0c2cd6d4546a66298996ce8001d228d01f4 100644 (file)
@@ -321,10 +321,10 @@ static int checkout_path(unsigned mode, struct object_id *oid,
        struct cache_entry *ce;
        int ret;
 
-       ce = make_cache_entry(mode, oid, path, 0, 0);
+       ce = make_transient_cache_entry(mode, oid, path, 0);
        ret = checkout_entry(ce, state, NULL);
 
-       free(ce);
+       discard_cache_entry(ce);
        return ret;
 }
 
@@ -488,7 +488,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
                                 * index.
                                 */
                                struct cache_entry *ce2 =
-                                       make_cache_entry(rmode, &roid,
+                                       make_cache_entry(&wtindex, rmode, &roid,
                                                         dst_path, 0, 0);
 
                                add_index_entry(&wtindex, ce2,
index 00109b041f9130dbd8d0e908032bfb60c3e1552b..c3f0cfa1e81d02bbfd3e84c7f62ef018c835403b 100644 (file)
@@ -134,7 +134,7 @@ static void update_index_from_diff(struct diff_queue_struct *q,
                        continue;
                }
 
-               ce = make_cache_entry(one->mode, &one->oid, one->path,
+               ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
                                      0, 0);
                if (!ce)
                        die(_("make_cache_entry failed for path '%s'"),
index a8709a26ec4b8bb79cbb20bfa4a7892e063c804d..ea2f2a476c13c57a206b8ad819dbb08371c9be80 100644 (file)
@@ -268,15 +268,14 @@ static int process_lstat_error(const char *path, int err)
 
 static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
 {
-       int option, size;
+       int option;
        struct cache_entry *ce;
 
        /* Was the old index entry already up-to-date? */
        if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
                return 0;
 
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, len);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = len;
@@ -285,13 +284,13 @@ static int add_one_path(const struct cache_entry *old, const char *path, int len
 
        if (index_path(&ce->oid, path, st,
                       info_only ? 0 : HASH_WRITE_OBJECT)) {
-               free(ce);
+               discard_cache_entry(ce);
                return -1;
        }
        option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
        option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
        if (add_cache_entry(ce, option)) {
-               free(ce);
+               discard_cache_entry(ce);
                return error("%s: cannot add to the index - missing --add option?", path);
        }
        return 0;
@@ -402,15 +401,14 @@ static int process_path(const char *path, struct stat *st, int stat_errno)
 static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
                         const char *path, int stage)
 {
-       int size, len, option;
+       int len, option;
        struct cache_entry *ce;
 
        if (!verify_path(path, mode))
                return error("Invalid path '%s'", path);
 
        len = strlen(path);
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, len);
 
        oidcpy(&ce->oid, oid);
        memcpy(ce->name, path, len);
@@ -599,7 +597,6 @@ static struct cache_entry *read_one_ent(const char *which,
 {
        unsigned mode;
        struct object_id oid;
-       int size;
        struct cache_entry *ce;
 
        if (get_tree_entry(ent, path, &oid, &mode)) {
@@ -612,8 +609,7 @@ static struct cache_entry *read_one_ent(const char *which,
                        error("%s: not a blob in %s branch.", path, which);
                return NULL;
        }
-       size = cache_entry_size(namelen);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, namelen);
 
        oidcpy(&ce->oid, &oid);
        memcpy(ce->name, path, namelen);
@@ -690,8 +686,8 @@ static int unresolve_one(const char *path)
        error("%s: cannot add their version to the index.", path);
        ret = -1;
  free_return:
-       free(ce_2);
-       free(ce_3);
+       discard_cache_entry(ce_2);
+       discard_cache_entry(ce_3);
        return ret;
 }
 
@@ -758,7 +754,7 @@ static int do_reupdate(int ac, const char **av,
                                           ce->name, ce_namelen(ce), 0);
                if (old && ce->ce_mode == old->ce_mode &&
                    !oidcmp(&ce->oid, &old->oid)) {
-                       free(old);
+                       discard_cache_entry(old);
                        continue; /* unchanged */
                }
                /* Be careful.  The working tree may not have the
@@ -769,7 +765,7 @@ static int do_reupdate(int ac, const char **av,
                path = xstrdup(ce->name);
                update_one(path);
                free(path);
-               free(old);
+               discard_cache_entry(old);
                if (save_nr != active_nr)
                        goto redo;
        }
diff --git a/cache.h b/cache.h
index 7953d52caa04c1068101408802947d843e438694..5aadaebaebc878136bb7a81ad29b3da699c4ad59 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -339,6 +339,40 @@ extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce)
 extern void free_name_hash(struct index_state *istate);
 
 
+/* Cache entry creation and cleanup */
+
+/*
+ * Create cache_entry intended for use in the specified index. Caller
+ * is responsible for discarding the cache_entry with
+ * `discard_cache_entry`.
+ */
+struct cache_entry *make_cache_entry(struct index_state *istate,
+                                    unsigned int mode,
+                                    const struct object_id *oid,
+                                    const char *path,
+                                    int stage,
+                                    unsigned int refresh_options);
+
+struct cache_entry *make_empty_cache_entry(struct index_state *istate,
+                                          size_t name_len);
+
+/*
+ * Create a cache_entry that is not intended to be added to an index.
+ * Caller is responsible for discarding the cache_entry
+ * with `discard_cache_entry`.
+ */
+struct cache_entry *make_transient_cache_entry(unsigned int mode,
+                                              const struct object_id *oid,
+                                              const char *path,
+                                              int stage);
+
+struct cache_entry *make_empty_transient_cache_entry(size_t name_len);
+
+/*
+ * Discard cache entry.
+ */
+void discard_cache_entry(struct cache_entry *ce);
+
 #ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
 #define active_cache (the_index.cache)
 #define active_nr (the_index.cache_nr)
@@ -698,12 +732,6 @@ extern int remove_file_from_index(struct index_state *, const char *path);
 extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
 extern int add_file_to_index(struct index_state *, const char *path, int flags);
 
-extern struct cache_entry *make_cache_entry(unsigned int mode,
-                                           const struct object_id *oid,
-                                           const char *path,
-                                           int stage,
-                                           unsigned int refresh_options);
-
 extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
 extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
 extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
index 8b30cc7e35e5f5cccd5e12477da0dc904bd3ad98..a580cff886d5d0a30dbffeae167cfd999ce6dfee 100644 (file)
@@ -315,7 +315,7 @@ static int add_cacheinfo(struct merge_options *o,
        struct cache_entry *ce;
        int ret;
 
-       ce = make_cache_entry(mode, oid ? oid : &null_oid, path, stage, 0);
+       ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0);
        if (!ce)
                return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
 
index c12664c78966d0ce5d5403ce79c095e5aa42d408..41e4d0e67a196f660944c561e6bfd0c0278ab637 100644 (file)
@@ -61,7 +61,7 @@ static void replace_index_entry(struct index_state *istate, int nr, struct cache
 
        replace_index_entry_in_base(istate, old, ce);
        remove_name_hash(istate, old);
-       free(old);
+       discard_cache_entry(old);
        ce->ce_flags &= ~CE_HASHED;
        set_index_entry(istate, nr, ce);
        ce->ce_flags |= CE_UPDATE_IN_BASE;
@@ -74,7 +74,7 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
        struct cache_entry *old_entry = istate->cache[nr], *new_entry;
        int namelen = strlen(new_name);
 
-       new_entry = xmalloc(cache_entry_size(namelen));
+       new_entry = make_empty_cache_entry(istate, namelen);
        copy_cache_entry(new_entry, old_entry);
        new_entry->ce_flags &= ~CE_HASHED;
        new_entry->ce_namelen = namelen;
@@ -623,7 +623,7 @@ static struct cache_entry *create_alias_ce(struct index_state *istate,
 
        /* Ok, create the new entry using the name of the existing alias */
        len = ce_namelen(alias);
-       new_entry = xcalloc(1, cache_entry_size(len));
+       new_entry = make_empty_cache_entry(istate, len);
        memcpy(new_entry->name, alias->name, len);
        copy_cache_entry(new_entry, ce);
        save_or_free_index_entry(istate, ce);
@@ -640,7 +640,7 @@ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
 
 int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
 {
-       int size, namelen, was_same;
+       int namelen, was_same;
        mode_t st_mode = st->st_mode;
        struct cache_entry *ce, *alias = NULL;
        unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;
@@ -662,8 +662,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
                while (namelen && path[namelen-1] == '/')
                        namelen--;
        }
-       size = cache_entry_size(namelen);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(istate, namelen);
        memcpy(ce->name, path, namelen);
        ce->ce_namelen = namelen;
        if (!intent_only)
@@ -704,13 +703,13 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
                                ce_mark_uptodate(alias);
                        alias->ce_flags |= CE_ADDED;
 
-                       free(ce);
+                       discard_cache_entry(ce);
                        return 0;
                }
        }
        if (!intent_only) {
                if (index_path(&ce->oid, path, st, newflags)) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error("unable to index file %s", path);
                }
        } else
@@ -727,9 +726,9 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
                    ce->ce_mode == alias->ce_mode);
 
        if (pretend)
-               free(ce);
+               discard_cache_entry(ce);
        else if (add_index_entry(istate, ce, add_option)) {
-               free(ce);
+               discard_cache_entry(ce);
                return error("unable to add %s to index", path);
        }
        if (verbose && !was_same)
@@ -745,14 +744,25 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)
        return add_to_index(istate, path, &st, flags);
 }
 
-struct cache_entry *make_cache_entry(unsigned int mode,
+struct cache_entry *make_empty_cache_entry(struct index_state *istate, size_t len)
+{
+       return xcalloc(1, cache_entry_size(len));
+}
+
+struct cache_entry *make_empty_transient_cache_entry(size_t len)
+{
+       return xcalloc(1, cache_entry_size(len));
+}
+
+struct cache_entry *make_cache_entry(struct index_state *istate,
+                                    unsigned int mode,
                                     const struct object_id *oid,
                                     const char *path,
                                     int stage,
                                     unsigned int refresh_options)
 {
-       int size, len;
        struct cache_entry *ce, *ret;
+       int len;
 
        if (!verify_path(path, mode)) {
                error("Invalid path '%s'", path);
@@ -760,8 +770,7 @@ struct cache_entry *make_cache_entry(unsigned int mode,
        }
 
        len = strlen(path);
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(istate, len);
 
        oidcpy(&ce->oid, oid);
        memcpy(ce->name, path, len);
@@ -771,10 +780,33 @@ struct cache_entry *make_cache_entry(unsigned int mode,
 
        ret = refresh_cache_entry(&the_index, ce, refresh_options);
        if (ret != ce)
-               free(ce);
+               discard_cache_entry(ce);
        return ret;
 }
 
+struct cache_entry *make_transient_cache_entry(unsigned int mode, const struct object_id *oid,
+                                              const char *path, int stage)
+{
+       struct cache_entry *ce;
+       int len;
+
+       if (!verify_path(path, mode)) {
+               error("Invalid path '%s'", path);
+               return NULL;
+       }
+
+       len = strlen(path);
+       ce = make_empty_transient_cache_entry(len);
+
+       oidcpy(&ce->oid, oid);
+       memcpy(ce->name, path, len);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = len;
+       ce->ce_mode = create_ce_mode(mode);
+
+       return ce;
+}
+
 /*
  * Chmod an index entry with either +x or -x.
  *
@@ -1270,7 +1302,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
 {
        struct stat st;
        struct cache_entry *updated;
-       int changed, size;
+       int changed;
        int refresh = options & CE_MATCH_REFRESH;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
        int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
@@ -1350,8 +1382,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                return NULL;
        }
 
-       size = ce_size(ce);
-       updated = xmalloc(size);
+       updated = make_empty_cache_entry(istate, ce_namelen(ce));
        copy_cache_entry(updated, ce);
        memcpy(updated->name, ce->name, ce->ce_namelen + 1);
        fill_stat_cache_info(updated, &st);
@@ -1637,12 +1668,13 @@ int read_index(struct index_state *istate)
        return read_index_from(istate, get_index_file(), get_git_dir());
 }
 
-static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
+static struct cache_entry *cache_entry_from_ondisk(struct index_state *istate,
+                                                  struct ondisk_cache_entry *ondisk,
                                                   unsigned int flags,
                                                   const char *name,
                                                   size_t len)
 {
-       struct cache_entry *ce = xmalloc(cache_entry_size(len));
+       struct cache_entry *ce = make_empty_cache_entry(istate, len);
 
        ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
        ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
@@ -1684,7 +1716,8 @@ static unsigned long expand_name_field(struct strbuf *name, const char *cp_)
        return (const char *)ep + 1 - cp_;
 }
 
-static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
+static struct cache_entry *create_from_disk(struct index_state *istate,
+                                           struct ondisk_cache_entry *ondisk,
                                            unsigned long *ent_size,
                                            struct strbuf *previous_name)
 {
@@ -1715,13 +1748,13 @@ static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
                /* v3 and earlier */
                if (len == CE_NAMEMASK)
                        len = strlen(name);
-               ce = cache_entry_from_ondisk(ondisk, flags, name, len);
+               ce = cache_entry_from_ondisk(istate, ondisk, flags, name, len);
 
                *ent_size = ondisk_ce_size(ce);
        } else {
                unsigned long consumed;
                consumed = expand_name_field(previous_name, name);
-               ce = cache_entry_from_ondisk(ondisk, flags,
+               ce = cache_entry_from_ondisk(istate, ondisk, flags,
                                             previous_name->buf,
                                             previous_name->len);
 
@@ -1853,7 +1886,7 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
                unsigned long consumed;
 
                disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
-               ce = create_from_disk(disk_ce, &consumed, previous_name);
+               ce = create_from_disk(istate, disk_ce, &consumed, previous_name);
                set_index_entry(istate, i, ce);
 
                src_offset += consumed;
@@ -1959,7 +1992,7 @@ int discard_index(struct index_state *istate)
                    istate->cache[i]->index <= istate->split_index->base->cache_nr &&
                    istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1])
                        continue;
-               free(istate->cache[i]);
+               discard_cache_entry(istate->cache[i]);
        }
        resolve_undo_clear_index(istate);
        istate->cache_nr = 0;
@@ -2649,14 +2682,13 @@ int read_index_unmerged(struct index_state *istate)
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
                struct cache_entry *new_ce;
-               int size, len;
+               int len;
 
                if (!ce_stage(ce))
                        continue;
                unmerged = 1;
                len = ce_namelen(ce);
-               size = cache_entry_size(len);
-               new_ce = xcalloc(1, size);
+               new_ce = make_empty_cache_entry(istate, len);
                memcpy(new_ce->name, ce->name, len);
                new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED;
                new_ce->ce_namelen = len;
@@ -2765,3 +2797,8 @@ void move_index_extensions(struct index_state *dst, struct index_state *src)
        dst->untracked = src->untracked;
        src->untracked = NULL;
 }
+
+void discard_cache_entry(struct cache_entry *ce)
+{
+       free(ce);
+}
index 4d4e5cb6bf9c48aa66ec70eee780d2455563d099..c30ae5cf49aab6a3a88060740ffc679ad940c2aa 100644 (file)
@@ -146,7 +146,9 @@ int unmerge_index_entry_at(struct index_state *istate, int pos)
                struct cache_entry *nce;
                if (!ru->mode[i])
                        continue;
-               nce = make_cache_entry(ru->mode[i], &ru->oid[i],
+               nce = make_cache_entry(istate,
+                                      ru->mode[i],
+                                      &ru->oid[i],
                                       name, i + 1, 0);
                if (matched)
                        nce->ce_flags |= CE_MATCHED;
index 660c75f31fb970af06af3aad48b4ecc57e8cc136..317900db8bb2dc641c5f32246f067c45cf1e91a8 100644 (file)
@@ -123,7 +123,7 @@ static void replace_entry(size_t pos, void *data)
        src->ce_flags |= CE_UPDATE_IN_BASE;
        src->ce_namelen = dst->ce_namelen;
        copy_cache_entry(dst, src);
-       free(src);
+       discard_cache_entry(src);
        si->nr_replacements++;
 }
 
@@ -224,7 +224,7 @@ void prepare_to_write_split_index(struct index_state *istate)
                        base->ce_flags = base_flags;
                        if (ret)
                                ce->ce_flags |= CE_UPDATE_IN_BASE;
-                       free(base);
+                       discard_cache_entry(base);
                        si->base->cache[ce->index - 1] = ce;
                }
                for (i = 0; i < si->base->cache_nr; i++) {
@@ -301,7 +301,7 @@ void save_or_free_index_entry(struct index_state *istate, struct cache_entry *ce
            ce == istate->split_index->base->cache[ce->index - 1])
                ce->ce_flags |= CE_REMOVE;
        else
-               free(ce);
+               discard_cache_entry(ce);
 }
 
 void replace_index_entry_in_base(struct index_state *istate,
@@ -314,7 +314,7 @@ void replace_index_entry_in_base(struct index_state *istate,
            old_entry->index <= istate->split_index->base->cache_nr) {
                new_entry->index = old_entry->index;
                if (old_entry != istate->split_index->base->cache[new_entry->index - 1])
-                       free(istate->split_index->base->cache[new_entry->index - 1]);
+                       discard_cache_entry(istate->split_index->base->cache[new_entry->index - 1]);
                istate->split_index->base->cache[new_entry->index - 1] = new_entry;
        }
 }
diff --git a/tree.c b/tree.c
index 244eb5e665e931a6b735366d74b5ed2bcbce4c9b..5111ce8376c54f4cb323bc527185e209f0a6739d 100644 (file)
--- a/tree.c
+++ b/tree.c
@@ -16,15 +16,13 @@ static int read_one_entry_opt(struct index_state *istate,
                              unsigned mode, int stage, int opt)
 {
        int len;
-       unsigned int size;
        struct cache_entry *ce;
 
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
 
        len = strlen(pathname);
-       size = cache_entry_size(baselen + len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(istate, baselen + len);
 
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = create_ce_flags(stage);
index 3a85a02a7733aeeee86da1a324319d026c32d787..33cba550b09af1bf1b6b4cd5530c0f752defcd24 100644 (file)
@@ -203,10 +203,10 @@ static int do_add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
                               ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
 }
 
-static struct cache_entry *dup_entry(const struct cache_entry *ce)
+static struct cache_entry *dup_entry(const struct cache_entry *ce, struct index_state *istate)
 {
        unsigned int size = ce_size(ce);
-       struct cache_entry *new_entry = xmalloc(size);
+       struct cache_entry *new_entry = make_empty_cache_entry(istate, ce_namelen(ce));
 
        memcpy(new_entry, ce, size);
        return new_entry;
@@ -216,7 +216,7 @@ static void add_entry(struct unpack_trees_options *o,
                      const struct cache_entry *ce,
                      unsigned int set, unsigned int clear)
 {
-       do_add_entry(o, dup_entry(ce), set, clear);
+       do_add_entry(o, dup_entry(ce, &o->result), set, clear);
 }
 
 /*
@@ -797,10 +797,17 @@ static int ce_in_traverse_path(const struct cache_entry *ce,
        return (info->pathlen < ce_namelen(ce));
 }
 
-static struct cache_entry *create_ce_entry(const struct traverse_info *info, const struct name_entry *n, int stage)
+static struct cache_entry *create_ce_entry(const struct traverse_info *info,
+       const struct name_entry *n,
+       int stage,
+       struct index_state *istate,
+       int is_transient)
 {
        int len = traverse_path_len(info, n);
-       struct cache_entry *ce = xcalloc(1, cache_entry_size(len));
+       struct cache_entry *ce =
+               is_transient ?
+               make_empty_transient_cache_entry(len) :
+               make_empty_cache_entry(istate, len);
 
        ce->ce_mode = create_ce_mode(n->mode);
        ce->ce_flags = create_ce_flags(stage);
@@ -846,7 +853,15 @@ static int unpack_nondirectories(int n, unsigned long mask,
                        stage = 3;
                else
                        stage = 2;
-               src[i + o->merge] = create_ce_entry(info, names + i, stage);
+
+               /*
+                * If the merge bit is set, then the cache entries are
+                * discarded in the following block.  In this case,
+                * construct "transient" cache_entries, as they are
+                * not stored in the index.  otherwise construct the
+                * cache entry from the index aware logic.
+                */
+               src[i + o->merge] = create_ce_entry(info, names + i, stage, &o->result, o->merge);
        }
 
        if (o->merge) {
@@ -855,7 +870,7 @@ static int unpack_nondirectories(int n, unsigned long mask,
                for (i = 0; i < n; i++) {
                        struct cache_entry *ce = src[i + o->merge];
                        if (ce != o->df_conflict_entry)
-                               free(ce);
+                               discard_cache_entry(ce);
                }
                return rc;
        }
@@ -1787,7 +1802,7 @@ static int merged_entry(const struct cache_entry *ce,
                        struct unpack_trees_options *o)
 {
        int update = CE_UPDATE;
-       struct cache_entry *merge = dup_entry(ce);
+       struct cache_entry *merge = dup_entry(ce, &o->result);
 
        if (!old) {
                /*
@@ -1807,7 +1822,7 @@ static int merged_entry(const struct cache_entry *ce,
 
                if (verify_absent(merge,
                                  ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
-                       free(merge);
+                       discard_cache_entry(merge);
                        return -1;
                }
                invalidate_ce_path(merge, o);
@@ -1833,7 +1848,7 @@ static int merged_entry(const struct cache_entry *ce,
                        update = 0;
                } else {
                        if (verify_uptodate(old, o)) {
-                               free(merge);
+                               discard_cache_entry(merge);
                                return -1;
                        }
                        /* Migrate old flags over */