Merge branch 'jc/pickaxe' into next

* jc/pickaxe:
  git-pickaxe: WIP to refcount origin structure.
This commit is contained in:
Junio C Hamano
2006-10-29 15:33:57 -08:00

View File

@@ -36,6 +36,10 @@ static int max_orig_digits;
static int max_digits;
static int max_score_digits;
#ifndef DEBUG
#define DEBUG 0
#endif
#define PICKAXE_BLAME_MOVE 01
#define PICKAXE_BLAME_COPY 02
#define PICKAXE_BLAME_COPY_HARDER 04
@@ -54,14 +58,30 @@ static unsigned blame_copy_score;
#define MORE_THAN_ONE_PATH (1u<<13)
/*
* One blob in a commit
* One blob in a commit that is being suspected
*/
struct origin {
int refcnt;
struct commit *commit;
unsigned char blob_sha1[20];
char path[FLEX_ARRAY];
};
static inline struct origin *origin_incref(struct origin *o)
{
if (o)
o->refcnt++;
return o;
}
static void origin_decref(struct origin *o)
{
if (o && --o->refcnt <= 0) {
memset(o, 0, sizeof(*o));
free(o);
}
}
struct blame_entry {
struct blame_entry *prev;
struct blame_entry *next;
@@ -121,6 +141,8 @@ static int cmp_suspect(struct origin *a, struct origin *b)
return strcmp(a->path, b->path);
}
static void sanity_check_refcnt(struct scoreboard *);
static void coalesce(struct scoreboard *sb)
{
struct blame_entry *ent, *next;
@@ -133,11 +155,15 @@ static void coalesce(struct scoreboard *sb)
ent->next = next->next;
if (ent->next)
ent->next->prev = ent;
origin_decref(next->suspect);
free(next);
ent->score = 0;
next = ent; /* again */
}
}
if (DEBUG) /* sanity */
sanity_check_refcnt(sb);
}
static struct origin *get_origin(struct scoreboard *sb,
@@ -150,10 +176,11 @@ static struct origin *get_origin(struct scoreboard *sb,
for (e = sb->ent; e; e = e->next) {
if (e->suspect->commit == commit &&
!strcmp(e->suspect->path, path))
return e->suspect;
return origin_incref(e->suspect);
}
o = xcalloc(1, sizeof(*o) + strlen(path) + 1);
o->commit = commit;
o->refcnt = 1;
strcpy(o->path, path);
return o;
}
@@ -400,6 +427,8 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
{
struct blame_entry *ent, *prev = NULL;
origin_incref(e->suspect);
for (ent = sb->ent; ent && ent->lno < e->lno; ent = ent->next)
prev = ent;
@@ -420,8 +449,11 @@ static void add_blame_entry(struct scoreboard *sb, struct blame_entry *e)
static void dup_entry(struct blame_entry *dst, struct blame_entry *src)
{
struct blame_entry *p, *n;
p = dst->prev;
n = dst->next;
origin_incref(src->suspect);
origin_decref(dst->suspect);
memcpy(dst, src, sizeof(*src));
dst->prev = p;
dst->next = n;
@@ -433,7 +465,7 @@ static const char *nth_line(struct scoreboard *sb, int lno)
return sb->final_buf + sb->lineno[lno];
}
static void split_overlap(struct blame_entry split[3],
static void split_overlap(struct blame_entry *split,
struct blame_entry *e,
int tlno, int plno, int same,
struct origin *parent)
@@ -457,7 +489,7 @@ static void split_overlap(struct blame_entry split[3],
if (e->s_lno < tlno) {
/* there is a pre-chunk part not blamed on parent */
split[0].suspect = e->suspect;
split[0].suspect = origin_incref(e->suspect);
split[0].lno = e->lno;
split[0].s_lno = e->s_lno;
split[0].num_lines = tlno - e->s_lno;
@@ -471,7 +503,7 @@ static void split_overlap(struct blame_entry split[3],
if (same < e->s_lno + e->num_lines) {
/* there is a post-chunk part not blamed on parent */
split[2].suspect = e->suspect;
split[2].suspect = origin_incref(e->suspect);
split[2].lno = e->lno + (same - e->s_lno);
split[2].s_lno = e->s_lno + (same - e->s_lno);
split[2].num_lines = e->s_lno + e->num_lines - same;
@@ -483,11 +515,11 @@ static void split_overlap(struct blame_entry split[3],
if (split[1].num_lines < 1)
return;
split[1].suspect = parent;
split[1].suspect = origin_incref(parent);
}
static void split_blame(struct scoreboard *sb,
struct blame_entry split[3],
struct blame_entry *split,
struct blame_entry *e)
{
struct blame_entry *new_entry;
@@ -522,7 +554,7 @@ static void split_blame(struct scoreboard *sb,
add_blame_entry(sb, new_entry);
}
if (1) { /* sanity */
if (DEBUG) { /* sanity */
struct blame_entry *ent;
int lno = sb->ent->lno, corrupt = 0;
@@ -545,6 +577,14 @@ static void split_blame(struct scoreboard *sb,
}
}
static void decref_split(struct blame_entry *split)
{
int i;
for (i = 0; i < 3; i++)
origin_decref(split[i].suspect);
}
static void blame_overlap(struct scoreboard *sb, struct blame_entry *e,
int tlno, int plno, int same,
struct origin *parent)
@@ -552,9 +592,9 @@ static void blame_overlap(struct scoreboard *sb, struct blame_entry *e,
struct blame_entry split[3];
split_overlap(split, e, tlno, plno, same, parent);
if (!split[1].suspect)
return;
split_blame(sb, split, e);
if (split[1].suspect)
split_blame(sb, split, e);
decref_split(split);
}
static int find_last_in_target(struct scoreboard *sb, struct origin *target)
@@ -636,22 +676,28 @@ static unsigned ent_score(struct scoreboard *sb, struct blame_entry *e)
}
static void copy_split_if_better(struct scoreboard *sb,
struct blame_entry best_so_far[3],
struct blame_entry this[3])
struct blame_entry *best_so_far,
struct blame_entry *this)
{
int i;
if (!this[1].suspect)
return;
if (best_so_far[1].suspect) {
if (ent_score(sb, &this[1]) < ent_score(sb, &best_so_far[1]))
return;
}
for (i = 0; i < 3; i++)
origin_incref(this[i].suspect);
decref_split(best_so_far);
memcpy(best_so_far, this, sizeof(struct blame_entry [3]));
}
static void find_copy_in_blob(struct scoreboard *sb,
struct blame_entry *ent,
struct origin *parent,
struct blame_entry split[3],
struct blame_entry *split,
mmfile_t *file_p)
{
const char *cp;
@@ -687,6 +733,7 @@ static void find_copy_in_blob(struct scoreboard *sb,
chunk->same + ent->s_lno,
parent);
copy_split_if_better(sb, split, this);
decref_split(this);
}
plno = chunk->p_next;
tlno = chunk->t_next;
@@ -723,6 +770,7 @@ static int find_move_in_parent(struct scoreboard *sb,
if (split[1].suspect &&
blame_move_score < ent_score(sb, &split[1]))
split_blame(sb, split, e);
decref_split(split);
}
free(blob_p);
return 0;
@@ -806,6 +854,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
this);
}
free(blob);
origin_decref(norigin);
}
diff_flush(&diff_opts);
@@ -814,6 +863,7 @@ static int find_copy_in_parent(struct scoreboard *sb,
if (split[1].suspect &&
blame_copy_score < ent_score(sb, &split[1]))
split_blame(sb, split, blame_list[j].ent);
decref_split(split);
}
free(blame_list);
@@ -843,9 +893,13 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
if (!hashcmp(porigin->blob_sha1, origin->blob_sha1)) {
struct blame_entry *e;
for (e = sb->ent; e; e = e->next)
if (e->suspect == origin)
if (e->suspect == origin) {
origin_incref(porigin);
origin_decref(e->suspect);
e->suspect = porigin;
return;
}
origin_decref(porigin);
goto finish;
}
parent_origin[i] = porigin;
}
@@ -857,7 +911,7 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
if (!porigin)
continue;
if (pass_blame_to_parent(sb, origin, porigin))
return;
goto finish;
}
/*
@@ -871,7 +925,7 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
if (!porigin)
continue;
if (find_move_in_parent(sb, origin, porigin))
return;
goto finish;
}
/*
@@ -884,8 +938,12 @@ static void pass_blame(struct scoreboard *sb, struct origin *origin, int opt)
struct origin *porigin = parent_origin[i];
if (find_copy_in_parent(sb, origin, parent->item,
porigin, opt))
return;
goto finish;
}
finish:
for (i = 0; i < MAXPARENT; i++)
origin_decref(parent_origin[i]);
}
static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
@@ -902,6 +960,7 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
if (!suspect)
return; /* all done */
origin_incref(suspect);
commit = suspect->commit;
parse_commit(commit);
if (!(commit->object.flags & UNINTERESTING) &&
@@ -912,7 +971,7 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
for (ent = sb->ent; ent; ent = ent->next)
if (!cmp_suspect(ent->suspect, suspect))
ent->guilty = 1;
origin_decref(suspect);
coalesce(sb);
}
}
@@ -1132,7 +1191,9 @@ static void emit_other(struct scoreboard *sb, struct blame_entry *ent, int opt)
ent->lno + 1 + cnt);
else {
if (opt & OUTPUT_SHOW_SCORE)
printf(" %*d", max_score_digits, ent->score);
printf(" %*d %02d",
max_score_digits, ent->score,
ent->suspect->refcnt);
if (opt & OUTPUT_SHOW_NAME)
printf(" %-*.*s", longest_file, longest_file,
suspect->path);
@@ -1273,6 +1334,45 @@ static void find_alignment(struct scoreboard *sb, int *option)
max_score_digits = lineno_width(largest_score);
}
static void sanity_check_refcnt(struct scoreboard *sb)
{
int baa = 0;
struct blame_entry *ent;
for (ent = sb->ent; ent; ent = ent->next) {
/* first mark the ones that haven't been checked */
if (0 < ent->suspect->refcnt)
ent->suspect->refcnt = -ent->suspect->refcnt;
else if (!ent->suspect->refcnt)
baa = 1;
}
for (ent = sb->ent; ent; ent = ent->next) {
/* then pick each and see if they have the the
* correct refcnt
*/
int found;
struct blame_entry *e;
struct origin *suspect = ent->suspect;
if (0 < suspect->refcnt)
continue;
suspect->refcnt = -suspect->refcnt;
for (found = 0, e = sb->ent; e; e = e->next) {
if (e->suspect != suspect)
continue;
found++;
}
if (suspect->refcnt != found)
baa = 1;
}
if (baa) {
int opt = 0160;
find_alignment(sb, &opt);
output(sb, opt);
die("Baa!");
}
}
static int has_path_in_work_tree(const char *path)
{
struct stat st;