Merge branch 'dj/runtime-prefix'
[gitweb.git] / commit.c
index 2d4431a21fd16f55d873b6fe2ba1126722d3c4bf..a7c0b5f8c6ce1d1d41c7ede357116fee4a643bbc 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -2,11 +2,14 @@
 #include "tag.h"
 #include "commit.h"
 #include "commit-graph.h"
+#include "repository.h"
+#include "object-store.h"
 #include "pkt-line.h"
 #include "utf8.h"
 #include "diff.h"
 #include "revision.h"
 #include "notes.h"
+#include "alloc.h"
 #include "gpg-interface.h"
 #include "mergesort.h"
 #include "commit-slab.h"
@@ -52,7 +55,8 @@ struct commit *lookup_commit(const struct object_id *oid)
 {
        struct object *obj = lookup_object(oid->hash);
        if (!obj)
-               return create_object(oid->hash, alloc_commit_node());
+               return create_object(the_repository, oid->hash,
+                                    alloc_commit_node(the_repository));
        return object_as_type(obj, OBJ_COMMIT, 0);
 }
 
@@ -96,41 +100,44 @@ static timestamp_t parse_commit_date(const char *buf, const char *tail)
        return parse_timestamp(dateptr, NULL, 10);
 }
 
-static struct commit_graft **commit_graft;
-static int commit_graft_alloc, commit_graft_nr;
-
 static const unsigned char *commit_graft_sha1_access(size_t index, void *table)
 {
        struct commit_graft **commit_graft_table = table;
        return commit_graft_table[index]->oid.hash;
 }
 
-static int commit_graft_pos(const unsigned char *sha1)
+static int commit_graft_pos(struct repository *r, const unsigned char *sha1)
 {
-       return sha1_pos(sha1, commit_graft, commit_graft_nr,
+       return sha1_pos(sha1, r->parsed_objects->grafts,
+                       r->parsed_objects->grafts_nr,
                        commit_graft_sha1_access);
 }
 
-int register_commit_graft(struct commit_graft *graft, int ignore_dups)
+int register_commit_graft(struct repository *r, struct commit_graft *graft,
+                         int ignore_dups)
 {
-       int pos = commit_graft_pos(graft->oid.hash);
+       int pos = commit_graft_pos(r, graft->oid.hash);
 
        if (0 <= pos) {
                if (ignore_dups)
                        free(graft);
                else {
-                       free(commit_graft[pos]);
-                       commit_graft[pos] = graft;
+                       free(r->parsed_objects->grafts[pos]);
+                       r->parsed_objects->grafts[pos] = graft;
                }
                return 1;
        }
        pos = -pos - 1;
-       ALLOC_GROW(commit_graft, commit_graft_nr + 1, commit_graft_alloc);
-       commit_graft_nr++;
-       if (pos < commit_graft_nr)
-               MOVE_ARRAY(commit_graft + pos + 1, commit_graft + pos,
-                          commit_graft_nr - pos - 1);
-       commit_graft[pos] = graft;
+       ALLOC_GROW(r->parsed_objects->grafts,
+                  r->parsed_objects->grafts_nr + 1,
+                  r->parsed_objects->grafts_alloc);
+       r->parsed_objects->grafts_nr++;
+       if (pos < r->parsed_objects->grafts_nr)
+               memmove(r->parsed_objects->grafts + pos + 1,
+                       r->parsed_objects->grafts + pos,
+                       (r->parsed_objects->grafts_nr - pos - 1) *
+                       sizeof(*r->parsed_objects->grafts));
+       r->parsed_objects->grafts[pos] = graft;
        return 0;
 }
 
@@ -172,7 +179,7 @@ struct commit_graft *read_graft_line(struct strbuf *line)
        return NULL;
 }
 
-static int read_graft_file(const char *graft_file)
+static int read_graft_file(struct repository *r, const char *graft_file)
 {
        FILE *fp = fopen_or_warn(graft_file, "r");
        struct strbuf buf = STRBUF_INIT;
@@ -192,7 +199,7 @@ static int read_graft_file(const char *graft_file)
                struct commit_graft *graft = read_graft_line(&buf);
                if (!graft)
                        continue;
-               if (register_commit_graft(graft, 1))
+               if (register_commit_graft(r, graft, 1))
                        error("duplicate graft data: %s", buf.buf);
        }
        fclose(fp);
