From cd1f9c36beeafd3dea4672494a98e1ed39ae63f1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 6 Jan 2007 22:32:41 -0800 Subject: [PATCH] reflog --fix-stale: do not check the same trees and commits repeatedly. Since we use the reachability tracking machinery now, we should keep the already checked trees and commits whose completeness is known, to avoid checking the same thing over and over again. Signed-off-by: Junio C Hamano --- builtin-reflog.c | 75 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/builtin-reflog.c b/builtin-reflog.c index 1da7da0916..a967117661 100644 --- a/builtin-reflog.c +++ b/builtin-reflog.c @@ -34,35 +34,51 @@ struct expire_reflog_cb { struct cmd_reflog_expire_cb *cmd; }; +#define INCOMPLETE (1u<<10) +#define STUDYING (1u<<11) + static int tree_is_complete(const unsigned char *sha1) { struct tree_desc desc; - void *buf; - char type[20]; + struct name_entry entry; + int complete; + struct tree *tree; - buf = read_sha1_file(sha1, type, &desc.size); - if (!buf) + tree = lookup_tree(sha1); + if (!tree) + return 0; + if (tree->object.flags & SEEN) + return 1; + if (tree->object.flags & INCOMPLETE) return 0; - desc.buf = buf; - while (desc.size) { - const unsigned char *elem; - const char *name; - unsigned mode; - elem = tree_entry_extract(&desc, &name, &mode); - if (!has_sha1_file(elem) || - (S_ISDIR(mode) && !tree_is_complete(elem))) { - free(buf); + desc.buf = tree->buffer; + desc.size = tree->size; + if (!desc.buf) { + char type[20]; + void *data = read_sha1_file(sha1, type, &desc.size); + if (!data) { + tree->object.flags |= INCOMPLETE; return 0; } - update_tree_entry(&desc); + desc.buf = data; + tree->buffer = data; } - free(buf); - return 1; -} + complete = 1; + while (tree_entry(&desc, &entry)) { + if (!has_sha1_file(entry.sha1) || + (S_ISDIR(entry.mode) && !tree_is_complete(entry.sha1))) { + tree->object.flags |= INCOMPLETE; + complete = 0; + } + } + free(tree->buffer); + tree->buffer = NULL; -#define INCOMPLETE (1u<<10) -#define STUDYING (1u<<11) + if (complete) + tree->object.flags |= SEEN; + return complete; +} static int commit_is_complete(struct commit *commit) { @@ -112,14 +128,17 @@ static int commit_is_complete(struct commit *commit) } } if (!is_incomplete) { - /* make sure all commits in found have all the + /* + * make sure all commits in "found" array have all the * necessary objects. */ - for (i = 0; !is_incomplete && i < found.nr; i++) { + for (i = 0; i < found.nr; i++) { struct commit *c = (struct commit *)found.objects[i].item; - if (!tree_is_complete(c->tree->object.sha1)) + if (!tree_is_complete(c->tree->object.sha1)) { is_incomplete = 1; + c->object.flags |= INCOMPLETE; + } } if (!is_incomplete) { /* mark all found commits as complete, iow SEEN */ @@ -132,6 +151,18 @@ static int commit_is_complete(struct commit *commit) found.objects[i].item->flags &= ~STUDYING; if (is_incomplete) commit->object.flags |= INCOMPLETE; + else { + /* + * If we come here, we have (1) traversed the ancestry chain + * from the "commit" until we reach SEEN commits (which are + * known to be complete), and (2) made sure that the commits + * encountered during the above traversal refer to trees that + * are complete. Which means that we know *all* the commits + * we have seen during this process are complete. + */ + for (i = 0; i < found.nr; i++) + found.objects[i].item->flags |= SEEN; + } /* free object arrays */ free(study.objects); free(found.objects);