repack_without_ref(): split list curation and entry writing
The repack_without_ref() function first removes the deleted ref from the internal packed-refs list, then writes the packed-refs list to disk, omitting any broken or stale entries. This patch splits that second step into multiple passes: * collect the list of refnames that should be deleted from packed_refs * delete those refnames from the cache * write the remainder to the packed-refs file The purpose of this change is to make the "write the remainder" part reusable. Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Michael Haggerty committed
Jun 20, 2013 at 10:37 UTC
7b40d3963835699e138d21f6040a60c07e797853
1 file changed
+50
-12
refs.c
+50
-12
@@ -1998,6 +1998,23 @@ static void write_packed_entry(int fd, char *refname, unsigned char *sha1,
1998
}
1999
}
2000
2001
+/*
2002
+ * An each_ref_entry_fn that writes the entry to a packed-refs file.
2003
+ */
2004
+static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
2005
+{
2006
+ int *fd = cb_data;
2007
+ enum peel_status peel_status = peel_entry(entry, 0);
2008
+
2009
+ if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
2010
+ error("internal error: %s is not a valid packed reference!",
2011
+ entry->name);
2012
+ write_packed_entry(*fd, entry->name, entry->u.value.sha1,
2013
+ peel_status == PEEL_PEELED ?
2014
+ entry->u.value.peeled : NULL);
2015
+ return 0;
2016
+}
2017
+
2018
struct ref_to_prune {
2019
struct ref_to_prune *next;
2020
unsigned char sha1[20];
@@ -2117,14 +2134,25 @@ int pack_refs(unsigned int flags)
2134
return 0;
2135
}
2136
2120
-static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
2137
+/*
2138
+ * If entry is no longer needed in packed-refs, add it to the string
2139
+ * list pointed to by cb_data. Reasons for deleting entries:
2140
+ *
2141
+ * - Entry is broken.
2142
+ * - Entry is overridden by a loose ref.
2143
+ * - Entry does not point at a valid object.
2144
+ *
2145
+ * In the first and third cases, also emit an error message because these
2146
+ * are indications of repository corruption.
2147
+ */
2148
+static int curate_packed_ref_fn(struct ref_entry *entry, void *cb_data)
2149
{
2122
- int *fd = cb_data;
2123
- enum peel_status peel_status;
2150
+ struct string_list *refs_to_delete = cb_data;
2151
2152
if (entry->flag & REF_ISBROKEN) {
2153
/* This shouldn't happen to packed refs. */
2154
error("%s is broken!", entry->name);
2155
+ string_list_append(refs_to_delete, entry->name);
2156
return 0;
2157
}
2158
if (!has_sha1_file(entry->u.value.sha1)) {
@@ -2134,7 +2162,7 @@ static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
2162
if (read_ref_full(entry->name, sha1, 0, &flags))
2163
/* We should at least have found the packed ref. */
2164
die("Internal error");
2137
- if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED))
2165
+ if ((flags & REF_ISSYMREF) || !(flags & REF_ISPACKED)) {
2166
/*
2167
* This packed reference is overridden by a
2168
* loose reference, so it is OK that its value
@@ -2143,9 +2171,11 @@ static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
2171
* collected. For this purpose we don't even
2172
* care whether the loose reference itself is
2173
* invalid, broken, symbolic, etc. Silently
2146
- * omit the packed reference from the output.
2174
+ * remove the packed reference.
2175
*/
2176
+ string_list_append(refs_to_delete, entry->name);
2177
return 0;
2178
+ }
2179
/*
2180
* There is no overriding loose reference, so the fact
2181
* that this reference doesn't refer to a valid object
@@ -2154,14 +2184,10 @@ static int repack_ref_fn(struct ref_entry *entry, void *cb_data)
2184
* the output.
2185
*/
2186
error("%s does not point to a valid object!", entry->name);
2187
+ string_list_append(refs_to_delete, entry->name);
2188
return 0;
2189
}
2190
2160
- peel_status = peel_entry(entry, 0);
2161
- write_packed_entry(*fd, entry->name, entry->u.value.sha1,
2162
- peel_status == PEEL_PEELED ?
2163
- entry->u.value.peeled : NULL);
2164
-
2191
return 0;
2192
}
2193
@@ -2169,6 +2195,8 @@ static int repack_without_ref(const char *refname)
2195
{
2196
int fd;
2197
struct ref_dir *packed;
2198
+ struct string_list refs_to_delete = STRING_LIST_INIT_DUP;
2199
+ struct string_list_item *ref_to_delete;
2200
2201
if (!get_packed_ref(refname))
2202
return 0; /* refname does not exist in packed refs */
@@ -2180,7 +2208,8 @@ static int repack_without_ref(const char *refname)
2208
}
2209
clear_packed_ref_cache(&ref_cache);
2210
packed = get_packed_refs(&ref_cache);
2183
- /* Remove refname from the cache. */
2211
+
2212
+ /* Remove refname from the cache: */
2213
if (remove_entry(packed, refname) == -1) {
2214
/*
2215
* The packed entry disappeared while we were
@@ -2189,8 +2218,17 @@ static int repack_without_ref(const char *refname)
2218
rollback_lock_file(&packlock);
2219
return 0;
2220
}
2221
+
2222
+ /* Remove any other accumulated cruft: */
2223
+ do_for_each_entry_in_dir(packed, 0, curate_packed_ref_fn, &refs_to_delete);
2224
+ for_each_string_list_item(ref_to_delete, &refs_to_delete) {
2225
+ if (remove_entry(packed, ref_to_delete->string) == -1)
2226
+ die("internal error");
2227
+ }
2228
+
2229
+ /* Write what remains: */
2230
write_or_die(fd, PACKED_REFS_HEADER, strlen(PACKED_REFS_HEADER));
2193
- do_for_each_entry_in_dir(packed, 0, repack_ref_fn, &fd);
2231
+ do_for_each_entry_in_dir(packed, 0, write_packed_entry_fn, &fd);
2232
return commit_lock_file(&packlock);
2233
}
2234