@@ -200,50 +207,50 @@ static int read_graft_file(const char *graft_file)
        return 0;
 }
 
-static void prepare_commit_graft(void)
+static void prepare_commit_graft(struct repository *r)
 {
-       static int commit_graft_prepared;
        char *graft_file;
 
-       if (commit_graft_prepared)
+       if (r->parsed_objects->commit_graft_prepared)
                return;
        if (!startup_info->have_repository)
                return;
 
-       graft_file = get_graft_file();
-       read_graft_file(graft_file);
+       graft_file = get_graft_file(r);
+       read_graft_file(r, graft_file);
        /* make sure shallows are read */
-       is_repository_shallow();
-       commit_graft_prepared = 1;
+       is_repository_shallow(r);
+       r->parsed_objects->commit_graft_prepared = 1;
 }
 
-struct commit_graft *lookup_commit_graft(const struct object_id *oid)
+struct commit_graft *lookup_commit_graft(struct repository *r, const struct object_id *oid)
 {
        int pos;
-       prepare_commit_graft();
-       pos = commit_graft_pos(oid->hash);
+       prepare_commit_graft(r);
+       pos = commit_graft_pos(r, oid->hash);
        if (pos < 0)
                return NULL;
-       return commit_graft[pos];
+       return r->parsed_objects->grafts[pos];
 }
 
 int for_each_commit_graft(each_commit_graft_fn fn, void *cb_data)
 {
        int i, ret;
-       for (i = ret = 0; i < commit_graft_nr && !ret; i++)
-               ret = fn(commit_graft[i], cb_data);
+       for (i = ret = 0; i < the_repository->parsed_objects->grafts_nr && !ret; i++)
+               ret = fn(the_repository->parsed_objects->grafts[i], cb_data);
        return ret;
 }
 
 int unregister_shallow(const struct object_id *oid)
 {
-       int pos = commit_graft_pos(oid->hash);
+       int pos = commit_graft_pos(the_repository, oid->hash);
        if (pos < 0)
                return -1;
-       if (pos + 1 < commit_graft_nr)
-               MOVE_ARRAY(commit_graft + pos, commit_graft + pos + 1,
-                          commit_graft_nr - pos - 1);
-       commit_graft_nr--;
+       if (pos + 1 < the_repository->parsed_objects->grafts_nr)
+               MOVE_ARRAY(the_repository->parsed_objects->grafts + pos,
+                          the_repository->parsed_objects->grafts + pos + 1,
+                          the_repository->parsed_objects->grafts_nr - pos - 1);
+       the_repository->parsed_objects->grafts_nr--;
        return 0;
 }
 
@@ -325,6 +332,17 @@ struct object_id *get_commit_tree_oid(const struct commit *commit)
        return &get_commit_tree(commit)->object.oid;
 }
 
+void release_commit_memory(struct commit *c)
+{
+       c->maybe_tree = NULL;
+       c->index = 0;
+       free_commit_buffer(c);
+       free_commit_list(c->parents);
+       /* TODO: what about commit->util? */
+
+       c->object.parsed = 0;
+}
+
 const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
 {
        struct commit_buffer *v = buffer_slab_peek(&buffer_slab, commit);
@@ -344,7 +362,7 @@ const void *detach_commit_buffer(struct commit *commit, unsigned long *sizep)
        return ret;
 }
 
-int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size)
+int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size, int check_graph)
 {
        const char *tail = buffer;
        const char *bufptr = buffer;
@@ -368,7 +386,7 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
        bufptr += tree_entry_len + 1; /* "tree " + "hex sha1" + "\n" */
        pptr = &item->parents;
 
-       graft = lookup_commit_graft(&item->object.oid);
+       graft = lookup_commit_graft(the_repository, &item->object.oid);
        while (bufptr + parent_entry_len < tail && !memcmp(bufptr, "parent ", 7)) {
                struct commit *new_parent;
 
@@ -399,6 +417,9 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s
        }
        item->date = parse_commit_date(bufptr, tail);
 
+       if (check_graph)
+               load_commit_graph_info(item);
+
        return 0;
 }
 
@@ -425,7 +446,7 @@ int parse_commit_gently(struct commit *item, int quiet_on_missing)
                return error("Object %s not a commit",
                             oid_to_hex(&item->object.oid));
        }
