git/get: keep sending what we have until we get an ack
Git9 was sloppy about telling git what commits we have. We would list the commits at the tip of the branch, but not walk down it, which means we would request too much data if our local branches were ahead of the remote. This patch changes that, sending the tips *and* the first 256 commits after them, so that git can produce a better pack for us, with fewer redundant commits.
This commit is contained in:
parent
4eeefed7b0
commit
bb33663b40
4 changed files with 76 additions and 28 deletions
|
@ -177,17 +177,35 @@ fail(char *pack, char *idx, char *msg, ...)
|
||||||
exits(buf);
|
exits(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
enqueueparent(Objq *q, Object *o)
|
||||||
|
{
|
||||||
|
Object *p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(o->type != GCommit)
|
||||||
|
return;
|
||||||
|
for(i = 0; i < o->commit->nparent; i++){
|
||||||
|
if((p = readobject(o->commit->parent[i])) == nil)
|
||||||
|
continue;
|
||||||
|
qput(q, p, 0);
|
||||||
|
unref(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
fetchpack(Conn *c)
|
fetchpack(Conn *c)
|
||||||
{
|
{
|
||||||
char buf[Pktmax], *sp[3], *ep;
|
char buf[Pktmax], *sp[3], *ep;
|
||||||
char *packtmp, *idxtmp, **ref;
|
char *packtmp, *idxtmp, **ref, *caps;
|
||||||
Hash h, *have, *want;
|
Hash h, *have, *want;
|
||||||
int nref, refsz, first;
|
int nref, refsz, first, nsent;
|
||||||
int i, n, l, req, pfd;
|
int i, l, n, req, pfd;
|
||||||
vlong packsz;
|
vlong packsz;
|
||||||
Objset hadobj;
|
Objset hadobj;
|
||||||
Object *o;
|
Object *o;
|
||||||
|
Objq haveq;
|
||||||
|
Qelt e;
|
||||||
|
|
||||||
nref = 0;
|
nref = 0;
|
||||||
refsz = 16;
|
refsz = 16;
|
||||||
|
@ -234,6 +252,7 @@ fetchpack(Conn *c)
|
||||||
if(writephase(c) == -1)
|
if(writephase(c) == -1)
|
||||||
sysfatal("write: %r");
|
sysfatal("write: %r");
|
||||||
req = 0;
|
req = 0;
|
||||||
|
caps = " multi_ack";
|
||||||
for(i = 0; i < nref; i++){
|
for(i = 0; i < nref; i++){
|
||||||
if(hasheq(&have[i], &want[i]))
|
if(hasheq(&have[i], &want[i]))
|
||||||
continue;
|
continue;
|
||||||
|
@ -241,30 +260,58 @@ fetchpack(Conn *c)
|
||||||
unref(o);
|
unref(o);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
n = snprint(buf, sizeof(buf), "want %H\n", want[i]);
|
if(fmtpkt(c, "want %H%s\n", want[i], caps) == -1)
|
||||||
if(writepkt(c, buf, n) == -1)
|
|
||||||
sysfatal("could not send want for %H", want[i]);
|
sysfatal("could not send want for %H", want[i]);
|
||||||
|
caps = "";
|
||||||
req = 1;
|
req = 1;
|
||||||
}
|
}
|
||||||
flushpkt(c);
|
flushpkt(c);
|
||||||
|
|
||||||
|
nsent = 0;
|
||||||
|
qinit(&haveq);
|
||||||
osinit(&hadobj);
|
osinit(&hadobj);
|
||||||
|
/*
|
||||||
|
* We know we have these objects, and we want to make sure that
|
||||||
|
* they end up at the front of the queue. Send the 'have lines'
|
||||||
|
* first, and then enqueue their parents for a second round of
|
||||||
|
* sends.
|
||||||
|
*/
|
||||||
for(i = 0; i < nref; i++){
|
for(i = 0; i < nref; i++){
|
||||||
if(hasheq(&have[i], &Zhash) || oshas(&hadobj, have[i]))
|
if(hasheq(&have[i], &Zhash) || oshas(&hadobj, have[i]))
|
||||||
continue;
|
continue;
|
||||||
if((o = readobject(have[i])) == nil)
|
if((o = readobject(have[i])) == nil)
|
||||||
sysfatal("missing object we should have: %H", have[i]);
|
sysfatal("missing object we should have: %H", have[i]);
|
||||||
|
if(fmtpkt(c, "have %H", o->hash) == -1)
|
||||||
|
sysfatal("write: %r");
|
||||||
|
enqueueparent(&haveq, o);
|
||||||
osadd(&hadobj, o);
|
osadd(&hadobj, o);
|
||||||
unref(o);
|
unref(o);
|
||||||
n = snprint(buf, sizeof(buf), "have %H\n", have[i]);
|
}
|
||||||
if(writepkt(c, buf, n + 1) == -1)
|
/*
|
||||||
sysfatal("could not send have for %H", have[i]);
|
* While we could short circuit this and check if upstream has
|
||||||
|
* acked our objects, for the first 256 haves, this is simple
|
||||||
|
* enough.
|
||||||
|
*
|
||||||
|
* Also, doing multiple rounds of reference discovery breaks
|
||||||
|
* when using smart http.
|
||||||
|
*/
|
||||||
|
while(req && qpop(&haveq, &e) && nsent < 256){
|
||||||
|
if(oshas(&hadobj, e.o->hash))
|
||||||
|
continue;
|
||||||
|
if((o = readobject(e.o->hash)) == nil)
|
||||||
|
sysfatal("missing object we should have: %H", have[i]);
|
||||||
|
if(fmtpkt(c, "have %H", o->hash) == -1)
|
||||||
|
sysfatal("write: %r");
|
||||||
|
enqueueparent(&haveq, o);
|
||||||
|
osadd(&hadobj, o);
|
||||||
|
unref(o);
|
||||||
|
nsent++;
|
||||||
}
|
}
|
||||||
osclear(&hadobj);
|
osclear(&hadobj);
|
||||||
|
qclear(&haveq);
|
||||||
if(!req)
|
if(!req)
|
||||||
flushpkt(c);
|
flushpkt(c);
|
||||||
|
if(fmtpkt(c, "done\n") == -1)
|
||||||
n = snprint(buf, sizeof(buf), "done\n");
|
|
||||||
if(writepkt(c, buf, n) == -1)
|
|
||||||
sysfatal("write: %r");
|
sysfatal("write: %r");
|
||||||
if(!req)
|
if(!req)
|
||||||
goto showrefs;
|
goto showrefs;
|
||||||
|
@ -298,9 +345,9 @@ fetchpack(Conn *c)
|
||||||
if(strncmp(buf, "PACK", 4) == 0)
|
if(strncmp(buf, "PACK", 4) == 0)
|
||||||
break;
|
break;
|
||||||
l = strtol(buf, &ep, 16);
|
l = strtol(buf, &ep, 16);
|
||||||
if(l == 0 || ep != buf + 4)
|
if(ep != buf + 4)
|
||||||
sysfatal("fetch packfile: junk pktline");
|
sysfatal("fetch packfile: junk pktline");
|
||||||
if(readn(c->rfd, buf, l) != l)
|
if(readn(c->rfd, buf, l-4) != l-4)
|
||||||
sysfatal("fetch packfile: short read");
|
sysfatal("fetch packfile: short read");
|
||||||
}
|
}
|
||||||
if(write(pfd, "PACK", 4) != 4)
|
if(write(pfd, "PACK", 4) != 4)
|
||||||
|
|
|
@ -313,6 +313,7 @@ Delta* deltify(Object*, Dtab*, int*);
|
||||||
/* proto handling */
|
/* proto handling */
|
||||||
int readpkt(Conn*, char*, int);
|
int readpkt(Conn*, char*, int);
|
||||||
int writepkt(Conn*, char*, int);
|
int writepkt(Conn*, char*, int);
|
||||||
|
int fmtpkt(Conn*, char*, ...);
|
||||||
int flushpkt(Conn*);
|
int flushpkt(Conn*);
|
||||||
void initconn(Conn*, int, int);
|
void initconn(Conn*, int, int);
|
||||||
int gitconnect(Conn *, char *, char *);
|
int gitconnect(Conn *, char *, char *);
|
||||||
|
|
|
@ -93,6 +93,20 @@ writepkt(Conn *c, char *buf, int nbuf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fmtpkt(Conn *c, char *fmt, ...)
|
||||||
|
{
|
||||||
|
char pkt[Pktmax];
|
||||||
|
va_list ap;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
va_start(ap, fmt);
|
||||||
|
n = vsnprint(pkt, sizeof(pkt), fmt, ap);
|
||||||
|
n = writepkt(c, pkt, n);
|
||||||
|
va_end(ap);
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
flushpkt(Conn *c)
|
flushpkt(Conn *c)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,20 +8,6 @@
|
||||||
char *pathpfx = nil;
|
char *pathpfx = nil;
|
||||||
int allowwrite;
|
int allowwrite;
|
||||||
|
|
||||||
int
|
|
||||||
fmtpkt(Conn *c, char *fmt, ...)
|
|
||||||
{
|
|
||||||
char pkt[Pktmax];
|
|
||||||
va_list ap;
|
|
||||||
int n;
|
|
||||||
|
|
||||||
va_start(ap, fmt);
|
|
||||||
n = vsnprint(pkt, sizeof(pkt), fmt, ap);
|
|
||||||
n = writepkt(c, pkt, n);
|
|
||||||
va_end(ap);
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
int
|
||||||
showrefs(Conn *c)
|
showrefs(Conn *c)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue