summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2008-12-11 00:36:31 -0800
committerJunio C Hamano <gitster@pobox.com>2008-12-11 00:36:31 -0800
commitde0db422782ddaf7754ac5b03fdc6dc5de1a9ae4 (patch)
tree643c6f8be7804462cc1e21f95cd33bd8dfb27f5f
parent07e62b733fad4236371a8cd6abc32409fb1fb87d (diff)
parent04d39759373e5de017e7c17ef4b762ac5ad3afcc (diff)
downloadgit-de0db422782ddaf7754ac5b03fdc6dc5de1a9ae4.tar.gz
Merge branch 'maint'
* maint: fsck: reduce stack footprint make sure packs to be replaced are closed beforehand
-rw-r--r--builtin-fsck.c38
-rw-r--r--builtin-pack-objects.c1
-rw-r--r--cache.h1
-rw-r--r--sha1_file.c31
4 files changed, 64 insertions, 7 deletions
diff --git a/builtin-fsck.c b/builtin-fsck.c
index afded5e68d..297b2c41c6 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)
@@ -237,6 +258,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)
diff --git a/builtin-pack-objects.c b/builtin-pack-objects.c
index 67eefa2932..cedef52fd3 100644
--- a/builtin-pack-objects.c
+++ b/builtin-pack-objects.c
@@ -535,6 +535,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 f15b3fc906..231c06d772 100644
--- a/cache.h
+++ b/cache.h
@@ -820,6 +820,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 6c0e251e02..0e021c5eca 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -673,6 +673,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.
*/