Merge branch 'bc/object-id'
[gitweb.git] / split-index.c
index 35da553655bdf7b70519ecf529544796ca8185b5..49bd197f715ae783d7fdbe8e1d638a1bcac0073c 100644 (file)
@@ -73,10 +73,17 @@ void move_cache_to_base_index(struct index_state *istate)
        int i;
 
        /*
-        * do not delete old si->base, its index entries may be shared
-        * with istate->cache[]. Accept a bit of leaking here because
-        * this code is only used by short-lived update-index.
+        * If "si" is shared with another index_state (e.g. by
+        * unpack-trees code), we will need to duplicate split_index
+        * struct. It's not happening now though, luckily.
         */
+       assert(si->refcount <= 1);
+
+       unshare_split_index(istate, 0);
+       if (si->base) {
+               discard_index(si->base);
+               free(si->base);
+       }
        si->base = xcalloc(1, sizeof(*si->base));
        si->base->version = istate->version;
        /* zero timestamp disables racy test in ce_write_index() */
@@ -187,7 +194,7 @@ void prepare_to_write_split_index(struct index_state *istate)
                /* Go through istate->cache[] and mark CE_MATCHED to
                 * entry with positive index. We'll go through
                 * base->cache[] later to delete all entries in base
-                * that are not marked eith either CE_MATCHED or
+                * that are not marked with either CE_MATCHED or
                 * CE_UPDATE_IN_BASE. If istate->cache[i] is a
                 * duplicate, deduplicate it.
                 */
@@ -275,11 +282,41 @@ void finish_writing_split_index(struct index_state *istate)
        istate->cache_nr = si->saved_cache_nr;
 }
 
+void unshare_split_index(struct index_state *istate, int discard)
+{
+       struct split_index *si = istate->split_index;
+       int i;
+
+       if (!si || !si->base)
+               return;
+
+       for (i = 0; i < istate->cache_nr; i++) {
+               struct cache_entry *ce = istate->cache[i];
+               struct cache_entry *new = NULL;
+
+               if (!ce->index ||
+                   ce->index > si->base->cache_nr ||
+                   ce != si->base->cache[ce->index - 1])
+                       continue;
+
+               if (!discard) {
+                       int len = ce_namelen(ce);
+                       new = xcalloc(1, cache_entry_size(len));
+                       copy_cache_entry(new, ce);
+                       memcpy(new->name, ce->name, len);
+                       new->index = 0;
+               }
+               istate->cache[i] = new;
+       }
+}
+
+
 void discard_split_index(struct index_state *istate)
 {
        struct split_index *si = istate->split_index;
        if (!si)
                return;
+       unshare_split_index(istate, 0);
        istate->split_index = NULL;
        si->refcount--;
        if (si->refcount)
@@ -317,3 +354,19 @@ void replace_index_entry_in_base(struct index_state *istate,
                istate->split_index->base->cache[new->index - 1] = new;
        }
 }
+
+void add_split_index(struct index_state *istate)
+{
+       if (!istate->split_index) {
+               init_split_index(istate);
+               istate->cache_changed |= SPLIT_INDEX_ORDERED;
+       }
+}
+
+void remove_split_index(struct index_state *istate)
+{
+       if (!istate->split_index)
+               return;
+       discard_split_index(istate);
+       istate->cache_changed |= SOMETHING_CHANGED;
+}