The MAX_IN_VAIN mechanism was introduced in commit f061e5f ("fetch-pack:
give up after getting too many "ack continue"", 2006-05-24) to stop ref
negotiation if a number of consecutive "have"s have been sent with no
corresponding new acks. A use case (as described in that commit) is the
scenario in which the local repository has more roots than the remote
repository.

However, during a negotiation in which stateless RPCs are used,
MAX_IN_VAIN will (almost) never trigger (in the more-roots scenario
above and others) because in each new request, the client has to inform
the server of objects it already has and knows the server has (to remind
the server of the state), which the server then acks.

Make fetch-pack only consider novel acks (acks for objects for which the
client has never received an ack before in this session) as new acks for
the purpose of MAX_IN_VAIN.

Signed-off-by: Jonathan Tan <jonathanta...@google.com>
---
 fetch-pack.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/fetch-pack.c b/fetch-pack.c
index 85e77af..1141e3c 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -428,10 +428,18 @@ static int find_common(struct fetch_pack_args *args,
                                                const char *hex = 
sha1_to_hex(result_sha1);
                                                packet_buf_write(&req_buf, 
"have %s\n", hex);
                                                state_len = req_buf.len;
-                                       }
+                                               /*
+                                                * Reset in_vain because this
+                                                * ack is a novel ack (that is,
+                                                * an ack for this commit has
+                                                * not been seen).
+                                                */
+                                               in_vain = 0;
+                                       } else if (!args->stateless_rpc
+                                                  || ack != ACK_common)
+                                               in_vain = 0;
                                        mark_common(commit, 0, 1);
                                        retval = 0;
-                                       in_vain = 0;
                                        got_continue = 1;
                                        if (ack == ACK_ready) {
                                                clear_prio_queue(&rev_list);
-- 
2.8.0.rc3.226.g39d4020

Reply via email to