unpack_trees(): protect the handcrafted in-core index from read_cache()
authorJunio C Hamano <gitster@pobox.com>
Sat, 23 Aug 2008 19:57:30 +0000 (12:57 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 24 Aug 2008 01:09:27 +0000 (18:09 -0700)
unpack_trees() rebuilds the in-core index from scratch by allocating a new
structure and finishing it off by copying the built one to the final
index.

The resulting in-core index is Ok for most use, but read_cache() does not
recognize it as such. The function is meant to be no-op if you already
have loaded the index, until you call discard_cache().

This change the way read_cache() detects an already initialized in-core
index, by introducing an extra bit, and marks the handcrafted in-core
index as initialized, to avoid this problem.

A better fix in the longer term would be to change the read_cache() API so
that it will always discard and re-read from the on-disk index to avoid
confusion. But there are higher level API that have relied on the current
semantics, and they and their users all need to get converted, which is
outside the scope of 'maint' track.

An example of such a higher level API is write_cache_as_tree(), which is
used by git-write-tree as well as later Porcelains like git-merge, revert
and cherry-pick. In the longer term, we should remove read_cache() from
there and add one to cmd_write_tree(); other callers expect that the
in-core index they prepared is what gets written as a tree so no other
change is necessary for this particular codepath.

The original version of this patch marked the index by pointing an
otherwise wasted malloc'ed memory with o->result.alloc, but this version
uses Linus's idea to use a new "initialized" bit, which is conceptually
much cleaner.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
cache.h
read-cache.c
unpack-trees.c
diff --git a/cache.h b/cache.h
index 2475de9fa837596303284157e08b3080d64351ee..884fae826cb8c296520aecbc8c23d9848dacb606 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -222,7 +222,8 @@ struct index_state {
        struct cache_tree *cache_tree;
        time_t timestamp;
        void *alloc;
-       unsigned name_hash_initialized : 1;
+       unsigned name_hash_initialized : 1,
+                initialized : 1;
        struct hash_table name_hash;
 };
 
index 2c03ec3069decb20f7557af4ac7dbe295f2dcf9c..35fec468b1951cc17606fca8edc47f809471f652 100644 (file)
@@ -1155,7 +1155,7 @@ int read_index_from(struct index_state *istate, const char *path)
        size_t mmap_size;
 
        errno = EBUSY;
-       if (istate->alloc)
+       if (istate->initialized)
                return istate->cache_nr;
 
        errno = ENOENT;
@@ -1195,6 +1195,7 @@ int read_index_from(struct index_state *istate, const char *path)
         * index size
         */
        istate->alloc = xmalloc(estimate_cache_size(mmap_size, istate->cache_nr));
+       istate->initialized = 1;
 
        src_offset = sizeof(*hdr);
        dst_offset = 0;
@@ -1247,6 +1248,7 @@ int discard_index(struct index_state *istate)
        cache_tree_free(&(istate->cache_tree));
        free(istate->alloc);
        istate->alloc = NULL;
+       istate->initialized = 0;
 
        /* no need to throw away allocated active_cache */
        return 0;
index cba0aca062f201c5cd5f8799f2190d4a6f06e7c7..ef21c62195d61980d4727e3f6d9c285422fcfe91 100644 (file)
@@ -376,6 +376,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
        state.refresh_cache = 1;
 
        memset(&o->result, 0, sizeof(o->result));
+       o->result.initialized = 1;
        if (o->src_index)
                o->result.timestamp = o->src_index->timestamp;
        o->merge_size = len;