Skip to content

Commit b6b10bb

Browse files
rsahlberggitster
authored andcommitted
walker.c: use ref transaction for ref updates
Switch to using ref transactions in walker_fetch(). As part of the refactoring to use ref transactions we also fix a potential memory leak where in the original code if write_ref_sha1() would fail we would end up returning from the function without free()ing the msg string. Note that this function is only called when fetching from a remote HTTP repository onto the local (most of the time single-user) repository which likely means that the type of collisions that the previous locking would protect against and cause the fetch to fail for are even more rare. Signed-off-by: Ronnie Sahlberg <sahlberg@google.com> Reviewed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 3f09ba7 commit b6b10bb

1 file changed

Lines changed: 40 additions & 30 deletions

File tree

walker.c

Lines changed: 40 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -251,64 +251,74 @@ void walker_targets_free(int targets, char **target, const char **write_ref)
251251
int walker_fetch(struct walker *walker, int targets, char **target,
252252
const char **write_ref, const char *write_ref_log_details)
253253
{
254-
struct ref_lock **lock = xcalloc(targets, sizeof(struct ref_lock *));
254+
struct strbuf refname = STRBUF_INIT;
255+
struct strbuf err = STRBUF_INIT;
256+
struct ref_transaction *transaction = NULL;
255257
unsigned char *sha1 = xmalloc(targets * 20);
256-
char *msg;
257-
int ret;
258-
int i;
258+
char *msg = NULL;
259+
int i, ret = -1;
259260

260261
save_commit_buffer = 0;
261262

262-
for (i = 0; i < targets; i++) {
263-
if (!write_ref || !write_ref[i])
264-
continue;
265-
266-
lock[i] = lock_ref_sha1(write_ref[i], NULL);
267-
if (!lock[i]) {
268-
error("Can't lock ref %s", write_ref[i]);
269-
goto unlock_and_fail;
263+
if (write_ref) {
264+
transaction = ref_transaction_begin(&err);
265+
if (!transaction) {
266+
error("%s", err.buf);
267+
goto done;
270268
}
271269
}
272-
273270
if (!walker->get_recover)
274271
for_each_ref(mark_complete, NULL);
275272

276273
for (i = 0; i < targets; i++) {
277274
if (interpret_target(walker, target[i], &sha1[20 * i])) {
278275
error("Could not interpret response from server '%s' as something to pull", target[i]);
279-
goto unlock_and_fail;
276+
goto done;
280277
}
281278
if (process(walker, lookup_unknown_object(&sha1[20 * i])))
282-
goto unlock_and_fail;
279+
goto done;
283280
}
284281

285282
if (loop(walker))
286-
goto unlock_and_fail;
287-
283+
goto done;
284+
if (!write_ref) {
285+
ret = 0;
286+
goto done;
287+
}
288288
if (write_ref_log_details) {
289289
msg = xmalloc(strlen(write_ref_log_details) + 12);
290290
sprintf(msg, "fetch from %s", write_ref_log_details);
291291
} else {
292292
msg = NULL;
293293
}
294294
for (i = 0; i < targets; i++) {
295-
if (!write_ref || !write_ref[i])
295+
if (!write_ref[i])
296296
continue;
297-
ret = write_ref_sha1(lock[i], &sha1[20 * i], msg ? msg : "fetch (unknown)");
298-
lock[i] = NULL;
299-
if (ret)
300-
goto unlock_and_fail;
297+
strbuf_reset(&refname);
298+
strbuf_addf(&refname, "refs/%s", write_ref[i]);
299+
if (ref_transaction_update(transaction, refname.buf,
300+
&sha1[20 * i], NULL, 0, 0,
301+
&err)) {
302+
error("%s", err.buf);
303+
goto done;
304+
}
305+
}
306+
if (ref_transaction_commit(transaction,
307+
msg ? msg : "fetch (unknown)",
308+
&err)) {
309+
error("%s", err.buf);
310+
goto done;
301311
}
302-
free(msg);
303-
304-
return 0;
305312

306-
unlock_and_fail:
307-
for (i = 0; i < targets; i++)
308-
if (lock[i])
309-
unlock_ref(lock[i]);
313+
ret = 0;
310314

311-
return -1;
315+
done:
316+
ref_transaction_free(transaction);
317+
free(msg);
318+
free(sha1);
319+
strbuf_release(&err);
320+
strbuf_release(&refname);
321+
return ret;
312322
}
313323

314324
void walker_free(struct walker *walker)

0 commit comments

Comments
 (0)