From c74faea19e39ca933492f697596310397175c329 Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Tue, 9 Dec 2008 14:26:52 -0500 Subject: [PATCH 1/2] make sure packs to be replaced are closed beforehand Especially on Windows where an opened file cannot be replaced, make sure pack-objects always close packs it is about to replace. Even on non Windows systems, this could save potential bad results if ever objects were to be read from the new pack file using offset from the old index. This should fix t5303 on Windows. Signed-off-by: Nicolas Pitre Tested-by: Johannes Sixt (MinGW) Signed-off-by: Junio C Hamano --- builtin-pack-objects.c | 1 + cache.h | 1 + sha1_file.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c index 4411a480c1..fb5e14d56e 100644 --- a/builtin-pack-objects.c +++ b/builtin-pack-objects.c @@ -520,6 +520,7 @@ static void write_pack_file(void) snprintf(tmpname, sizeof(tmpname), "%s-%s.pack", base_name, sha1_to_hex(sha1)); + free_pack_by_name(tmpname); if (adjust_perm(pack_tmp_name, mode)) die("unable to make temporary pack file readable: %s", strerror(errno)); diff --git a/cache.h b/cache.h index d1cd6aaf73..42f2f2754b 100644 --- a/cache.h +++ b/cache.h @@ -738,6 +738,7 @@ extern int open_pack_index(struct packed_git *); extern unsigned char* use_pack(struct packed_git *, struct pack_window **, off_t, unsigned int *); extern void close_pack_windows(struct packed_git *); extern void unuse_pack(struct pack_window **); +extern void free_pack_by_name(const char *); extern struct packed_git *add_packed_git(const char *, int, int); extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t); extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t); diff --git a/sha1_file.c b/sha1_file.c index c35469d488..88035a0cd1 100644 --- a/sha1_file.c +++ b/sha1_file.c @@ -659,6 +659,37 @@ void unuse_pack(struct pack_window **w_cursor) } } +/* + * This is used by git-repack in case a newly created pack happens to + * contain the same set of objects as an existing one. In that case + * the resulting file might be different even if its name would be the + * same. It is best to close any reference to the old pack before it is + * replaced on disk. Of course no index pointers nor windows for given pack + * must subsist at this point. If ever objects from this pack are requested + * again, the new version of the pack will be reinitialized through + * reprepare_packed_git(). + */ +void free_pack_by_name(const char *pack_name) +{ + struct packed_git *p, **pp = &packed_git; + + while (*pp) { + p = *pp; + if (strcmp(pack_name, p->pack_name) == 0) { + close_pack_windows(p); + if (p->pack_fd != -1) + close(p->pack_fd); + if (p->index_data) + munmap((void *)p->index_data, p->index_size); + free(p->bad_object_sha1); + *pp = p->next; + free(p); + return; + } + pp = &p->next; + } +} + /* * Do not call this directly as this leaks p->pack_fd on error return; * call open_packed_git() instead. From 04d39759373e5de017e7c17ef4b762ac5ad3afcc Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Wed, 10 Dec 2008 19:44:37 -0800 Subject: [PATCH 2/2] fsck: reduce stack footprint The logic to mark all objects that are reachable from tips of refs were implemented as a set of recursive functions. In a repository with a deep enough history, this can easily eat up all the available stack space. Restructure the code to require less stackspace by using an object array to keep track of the objects that still need to be processed. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- builtin-fsck.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/builtin-fsck.c b/builtin-fsck.c index d3f3de9446..30971ce0ad 100644 --- a/builtin-fsck.c +++ b/builtin-fsck.c @@ -64,11 +64,11 @@ static int fsck_error_func(struct object *obj, int type, const char *err, ...) return (type == FSCK_WARN) ? 0 : 1; } +static struct object_array pending; + static int mark_object(struct object *obj, int type, void *data) { - struct tree *tree = NULL; struct object *parent = data; - int result; if (!obj) { printf("broken link from %7s %s\n", @@ -96,6 +96,20 @@ static int mark_object(struct object *obj, int type, void *data) return 1; } + add_object_array(obj, (void *) parent, &pending); + return 0; +} + +static void mark_object_reachable(struct object *obj) +{ + mark_object(obj, OBJ_ANY, 0); +} + +static int traverse_one_object(struct object *obj, struct object *parent) +{ + int result; + struct tree *tree = NULL; + if (obj->type == OBJ_TREE) { obj->parsed = 0; tree = (struct tree *)obj; @@ -107,15 +121,22 @@ static int mark_object(struct object *obj, int type, void *data) free(tree->buffer); tree->buffer = NULL; } - if (result < 0) - result = 1; - return result; } -static void mark_object_reachable(struct object *obj) +static int traverse_reachable(void) { - mark_object(obj, OBJ_ANY, 0); + int result = 0; + while (pending.nr) { + struct object_array_entry *entry; + struct object *obj, *parent; + + entry = pending.objects + --pending.nr; + obj = entry->item; + parent = (struct object *) entry->name; + result |= traverse_one_object(obj, parent); + } + return !!result; } static int mark_used(struct object *obj, int type, void *data) @@ -233,6 +254,9 @@ static void check_connectivity(void) { int i, max; + /* Traverse the pending reachable objects */ + traverse_reachable(); + /* Look up all the requirements, warn about missing objects.. */ max = get_max_object_index(); if (verbose)