diff options
Diffstat (limited to 'shallow.c')
-rw-r--r-- | shallow.c | 167 |
1 files changed, 125 insertions, 42 deletions
@@ -10,6 +10,8 @@ #include "diff.h" #include "revision.h" #include "commit-slab.h" +#include "revision.h" +#include "list-objects.h" static int is_shallow = -1; static struct stat_validity shallow_stat; @@ -137,6 +139,82 @@ struct commit_list *get_shallow_commits(struct object_array *heads, int depth, return result; } +static void show_commit(struct commit *commit, void *data) +{ + commit_list_insert(commit, data); +} + +/* + * Given rev-list arguments, run rev-list. All reachable commits + * except border ones are marked with not_shallow_flag. Border commits + * are marked with shallow_flag. The list of border/shallow commits + * are also returned. + */ +struct commit_list *get_shallow_commits_by_rev_list(int ac, const char **av, + int shallow_flag, + int not_shallow_flag) +{ + struct commit_list *result = NULL, *p; + struct commit_list *not_shallow_list = NULL; + struct rev_info revs; + int both_flags = shallow_flag | not_shallow_flag; + + /* + * SHALLOW (excluded) and NOT_SHALLOW (included) should not be + * set at this point. But better be safe than sorry. + */ + clear_object_flags(both_flags); + + is_repository_shallow(); /* make sure shallows are read */ + + init_revisions(&revs, NULL); + save_commit_buffer = 0; + setup_revisions(ac, av, &revs, NULL); + + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); + traverse_commit_list(&revs, show_commit, NULL, ¬_shallow_list); + + /* Mark all reachable commits as NOT_SHALLOW */ + for (p = not_shallow_list; p; p = p->next) + p->item->object.flags |= not_shallow_flag; + + /* + * mark border commits SHALLOW + NOT_SHALLOW. + * We cannot clear NOT_SHALLOW right now. Imagine border + * commit A is processed first, then commit B, whose parent is + * A, later. If NOT_SHALLOW on A is cleared at step 1, B + * itself is considered border at step 2, which is incorrect. + */ + for (p = not_shallow_list; p; p = p->next) { + struct commit *c = p->item; + struct commit_list *parent; + + if (parse_commit(c)) + die("unable to parse commit %s", + oid_to_hex(&c->object.oid)); + + for (parent = c->parents; parent; parent = parent->next) + if (!(parent->item->object.flags & not_shallow_flag)) { + c->object.flags |= shallow_flag; + commit_list_insert(c, &result); + break; + } + } + free_commit_list(not_shallow_list); + + /* + * Now we can clean up NOT_SHALLOW on border commits. Having + * both flags set can confuse the caller. + */ + for (p = result; p; p = p->next) { + struct object *o = &p->item->object; + if ((o->flags & both_flags) == both_flags) + o->flags &= ~not_shallow_flag; + } + return result; +} + static void check_shallow_file_for_update(void) { if (is_shallow == -1) @@ -182,7 +260,7 @@ static int write_one_shallow(const struct commit_graft *graft, void *cb_data) } static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, - const struct sha1_array *extra, + const struct oid_array *extra, unsigned flags) { struct write_shallow_data data; @@ -195,7 +273,7 @@ static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, if (!extra) return data.count; for (i = 0; i < extra->nr; i++) { - strbuf_addstr(out, sha1_to_hex(extra->sha1[i])); + strbuf_addstr(out, oid_to_hex(extra->oid + i)); strbuf_addch(out, '\n'); data.count++; } @@ -203,14 +281,14 @@ static int write_shallow_commits_1(struct strbuf *out, int use_pack_protocol, } int write_shallow_commits(struct strbuf *out, int use_pack_protocol, - const struct sha1_array *extra) + const struct oid_array *extra) { return write_shallow_commits_1(out, use_pack_protocol, extra, 0); } static struct tempfile temporary_shallow; -const char *setup_temporary_shallow(const struct sha1_array *extra) +const char *setup_temporary_shallow(const struct oid_array *extra) { struct strbuf sb = STRBUF_INIT; int fd; @@ -234,7 +312,7 @@ const char *setup_temporary_shallow(const struct sha1_array *extra) void setup_alternate_shallow(struct lock_file *shallow_lock, const char **alternate_shallow_file, - const struct sha1_array *extra) + const struct oid_array *extra) { struct strbuf sb = STRBUF_INIT; int fd; @@ -260,7 +338,7 @@ static int advertise_shallow_grafts_cb(const struct commit_graft *graft, void *c { int fd = *(int *)cb; if (graft->nr_parent == -1) - packet_write(fd, "shallow %s\n", oid_to_hex(&graft->oid)); + packet_write_fmt(fd, "shallow %s\n", oid_to_hex(&graft->oid)); return 0; } @@ -307,7 +385,7 @@ struct trace_key trace_shallow = TRACE_KEY_INIT(SHALLOW); * Step 1, split sender shallow commits into "ours" and "theirs" * Step 2, clean "ours" based on .git/shallow */ -void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa) +void prepare_shallow_info(struct shallow_info *info, struct oid_array *sa) { int i; trace_printf_key(&trace_shallow, "shallow: prepare_shallow_info\n"); @@ -318,9 +396,9 @@ void prepare_shallow_info(struct shallow_info *info, struct sha1_array *sa) ALLOC_ARRAY(info->ours, sa->nr); ALLOC_ARRAY(info->theirs, sa->nr); for (i = 0; i < sa->nr; i++) { - if (has_sha1_file(sa->sha1[i])) { + if (has_object_file(sa->oid + i)) { struct commit_graft *graft; - graft = lookup_commit_graft(sa->sha1[i]); + graft = lookup_commit_graft(sa->oid[i].hash); if (graft && graft->nr_parent < 0) continue; info->ours[info->nr_ours++] = i; @@ -339,13 +417,13 @@ void clear_shallow_info(struct shallow_info *info) void remove_nonexistent_theirs_shallow(struct shallow_info *info) { - unsigned char (*sha1)[20] = info->shallow->sha1; + struct object_id *oid = info->shallow->oid; int i, dst; trace_printf_key(&trace_shallow, "shallow: remove_nonexistent_theirs_shallow\n"); for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) info->theirs[dst] = info->theirs[i]; - if (has_sha1_file(sha1[info->theirs[i]])) + if (has_object_file(oid + info->theirs[i])) dst++; } info->nr_theirs = dst; @@ -353,12 +431,14 @@ void remove_nonexistent_theirs_shallow(struct shallow_info *info) define_commit_slab(ref_bitmap, uint32_t *); +#define POOL_SIZE (512 * 1024) + struct paint_info { struct ref_bitmap ref_bitmap; unsigned nr_bits; - char **slab; + char **pools; char *free, *end; - unsigned slab_count; + unsigned pool_count; }; static uint32_t *paint_alloc(struct paint_info *info) @@ -366,12 +446,15 @@ static uint32_t *paint_alloc(struct paint_info *info) unsigned nr = (info->nr_bits + 31) / 32; unsigned size = nr * sizeof(uint32_t); void *p; - if (!info->slab_count || info->free + size > info->end) { - info->slab_count++; - REALLOC_ARRAY(info->slab, info->slab_count); - info->free = xmalloc(COMMIT_SLAB_SIZE); - info->slab[info->slab_count - 1] = info->free; - info->end = info->free + COMMIT_SLAB_SIZE; + if (!info->pool_count || size > info->end - info->free) { + if (size > POOL_SIZE) + die("BUG: pool size too small for %d in paint_alloc()", + size); + info->pool_count++; + REALLOC_ARRAY(info->pools, info->pool_count); + info->free = xmalloc(POOL_SIZE); + info->pools[info->pool_count - 1] = info->free; + info->end = info->free + POOL_SIZE; } p = info->free; info->free += size; @@ -384,19 +467,23 @@ static uint32_t *paint_alloc(struct paint_info *info) * all walked commits. */ static void paint_down(struct paint_info *info, const unsigned char *sha1, - int id) + unsigned int id) { unsigned int i, nr; struct commit_list *head = NULL; int bitmap_nr = (info->nr_bits + 31) / 32; - size_t bitmap_size = st_mult(bitmap_nr, sizeof(uint32_t)); - uint32_t *tmp = xmalloc(bitmap_size); /* to be freed before return */ - uint32_t *bitmap = paint_alloc(info); + size_t bitmap_size = st_mult(sizeof(uint32_t), bitmap_nr); struct commit *c = lookup_commit_reference_gently(sha1, 1); + uint32_t *tmp; /* to be freed before return */ + uint32_t *bitmap; + if (!c) return; + + tmp = xmalloc(bitmap_size); + bitmap = paint_alloc(info); memset(bitmap, 0, bitmap_size); - bitmap[id / 32] |= (1 << (id % 32)); + bitmap[id / 32] |= (1U << (id % 32)); commit_list_insert(c, &head); while (head) { struct commit_list *p; @@ -429,12 +516,8 @@ static void paint_down(struct paint_info *info, const unsigned char *sha1, oid_to_hex(&c->object.oid)); for (p = c->parents; p; p = p->next) { - uint32_t **p_refs = ref_bitmap_at(&info->ref_bitmap, - p->item); if (p->item->object.flags & SEEN) continue; - if (*p_refs == NULL || *p_refs == *refs) - *p_refs = *refs; commit_list_insert(p->item, &head); } } @@ -480,8 +563,8 @@ static void post_assign_shallow(struct shallow_info *info, void assign_shallow_commits_to_refs(struct shallow_info *info, uint32_t **used, int *ref_status) { - unsigned char (*sha1)[20] = info->shallow->sha1; - struct sha1_array *ref = info->ref; + struct object_id *oid = info->shallow->oid; + struct oid_array *ref = info->ref; unsigned int i, nr; int *shallow, nr_shallow = 0; struct paint_info pi; @@ -520,18 +603,18 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, /* Mark potential bottoms so we won't go out of bound */ for (i = 0; i < nr_shallow; i++) { - struct commit *c = lookup_commit(sha1[shallow[i]]); + struct commit *c = lookup_commit(oid[shallow[i]].hash); c->object.flags |= BOTTOM; } for (i = 0; i < ref->nr; i++) - paint_down(&pi, ref->sha1[i], i); + paint_down(&pi, ref->oid[i].hash, i); if (used) { int bitmap_size = ((pi.nr_bits + 31) / 32) * sizeof(uint32_t); memset(used, 0, sizeof(*used) * info->shallow->nr); for (i = 0; i < nr_shallow; i++) { - const struct commit *c = lookup_commit(sha1[shallow[i]]); + const struct commit *c = lookup_commit(oid[shallow[i]].hash); uint32_t **map = ref_bitmap_at(&pi.ref_bitmap, c); if (*map) used[shallow[i]] = xmemdupz(*map, bitmap_size); @@ -546,9 +629,9 @@ void assign_shallow_commits_to_refs(struct shallow_info *info, post_assign_shallow(info, &pi.ref_bitmap, ref_status); clear_ref_bitmap(&pi.ref_bitmap); - for (i = 0; i < pi.slab_count; i++) - free(pi.slab[i]); - free(pi.slab); + for (i = 0; i < pi.pool_count; i++) + free(pi.pools[i]); + free(pi.pools); free(shallow); } @@ -570,11 +653,11 @@ static int add_ref(const char *refname, const struct object_id *oid, static void update_refstatus(int *ref_status, int nr, uint32_t *bitmap) { - int i; + unsigned int i; if (!ref_status) return; for (i = 0; i < nr; i++) - if (bitmap[i / 32] & (1 << (i % 32))) + if (bitmap[i / 32] & (1U << (i % 32))) ref_status[i]++; } @@ -585,7 +668,7 @@ static void post_assign_shallow(struct shallow_info *info, struct ref_bitmap *ref_bitmap, int *ref_status) { - unsigned char (*sha1)[20] = info->shallow->sha1; + struct object_id *oid = info->shallow->oid; struct commit *c; uint32_t **bitmap; int dst, i, j; @@ -600,7 +683,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_theirs; i++) { if (i != dst) info->theirs[dst] = info->theirs[i]; - c = lookup_commit(sha1[info->theirs[i]]); + c = lookup_commit(oid[info->theirs[i]].hash); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -621,7 +704,7 @@ static void post_assign_shallow(struct shallow_info *info, for (i = dst = 0; i < info->nr_ours; i++) { if (i != dst) info->ours[dst] = info->ours[i]; - c = lookup_commit(sha1[info->ours[i]]); + c = lookup_commit(oid[info->ours[i]].hash); bitmap = ref_bitmap_at(ref_bitmap, c); if (!*bitmap) continue; @@ -643,7 +726,7 @@ static void post_assign_shallow(struct shallow_info *info, int delayed_reachability_test(struct shallow_info *si, int c) { if (si->need_reachability_test[c]) { - struct commit *commit = lookup_commit(si->shallow->sha1[c]); + struct commit *commit = lookup_commit(si->shallow->oid[c].hash); if (!si->commits) { struct commit_array ca; |