summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: aec8fa1)
raw | patch | inline | side by side (parent: aec8fa1)
author | Junio C Hamano <junkio@cox.net> | |
Sun, 29 Oct 2006 11:07:40 +0000 (03:07 -0800) | ||
committer | Junio C Hamano <junkio@cox.net> | |
Sun, 29 Oct 2006 23:29:25 +0000 (15:29 -0800) |
The origin structure is allocated for each commit and path while
the code traverse down it is copied into different blame entries.
To avoid leaks, try refcounting them.
This still seems to leak, which I haven't tracked down fully yet.
Signed-off-by: Junio C Hamano <junkio@cox.net>
the code traverse down it is copied into different blame entries.
To avoid leaks, try refcounting them.
This still seems to leak, which I haven't tracked down fully yet.
Signed-off-by: Junio C Hamano <junkio@cox.net>
builtin-pickaxe.c | patch | blob | history |
diff --git a/builtin-pickaxe.c b/builtin-pickaxe.c
index 663b96dac55cff41cd5ed223568508297a9f8788..b53c7b061762e1c9fa0d3ef48405431e8a1526bb 100644 (file)
--- a/builtin-pickaxe.c
+++ b/builtin-pickaxe.c
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
#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;
return strcmp(a->path, b->path);
}
+static void sanity_check_refcnt(struct scoreboard *);
+
static void coalesce(struct scoreboard *sb)
{
struct blame_entry *ent, *next;
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,
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;
}
{
struct blame_entry *ent, *prev = NULL;
+ origin_incref(e->suspect);
+
for (ent = sb->ent; ent && ent->lno < e->lno; ent = ent->next)
prev = ent;
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;
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)
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;
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;
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;
add_blame_entry(sb, new_entry);
}
- if (1) { /* sanity */
+ if (DEBUG) { /* sanity */
struct blame_entry *ent;
int lno = sb->ent->lno, corrupt = 0;
}
}
+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)
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)
}
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;
chunk->same + ent->s_lno,
parent);
copy_split_if_better(sb, split, this);
+ decref_split(this);
}
plno = chunk->p_next;
tlno = chunk->t_next;
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;
this);
}
free(blob);
+ origin_decref(norigin);
}
diff_flush(&diff_opts);
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);
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;
}
if (!porigin)
continue;
if (pass_blame_to_parent(sb, origin, porigin))
- return;
+ goto finish;
}
/*
if (!porigin)
continue;
if (find_move_in_parent(sb, origin, porigin))
- return;
+ goto finish;
}
/*
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)
if (!suspect)
return; /* all done */
+ origin_incref(suspect);
commit = suspect->commit;
parse_commit(commit);
if (!(commit->object.flags & UNINTERESTING) &&
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);
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;