@matheusbsbs / matheus-bagliano / commits / 603960b50e
Fork 0

promisor-remote: remove fetch_if_missing=0

Commit 6462d5eb9a ("fetch: remove fetch_if_missing=0", 2019-11-08) strove to remove the need for fetch_if_missing=0 from the fetching mechanism, so it is plausible to attempt removing fetch_if_missing=0 from the lazy-fetching mechanism in promisor-remote as well. But doing so reveals a bug - when the server does not send an object pointed to by a tag object, an infinite loop occurs: Git attempts to fetch the missing object, which causes a deferencing of all refs (for negotiation), which causes a lazy fetch of that missing object, and so on. This bug is because of unnecessary use of the fetch negotiator during lazy fetching - it is not used after initialization, but it is still initialized (which causes the dereferencing of all refs). Thus, when the negotiator is not used during fetching, refrain from initializing it. Then, remove fetch_if_missing from promisor-remote. Signed-off-by: Jonathan Tan <jonathantanmy@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jonathan Tan committed Nov 12, 2019 at 16:34 UTC 603960b50edeb1f0afa694f2f0283e553c031129
2 files changed +32 -17
fetch-pack.c
+32 -14
@@ -896,8 +896,15 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
896 struct object_id oid;
897 const char *agent_feature;
898 int agent_len;
899 - struct fetch_negotiator negotiator;
900 - fetch_negotiator_init(r, &negotiator);
899 + struct fetch_negotiator negotiator_alloc;
900 + struct fetch_negotiator *negotiator;
901 +
902 + if (args->no_dependents) {
903 + negotiator = NULL;
904 + } else {
905 + negotiator = &negotiator_alloc;
906 + fetch_negotiator_init(r, negotiator);
907 + }
908
909 sort_ref_list(&ref, ref_compare_name);
910 QSORT(sought, nr_sought, cmp_ref_by_name);
@@ -984,7 +991,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
991 die(_("Server does not support --deepen"));
992
993 if (!args->no_dependents) {
987 - mark_complete_and_common_ref(&negotiator, args, &ref);
994 + mark_complete_and_common_ref(negotiator, args, &ref);
995 filter_refs(args, &ref, sought, nr_sought);
996 if (everything_local(args, &ref)) {
997 packet_flush(fd[1]);
@@ -993,7 +1000,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
1000 } else {
1001 filter_refs(args, &ref, sought, nr_sought);
1002 }
996 - if (find_common(&negotiator, args, fd, &oid, ref) < 0)
1003 + if (find_common(negotiator, args, fd, &oid, ref) < 0)
1004 if (!args->keep_pack)
1005 /* When cloning, it is not unusual to have
1006 * no common commit.
@@ -1013,7 +1020,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
1020 die(_("git fetch-pack: fetch failed."));
1021
1022 all_done:
1016 - negotiator.release(&negotiator);
1023 + if (negotiator)
1024 + negotiator->release(negotiator);
1025 return ref;
1026 }
1027
@@ -1231,7 +1239,8 @@ static int process_acks(struct fetch_negotiator *negotiator,
1239 struct commit *commit;
1240 oidset_insert(common, &oid);
1241 commit = lookup_commit(the_repository, &oid);
1234 - negotiator->ack(negotiator, commit);
1242 + if (negotiator)
1243 + negotiator->ack(negotiator, commit);
1244 }
1245 continue;
1246 }
@@ -1383,8 +1392,16 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1392 struct packet_reader reader;
1393 int in_vain = 0, negotiation_started = 0;
1394 int haves_to_send = INITIAL_FLUSH;
1386 - struct fetch_negotiator negotiator;
1387 - fetch_negotiator_init(r, &negotiator);
1395 + struct fetch_negotiator negotiator_alloc;
1396 + struct fetch_negotiator *negotiator;
1397 +
1398 + if (args->no_dependents) {
1399 + negotiator = NULL;
1400 + } else {
1401 + negotiator = &negotiator_alloc;
1402 + fetch_negotiator_init(r, negotiator);
1403 + }
1404 +
1405 packet_reader_init(&reader, fd[0], NULL, 0,
1406 PACKET_READ_CHOMP_NEWLINE |
1407 PACKET_READ_DIE_ON_ERR_PACKET);
@@ -1408,15 +1425,15 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1425
1426 /* Filter 'ref' by 'sought' and those that aren't local */
1427 if (!args->no_dependents) {
1411 - mark_complete_and_common_ref(&negotiator, args, &ref);
1428 + mark_complete_and_common_ref(negotiator, args, &ref);
1429 filter_refs(args, &ref, sought, nr_sought);
1430 if (everything_local(args, &ref))
1431 state = FETCH_DONE;
1432 else
1433 state = FETCH_SEND_REQUEST;
1434
1418 - mark_tips(&negotiator, args->negotiation_tips);
1419 - for_each_cached_alternate(&negotiator,
1435 + mark_tips(negotiator, args->negotiation_tips);
1436 + for_each_cached_alternate(negotiator,
1437 insert_one_alternate_object);
1438 } else {
1439 filter_refs(args, &ref, sought, nr_sought);
@@ -1430,7 +1447,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1447 "negotiation_v2",
1448 the_repository);
1449 }
1433 - if (send_fetch_request(&negotiator, fd[1], args, ref,
1450 + if (send_fetch_request(negotiator, fd[1], args, ref,
1451 &common,
1452 &haves_to_send, &in_vain,
1453 reader.use_sideband))
@@ -1440,7 +1457,7 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1457 break;
1458 case FETCH_PROCESS_ACKS:
1459 /* Process ACKs/NAKs */
1443 - switch (process_acks(&negotiator, &reader, &common)) {
1460 + switch (process_acks(negotiator, &reader, &common)) {
1461 case 2:
1462 state = FETCH_GET_PACK;
1463 break;
@@ -1475,7 +1492,8 @@ static struct ref *do_fetch_pack_v2(struct fetch_pack_args *args,
1492 }
1493 }
1494
1478 - negotiator.release(&negotiator);
1495 + if (negotiator)
1496 + negotiator->release(negotiator);
1497 oidset_clear(&common);
1498 return ref;
1499 }
promisor-remote.c
-3
@@ -16,10 +16,8 @@ static int fetch_refs(const char *remote_name, struct ref *ref)
16 {
17 struct remote *remote;
18 struct transport *transport;
19 - int original_fetch_if_missing = fetch_if_missing;
19 int res;
20
22 - fetch_if_missing = 0;
21 remote = remote_get(remote_name);
22 if (!remote->url[0])
23 die(_("Remote with no URL"));
@@ -28,7 +26,6 @@ static int fetch_refs(const char *remote_name, struct ref *ref)
26 transport_set_option(transport, TRANS_OPT_FROM_PROMISOR, "1");
27 transport_set_option(transport, TRANS_OPT_NO_DEPENDENTS, "1");
28 res = transport_fetch_refs(transport, ref);
31 - fetch_if_missing = original_fetch_if_missing;
29
30 return res;
31 }