-       ret = parse_commit_buffer(item, buffer, size);
+       ret = parse_commit_buffer(item, buffer, size, 0);
        if (save_commit_buffer && !ret) {
                set_commit_buffer(item, buffer, size);
                return 0;
@@ -653,6 +674,24 @@ static int compare_commits_by_author_date(const void *a_, const void *b_,
        return 0;
 }
 
+int compare_commits_by_gen_then_commit_date(const void *a_, const void *b_, void *unused)
+{
+       const struct commit *a = a_, *b = b_;
+
+       /* newer commits first */
+       if (a->generation < b->generation)
+               return 1;
+       else if (a->generation > b->generation)
+               return -1;
+
+       /* use date as a heuristic when generations are equal */
+       if (a->date < b->date)
+               return 1;
+       else if (a->date > b->date)
+               return -1;
+       return 0;
+}
+
 int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
 {
        const struct commit *a = a_, *b = b_;
@@ -800,11 +839,14 @@ static int queue_has_nonstale(struct prio_queue *queue)
 }
 
 /* all input commits in one and twos[] must have been parsed! */
-static struct commit_list *paint_down_to_common(struct commit *one, int n, struct commit **twos)
+static struct commit_list *paint_down_to_common(struct commit *one, int n,
+                                               struct commit **twos,
+                                               int min_generation)
 {
-       struct prio_queue queue = { compare_commits_by_commit_date };
+       struct prio_queue queue = { compare_commits_by_gen_then_commit_date };
        struct commit_list *result = NULL;
        int i;
+       uint32_t last_gen = GENERATION_NUMBER_INFINITY;
 
        one->object.flags |= PARENT1;
        if (!n) {
@@ -823,6 +865,15 @@ static struct commit_list *paint_down_to_common(struct commit *one, int n, struc
                struct commit_list *parents;
                int flags;
 
+               if (commit->generation > last_gen)
+                       BUG("bad generation skip %8x > %8x at %s",
+                           commit->generation, last_gen,
+                           oid_to_hex(&commit->object.oid));
+               last_gen = commit->generation;
+
+               if (commit->generation < min_generation)
+                       break;
+
                flags = commit->object.flags & (PARENT1 | PARENT2 | STALE);
                if (flags == (PARENT1 | PARENT2)) {
                        if (!(commit->object.flags & RESULT)) {
@@ -871,7 +922,7 @@ static struct commit_list *merge_bases_many(struct commit *one, int n, struct co
                        return NULL;
        }
 
-       list = paint_down_to_common(one, n, twos);
+       list = paint_down_to_common(one, n, twos, 0);
 
        while (list) {
                struct commit *commit = pop_commit(&list);
@@ -929,6 +980,7 @@ static int remove_redundant(struct commit **array, int cnt)
                parse_commit(array[i]);
        for (i = 0; i < cnt; i++) {
                struct commit_list *common;
+               uint32_t min_generation = array[i]->generation;
 
                if (redundant[i])
                        continue;
@@ -937,8 +989,12 @@ static int remove_redundant(struct commit **array, int cnt)
                                continue;
                        filled_index[filled] = j;
                        work[filled++] = array[j];
+
+                       if (array[j]->generation < min_generation)
+                               min_generation = array[j]->generation;
                }
-               common = paint_down_to_common(array[i], filled, work);
+               common = paint_down_to_common(array[i], filled, work,
+                                             min_generation);
                if (array[i]->object.flags & PARENT2)
                        redundant[i] = 1;
                for (j = 0; j < filled; j++)
@@ -1048,14 +1104,21 @@ int in_merge_bases_many(struct commit *commit, int nr_reference, struct commit *
 {
        struct commit_list *bases;
        int ret = 0, i;
+       uint32_t min_generation = GENERATION_NUMBER_INFINITY;
 
        if (parse_commit(commit))
                return ret;
-       for (i = 0; i < nr_reference; i++)
+       for (i = 0; i < nr_reference; i++) {
                if (parse_commit(reference[i]))
                        return ret;
+               if (reference[i]->generation < min_generation)
+                       min_generation = reference[i]->generation;
+       }
+
+       if (commit->generation > min_generation)
+               return ret;
 
-       bases = paint_down_to_common(commit, nr_reference, reference);
+       bases = paint_down_to_common(commit, nr_reference, reference, commit->generation);
        if (commit->object.flags & PARENT2)
                ret = 1;
        clear_commit_marks(commit, all_flags);